summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/.gitignore2
-rw-r--r--lib/spack/docs/Makefile10
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/__init__.py17
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/breadcrumbs.html23
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/footer.html40
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/layout.html181
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/layout_old.html205
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/search.html50
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/searchbox.html9
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css2
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map7
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css5
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map7
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otfbin62856 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttfbin47064 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata.ttfbin63184 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttfbin82368 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttfbin81980 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttfbin36596 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttfbin36276 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eotbin38205 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg414
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttfbin80652 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woffbin44432 -> 0 bytes
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js4
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/static/js/theme.js113
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/theme.conf9
-rw-r--r--lib/spack/docs/_themes/sphinx_rtd_theme/versions.html37
-rw-r--r--lib/spack/docs/basic_usage.rst118
-rw-r--r--lib/spack/docs/binary_caches.rst7
-rw-r--r--lib/spack/docs/build_settings.rst104
-rw-r--r--lib/spack/docs/build_systems.rst89
-rw-r--r--lib/spack/docs/build_systems/Autoconf-automake-process.svg840
-rw-r--r--lib/spack/docs/build_systems/autotoolspackage.rst305
-rw-r--r--lib/spack/docs/build_systems/cmakepackage.rst279
-rw-r--r--lib/spack/docs/build_systems/cudapackage.rst43
-rw-r--r--lib/spack/docs/build_systems/custompackage.rst209
-rw-r--r--lib/spack/docs/build_systems/intelpackage.rst1060
-rw-r--r--lib/spack/docs/build_systems/makefilepackage.rst309
-rw-r--r--lib/spack/docs/build_systems/mesonpackage.rst90
-rw-r--r--lib/spack/docs/build_systems/octavepackage.rst52
-rw-r--r--lib/spack/docs/build_systems/perlpackage.rst212
-rw-r--r--lib/spack/docs/build_systems/pythonpackage.rst747
-rw-r--r--lib/spack/docs/build_systems/qmakepackage.rst116
-rw-r--r--lib/spack/docs/build_systems/rpackage.rst346
-rw-r--r--lib/spack/docs/build_systems/rubypackage.rst16
-rw-r--r--lib/spack/docs/build_systems/sconspackage.rst306
-rw-r--r--lib/spack/docs/build_systems/wafpackage.rst129
-rw-r--r--lib/spack/docs/command_index.in14
-rw-r--r--lib/spack/docs/conf.py89
-rw-r--r--lib/spack/docs/config_yaml.rst45
-rw-r--r--lib/spack/docs/configuration.rst433
-rw-r--r--lib/spack/docs/contribution_guide.rst123
-rw-r--r--lib/spack/docs/developer_guide.rst9
-rw-r--r--lib/spack/docs/docker_for_developers.rst41
-rw-r--r--lib/spack/docs/features.rst7
-rw-r--r--lib/spack/docs/getting_started.rst161
-rw-r--r--lib/spack/docs/index.rst7
-rw-r--r--lib/spack/docs/known_issues.rst57
-rw-r--r--lib/spack/docs/mirrors.rst21
-rw-r--r--lib/spack/docs/module_file_support.rst99
-rw-r--r--lib/spack/docs/package_list.rst17
-rw-r--r--lib/spack/docs/packaging_guide.rst397
-rw-r--r--lib/spack/docs/repositories.rst13
-rw-r--r--lib/spack/docs/requirements.txt3
-rw-r--r--lib/spack/docs/tutorial.rst34
-rw-r--r--lib/spack/docs/tutorial/examples/0.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/1.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/2.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/3.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/4.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/5.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Autotools/0.package.py29
-rw-r--r--lib/spack/docs/tutorial/examples/Autotools/1.package.py29
-rw-r--r--lib/spack/docs/tutorial/examples/Cmake/0.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Cmake/1.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Cmake/2.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Makefile/0.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Makefile/1.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Makefile/2.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/Makefile/3.package.py39
-rw-r--r--lib/spack/docs/tutorial/examples/PyPackage/0.package.py27
-rw-r--r--lib/spack/docs/tutorial/examples/PyPackage/1.package.py27
-rw-r--r--lib/spack/docs/tutorial_advanced_packaging.rst606
-rw-r--r--lib/spack/docs/tutorial_basics.rst1419
-rw-r--r--lib/spack/docs/tutorial_buildsystems.rst108
-rw-r--r--lib/spack/docs/tutorial_configuration.rst448
-rw-r--r--lib/spack/docs/tutorial_environments.rst815
-rw-r--r--lib/spack/docs/tutorial_modules.rst693
-rw-r--r--lib/spack/docs/tutorial_packaging.rst246
-rw-r--r--lib/spack/docs/workflows.rst103
-rwxr-xr-xlib/spack/env/cc424
-rw-r--r--lib/spack/external/__init__.py147
-rw-r--r--lib/spack/external/_pytest/AUTHORS141
-rw-r--r--lib/spack/external/_pytest/LICENSE2
-rw-r--r--lib/spack/external/_pytest/README.rst102
-rw-r--r--lib/spack/external/_pytest/__init__.py10
-rw-r--r--lib/spack/external/_pytest/_argcomplete.py14
-rw-r--r--lib/spack/external/_pytest/_code/__init__.py1
-rw-r--r--lib/spack/external/_pytest/_code/_py2traceback.py6
-rw-r--r--lib/spack/external/_pytest/_code/code.py141
-rw-r--r--lib/spack/external/_pytest/_code/source.py66
-rw-r--r--lib/spack/external/_pytest/_pluggy.py2
-rw-r--r--lib/spack/external/_pytest/_version.py4
-rw-r--r--lib/spack/external/_pytest/assertion/__init__.py26
-rw-r--r--lib/spack/external/_pytest/assertion/rewrite.py61
-rw-r--r--lib/spack/external/_pytest/assertion/truncate.py102
-rw-r--r--lib/spack/external/_pytest/assertion/util.py41
-rwxr-xr-x[-rw-r--r--]lib/spack/external/_pytest/cacheprovider.py71
-rw-r--r--lib/spack/external/_pytest/capture.py102
-rw-r--r--lib/spack/external/_pytest/compat.py140
-rw-r--r--lib/spack/external/_pytest/config.py320
-rw-r--r--lib/spack/external/_pytest/debugging.py41
-rw-r--r--lib/spack/external/_pytest/deprecated.py22
-rw-r--r--lib/spack/external/_pytest/doctest.py73
-rw-r--r--lib/spack/external/_pytest/fixtures.py229
-rw-r--r--lib/spack/external/_pytest/freeze_support.py4
-rw-r--r--lib/spack/external/_pytest/helpconfig.py82
-rw-r--r--lib/spack/external/_pytest/hookspec.py157
-rw-r--r--lib/spack/external/_pytest/junitxml.py74
-rw-r--r--lib/spack/external/_pytest/main.py245
-rw-r--r--lib/spack/external/_pytest/mark.py291
-rw-r--r--lib/spack/external/_pytest/monkeypatch.py21
-rw-r--r--lib/spack/external/_pytest/nodes.py37
-rw-r--r--lib/spack/external/_pytest/nose.py24
-rw-r--r--lib/spack/external/_pytest/outcomes.py140
-rw-r--r--lib/spack/external/_pytest/pastebin.py10
-rw-r--r--lib/spack/external/_pytest/pytester.py184
-rw-r--r--lib/spack/external/_pytest/python.py807
-rw-r--r--lib/spack/external/_pytest/python_api.py626
-rw-r--r--lib/spack/external/_pytest/recwarn.py133
-rw-r--r--lib/spack/external/_pytest/resultlog.py18
-rw-r--r--lib/spack/external/_pytest/runner.py224
-rw-r--r--lib/spack/external/_pytest/setuponly.py2
-rw-r--r--lib/spack/external/_pytest/setupplan.py2
-rw-r--r--lib/spack/external/_pytest/skipping.py147
-rw-r--r--lib/spack/external/_pytest/terminal.py193
-rw-r--r--lib/spack/external/_pytest/tmpdir.py8
-rw-r--r--lib/spack/external/_pytest/unittest.py80
-rw-r--r--lib/spack/external/_pytest/vendored_packages/pluggy.py2
-rw-r--r--lib/spack/external/_pytest/warnings.py94
-rw-r--r--lib/spack/external/argparse.py91
-rw-r--r--lib/spack/external/ctest_log_parser.py270
-rw-r--r--lib/spack/external/distro.py63
-rw-r--r--lib/spack/external/jinja2/AUTHORS33
-rw-r--r--lib/spack/external/jinja2/LICENSE31
-rw-r--r--lib/spack/external/jinja2/README.rst51
-rw-r--r--lib/spack/external/jinja2/__init__.py5
-rw-r--r--lib/spack/external/jinja2/_identifier.py2
-rw-r--r--lib/spack/external/jinja2/_stringdefs.py71
-rw-r--r--lib/spack/external/jinja2/asyncsupport.py14
-rw-r--r--lib/spack/external/jinja2/bccache.py2
-rw-r--r--lib/spack/external/jinja2/compiler.py88
-rw-r--r--lib/spack/external/jinja2/debug.py2
-rw-r--r--lib/spack/external/jinja2/defaults.py6
-rw-r--r--lib/spack/external/jinja2/environment.py2
-rw-r--r--lib/spack/external/jinja2/ext.py20
-rw-r--r--lib/spack/external/jinja2/filters.py203
-rw-r--r--lib/spack/external/jinja2/idtracking.py25
-rw-r--r--lib/spack/external/jinja2/lexer.py56
-rw-r--r--lib/spack/external/jinja2/nativetypes.py220
-rw-r--r--lib/spack/external/jinja2/nodes.py94
-rw-r--r--lib/spack/external/jinja2/parser.py33
-rw-r--r--lib/spack/external/jinja2/runtime.py54
-rw-r--r--lib/spack/external/jinja2/sandbox.py2
-rw-r--r--lib/spack/external/jinja2/tests.py54
-rw-r--r--lib/spack/external/jinja2/utils.py25
-rw-r--r--lib/spack/external/ordereddict_backport.py278
-rw-r--r--lib/spack/external/py/AUTHORS24
-rw-r--r--lib/spack/external/py/LICENSE19
-rw-r--r--lib/spack/external/py/README.rst21
-rw-r--r--lib/spack/external/py/__init__.py6
-rw-r--r--lib/spack/external/py/_code/code.py2
-rw-r--r--lib/spack/external/py/_path/common.py14
-rw-r--r--lib/spack/external/py/_path/local.py14
-rw-r--r--lib/spack/external/py/_path/svnurl.py2
-rw-r--r--lib/spack/external/py/_path/svnwc.py2
-rw-r--r--lib/spack/external/py26/ordereddict.py127
-rw-r--r--lib/spack/external/pytest.py94
-rw-r--r--lib/spack/external/ruamel/__init__.py0
-rw-r--r--lib/spack/external/ruamel/yaml/.ruamel/__init__.py2
-rw-r--r--lib/spack/external/ruamel/yaml/LICENSE21
-rw-r--r--lib/spack/external/ruamel/yaml/README.rst38
-rw-r--r--lib/spack/external/ruamel/yaml/__init__.py85
-rw-r--r--lib/spack/external/ruamel/yaml/comments.py481
-rw-r--r--lib/spack/external/ruamel/yaml/compat.py120
-rw-r--r--lib/spack/external/ruamel/yaml/composer.py (renamed from lib/spack/external/yaml/lib/yaml/composer.py)95
-rw-r--r--lib/spack/external/ruamel/yaml/configobjwalker.py9
-rw-r--r--lib/spack/external/ruamel/yaml/constructor.py1167
-rw-r--r--lib/spack/external/ruamel/yaml/dumper.py102
-rw-r--r--lib/spack/external/ruamel/yaml/emitter.py (renamed from lib/spack/external/yaml/lib/yaml/emitter.py)340
-rw-r--r--lib/spack/external/ruamel/yaml/error.py (renamed from lib/spack/external/yaml/lib/yaml/error.py)36
-rw-r--r--lib/spack/external/ruamel/yaml/events.py (renamed from lib/spack/external/yaml/lib3/yaml/events.py)68
-rw-r--r--lib/spack/external/ruamel/yaml/loader.py61
-rw-r--r--lib/spack/external/ruamel/yaml/main.py (renamed from lib/spack/external/yaml/lib3/yaml/__init__.py)189
-rw-r--r--lib/spack/external/ruamel/yaml/nodes.py86
-rw-r--r--lib/spack/external/ruamel/yaml/parser.py (renamed from lib/spack/external/yaml/lib/yaml/parser.py)242
-rw-r--r--lib/spack/external/ruamel/yaml/reader.py (renamed from lib/spack/external/yaml/lib3/yaml/reader.py)99
-rw-r--r--lib/spack/external/ruamel/yaml/representer.py888
-rw-r--r--lib/spack/external/ruamel/yaml/resolver.py397
-rw-r--r--lib/spack/external/ruamel/yaml/scalarstring.py60
-rw-r--r--lib/spack/external/ruamel/yaml/scanner.py (renamed from lib/spack/external/yaml/lib/yaml/scanner.py)524
-rw-r--r--lib/spack/external/ruamel/yaml/serializer.py178
-rw-r--r--lib/spack/external/ruamel/yaml/setup.cfg5
-rw-r--r--lib/spack/external/ruamel/yaml/tokens.py195
-rw-r--r--lib/spack/external/ruamel/yaml/util.py139
-rw-r--r--lib/spack/external/six.py11
-rw-r--r--lib/spack/external/yaml/LICENSE19
-rw-r--r--lib/spack/external/yaml/README35
-rw-r--r--lib/spack/external/yaml/lib/yaml/__init__.py315
-rw-r--r--lib/spack/external/yaml/lib/yaml/constructor.py675
-rw-r--r--lib/spack/external/yaml/lib/yaml/cyaml.py85
-rw-r--r--lib/spack/external/yaml/lib/yaml/dumper.py62
-rw-r--r--lib/spack/external/yaml/lib/yaml/events.py86
-rw-r--r--lib/spack/external/yaml/lib/yaml/loader.py40
-rw-r--r--lib/spack/external/yaml/lib/yaml/nodes.py49
-rw-r--r--lib/spack/external/yaml/lib/yaml/reader.py190
-rw-r--r--lib/spack/external/yaml/lib/yaml/representer.py486
-rw-r--r--lib/spack/external/yaml/lib/yaml/resolver.py227
-rw-r--r--lib/spack/external/yaml/lib/yaml/serializer.py111
-rw-r--r--lib/spack/external/yaml/lib/yaml/tokens.py104
-rw-r--r--lib/spack/external/yaml/lib3/yaml/composer.py139
-rw-r--r--lib/spack/external/yaml/lib3/yaml/constructor.py686
-rw-r--r--lib/spack/external/yaml/lib3/yaml/cyaml.py85
-rw-r--r--lib/spack/external/yaml/lib3/yaml/dumper.py62
-rw-r--r--lib/spack/external/yaml/lib3/yaml/emitter.py1137
-rw-r--r--lib/spack/external/yaml/lib3/yaml/error.py75
-rw-r--r--lib/spack/external/yaml/lib3/yaml/loader.py40
-rw-r--r--lib/spack/external/yaml/lib3/yaml/nodes.py49
-rw-r--r--lib/spack/external/yaml/lib3/yaml/parser.py589
-rw-r--r--lib/spack/external/yaml/lib3/yaml/representer.py387
-rw-r--r--lib/spack/external/yaml/lib3/yaml/resolver.py227
-rw-r--r--lib/spack/external/yaml/lib3/yaml/scanner.py1444
-rw-r--r--lib/spack/external/yaml/lib3/yaml/serializer.py111
-rw-r--r--lib/spack/external/yaml/lib3/yaml/tokens.py104
-rw-r--r--lib/spack/llnl/__init__.py26
-rw-r--r--lib/spack/llnl/util/__init__.py26
-rw-r--r--lib/spack/llnl/util/argparsewriter.py203
-rw-r--r--lib/spack/llnl/util/filesystem.py348
-rw-r--r--lib/spack/llnl/util/lang.py183
-rw-r--r--lib/spack/llnl/util/link_tree.py170
-rw-r--r--lib/spack/llnl/util/lock.py284
-rw-r--r--lib/spack/llnl/util/multiproc.py (renamed from lib/spack/spack/util/multiproc.py)33
-rw-r--r--lib/spack/llnl/util/tty/__init__.py33
-rw-r--r--lib/spack/llnl/util/tty/colify.py31
-rw-r--r--lib/spack/llnl/util/tty/color.py58
-rw-r--r--lib/spack/llnl/util/tty/log.py34
-rw-r--r--lib/spack/spack/__init__.py269
-rw-r--r--lib/spack/spack/abi.py33
-rw-r--r--lib/spack/spack/architecture.py57
-rw-r--r--lib/spack/spack/binary_distribution.py340
-rw-r--r--lib/spack/spack/build_environment.py356
-rw-r--r--lib/spack/spack/build_systems/README-intel.rst660
-rw-r--r--lib/spack/spack/build_systems/__init__.py26
-rw-r--r--lib/spack/spack/build_systems/aspell_dict.py41
-rw-r--r--lib/spack/spack/build_systems/autotools.py46
-rw-r--r--lib/spack/spack/build_systems/cmake.py51
-rw-r--r--lib/spack/spack/build_systems/cuda.py72
-rw-r--r--lib/spack/spack/build_systems/intel.py1283
-rw-r--r--lib/spack/spack/build_systems/makefile.py27
-rw-r--r--lib/spack/spack/build_systems/meson.py171
-rw-r--r--lib/spack/spack/build_systems/octave.py52
-rw-r--r--lib/spack/spack/build_systems/perl.py30
-rw-r--r--lib/spack/spack/build_systems/python.py115
-rw-r--r--lib/spack/spack/build_systems/qmake.py27
-rw-r--r--lib/spack/spack/build_systems/r.py27
-rw-r--r--lib/spack/spack/build_systems/scons.py27
-rw-r--r--lib/spack/spack/build_systems/waf.py27
-rw-r--r--lib/spack/spack/caches.py51
-rw-r--r--lib/spack/spack/cmd/__init__.py220
-rw-r--r--lib/spack/spack/cmd/activate.py50
-rw-r--r--lib/spack/spack/cmd/add.py33
-rw-r--r--lib/spack/spack/cmd/arch.py46
-rw-r--r--lib/spack/spack/cmd/blame.py34
-rw-r--r--lib/spack/spack/cmd/bootstrap.py46
-rw-r--r--lib/spack/spack/cmd/build.py29
-rw-r--r--lib/spack/spack/cmd/build_env.py59
-rw-r--r--lib/spack/spack/cmd/buildcache.py154
-rw-r--r--lib/spack/spack/cmd/cd.py34
-rw-r--r--lib/spack/spack/cmd/checksum.py33
-rw-r--r--lib/spack/spack/cmd/clean.py67
-rw-r--r--lib/spack/spack/cmd/clone.py33
-rw-r--r--lib/spack/spack/cmd/commands.py123
-rw-r--r--lib/spack/spack/cmd/common/__init__.py65
-rw-r--r--lib/spack/spack/cmd/common/arguments.py105
-rw-r--r--lib/spack/spack/cmd/compiler.py46
-rw-r--r--lib/spack/spack/cmd/compilers.py37
-rw-r--r--lib/spack/spack/cmd/concretize.py22
-rw-r--r--lib/spack/spack/cmd/config.py131
-rw-r--r--lib/spack/spack/cmd/configure.py31
-rw-r--r--lib/spack/spack/cmd/create.py109
-rw-r--r--lib/spack/spack/cmd/deactivate.py60
-rw-r--r--lib/spack/spack/cmd/debug.py35
-rw-r--r--lib/spack/spack/cmd/dependencies.py42
-rw-r--r--lib/spack/spack/cmd/dependents.py35
-rw-r--r--lib/spack/spack/cmd/diy.py56
-rw-r--r--lib/spack/spack/cmd/docs.py27
-rw-r--r--lib/spack/spack/cmd/edit.py82
-rw-r--r--lib/spack/spack/cmd/env.py404
-rw-r--r--lib/spack/spack/cmd/extensions.py48
-rw-r--r--lib/spack/spack/cmd/fetch.py37
-rw-r--r--lib/spack/spack/cmd/find.py121
-rw-r--r--lib/spack/spack/cmd/flake8.py48
-rw-r--r--lib/spack/spack/cmd/gpg.py38
-rw-r--r--lib/spack/spack/cmd/graph.py34
-rw-r--r--lib/spack/spack/cmd/help.py31
-rw-r--r--lib/spack/spack/cmd/info.py41
-rw-r--r--lib/spack/spack/cmd/install.py491
-rw-r--r--lib/spack/spack/cmd/license.py156
-rw-r--r--lib/spack/spack/cmd/list.py173
-rw-r--r--lib/spack/spack/cmd/load.py34
-rw-r--r--lib/spack/spack/cmd/location.py55
-rw-r--r--lib/spack/spack/cmd/log_parse.py63
-rw-r--r--lib/spack/spack/cmd/md5.py92
-rw-r--r--lib/spack/spack/cmd/mirror.py165
-rw-r--r--lib/spack/spack/cmd/module.py374
-rw-r--r--lib/spack/spack/cmd/modules/__init__.py335
-rw-r--r--lib/spack/spack/cmd/modules/dotkit.py19
-rw-r--r--lib/spack/spack/cmd/modules/lmod.py50
-rw-r--r--lib/spack/spack/cmd/modules/tcl.py19
-rw-r--r--lib/spack/spack/cmd/patch.py37
-rw-r--r--lib/spack/spack/cmd/pkg.py44
-rw-r--r--lib/spack/spack/cmd/providers.py77
-rw-r--r--lib/spack/spack/cmd/pydoc.py27
-rw-r--r--lib/spack/spack/cmd/python.py28
-rw-r--r--lib/spack/spack/cmd/reindex.py32
-rw-r--r--lib/spack/spack/cmd/remove.py39
-rw-r--r--lib/spack/spack/cmd/repo.py53
-rw-r--r--lib/spack/spack/cmd/restage.py29
-rw-r--r--lib/spack/spack/cmd/setup.py54
-rw-r--r--lib/spack/spack/cmd/sha256.py40
-rw-r--r--lib/spack/spack/cmd/spec.py58
-rw-r--r--lib/spack/spack/cmd/stage.py48
-rw-r--r--lib/spack/spack/cmd/test.py33
-rw-r--r--lib/spack/spack/cmd/uninstall.py312
-rw-r--r--lib/spack/spack/cmd/unload.py29
-rw-r--r--lib/spack/spack/cmd/unuse.py29
-rw-r--r--lib/spack/spack/cmd/url.py123
-rw-r--r--lib/spack/spack/cmd/use.py32
-rw-r--r--lib/spack/spack/cmd/versions.py53
-rw-r--r--lib/spack/spack/cmd/view.py57
-rw-r--r--lib/spack/spack/compiler.py124
-rw-r--r--lib/spack/spack/compilers/__init__.py79
-rw-r--r--lib/spack/spack/compilers/arm.py73
-rw-r--r--lib/spack/spack/compilers/cce.py27
-rw-r--r--lib/spack/spack/compilers/clang.py137
-rw-r--r--lib/spack/spack/compilers/gcc.py70
-rw-r--r--lib/spack/spack/compilers/intel.py43
-rw-r--r--lib/spack/spack/compilers/nag.py31
-rw-r--r--lib/spack/spack/compilers/pgi.py29
-rw-r--r--lib/spack/spack/compilers/xl.py43
-rw-r--r--lib/spack/spack/compilers/xl_r.py46
-rw-r--r--lib/spack/spack/concretize.py136
-rw-r--r--lib/spack/spack/config.py915
-rw-r--r--lib/spack/spack/database.py308
-rw-r--r--lib/spack/spack/dependency.py31
-rw-r--r--lib/spack/spack/directives.py117
-rw-r--r--lib/spack/spack/directory_layout.py118
-rw-r--r--lib/spack/spack/environment.py1291
-rw-r--r--lib/spack/spack/error.py39
-rw-r--r--lib/spack/spack/fetch_strategy.py384
-rw-r--r--lib/spack/spack/filesystem_view.py142
-rw-r--r--lib/spack/spack/graph.py31
-rw-r--r--lib/spack/spack/hooks/__init__.py39
-rw-r--r--lib/spack/spack/hooks/case_consistency.py110
-rw-r--r--lib/spack/spack/hooks/extensions.py34
-rw-r--r--lib/spack/spack/hooks/licensing.py136
-rw-r--r--lib/spack/spack/hooks/module_file_generation.py29
-rw-r--r--lib/spack/spack/hooks/permissions_setters.py45
-rw-r--r--lib/spack/spack/hooks/sbang.py31
-rw-r--r--lib/spack/spack/hooks/yaml_version_check.py36
-rw-r--r--lib/spack/spack/main.py450
-rw-r--r--lib/spack/spack/mirror.py49
-rw-r--r--lib/spack/spack/mixins.py194
-rw-r--r--lib/spack/spack/modules/__init__.py27
-rw-r--r--lib/spack/spack/modules/common.py54
-rw-r--r--lib/spack/spack/modules/dotkit.py32
-rw-r--r--lib/spack/spack/modules/lmod.py89
-rw-r--r--lib/spack/spack/modules/tcl.py34
-rw-r--r--lib/spack/spack/multimethod.py27
-rw-r--r--lib/spack/spack/operating_systems/__init__.py26
-rw-r--r--lib/spack/spack/operating_systems/cnk.py27
-rw-r--r--lib/spack/spack/operating_systems/cnl.py53
-rw-r--r--lib/spack/spack/operating_systems/cray_frontend.py29
-rw-r--r--lib/spack/spack/operating_systems/linux_distro.py27
-rw-r--r--lib/spack/spack/operating_systems/mac_os.py32
-rw-r--r--lib/spack/spack/package.py1083
-rw-r--r--lib/spack/spack/package_prefs.py130
-rw-r--r--lib/spack/spack/package_test.py27
-rw-r--r--lib/spack/spack/parse.py27
-rw-r--r--lib/spack/spack/patch.py30
-rw-r--r--lib/spack/spack/paths.py61
-rw-r--r--lib/spack/spack/pkgkit.py49
-rw-r--r--lib/spack/spack/platforms/__init__.py26
-rw-r--r--lib/spack/spack/platforms/bgq.py29
-rw-r--r--lib/spack/spack/platforms/cray.py45
-rw-r--r--lib/spack/spack/platforms/darwin.py29
-rw-r--r--lib/spack/spack/platforms/linux.py29
-rw-r--r--lib/spack/spack/platforms/test.py37
-rw-r--r--lib/spack/spack/provider_index.py33
-rw-r--r--lib/spack/spack/relocate.py248
-rw-r--r--lib/spack/spack/repo.py (renamed from lib/spack/spack/repository.py)311
-rw-r--r--lib/spack/spack/report.py267
-rw-r--r--lib/spack/spack/reporter.py21
-rw-r--r--lib/spack/spack/reporters/__init__.py4
-rw-r--r--lib/spack/spack/reporters/cdash.py199
-rw-r--r--lib/spack/spack/reporters/junit.py29
-rw-r--r--lib/spack/spack/resource.py27
-rw-r--r--lib/spack/spack/schema/__init__.py35
-rw-r--r--lib/spack/spack/schema/compilers.py100
-rw-r--r--lib/spack/spack/schema/config.py119
-rw-r--r--lib/spack/spack/schema/env.py57
-rw-r--r--lib/spack/spack/schema/merged.py40
-rw-r--r--lib/spack/spack/schema/mirrors.py55
-rw-r--r--lib/spack/spack/schema/modules.py321
-rw-r--r--lib/spack/spack/schema/packages.py155
-rw-r--r--lib/spack/spack/schema/repos.py49
-rw-r--r--lib/spack/spack/spec.py521
-rw-r--r--lib/spack/spack/stage.py92
-rw-r--r--lib/spack/spack/store.py108
-rw-r--r--lib/spack/spack/tengine.py45
-rw-r--r--lib/spack/spack/test/__init__.py26
-rw-r--r--lib/spack/spack/test/architecture.py29
-rw-r--r--lib/spack/spack/test/build_environment.py180
-rw-r--r--lib/spack/spack/test/build_system_guess.py28
-rw-r--r--lib/spack/spack/test/build_systems.py125
-rw-r--r--lib/spack/spack/test/cc.py884
-rw-r--r--lib/spack/spack/test/cmd/__init__.py24
-rw-r--r--lib/spack/spack/test/cmd/activate.py42
-rw-r--r--lib/spack/spack/test/cmd/arch.py36
-rw-r--r--lib/spack/spack/test/cmd/blame.py39
-rw-r--r--lib/spack/spack/test/cmd/build_env.py29
-rw-r--r--lib/spack/spack/test/cmd/cd.py17
-rw-r--r--lib/spack/spack/test/cmd/clean.py50
-rw-r--r--lib/spack/spack/test/cmd/commands.py51
-rw-r--r--lib/spack/spack/test/cmd/config.py93
-rw-r--r--lib/spack/spack/test/cmd/debug.py40
-rw-r--r--lib/spack/spack/test/cmd/dependencies.py40
-rw-r--r--lib/spack/spack/test/cmd/dependents.py41
-rw-r--r--lib/spack/spack/test/cmd/env.py628
-rw-r--r--lib/spack/spack/test/cmd/find.py70
-rw-r--r--lib/spack/spack/test/cmd/flake8.py35
-rw-r--r--lib/spack/spack/test/cmd/gpg.py39
-rw-r--r--lib/spack/spack/test/cmd/graph.py64
-rw-r--r--lib/spack/spack/test/cmd/help.py56
-rw-r--r--lib/spack/spack/test/cmd/info.py27
-rw-r--r--lib/spack/spack/test/cmd/install.py337
-rw-r--r--lib/spack/spack/test/cmd/license.py68
-rw-r--r--lib/spack/spack/test/cmd/list.py98
-rw-r--r--lib/spack/spack/test/cmd/mirror.py19
-rw-r--r--lib/spack/spack/test/cmd/module.py231
-rw-r--r--lib/spack/spack/test/cmd/print_shell_vars.py46
-rw-r--r--lib/spack/spack/test/cmd/providers.py50
-rw-r--r--lib/spack/spack/test/cmd/python.py29
-rw-r--r--lib/spack/spack/test/cmd/spec.py77
-rw-r--r--lib/spack/spack/test/cmd/test_compiler_cmd.py29
-rw-r--r--lib/spack/spack/test/cmd/uninstall.py39
-rw-r--r--lib/spack/spack/test/cmd/url.py54
-rw-r--r--lib/spack/spack/test/cmd/versions.py45
-rw-r--r--lib/spack/spack/test/cmd/view.py43
-rw-r--r--lib/spack/spack/test/compilers.py240
-rw-r--r--lib/spack/spack/test/concretize.py134
-rw-r--r--lib/spack/spack/test/concretize_preferences.py130
-rw-r--r--lib/spack/spack/test/config.py832
-rw-r--r--lib/spack/spack/test/conftest.py456
-rw-r--r--lib/spack/spack/test/data/config.yaml2
-rw-r--r--lib/spack/spack/test/data/directory_search/a/foobar.txt0
-rw-r--r--lib/spack/spack/test/data/directory_search/b/bar.txp0
-rw-r--r--lib/spack/spack/test/data/directory_search/c/bar.txt0
-rw-r--r--lib/spack/spack/test/data/make/affirmative/capital_makefile/Makefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/check_test/Makefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/expansion/Makefile5
-rw-r--r--lib/spack/spack/test/data/make/affirmative/gnu_makefile/GNUmakefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/include/Makefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/include/make.mk1
-rw-r--r--lib/spack/spack/test/data/make/affirmative/lowercase_makefile/makefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/prerequisites/Makefile5
-rw-r--r--lib/spack/spack/test/data/make/affirmative/spaces/Makefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/test_check/Makefile3
-rw-r--r--lib/spack/spack/test/data/make/affirmative/three_targets/Makefile3
-rw-r--r--lib/spack/spack/test/data/make/negative/no_makefile/readme.txt3
-rw-r--r--lib/spack/spack/test/data/make/negative/partial_match/Makefile11
-rw-r--r--lib/spack/spack/test/data/make/negative/variable/Makefile5
-rw-r--r--lib/spack/spack/test/data/modules/lmod/module_path_separator.yaml5
-rw-r--r--lib/spack/spack/test/data/modules/tcl/autoload_with_constraints.yaml8
-rw-r--r--lib/spack/spack/test/data/modules/tcl/blacklist_implicits.yaml6
-rw-r--r--lib/spack/spack/test/data/ninja/.gitignore2
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/check_test/build.ninja6
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/include/build.ninja3
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/include/include.ninja4
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/simple/build.ninja6
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/spaces/build.ninja6
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/subninja/build.ninja3
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/subninja/subninja.ninja4
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/test_check/build.ninja6
-rw-r--r--lib/spack/spack/test/data/ninja/affirmative/three_targets/build.ninja6
-rw-r--r--lib/spack/spack/test/data/ninja/negative/no_ninja/readme.txt8
-rw-r--r--lib/spack/spack/test/data/ninja/negative/partial_match/build.ninja16
-rw-r--r--lib/spack/spack/test/data/ninja/negative/rule/build.ninja8
-rw-r--r--lib/spack/spack/test/data/ninja/negative/variable/build.ninja8
-rw-r--r--lib/spack/spack/test/data/packages.yaml1
-rw-r--r--lib/spack/spack/test/data/repos.yaml2
-rw-r--r--lib/spack/spack/test/data/sourceme_first.sh28
-rw-r--r--lib/spack/spack/test/data/sourceme_parameters.sh28
-rw-r--r--lib/spack/spack/test/data/sourceme_second.sh28
-rw-r--r--lib/spack/spack/test/data/sourceme_unicode.sh28
-rw-r--r--lib/spack/spack/test/database.py320
-rw-r--r--lib/spack/spack/test/directory_layout.py80
-rw-r--r--lib/spack/spack/test/environment_modifications.py (renamed from lib/spack/spack/test/environment.py)56
-rw-r--r--lib/spack/spack/test/flag_handlers.py69
-rw-r--r--lib/spack/spack/test/git_fetch.py45
-rw-r--r--lib/spack/spack/test/graph.py35
-rw-r--r--lib/spack/spack/test/hg_fetch.py45
-rw-r--r--lib/spack/spack/test/install.py31
-rw-r--r--lib/spack/spack/test/llnl/util/file_list.py105
-rw-r--r--lib/spack/spack/test/llnl/util/filesystem.py217
-rw-r--r--lib/spack/spack/test/llnl/util/lang.py60
-rw-r--r--lib/spack/spack/test/llnl/util/link_tree.py27
-rw-r--r--lib/spack/spack/test/llnl/util/lock.py323
-rw-r--r--lib/spack/spack/test/llnl/util/log.py27
-rw-r--r--lib/spack/spack/test/make_executable.py37
-rw-r--r--lib/spack/spack/test/mirror.py177
-rw-r--r--lib/spack/spack/test/module_parsing.py82
-rw-r--r--lib/spack/spack/test/modules/common.py27
-rw-r--r--lib/spack/spack/test/modules/conftest.py54
-rw-r--r--lib/spack/spack/test/modules/dotkit.py43
-rw-r--r--lib/spack/spack/test/modules/lmod.py118
-rw-r--r--lib/spack/spack/test/modules/tcl.py136
-rw-r--r--lib/spack/spack/test/multimethod.py50
-rw-r--r--lib/spack/spack/test/namespace_trie.py27
-rw-r--r--lib/spack/spack/test/optional_deps.py31
-rw-r--r--lib/spack/spack/test/package_hash.py65
-rw-r--r--lib/spack/spack/test/package_sanity.py96
-rw-r--r--lib/spack/spack/test/packages.py291
-rw-r--r--lib/spack/spack/test/packaging.py87
-rw-r--r--lib/spack/spack/test/patch.py64
-rw-r--r--lib/spack/spack/test/pattern.py27
-rw-r--r--lib/spack/spack/test/provider_index.py39
-rw-r--r--lib/spack/spack/test/pytest.ini9
-rw-r--r--lib/spack/spack/test/python_version.py63
-rw-r--r--lib/spack/spack/test/repo.py42
-rw-r--r--lib/spack/spack/test/sbang.py31
-rw-r--r--lib/spack/spack/test/spack_yaml.py31
-rw-r--r--lib/spack/spack/test/spec_dag.py86
-rw-r--r--lib/spack/spack/test/spec_semantics.py71
-rw-r--r--lib/spack/spack/test/spec_syntax.py126
-rw-r--r--lib/spack/spack/test/spec_yaml.py51
-rw-r--r--lib/spack/spack/test/stage.py68
-rw-r--r--lib/spack/spack/test/svn_fetch.py45
-rw-r--r--lib/spack/spack/test/tengine.py29
-rw-r--r--lib/spack/spack/test/test_activations.py278
-rw-r--r--lib/spack/spack/test/url_fetch.py116
-rw-r--r--lib/spack/spack/test/url_parse.py40
-rw-r--r--lib/spack/spack/test/url_substitution.py27
-rw-r--r--lib/spack/spack/test/util/file_cache.py (renamed from lib/spack/spack/test/file_cache.py)29
-rw-r--r--lib/spack/spack/test/util/filesystem.py61
-rw-r--r--lib/spack/spack/test/util/log_parser.py27
-rw-r--r--lib/spack/spack/test/util/prefix.py56
-rw-r--r--lib/spack/spack/test/util/spack_lock_wrapper.py104
-rw-r--r--lib/spack/spack/test/util/spack_yaml.py67
-rw-r--r--lib/spack/spack/test/util/util_string.py14
-rw-r--r--lib/spack/spack/test/variant.py27
-rw-r--r--lib/spack/spack/test/versions.py35
-rw-r--r--lib/spack/spack/test/views.py29
-rw-r--r--lib/spack/spack/test/web.py31
-rw-r--r--lib/spack/spack/url.py52
-rw-r--r--lib/spack/spack/util/__init__.py26
-rw-r--r--lib/spack/spack/util/compression.py29
-rw-r--r--lib/spack/spack/util/crypto.py126
-rw-r--r--lib/spack/spack/util/debug.py27
-rw-r--r--lib/spack/spack/util/editor.py35
-rw-r--r--lib/spack/spack/util/environment.py673
-rw-r--r--lib/spack/spack/util/executable.py60
-rw-r--r--lib/spack/spack/util/file_cache.py (renamed from lib/spack/spack/file_cache.py)53
-rw-r--r--lib/spack/spack/util/gpg.py30
-rw-r--r--lib/spack/spack/util/imp/__init__.py22
-rw-r--r--lib/spack/spack/util/imp/imp_importer.py67
-rw-r--r--lib/spack/spack/util/imp/importlib_importer.py42
-rw-r--r--lib/spack/spack/util/lock.py74
-rw-r--r--lib/spack/spack/util/log_parse.py96
-rw-r--r--lib/spack/spack/util/module_cmd.py89
-rw-r--r--lib/spack/spack/util/naming.py29
-rw-r--r--lib/spack/spack/util/package_hash.py133
-rw-r--r--lib/spack/spack/util/path.py35
-rw-r--r--lib/spack/spack/util/pattern.py27
-rw-r--r--lib/spack/spack/util/prefix.py40
-rw-r--r--lib/spack/spack/util/spack_json.py29
-rw-r--r--lib/spack/spack/util/spack_yaml.py203
-rw-r--r--lib/spack/spack/util/string.py52
-rw-r--r--lib/spack/spack/util/web.py87
-rw-r--r--lib/spack/spack/variant.py32
-rw-r--r--lib/spack/spack/version.py31
592 files changed, 40436 insertions, 27823 deletions
diff --git a/lib/spack/docs/.gitignore b/lib/spack/docs/.gitignore
index 9afb658706..0b6258af50 100644
--- a/lib/spack/docs/.gitignore
+++ b/lib/spack/docs/.gitignore
@@ -1,4 +1,4 @@
-package_list.rst
+package_list.html
command_index.rst
spack*.rst
llnl*.rst
diff --git a/lib/spack/docs/Makefile b/lib/spack/docs/Makefile
index 3503794021..1ce5c1910c 100644
--- a/lib/spack/docs/Makefile
+++ b/lib/spack/docs/Makefile
@@ -17,7 +17,7 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext apidoc
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext apidoc dashdoc
all: html
@@ -83,7 +83,7 @@ help:
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
- -rm -f package_list.rst command_index.rst
+ -rm -f command_index.rst
-rm -rf $(BUILDDIR)/* $(APIDOC_FILES)
html:
@@ -196,3 +196,9 @@ doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
+
+dashdoc:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/dashdoc
+ doc2dash -A -v -n spack -d $(BUILDDIR)/ -f -I index.html -j $(BUILDDIR)/dashdoc
+ @echo
+ @echo "Build finished. The Docset is in $(BUILDDIR)/dashdoc."
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/__init__.py b/lib/spack/docs/_themes/sphinx_rtd_theme/__init__.py
deleted file mode 100644
index 95ddc52ae0..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Sphinx ReadTheDocs theme.
-
-From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
-
-"""
-import os
-
-VERSION = (0, 1, 8)
-
-__version__ = ".".join(str(v) for v in VERSION)
-__version_full__ = __version__
-
-
-def get_html_theme_path():
- """Return list of HTML theme paths."""
- cur_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
- return cur_dir
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/breadcrumbs.html b/lib/spack/docs/_themes/sphinx_rtd_theme/breadcrumbs.html
deleted file mode 100644
index 0028421e1c..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/breadcrumbs.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<div role="navigation" aria-label="breadcrumbs navigation">
- <ul class="wy-breadcrumbs">
- <li><a href="{{ pathto(master_doc) }}">Docs</a> &raquo;</li>
- {% for doc in parents %}
- <li><a href="{{ doc.link|e }}">{{ doc.title }}</a> &raquo;</li>
- {% endfor %}
- <li>{{ title }}</li>
- <li class="wy-breadcrumbs-aside">
- {% if pagename != "search" %}
- {% if display_github %}
- <a href="https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-github"> Edit on GitHub</a>
- {% elif display_bitbucket %}
- <a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ source_suffix }}" class="fa fa-bitbucket"> Edit on Bitbucket</a>
- {% elif show_source and source_url_prefix %}
- <a href="{{ source_url_prefix }}{{ pagename }}{{ source_suffix }}">View page source</a>
- {% elif show_source and has_source and sourcename %}
- <a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> View page source</a>
- {% endif %}
- {% endif %}
- </li>
- </ul>
- <hr/>
-</div>
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html b/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html
deleted file mode 100644
index 958ebbd2f7..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<footer>
- {% if next or prev %}
- <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
- {% if next %}
- <a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
- {% endif %}
- {% if prev %}
- <a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
- {% endif %}
- </div>
- {% endif %}
-
- <hr/>
-
- <div role="contentinfo">
- <p>
- {%- if show_copyright %}
- {%- if hasdoc('copyright') %}
- {% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
- {%- else %}
- {% trans copyright=copyright|e %}&copy; Copyright {{ copyright }}.{% endtrans %}
- {%- endif %}
- {%- endif %}
-
- <br/>
- Written by Todd Gamblin (<a href="mailto:tgamblin@llnl.gov">tgamblin@llnl.gov</a>) and
- many <a href="https://github.com/spack/spack/graphs/contributors">contributors.</a> LLNL-CODE-647188.
-
- {%- if last_updated %}
- <br/>
- {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
- {%- endif %}
- </p>
- </div>
-
- {%- if show_sphinx %}
- {% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
- {%- endif %}
-
-</footer>
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/layout.html b/lib/spack/docs/_themes/sphinx_rtd_theme/layout.html
deleted file mode 100644
index 9481d8b426..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/layout.html
+++ /dev/null
@@ -1,181 +0,0 @@
-{# TEMPLATE VAR SETTINGS #}
-{%- set url_root = pathto('', 1) %}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-<!DOCTYPE html>
-<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
-<head>
- <meta charset="utf-8">
- {{ metatags }}
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- {% block htmltitle %}
- <title>{{ title|striptags|e }}{{ titlesuffix }}</title>
- {% endblock %}
-
- {# FAVICON #}
- {% if favicon %}
- <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
- {% endif %}
-
- {# CSS #}
-
- {# OPENSEARCH #}
- {% if not embedded %}
- {% if use_opensearch %}
- <link rel="search" type="application/opensearchdescription+xml" title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}" href="{{ pathto('_static/opensearch.xml', 1) }}"/>
- {% endif %}
-
- {% endif %}
-
- {# RTD hosts this file, so just load on non RTD builds #}
- {% if not READTHEDOCS %}
- <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
- {% endif %}
-
- {% for cssfile in css_files %}
- <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
- {% endfor %}
-
- {% for cssfile in extra_css_files %}
- <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
- {% endfor %}
-
- {%- block linktags %}
- {%- if hasdoc('about') %}
- <link rel="author" title="{{ _('About these documents') }}"
- href="{{ pathto('about') }}"/>
- {%- endif %}
- {%- if hasdoc('genindex') %}
- <link rel="index" title="{{ _('Index') }}"
- href="{{ pathto('genindex') }}"/>
- {%- endif %}
- {%- if hasdoc('search') %}
- <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}"/>
- {%- endif %}
- {%- if hasdoc('copyright') %}
- <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}"/>
- {%- endif %}
- <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}"/>
- {%- if parents %}
- <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}"/>
- {%- endif %}
- {%- if next %}
- <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}"/>
- {%- endif %}
- {%- if prev %}
- <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}"/>
- {%- endif %}
- {%- endblock %}
- {%- block extrahead %} {% endblock %}
-
- {# Keep modernizr in head - http://modernizr.com/docs/#installing #}
- <script src="_static/js/modernizr.min.js"></script>
-
-</head>
-
-<body class="wy-body-for-nav" role="document">
-
- <div class="wy-grid-for-nav">
-
- {# SIDE NAV, TOGGLES ON MOBILE #}
- <nav data-toggle="wy-nav-shift" class="wy-nav-side">
- <div class="wy-side-nav-search">
- {% block sidebartitle %}
-
- {% if logo and theme_logo_only %}
- <a href="{{ pathto(master_doc) }}">
- {% else %}
- <a href="{{ pathto(master_doc) }}" class="icon icon-home"> {{ project }}
- {% endif %}
-
- {% if logo %}
- {# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
- <img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
- {% endif %}
- </a>
-
- {% include "searchbox.html" %}
-
- {% endblock %}
- </div>
-
- <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
- {% block menu %}
- {% set toctree = toctree(maxdepth=4, collapse=False, includehidden=True) %}
- {% if toctree %}
- {{ toctree }}
- {% else %}
- <!-- Local TOC -->
- <div class="local-toc">{{ toc }}</div>
- {% endif %}
- {% endblock %}
- </div>
- &nbsp;
- </nav>
-
- <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
-
- {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
- <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
- <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
- <a href="{{ pathto(master_doc) }}">{{ project }}</a>
- </nav>
-
-
- {# PAGE CONTENT #}
- <div class="wy-nav-content">
- <div class="rst-content">
- {% include "breadcrumbs.html" %}
- <div role="main" class="document">
- {% block body %}{% endblock %}
- </div>
- {% include "footer.html" %}
- </div>
- </div>
-
- </section>
-
- </div>
- {% include "versions.html" %}
-
- {% if not embedded %}
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT:'{{ url_root }}',
- VERSION:'{{ release|e }}',
- COLLAPSE_INDEX:false,
- FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
- HAS_SOURCE: {{ has_source|lower }}
- };
- </script>
- {%- for scriptfile in script_files %}
- <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
- {%- endfor %}
-
- {% endif %}
-
- {# RTD hosts this file, so just load on non RTD builds #}
- {% if not READTHEDOCS %}
- <script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script>
- {% endif %}
-
- {# STICKY NAVIGATION #}
- {% if theme_sticky_navigation %}
- <script type="text/javascript">
- jQuery(function () {
- SphinxRtdTheme.StickyNav.enable();
- });
- </script>
- {% endif %}
-
- {%- block footer %} {% endblock %}
-
-</body>
-</html>
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/layout_old.html b/lib/spack/docs/_themes/sphinx_rtd_theme/layout_old.html
deleted file mode 100644
index deb8df2a1a..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/layout_old.html
+++ /dev/null
@@ -1,205 +0,0 @@
-{#
- basic/layout.html
- ~~~~~~~~~~~~~~~~~
-
- Master layout template for Sphinx themes.
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- block doctype -%}
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-{%- endblock %}
-{%- set reldelim1 = reldelim1 is not defined and ' &raquo;' or reldelim1 %}
-{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
-{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
- (sidebars != []) %}
-{%- set url_root = pathto('', 1) %}
-{# XXX necessary? #}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-{%- macro relbar() %}
- <div class="related">
- <h3>{{ _('Navigation') }}</h3>
- <ul>
- {%- for rellink in rellinks %}
- <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
- <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
- {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
- {%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
- {%- endfor %}
- {%- block rootrellink %}
- <li><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}</li>
- {%- endblock %}
- {%- for parent in parents %}
- <li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
- {%- endfor %}
- {%- block relbaritems %} {% endblock %}
- </ul>
- </div>
-{%- endmacro %}
-
-{%- macro sidebar() %}
- {%- if render_sidebar %}
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
- {%- block sidebarlogo %}
- {%- if logo %}
- <p class="logo"><a href="{{ pathto(master_doc) }}">
- <img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
- </a></p>
- {%- endif %}
- {%- endblock %}
- {%- if sidebars != None %}
- {#- new style sidebar: explicitly include/exclude templates #}
- {%- for sidebartemplate in sidebars %}
- {%- include sidebartemplate %}
- {%- endfor %}
- {%- else %}
- {#- old style sidebars: using blocks -- should be deprecated #}
- {%- block sidebartoc %}
- {%- include "localtoc.html" %}
- {%- endblock %}
- {%- block sidebarrel %}
- {%- include "relations.html" %}
- {%- endblock %}
- {%- block sidebarsourcelink %}
- {%- include "sourcelink.html" %}
- {%- endblock %}
- {%- if customsidebar %}
- {%- include customsidebar %}
- {%- endif %}
- {%- block sidebarsearch %}
- {%- include "searchbox.html" %}
- {%- endblock %}
- {%- endif %}
- </div>
- </div>
- {%- endif %}
-{%- endmacro %}
-
-{%- macro script() %}
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: '{{ url_root }}',
- VERSION: '{{ release|e }}',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
- HAS_SOURCE: {{ has_source|lower }}
- };
- </script>
- {%- for scriptfile in script_files %}
- <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
- {%- endfor %}
-{%- endmacro %}
-
-{%- macro css() %}
- <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
- <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
- {%- for cssfile in css_files %}
- <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
- {%- endfor %}
-{%- endmacro %}
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
- {{ metatags }}
- {%- block htmltitle %}
- <title>{{ title|striptags|e }}{{ titlesuffix }}</title>
- {%- endblock %}
- {{ css() }}
- {%- if not embedded %}
- {{ script() }}
- {%- if use_opensearch %}
- <link rel="search" type="application/opensearchdescription+xml"
- title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
- href="{{ pathto('_static/opensearch.xml', 1) }}"/>
- {%- endif %}
- {%- if favicon %}
- <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
- {%- endif %}
- {%- endif %}
-{%- block linktags %}
- {%- if hasdoc('about') %}
- <link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
- {%- endif %}
- {%- if hasdoc('genindex') %}
- <link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
- {%- endif %}
- {%- if hasdoc('search') %}
- <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
- {%- endif %}
- {%- if hasdoc('copyright') %}
- <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
- {%- endif %}
- <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
- {%- if parents %}
- <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
- {%- endif %}
- {%- if next %}
- <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
- {%- endif %}
- {%- if prev %}
- <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
- {%- endif %}
-{%- endblock %}
-{%- block extrahead %} {% endblock %}
- </head>
- <body>
-{%- block header %}{% endblock %}
-
-{%- block relbar1 %}{{ relbar() }}{% endblock %}
-
-{%- block content %}
- {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
-
- <div class="document">
- {%- block document %}
- <div class="documentwrapper">
- {%- if render_sidebar %}
- <div class="bodywrapper">
- {%- endif %}
- <div class="body">
- {% block body %} {% endblock %}
- </div>
- {%- if render_sidebar %}
- </div>
- {%- endif %}
- </div>
- {%- endblock %}
-
- {%- block sidebar2 %}{{ sidebar() }}{% endblock %}
- <div class="clearer"></div>
- </div>
-{%- endblock %}
-
-{%- block relbar2 %}{{ relbar() }}{% endblock %}
-
-{%- block footer %}
- <div class="footer">
- {%- if show_copyright %}
- {%- if hasdoc('copyright') %}
- {% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
- {%- else %}
- {% trans copyright=copyright|e %}&copy; Copyright {{ copyright }}.{% endtrans %}
- {%- endif %}
- {%- endif %}
- {%- if last_updated %}
- {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
- {%- endif %}
- {%- if show_sphinx %}
- {% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
- {%- endif %}
- </div>
- <p>asdf asdf asdf asdf 22</p>
-{%- endblock %}
- </body>
-</html>
-
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/search.html b/lib/spack/docs/_themes/sphinx_rtd_theme/search.html
deleted file mode 100644
index e3aa9b5c6e..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/search.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{#
- basic/search.html
- ~~~~~~~~~~~~~~~~~
-
- Template for the search page.
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- extends "layout.html" %}
-{% set title = _('Search') %}
-{% set script_files = script_files + ['_static/searchtools.js'] %}
-{% block footer %}
- <script type="text/javascript">
- jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
- </script>
- {# this is used when loading the search index using $.ajax fails,
- such as on Chrome for documents on localhost #}
- <script type="text/javascript" id="searchindexloader"></script>
- {{ super() }}
-{% endblock %}
-{% block body %}
- <noscript>
- <div id="fallback" class="admonition warning">
- <p class="last">
- {% trans %}Please activate JavaScript to enable the search
- functionality.{% endtrans %}
- </p>
- </div>
- </noscript>
-
- {% if search_performed %}
- <h2>{{ _('Search Results') }}</h2>
- {% if not search_results %}
- <p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
- {% endif %}
- {% endif %}
- <div id="search-results">
- {% if search_results %}
- <ul>
- {% for href, caption, context in search_results %}
- <li>
- <a href="{{ pathto(item.href) }}">{{ caption }}</a>
- <p class="context">{{ context|e }}</p>
- </li>
- {% endfor %}
- </ul>
- {% endif %}
- </div>
-{% endblock %}
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/searchbox.html b/lib/spack/docs/_themes/sphinx_rtd_theme/searchbox.html
deleted file mode 100644
index 35ad52c5f6..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/searchbox.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{%- if builder != 'singlehtml' %}
-<div role="search">
- <form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
- <input type="text" name="q" placeholder="Search docs" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
-</div>
-{%- endif %}
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css b/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css
deleted file mode 100644
index 7e17fb148c..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css
+++ /dev/null
@@ -1,2 +0,0 @@
-.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
-/*# sourceMappingURL=badge_only.css.map */
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map b/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map
deleted file mode 100644
index b09cc628bf..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-"version": 3,
-"mappings": "CAyDA,SAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI,EC1Gb,SAkBC,EAjBC,UAAW,ECFJ,UAAW,EDGlB,UAAW,EAHqC,KAAM,EAItD,SAAU,EAJsD,KAAM,EAapE,EAAG,EAAE,qCAAwB,EAC7B,EAAG,EAAE,0PAAyE,ECZpF,SAAU,EACR,MAAO,EAAE,WAAY,EACrB,UAAW,EAAE,UAAW,EACxB,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,KAAM,EACnB,UAAW,EAAE,AAAC,EACd,cAAe,EAAE,MAAO,EAG1B,IAAK,EACH,MAAO,EAAE,WAAY,EACrB,cAAe,EAAE,MAAO,EAIxB,KAAG,EACD,MAAO,EAAE,WAAY,EACvB,sCAAiB,EAGf,IAAK,EAAE,MAAY,EAEvB,KAAM,EACJ,cAAe,EAAE,GAAI,EACrB,UAAW,EAAE,EAAG,EAChB,UAAW,EAAE,KAAM,EAEjB,YAAG,EACD,IAAK,EAAE,IAAI,EACb,oDAAiB,EAGf,aAAc,EAAE,OAAQ,EAG9B,cAAe,EACb,MAAO,EAAE,EAAO,EAElB,gBAAiB,EACf,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,kBAAmB,EACjB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,qBAAsB,EACpB,MAAO,EAAE,EAAO,EAElB,uBAAwB,EACtB,MAAO,EAAE,EAAO,ECnElB,YAAa,EACX,OAAQ,EAAE,IAAK,EACf,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,AAAC,EACP,IAAK,EC6E+B,IAAK,ED5EzC,IAAK,ECE+B,MAAyB,EDD7D,SAAU,EAAE,MAAkC,EAC9C,SAAU,EAAE,iBAAiC,EAC7C,UAAW,EEAyB,sDAAM,EFC1C,MAAO,EC+E6B,EAAG,ED9EvC,cAAC,EACC,IAAK,ECqE6B,MAAW,EDpE7C,cAAe,EAAE,GAAI,EACvB,6BAAgB,EACd,MAAO,EAAE,GAAI,EACf,iCAAoB,EAClB,MAAO,EAAE,GAAqB,EAC9B,eAAgB,EAAE,MAAkC,EACpD,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,IAAK,EACjB,QAAS,EAAE,EAAG,EACd,KAAM,EAAE,MAAO,EACf,IAAK,ECiD6B,MAAM,EJgC1C,IAAK,EAAE,AAAC,EACR,iFAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,uCAAO,EACL,IAAK,EAAE,GAAI,EGrFX,qCAAG,EACD,IAAK,EClB2B,MAAyB,EDmB3D,0CAAQ,EACN,IAAK,EAAE,GAAI,EACb,4CAAU,EACR,IAAK,EAAE,GAAI,EACb,iDAAiB,EACf,eAAgB,ECQgB,MAAI,EDPpC,IAAK,EC0B2B,GAAM,EDzBxC,wDAAwB,EACtB,eAAgB,ECXgB,MAAO,EDYvC,IAAK,ECzB2B,GAAI,ED0BxC,yCAA8B,EAC5B,MAAO,EAAE,IAAK,EAChB,gCAAmB,EACjB,QAAS,EAAE,EAAG,EACd,MAAO,EAAE,GAAqB,EAC9B,IAAK,ECE6B,GAAwB,EDD1D,MAAO,EAAE,GAAI,EACb,mCAAE,EACA,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,KAAM,EACd,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,gBAA6C,EAC3D,mCAAE,EACA,MAAO,EAAE,WAAY,EACrB,KAAM,EAAE,AAAC,EACT,qCAAC,EACC,MAAO,EAAE,WAAY,EACrB,MAAO,EAAE,EAAqB,EAC9B,IAAK,ECjDyB,MAAyB,EDkD7D,sBAAW,EACT,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,IAAK,EAAE,GAAI,EACX,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,QAAS,ECkByB,IAAK,EDjBvC,iCAAU,EACR,IAAK,EAAE,GAAI,EACb,+BAAQ,EACN,IAAK,EAAE,GAAI,EACb,oDAA+B,EAC7B,SAAU,EAAE,IAAK,EACjB,6DAAQ,EACN,IAAK,EAAE,GAAI,EACb,+DAAU,EACR,IAAK,EAAE,GAAI,EACf,2CAAoB,EAClB,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,UAAW,EAAE,GAAI,EACjB,MAAO,EAAE,IAAuB,EAChC,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,KAAM,EGhDpB,mCAAsB,EHmDxB,YAAa,EACX,IAAK,EAAE,EAAG,EACV,MAAO,EAAE,GAAI,EACb,kBAAO,EACL,MAAO,EAAE,IAAK,EAClB,EAAG,EACD,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI",
-"sources": ["../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/bourbon/dist/css3/_font-face.scss","../../../sass/_theme_badge_fa.sass","../../../sass/_theme_badge.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss"],
-"names": [],
-"file": "badge_only.css"
-}
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css b/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css
deleted file mode 100644
index 57b98fe6af..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css
+++ /dev/null
@@ -1,5 +0,0 @@
-*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,.rst-content p.caption,h3{orphans:3;widows:3}h2,.rst-content p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*!
- * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
- * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:0.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all 0.3s ease-in;-moz-transition:all 0.3s ease-in;transition:all 0.3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.35765%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{width:36px;height:12px;margin:12px 0;position:relative;border-radius:4px;background:#ccc;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:before{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:after{content:"false";position:absolute;left:48px;display:block;font-size:12px;color:#ccc}.wy-switch.active{background:#1e8449}.wy-switch.active:before{left:24px;background:#27AE60}.wy-switch.active:after{content:"true"}.wy-switch.disabled,.wy-switch.active.disabled{cursor:not-allowed}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9B59B6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],pre.literal-block div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}@media print{.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#EAF2F5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#555;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:0.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:0.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:0.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:0.4045em 5.663em;border-top:none;border-bottom:none}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:0.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#b3b3b3}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{z-index:200;background-color:#2980B9;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto 0.809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:0.85em}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:scroll;min-height:100%;background:#343131;z-index:200}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after{visibility:visible;content:"";font-family:FontAwesome;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content p.caption:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink,.rst-content p.caption:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list td>strong{display:inline-block;margin-top:3px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt,.rst-content tt,.rst-content code{color:#000}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt .xref,a .rst-content tt,.rst-content tt .xref,.rst-content code .xref,a .rst-content tt,a .rst-content code{font-weight:bold}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:gray}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:400;src:local("Inconsolata"),url(../fonts/Inconsolata.ttf) format("truetype")}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:700;src:local("Inconsolata Bold"),local("Inconsolata-Bold"),url(../fonts/Inconsolata-Bold.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:400;src:local("Lato Regular"),local("Lato-Regular"),url(../fonts/Lato-Regular.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:700;src:local("Lato Bold"),local("Lato-Bold"),url(../fonts/Lato-Bold.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:local("Roboto Slab Regular"),local("RobotoSlab-Regular"),url(../fonts/RobotoSlab-Regular.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:local("Roboto Slab Bold"),local("RobotoSlab-Bold"),url(../fonts/RobotoSlab-Bold.ttf) format("truetype")}
-/*# sourceMappingURL=theme.css.map */
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map b/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map
deleted file mode 100644
index eacfcab147..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-"version": 3,
-"mappings": "CACE,AAAE,ECQI,iBAAoB,EDPJ,SAAU,ECY1B,cAAiB,EDZD,SAAU,EC2B1B,SAAY,ED3BI,SAAU,EEFlC,uEAAiF,EAC/E,MAAO,EAAE,IAAK,EAEhB,iBAAoB,EAClB,MAAO,EAAE,WAAY,EACrB,OAAQ,EAAE,KAAM,EAChB,IAAK,EAAE,AAAC,EAEV,oBAAqB,EACnB,MAAO,EAAE,GAAI,EAEf,OAAQ,EACN,MAAO,EAAE,GAAI,EAEf,AAAC,EDLO,iBAAoB,ECMd,SAAU,EDDhB,cAAiB,ECCX,SAAU,EDchB,SAAY,ECdN,SAAU,EAExB,GAAI,EACF,QAAS,EAAE,GAAI,EACf,uBAAwB,EAAE,GAAI,EAC9B,mBAAoB,EAAE,GAAI,EAE5B,GAAI,EACF,KAAM,EAAE,AAAC,EAEX,eAAiB,EACf,MAAO,EAAE,AAAC,EAEZ,UAAW,EACT,YAAa,EAAE,SAAU,EAE3B,OAAS,EACP,UAAW,EAAE,GAAI,EAEnB,SAAU,EACR,KAAM,EAAE,AAAC,EAEX,EAAG,EACD,SAAU,EAAE,KAAM,EAGpB,EAAG,EACD,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAI,EACX,cAAe,EAAE,GAAI,EAEvB,GAAI,EACF,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAI,EACX,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,GAAI,EAEnB,kDAAoB,EAClB,UAAW,EAAE,cAAS,EACtB,WAAY,EAAE,sBAAa,EAC3B,QAAS,EAAE,EAAG,EAEhB,EAAG,EACD,UAAW,EAAE,EAAG,EAElB,AAAC,EACC,KAAM,EAAE,GAAI,EAEd,eAAiB,EACf,MAAO,EAAE,CAAE,EACX,MAAO,EAAE,GAAI,EAEf,IAAK,EACH,QAAS,EAAE,EAAG,EAEhB,MAAQ,EACN,QAAS,EAAE,EAAG,EACd,UAAW,EAAE,AAAC,EACd,OAAQ,EAAE,OAAQ,EAClB,aAAc,EAAE,OAAQ,EAE1B,EAAG,EACD,EAAG,EAAE,KAAM,EAEb,EAAG,EACD,KAAM,EAAE,MAAO,EAEjB,OAAU,EACR,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,GAAI,EAChB,eAAgB,EAAE,GAAI,EAExB,CAAE,EACA,SAAU,EAAE,GAAI,EAElB,CAAE,EACA,KAAM,EAAE,AAAC,EAEX,EAAG,EACD,KAAM,EAAE,AAAC,EACT,qBAAsB,EAAE,MAAO,EAC/B,aAAc,EAAE,KAAM,EACtB,QAAS,EAAE,GAAI,EAEjB,aAAc,EACZ,OAAQ,EAAE,KAAM,EAElB,KAAM,EACJ,KAAM,EAAE,AAAC,EAEX,GAAI,EACF,KAAM,EAAE,AAAC,EAEX,OAAQ,EACN,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EAEZ,IAAK,EACH,KAAM,EAAE,MAAO,EAEjB,KAAM,EACJ,KAAM,EAAE,AAAC,EACT,WAAY,EAAE,GAAI,EAClB,MAAO,EAAE,AAAC,EACV,UAAW,EAAE,KAAM,EAErB,2BAA+B,EAC7B,QAAS,EAAE,GAAI,EACf,KAAM,EAAE,AAAC,EACT,aAAc,EAAE,OAAQ,EACxB,cAAe,EAAE,KAAM,EAEzB,WAAa,EACX,UAAW,EAAE,KAAM,EAErB,mEAAuE,EACrE,KAAM,EAAE,MAAO,EACf,iBAAkB,EAAE,KAAM,EAC1B,QAAS,EAAE,MAAO,EAEpB,+BAAiC,EAC/B,KAAM,EAAE,MAAO,EAEjB,yCAA2C,EACzC,SAAU,EAAE,SAAU,EACtB,MAAO,EAAE,AAAC,EACV,KAAM,EAAE,GAAI,EACZ,MAAO,EAAE,GAAI,EAEf,mBAAoB,EAClB,iBAAkB,EAAE,QAAS,EAC7B,cAAe,EAAE,UAAW,EAC5B,iBAAkB,EAAE,UAAW,EAC/B,SAAU,EAAE,UAAW,EAEzB,iGAAmG,EACjG,iBAAkB,EAAE,GAAI,EAE1B,+CAAiD,EAC/C,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EAEZ,OAAQ,EACN,OAAQ,EAAE,GAAI,EACd,aAAc,EAAE,EAAG,EACnB,KAAM,EAAE,OAAQ,EAElB,IAAK,EACH,cAAe,EAAE,OAAQ,EACzB,aAAc,EAAE,AAAC,EAEnB,CAAE,EACA,aAAc,EAAE,EAAG,EAErB,WAAY,EACV,KAAM,EAAE,MAAO,EACf,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAK,EACZ,MAAO,EAAE,MAAO,EAElB,EAAG,EACD,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,AAAC,EACT,UAAW,EAAE,KAAM,EACnB,OAAQ,EAAE,KAAM,EAChB,eAAgB,EAAE,UAAW,EAC7B,gBAAiB,EAAE,QAAS,EAC5B,SAAU,EAAE,GAAI,EAChB,QAAS,EAAE,EAAG,EACd,WAAY,EAAE,AAAC,EAEjB,KAAM,EACJ,MAAO,EAAE,GAAI,EAEf,MAAO,EACL,MAAO,EAAE,cAAe,EACxB,SAAU,EAAE,KAAM,EAEpB,cAAe,EACb,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,YAAa,EACnB,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,GAAI,EACZ,OAAQ,EAAE,KAAM,EAChB,MAAO,EAAE,AAAC,EACV,OAAQ,EAAE,OAAQ,EAClB,IAAK,EAAE,EAAG,EAEZ,+DAAiE,EAC/D,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,KAAM,EAAE,AAAC,EACT,OAAQ,EAAE,MAAO,EACjB,OAAQ,EAAE,KAAM,EAChB,IAAK,EAAE,GAAI,EAEb,SAAU,EACR,SAAU,EAAE,KAAM,EAEpB,QAAS,EACP,OAAQ,EAAE,OAAQ,EAEpB,QAAU,EACR,QAAS,EAAE,GAAI,EAEjB,WAAY,EACV,gBAAmB,EACjB,SAAU,EAAE,cAAe,EAC7B,AAAC,EACC,SAAU,EAAE,cAAe,EAC3B,UAAW,EAAE,cAAe,EAC5B,KAAM,EAAE,cAAe,EACvB,SAAU,EAAE,cAAe,EAC7B,UAAY,EACV,cAAe,EAAE,QAAS,EAC5B,0DAA6D,EAC3D,MAAO,EAAE,CAAE,EACb,aAAe,EACb,gBAAiB,EAAE,IAAK,EAC1B,IAAK,EACH,MAAO,EAAE,iBAAkB,EAC7B,KAAO,EACL,gBAAiB,EAAE,IAAK,EAC1B,EAAG,EACD,QAAS,EAAE,cAAe,QAE1B,KAAM,EAAE,IAAK,EAEf,6BAAS,EACP,MAAO,EAAE,AAAC,EACV,KAAM,EAAE,AAAC,EACX,2BAAM,EACJ,eAAgB,EAAE,IAAK,GChM3B,ykDAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI;;;GC1Gf,UAUC,CATC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+CAAgE,CACrE,GAAG,CAAE,sSAAmG,CAKxG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCTpB,kfAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAAuC,CAC7C,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCLpC,MAAsB,CACpB,SAAS,CAAE,SAAS,CACpB,WAAW,CAAE,MAAS,CACtB,cAAc,CAAE,IAAI,CAEtB,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CCVtC,MAAsB,CACpB,KAAK,CAAE,SAAW,CAClB,UAAU,CAAE,MAAM,CCDpB,MAAsB,CACpB,YAAY,CAAE,CAAC,CACf,WAAW,CCIU,SAAS,CDH9B,eAAe,CAAE,IAAI,CACrB,SAAK,CAAE,QAAQ,CAAE,QAAQ,CAE3B,MAAsB,CACpB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,UAAa,CACnB,KAAK,CCHgB,SAAS,CDI9B,GAAG,CAAE,SAAU,CACf,UAAU,CAAE,MAAM,CAClB,YAAuB,CACrB,IAAI,CAAE,UAA0B,CEbpC,UAA0B,CACxB,OAAO,CAAE,gBAAgB,CACzB,MAAM,CAAE,iBAA4B,CACpC,aAAa,CAAE,IAAI,CAGrB,WAAY,CAAE,KAAK,CAAE,KAAK,CAC1B,UAAW,CAAE,KAAK,CAAE,IAAI,CAGtB,kpBAAY,CAAE,YAAY,CAAE,IAAI,CAChC,kqBAAa,CAAE,WAAW,CAAE,IAAI,CCXlC,QAAwB,CACtB,iBAAiB,CAAE,0BAA0B,CACrC,SAAS,CAAE,0BAA0B,CAG/C,0BASC,CARC,EAAG,CACD,iBAAiB,CAAE,YAAY,CACvB,SAAS,CAAE,YAAY,CAEjC,IAAK,CACH,iBAAiB,CAAE,cAAc,CACzB,SAAS,CAAE,cAAc,EAIrC,kBASC,CARC,EAAG,CACD,iBAAiB,CAAE,YAAY,CACvB,SAAS,CAAE,YAAY,CAEjC,IAAK,CACH,iBAAiB,CAAE,cAAc,CACzB,SAAS,CAAE,cAAc,ECvBrC,aAA8B,CCU5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,aAAgB,CAC/B,aAAa,CAAE,aAAgB,CAC3B,SAAS,CAAE,aAAgB,CDZrC,cAA8B,CCS5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,cAAgB,CAC/B,aAAa,CAAE,cAAgB,CAC3B,SAAS,CAAE,cAAgB,CDXrC,cAA8B,CCQ5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,cAAgB,CAC/B,aAAa,CAAE,cAAgB,CAC3B,SAAS,CAAE,cAAgB,CDTrC,mBAAmC,CCajC,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,YAAoB,CACnC,aAAa,CAAE,YAAoB,CAC/B,SAAS,CAAE,YAAoB,CDfzC,iBAAmC,CCYjC,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,YAAoB,CACnC,aAAa,CAAE,YAAoB,CAC/B,SAAS,CAAE,YAAoB,CDVzC,+GAIuC,CACrC,MAAM,CAAE,IAAI,CEfd,SAAyB,CACvB,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,YAAY,CACrB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,WAAW,CAAE,GAAG,CAChB,cAAc,CAAE,MAAM,CAExB,yBAAyD,CACvD,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAEpB,YAA4B,CAAE,WAAW,CAAE,OAAO,CAClD,YAA4B,CAAE,SAAS,CAAE,GAAG,CAC5C,WAA2B,CAAE,KAAK,CLXZ,IAAI,CML1B,gBAAgC,CAAE,OAAO,CNwP1B,GAAO,CMvPtB,gBAAgC,CAAE,OAAO,CNkV1B,GAAO,CMjVtB,qCAAiC,CAAE,OAAO,CNyZ1B,GAAO,CMxZvB,qBAAqC,CAAE,OAAO,CN2K1B,GAAO,CM1K3B,gBAAgC,CAAE,OAAO,CNqQ1B,GAAO,CMpQtB,eAA+B,CAAE,OAAO,CNkc1B,GAAO,CMjcrB,iBAAiC,CAAE,OAAO,CNsc1B,GAAO,CMrcvB,eAA+B,CAAE,OAAO,CN0gB1B,GAAO,CMzgBrB,eAA+B,CAAE,OAAO,CN+M1B,GAAO,CM9MrB,mBAAmC,CAAE,OAAO,CN8d1B,GAAO,CM7dzB,aAA6B,CAAE,OAAO,CN4d1B,GAAO,CM3dnB,kBAAkC,CAAE,OAAO,CN6d1B,GAAO,CM5dxB,gBAAgC,CAAE,OAAO,CN+F1B,GAAO,CM9FtB,mDAEgC,CAAE,OAAO,CNge1B,GAAO,CM/dtB,sBAAsC,CAAE,OAAO,CN6Y1B,GAAO,CM5Y5B,uBAAuC,CAAE,OAAO,CN2Y1B,GAAO,CM1Y7B,oBAAoC,CAAE,OAAO,CNqW1B,GAAO,CMpW1B,iBAAiC,CAAE,OAAO,CNwZ1B,GAAO,CMvZvB,8BAC8B,CAAE,OAAO,CNmH1B,GAAO,CMlHpB,kBAAkC,CAAE,OAAO,CNoe1B,GAAO,CMnexB,iCAA+B,CAAE,OAAO,CNqP1B,GAAO,CMpPrB,iBAAiC,CAAE,OAAO,CNmL1B,GAAO,CMlLvB,kBAAkC,CAAE,OAAO,CNqG1B,GAAO,CMpGxB,eAA+B,CAAE,OAAO,CNqX1B,GAAO,CMpXrB,uHAAmC,CAAE,OAAO,CNyI1B,GAAO,CMxIzB,8BAA8C,CAAE,OAAO,CNG1B,GAAO,CMFpC,4BAA4C,CAAE,OAAO,CNK1B,GAAO,CMJlC,gBAAgC,CAAE,OAAO,CNmP1B,GAAO,CMlPtB,wBAAwC,CAAE,OAAO,CNkV1B,GAAO,CMjV9B,yCACiC,CAAE,OAAO,CNyW1B,GAAO,CMxWvB,kBAAkC,CAAE,OAAO,CNoW1B,GAAO,CMnWxB,mBAAmC,CAAE,OAAO,CNiR1B,GAAO,CMhRzB,eAA+B,CAAE,OAAO,CNoR1B,GAAO,CMnRrB,eAA+B,CAAE,OAAO,CNsL1B,GAAO,CMrLrB,qBAAqC,CAAE,OAAO,CNkO1B,GAAO,CMjO3B,qBAAqC,CAAE,OAAO,CNkf1B,GAAO,CMjf3B,sBAAsC,CAAE,OAAO,CNgf1B,GAAO,CM/e5B,oBAAoC,CAAE,OAAO,CNif1B,GAAO,CMhf1B,iBAAiC,CAAE,OAAO,CNiV1B,GAAO,CMhVvB,kBAAkC,CAAE,OAAO,CNU1B,GAAO,CMTxB,cAA8B,CAAE,OAAO,CNkb1B,GAAO,CMjbpB,eAA+B,CAAE,OAAO,CNkb1B,GAAO,CMjbrB,iCAA+B,CAAE,OAAO,CNyB1B,GAAO,CMxBrB,mBAAmC,CAAE,OAAO,CNyB1B,GAAO,CMxBzB,gBAAgC,CAAE,OAAO,CNwU1B,GAAO,CMvUtB,iBAAiC,CAAE,OAAO,CNqC1B,GAAO,CMpCvB,eAA+B,CAAE,OAAO,CNoL1B,GAAO,CMnLrB,eAA+B,CAAE,OAAO,CNiB1B,GAAO,CMhBrB,iBAAiC,CAAE,OAAO,CNqO1B,GAAO,CMpOvB,sBAAsC,CAAE,OAAO,CN+a1B,GAAO,CM9a5B,qBAAqC,CAAE,OAAO,CN+a1B,GAAO,CM9a3B,qBAAqC,CAAE,OAAO,CN3C1B,GAAO,CM4C3B,uBAAuC,CAAE,OAAO,CN9C1B,GAAO,CM+C7B,sBAAsC,CAAE,OAAO,CN5C1B,GAAO,CM6C5B,wBAAwC,CAAE,OAAO,CN/C1B,GAAO,CMgD9B,eAA+B,CAAE,OAAO,CNwP1B,GAAO,CMvPrB,oCACkC,CAAE,OAAO,CN0R1B,GAAO,CMzRxB,iBAAiC,CAAE,OAAO,CNoN1B,GAAO,CMnNvB,uBAAuC,CAAE,OAAO,CNqd1B,GAAO,CMpd7B,sDAEoC,CAAE,OAAO,CNsS1B,GAAO,CMrS1B,iBAAiC,CAAE,OAAO,CN+R1B,GAAO,CM9RvB,qBAAqC,CAAE,OAAO,CN+P1B,GAAO,CM9P3B,iBAAiC,CAAE,OAAO,CN7D1B,GAAO,CM8DvB,eAA+B,CAAE,OAAO,CN4a1B,GAAO,CM3arB,0CAC0C,CAAE,OAAO,CN4R1B,GAAO,CM3RhC,yBAAyC,CAAE,OAAO,CN2V1B,GAAO,CM1V/B,yBAAyC,CAAE,OAAO,CNqC1B,GAAO,CMpC/B,iBAAiC,CAAE,OAAO,CNlC1B,GAAO,CMmCvB,wBAAwC,CAAE,OAAO,CNmY1B,GAAO,CMlY9B,wBAAwC,CAAE,OAAO,CNkH1B,GAAO,CMjH9B,mBAAmC,CAAE,OAAO,CN9B1B,GAAO,CM+BzB,eAA+B,CAAE,OAAO,CNgS1B,GAAO,CM/RrB,gBAAgC,CAAE,OAAO,CN+Q1B,GAAO,CM9QtB,eAA+B,CAAE,OAAO,CNiY1B,GAAO,CMhYrB,kBAAkC,CAAE,OAAO,CNqJ1B,GAAO,CMpJxB,uBAAuC,CAAE,OAAO,CN6G1B,GAAO,CM5G7B,uBAAuC,CAAE,OAAO,CN4X1B,GAAO,CM3X7B,gBAAgC,CAAE,OAAO,CNoF1B,GAAO,CMnFtB,uBAAuC,CAAE,OAAO,CN+B1B,GAAO,CM9B7B,wBAAwC,CAAE,OAAO,CN+B1B,GAAO,CM9B9B,sBAAsC,CAAE,OAAO,CN4R1B,GAAO,CM3R5B,uBAAuC,CAAE,OAAO,CNkP1B,GAAO,CMjP7B,8FAAuC,CAAE,OAAO,CNsZ1B,GAAO,CMrZ7B,+FAAuC,CAAE,OAAO,CNiB1B,GAAO,CMhB7B,0BAA0C,CAAE,OAAO,CNiS1B,GAAO,CMhShC,sBAAsC,CAAE,OAAO,CNuL1B,GAAO,CMtL5B,qBAAqC,CAAE,OAAO,CNuD1B,GAAO,CMtD3B,yBAAyC,CAAE,OAAO,CNkZ1B,GAAO,CMjZ/B,yBAAyC,CAAE,OAAO,CNa1B,GAAO,CMZ/B,cAA8B,CAAE,OAAO,CNhD1B,GAAO,CMiDpB,qBAAqC,CAAE,OAAO,CN5D1B,GAAO,CM6D3B,sBAAsC,CAAE,OAAO,CN5D1B,GAAO,CM6D5B,mBAAmC,CAAE,OAAO,CN5D1B,GAAO,CM6DzB,qBAAqC,CAAE,OAAO,CNhE1B,GAAO,CMiE3B,wCACgC,CAAE,OAAO,CNyT1B,GAAO,CMxTtB,iBAAiC,CAAE,OAAO,CN+E1B,GAAO,CM9EvB,mBAAmC,CAAE,OAAO,CNuC1B,GAAO,CMtCzB,eAA+B,CAAE,OAAO,CNyQ1B,GAAO,CMxQrB,gBAAgC,CAAE,OAAO,CN+N1B,GAAO,CM9NtB,mBAAmC,CAAE,OAAO,CN/D1B,GAAO,CMgEzB,gNAA6C,CAAE,OAAO,CNwE1B,GAAO,CMvEnC,eAA+B,CAAE,OAAO,CNmI1B,GAAO,CMlIrB,eAA+B,CAAE,OAAO,CNqL1B,GAAO,CMpLrB,iCAA+B,CAAE,OAAO,CNyG1B,GAAO,CMxGrB,cAA8B,CAAE,OAAO,CNyE1B,GAAO,CMxEpB,oBAAoC,CAAE,OAAO,CNyE1B,GAAO,CMxE1B,kDAC+C,CAAE,OAAO,CNkE1B,GAAO,CMjErC,gBAAgC,CAAE,OAAO,CNyP1B,GAAO,CMxPtB,mBAAmC,CAAE,OAAO,CNlC1B,GAAO,CMmCzB,iBAAiC,CAAE,OAAO,CN0Q1B,GAAO,CMzQvB,kBAAkC,CAAE,OAAO,CNmB1B,GAAO,CMlBxB,iBAAiC,CAAE,OAAO,CNqM1B,GAAO,CMpMvB,qBAAqC,CAAE,OAAO,CNH1B,GAAO,CMI3B,uBAAuC,CAAE,OAAO,CNP1B,GAAO,CMQ7B,kBAAkC,CAAE,OAAO,CNiR1B,GAAO,CMhRxB,wBAAwC,CAAE,OAAO,CN2S1B,GAAO,CM1S9B,iBAAiC,CAAE,OAAO,CNoG1B,GAAO,CMnGvB,sBAAsC,CAAE,OAAO,CNqG1B,GAAO,CMpG5B,mBAAmC,CAAE,OAAO,CNpF1B,GAAO,CMqFzB,mBAAmC,CAAE,OAAO,CNtF1B,GAAO,CMuFzB,2CACoC,CAAE,OAAO,CNhF1B,GAAO,CMiF1B,yBAAyC,CAAE,OAAO,CNkY1B,GAAO,CMjY/B,0BAA0C,CAAE,OAAO,CNyD1B,GAAO,CMxDhC,uBAAuC,CAAE,OAAO,CN/C1B,GAAO,CMgD7B,cAA8B,CAAE,OAAO,CNsJ1B,GAAO,CMrJpB,gCAC+B,CAAE,OAAO,CNA1B,GAAO,CMCrB,mBAAmC,CAAE,OAAO,CNG1B,GAAO,CMFzB,sBAAsC,CAAE,OAAO,CNiW1B,GAAO,CMhW5B,wBAAwC,CAAE,OAAO,CN+V1B,GAAO,CM9V9B,oBAAoC,CAAE,OAAO,CN2T1B,GAAO,CM1T1B,kBAAkC,CAAE,OAAO,CN4H1B,GAAO,CM3HxB,mBAAmC,CAAE,OAAO,CN2R1B,GAAO,CM1RzB,0BAA0C,CAAE,OAAO,CNiK1B,GAAO,CMhKhC,qBAAqC,CAAE,OAAO,CNwV1B,GAAO,CMvV3B,wBAAwC,CAAE,OAAO,CNsC1B,GAAO,CMrC9B,kBAAkC,CAAE,OAAO,CNsR1B,GAAO,CMrRxB,iBAAiC,CAAE,OAAO,CNyW1B,GAAO,CMxWvB,wBAAwC,CAAE,OAAO,CNiG1B,GAAO,CMhG9B,iBAAiC,CAAE,OAAO,CNyX1B,GAAO,CMxXvB,kBAAkC,CAAE,OAAO,CN+I1B,GAAO,CM9IxB,gBAAgC,CAAE,OAAO,CN6M1B,GAAO,CM5MtB,mBAAmC,CAAE,OAAO,CN2S1B,GAAO,CM1SzB,qBAAqC,CAAE,OAAO,CNjF1B,GAAO,CMkF3B,uBAAuC,CAAE,OAAO,CN2M1B,GAAO,CM1M7B,kBAAkC,CAAE,OAAO,CNyW1B,GAAO,CMxWxB,mBAAmC,CAAE,OAAO,CNgC1B,GAAO,CM/BzB,qCAAiC,CAAE,OAAO,CNsF1B,GAAO,CMrFvB,iBAAiC,CAAE,OAAO,CN6W1B,GAAO,CM5WvB,sBAAsC,CAAE,OAAO,CNb1B,GAAO,CMc5B,cAA8B,CAAE,OAAO,CNmP1B,GAAO,CMlPpB,gBAAgC,CAAE,OAAO,CNoG1B,GAAO,CMnGtB,mBAAmC,CAAE,OAAO,CNpF1B,GAAO,CMqFzB,eAA+B,CAAE,OAAO,CN1G1B,GAAO,CM2GrB,sBAAsC,CAAE,OAAO,CN7D1B,GAAO,CM8D5B,uBAAuC,CAAE,OAAO,CN8F1B,GAAO,CM7F7B,sBAAsC,CAAE,OAAO,CN4F1B,GAAO,CM3F5B,oBAAoC,CAAE,OAAO,CN6F1B,GAAO,CM5F1B,sBAAsC,CAAE,OAAO,CNyF1B,GAAO,CMxF5B,2DAA4C,CAAE,OAAO,CN5I1B,GAAO,CM6IlC,6DAA6C,CAAE,OAAO,CNxI1B,GAAO,CMyInC,0BAA0C,CAAE,OAAO,CNxI1B,GAAO,CMyIhC,4BAA4C,CAAE,OAAO,CNhJ1B,GAAO,CMiJlC,gBAAgC,CAAE,OAAO,CN2E1B,GAAO,CM1EtB,iBAAiC,CAAE,OAAO,CNqX1B,GAAO,CMpXvB,gBAAgC,CAAE,OAAO,CNgT1B,GAAO,CM/StB,iBAAiC,CAAE,OAAO,CNuC1B,GAAO,CMtCvB,oBAAoC,CAAE,OAAO,CNxG1B,GAAO,CMyG1B,qBAAqC,CAAE,OAAO,CNzI1B,GAAO,CM0I3B,iCACgC,CAAE,OAAO,CN8V1B,GAAO,CM7VtB,kDAC+B,CAAE,OAAO,CNwH1B,GAAO,CMvHrB,gBAAgC,CAAE,OAAO,CNxD1B,GAAO,CMyDtB,gBAAgC,CAAE,OAAO,CNsC1B,GAAO,CMrCtB,kCACmC,CAAE,OAAO,CN+N1B,GAAO,CM9NzB,kCACkC,CAAE,OAAO,CNyB1B,GAAO,CMxBxB,oBAAoC,CAAE,OAAO,CN8J1B,GAAO,CM7J1B,mCACmC,CAAE,OAAO,CNiC1B,GAAO,CMhCzB,iBAAiC,CAAE,OAAO,CNkQ1B,GAAO,CMjQvB,qDAE+B,CAAE,OAAO,CN9I1B,GAAO,CM+IrB,kBAAkC,CAAE,OAAO,CNiH1B,GAAO,CMhHxB,kBAAkC,CAAE,OAAO,CN+G1B,GAAO,CM9GxB,wBAAwC,CAAE,OAAO,CN4Q1B,GAAO,CM3Q9B,oBAAoC,CAAE,OAAO,CNgU1B,GAAO,CM/T1B,gBAAgC,CAAE,OAAO,CNkR1B,GAAO,CMjRtB,gBAAgC,CAAE,OAAO,CNmH1B,GAAO,CMlHtB,gBAAgC,CAAE,OAAO,CNmT1B,GAAO,CMlTtB,oBAAoC,CAAE,OAAO,CNgK1B,GAAO,CM/J1B,2BAA2C,CAAE,OAAO,CNgK1B,GAAO,CM/JjC,6BAA6C,CAAE,OAAO,CN8C1B,GAAO,CM7CnC,sBAAsC,CAAE,OAAO,CN4C1B,GAAO,CM3C5B,gBAAgC,CAAE,OAAO,CNgI1B,GAAO,CM/HtB,wEAAqC,CAAE,OAAO,CNxH1B,GAAO,CMyH3B,mBAAmC,CAAE,OAAO,CNlH1B,GAAO,CMmHzB,qBAAqC,CAAE,OAAO,CNzH1B,GAAO,CM0H3B,sBAAsC,CAAE,OAAO,CNzH1B,GAAO,CM0H5B,kBAAkC,CAAE,OAAO,CN3E1B,GAAO,CM4ExB,mCAC+B,CAAE,OAAO,CN4N1B,GAAO,CM3NrB,yCACoC,CAAE,OAAO,CNgO1B,GAAO,CM/N1B,sCACmC,CAAE,OAAO,CN6N1B,GAAO,CM5NzB,mBAAmC,CAAE,OAAO,CN/C1B,GAAO,CMgDzB,mBAAmC,CAAE,OAAO,CNmF1B,GAAO,CMlFzB,sCAC+B,CAAE,OAAO,CN0S1B,GAAO,CMzSrB,iCACgC,CAAE,OAAO,CNW1B,GAAO,CMVtB,0CACqC,CAAE,OAAO,CN0P1B,GAAO,CMzP3B,oBAAoC,CAAE,OAAO,CNxF1B,GAAO,CMyF1B,qBAAqC,CAAE,OAAO,CNvF1B,GAAO,CMwF3B,gCAC+B,CAAE,OAAO,CNlK1B,GAAO,CMmKrB,kBAAkC,CAAE,OAAO,CNoM1B,GAAO,CMnMxB,mBAAmC,CAAE,OAAO,CN8R1B,GAAO,CM7RzB,qCACoC,CAAE,OAAO,CN9G1B,GAAO,CM+G1B,sBAAsC,CAAE,OAAO,CNiE1B,GAAO,CMhE5B,mBAAmC,CAAE,OAAO,CN1D1B,GAAO,CM2DzB,yBAAyC,CAAE,OAAO,CN7G1B,GAAO,CM8G/B,uBAAuC,CAAE,OAAO,CN7G1B,GAAO,CM8G7B,kBAAkC,CAAE,OAAO,CNkS1B,GAAO,CMjSxB,sBAAsC,CAAE,OAAO,CNgO1B,GAAO,CM/N5B,mBAAmC,CAAE,OAAO,CNqO1B,GAAO,CMpOzB,iBAAiC,CAAE,OAAO,CNxL1B,GAAO,CMyLvB,iBAAiC,CAAE,OAAO,CN7G1B,GAAO,CM8GvB,kBAAkC,CAAE,OAAO,CN3F1B,GAAO,CM4FxB,sBAAsC,CAAE,OAAO,CNpC1B,GAAO,CMqC5B,qBAAqC,CAAE,OAAO,CNzK1B,GAAO,CM0K3B,qBAAqC,CAAE,OAAO,CNqB1B,GAAO,CMpB3B,oBAAoC,CAAE,OAAO,CN3O1B,GAAO,CM4O1B,iBAAiC,CAAE,OAAO,CN4E1B,GAAO,CM3EvB,sBAAsC,CAAE,OAAO,CNxD1B,GAAO,CMyD5B,eAA+B,CAAE,OAAO,CNrM1B,GAAO,CMsMrB,mBAAmC,CAAE,OAAO,CNG1B,GAAO,CMFzB,sBAAsC,CAAE,OAAO,CNuH1B,GAAO,CMtH5B,4BAA4C,CAAE,OAAO,CN5O1B,GAAO,CM6OlC,6BAA6C,CAAE,OAAO,CN5O1B,GAAO,CM6OnC,0BAA0C,CAAE,OAAO,CN5O1B,GAAO,CM6OhC,4BAA4C,CAAE,OAAO,CNhP1B,GAAO,CMiPlC,qBAAqC,CAAE,OAAO,CN5O1B,GAAO,CM6O3B,sBAAsC,CAAE,OAAO,CN5O1B,GAAO,CM6O5B,mBAAmC,CAAE,OAAO,CN5O1B,GAAO,CM6OzB,qBAAqC,CAAE,OAAO,CNhP1B,GAAO,CMiP3B,kBAAkC,CAAE,OAAO,CNxG1B,GAAO,CMyGxB,iBAAiC,CAAE,OAAO,CNyB1B,GAAO,CMxBvB,iBAAiC,CAAE,OAAO,CNmN1B,GAAO,CMlNvB,yCACiC,CAAE,OAAO,CNmE1B,GAAO,CMlEvB,mBAAmC,CAAE,OAAO,CNlJ1B,GAAO,CMmJzB,qBAAqC,CAAE,OAAO,CNiH1B,GAAO,CMhH3B,sBAAsC,CAAE,OAAO,CNiH1B,GAAO,CMhH5B,kBAAkC,CAAE,OAAO,CNiL1B,GAAO,CMhLxB,iBAAiC,CAAE,OAAO,CNvJ1B,GAAO,CMwJvB,sCACgC,CAAE,OAAO,CNyH1B,GAAO,CMxHtB,qBAAqC,CAAE,OAAO,CN9B1B,GAAO,CM+B3B,mBAAmC,CAAE,OAAO,CNjD1B,GAAO,CMkDzB,wBAAwC,CAAE,OAAO,CNhD1B,GAAO,CMiD9B,kBAAkC,CAAE,OAAO,CN2J1B,GAAO,CM1JxB,kBAAkC,CAAE,OAAO,CN9C1B,GAAO,CM+CxB,gBAAgC,CAAE,OAAO,CN+C1B,GAAO,CM9CtB,kBAAkC,CAAE,OAAO,CN9C1B,GAAO,CM+CxB,qBAAqC,CAAE,OAAO,CNI1B,GAAO,CMH3B,iBAAiC,CAAE,OAAO,CN9D1B,GAAO,CM+DvB,yBAAyC,CAAE,OAAO,CNhE1B,GAAO,CMiE/B,mBAAmC,CAAE,OAAO,CNsM1B,GAAO,CMrMzB,eAA+B,CAAE,OAAO,CN1J1B,GAAO,CM2JrB,8CACoC,CAAE,OAAO,CN4G1B,GAAO,CM3G1B,2EAEsC,CAAE,OAAO,CNwK1B,GAAO,CMvK5B,yBAAyC,CAAE,OAAO,CNmB1B,GAAO,CMlB/B,eAA+B,CAAE,OAAO,CNjJ1B,GAAO,CMkJrB,oBAAoC,CAAE,OAAO,CNjK1B,GAAO,CMkK1B,yCACuC,CAAE,OAAO,CN9L1B,GAAO,CM+L7B,mBAAmC,CAAE,OAAO,CNmF1B,GAAO,CMlFzB,eAA+B,CAAE,OAAO,CNvB1B,GAAO,CMwBrB,sBAAsC,CAAE,OAAO,CNvH1B,GAAO,CMwH5B,sBAAsC,CAAE,OAAO,CN6K1B,GAAO,CM5K5B,oBAAoC,CAAE,OAAO,CNyK1B,GAAO,CMxK1B,iBAAiC,CAAE,OAAO,CN9H1B,GAAO,CM+HvB,uBAAuC,CAAE,OAAO,CN0E1B,GAAO,CMzE7B,qBAAqC,CAAE,OAAO,CNwB1B,GAAO,CMvB3B,2BAA2C,CAAE,OAAO,CNwB1B,GAAO,CMvBjC,iBAAiC,CAAE,OAAO,CNqH1B,GAAO,CMpHvB,qBAAqC,CAAE,OAAO,CN9N1B,GAAO,CM+N3B,4BAA4C,CAAE,OAAO,CN1F1B,GAAO,CM2FlC,iBAAiC,CAAE,OAAO,CN2F1B,GAAO,CM1FvB,iBAAiC,CAAE,OAAO,CNc1B,GAAO,CMbvB,8BAA8C,CAAE,OAAO,CNtM1B,GAAO,CMuMpC,+BAA+C,CAAE,OAAO,CNtM1B,GAAO,CMuMrC,4BAA4C,CAAE,OAAO,CNtM1B,GAAO,CMuMlC,8BAA8C,CAAE,OAAO,CN1M1B,GAAO,CM2MpC,gBAAgC,CAAE,OAAO,CN7C1B,GAAO,CM8CtB,eAA+B,CAAE,OAAO,CNtK1B,GAAO,CMuKrB,iBAAiC,CAAE,OAAO,CN9S1B,GAAO,CM+SvB,qBAAqC,CAAE,OAAO,CN+M1B,GAAO,CM9M3B,mBAAmC,CAAE,OAAO,CN/O1B,GAAO,CMgPzB,qBAAqC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ3B,qBAAqC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ3B,qBAAqC,CAAE,OAAO,CNmF1B,GAAO,CMlF3B,sBAAsC,CAAE,OAAO,CN6C1B,GAAO,CM5C5B,iBAAiC,CAAE,OAAO,CN0K1B,GAAO,CMzKvB,uBAAuC,CAAE,OAAO,CNO1B,GAAO,CMN7B,wIAAyC,CAAE,OAAO,CNO1B,GAAO,CMN/B,mBAAmC,CAAE,OAAO,CN/B1B,GAAO,CMgCzB,qBAAqC,CAAE,OAAO,CNjC1B,GAAO,CMkC3B,uBAAuC,CAAE,OAAO,CN3N1B,GAAO,CM4N7B,wBAAwC,CAAE,OAAO,CNyB1B,GAAO,CMxB9B,+BAA+C,CAAE,OAAO,CNlJ1B,GAAO,CMmJrC,uBAAuC,CAAE,OAAO,CNuF1B,GAAO,CMtF7B,kBAAkC,CAAE,OAAO,CN9L1B,GAAO,CM+LxB,qDAC8C,CAAE,OAAO,CNnP1B,GAAO,CMoPpC,iDAC4C,CAAE,OAAO,CNlP1B,GAAO,CMmPlC,uDAC+C,CAAE,OAAO,CNrP1B,GAAO,CMsPrC,8BAC8B,CAAE,OAAO,CNpK1B,GAAO,CMqKpB,cAA8B,CAAE,OAAO,CNzG1B,GAAO,CM0GpB,gCAC8B,CAAE,OAAO,CNwL1B,GAAO,CMvLpB,+BAC8B,CAAE,OAAO,CNrE1B,GAAO,CMsEpB,2DAG8B,CAAE,OAAO,CNnE1B,GAAO,CMoEpB,iDAE8B,CAAE,OAAO,CNqD1B,GAAO,CMpDpB,6BAC8B,CAAE,OAAO,CNpE1B,GAAO,CMqEpB,iCAC8B,CAAE,OAAO,CN1R1B,GAAO,CM2RpB,eAA+B,CAAE,OAAO,CNlK1B,GAAO,CMmKrB,oBAAoC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ1B,yBAAyC,CAAE,OAAO,CN4E1B,GAAO,CM3E/B,0BAA0C,CAAE,OAAO,CN4E1B,GAAO,CM3EhC,0BAA0C,CAAE,OAAO,CN4E1B,GAAO,CM3EhC,2BAA2C,CAAE,OAAO,CN4E1B,GAAO,CM3EjC,2BAA2C,CAAE,OAAO,CN+E1B,GAAO,CM9EjC,4BAA4C,CAAE,OAAO,CN+E1B,GAAO,CM9ElC,oBAAoC,CAAE,OAAO,CN+H1B,GAAO,CM9H1B,sBAAsC,CAAE,OAAO,CN2H1B,GAAO,CM1H5B,yBAAyC,CAAE,OAAO,CN4L1B,GAAO,CM3L/B,kBAAkC,CAAE,OAAO,CNyL1B,GAAO,CMxLxB,eAA+B,CAAE,OAAO,CNmL1B,GAAO,CMlLrB,sBAAsC,CAAE,OAAO,CNmL1B,GAAO,CMlL5B,uBAAuC,CAAE,OAAO,CNuL1B,GAAO,CMtL7B,kBAAkC,CAAE,OAAO,CN/M1B,GAAO,CMgNxB,yBAAyC,CAAE,OAAO,CNgF1B,GAAO,CM/E/B,oBAAoC,CAAE,OAAO,CNjG1B,GAAO,CMkG1B,iBAAiC,CAAE,OAAO,CNxJ1B,GAAO,CMyJvB,cAA8B,CAAE,OAAO,CNhX1B,GAAO,CMiXpB,2CAAoC,CAAE,OAAO,CNzT1B,GAAO,CM0T1B,2BAA2C,CAAE,OAAO,CNzT1B,GAAO,CM0TjC,iBAAiC,CAAE,OAAO,CNqI1B,GAAO,CMpIvB,wBAAwC,CAAE,OAAO,CNqI1B,GAAO,CMpI9B,0BAA0C,CAAE,OAAO,CNrE1B,GAAO,CMsEhC,wBAAwC,CAAE,OAAO,CNnE1B,GAAO,CMoE9B,0BAA0C,CAAE,OAAO,CNtE1B,GAAO,CMuEhC,2BAA2C,CAAE,OAAO,CNtE1B,GAAO,CMuEjC,gBAAgC,CAAE,OAAO,CNxW1B,GAAO,CMyWtB,kBAAkC,CAAE,OAAO,CN8J1B,GAAO,CM7JxB,kBAAkC,CAAE,OAAO,CNpX1B,GAAO,CMqXxB,gBAAgC,CAAE,OAAO,CNnF1B,GAAO,CMoFtB,mBAAmC,CAAE,OAAO,CNjO1B,GAAO,CMkOzB,gBAAgC,CAAE,OAAO,CNsC1B,GAAO,CMrCtB,qBAAqC,CAAE,OAAO,CNhK1B,GAAO,CMiK3B,iBAAiC,CAAE,OAAO,CNmH1B,GAAO,CMlHvB,iBAAiC,CAAE,OAAO,CNxM1B,GAAO,CMyMvB,eAA+B,CAAE,OAAO,CNzE1B,GAAO,CM0ErB,iBAAiC,CAAE,OAAO,CNrJ1B,GAAO,CMsJvB,gBAAgC,CAAE,OAAO,CN2E1B,GAAO,CM1EtB,iBAAiC,CAAE,OAAO,CN7D1B,GAAO,CM8DvB,kBAAkC,CAAE,OAAO,CNpX1B,GAAO,CMqXxB,cAA8B,CAAE,OAAO,CNpU1B,GAAO,CMqUpB,aAA6B,CAAE,OAAO,CNsI1B,GAAO,CMrInB,gBAAgC,CAAE,OAAO,CN2I1B,GAAO,CM1ItB,iBAAiC,CAAE,OAAO,CNX1B,GAAO,CMYvB,oBAAoC,CAAE,OAAO,CN5D1B,GAAO,CM6D1B,yBAAyC,CAAE,OAAO,CNgD1B,GAAO,CM/C/B,+BAA+C,CAAE,OAAO,CNrX1B,GAAO,CMsXrC,8BAA8C,CAAE,OAAO,CNvX1B,GAAO,CMwXpC,qDAC8C,CAAE,OAAO,CN5T1B,GAAO,CM6TpC,uBAAuC,CAAE,OAAO,CNvP1B,GAAO,CMwP7B,qBAAqC,CAAE,OAAO,CNoI1B,GAAO,CMnI3B,uBAAuC,CAAE,OAAO,CNyH1B,GAAO,CMxH7B,sCAC8B,CAAE,OAAO,CNiG1B,GAAO,CMhGpB,wEAAwC,CAAE,OAAO,CNzC1B,GAAO,CM0C9B,wBAAwC,CAAE,OAAO,CN+B1B,GAAO,CM9B9B,gBAAgC,CAAE,OAAO,CNa1B,GAAO,CMZtB,0BAA0C,CAAE,OAAO,CNnP1B,GAAO,CMoPhC,oBAAoC,CAAE,OAAO,CNgI1B,GAAO,CM/H1B,iBAAiC,CAAE,OAAO,CN9E1B,GAAO,CM+EvB,4DAEqC,CAAE,OAAO,CNmG1B,GAAO,CMlG3B,iDACyC,CAAE,OAAO,CN3K1B,GAAO,CM4K/B,gBAAgC,CAAE,OAAO,CN6H1B,GAAO,CM5HtB,iBAAiC,CAAE,OAAO,CNjL1B,GAAO,CMkLvB,iBAAiC,CAAE,OAAO,CNxC1B,GAAO,CMyCvB,wBAAwC,CAAE,OAAO,CNxC1B,GAAO,CMyC9B,6BAA6C,CAAE,OAAO,CNuC1B,GAAO,CMtCnC,sBAAsC,CAAE,OAAO,CNqC1B,GAAO,CMpC5B,oBAAoC,CAAE,OAAO,CNlR1B,GAAO,CMmR1B,eAA+B,CAAE,OAAO,CNhR1B,GAAO,CMiRrB,qBAAqC,CAAE,OAAO,CNxE1B,GAAO,CMyE3B,yBAAyC,CAAE,OAAO,CNxE1B,GAAO,CMyE/B,iBAAiC,CAAE,OAAO,CN7Q1B,GAAO,CM8QvB,iBAAiC,CAAE,OAAO,CN3J1B,GAAO,CM4JvB,mBAAmC,CAAE,OAAO,CNtJ1B,GAAO,CMuJzB,cAA8B,CAAE,OAAO,CNtP1B,GAAO,CMuPpB,mBAAmC,CAAE,OAAO,CN3W1B,GAAO,CM4WzB,gBAAgC,CAAE,OAAO,CNjU1B,GAAO,CMkUtB,cAA8B,CAAE,OAAO,CN1F1B,GAAO,CM2FpB,gBAAgC,CAAE,OAAO,CNM1B,GAAO,CMLtB,eAA+B,CAAE,OAAO,CNrS1B,GAAO,CMsSrB,gBAAgC,CAAE,OAAO,CNrS1B,GAAO,CMsStB,kBAAkC,CAAE,OAAO,CNtY1B,GAAO,CMuYxB,yBAAyC,CAAE,OAAO,CNtY1B,GAAO,CMuY/B,gBAAgC,CAAE,OAAO,CNa1B,GAAO,CMZtB,uBAAuC,CAAE,OAAO,CNa1B,GAAO,CMZ7B,kBAAkC,CAAE,OAAO,CN/D1B,GAAO,CMgExB,oCAC8B,CAAE,OAAO,CN5W1B,GAAO,CM6WpB,8BAC+B,CAAE,OAAO,CN2B1B,GAAO,CM1BrB,eAA+B,CAAE,OAAO,CNoD1B,GAAO,CMnDrB,kBAAkC,CAAE,OAAO,CNN1B,GAAO,CMOxB,qBAAqC,CAAE,OAAO,CNzS1B,GAAO,CM0S3B,qBAAqC,CAAE,OAAO,CNZ1B,GAAO,CMa3B,mBAAmC,CAAE,OAAO,CN/S1B,GAAO,CMgTzB,qBAAqC,CAAE,OAAO,CNhQ1B,GAAO,CMiQ3B,sBAAsC,CAAE,OAAO,CNzP1B,GAAO,CM0P5B,uBAAuC,CAAE,OAAO,CNtQ1B,GAAO,CMuQ7B,4BAA4C,CAAE,OAAO,CNhQ1B,GAAO,CMiQlC,yEAEuC,CAAE,OAAO,CNzQ1B,GAAO,CM0Q7B,+CACyC,CAAE,OAAO,CN/Q1B,GAAO,CMgR/B,+CACuC,CAAE,OAAO,CNhR1B,GAAO,CMiR7B,+CACuC,CAAE,OAAO,CNrQ1B,GAAO,CMsQ7B,sBAAsC,CAAE,OAAO,CNlR1B,GAAO,CMmR5B,eAA+B,CAAE,OAAO,CN4D1B,GAAO,CM3DrB,kBAAkC,CAAE,OAAO,CNrV1B,GAAO,CMsVxB,mBAAmC,CAAE,OAAO,CNhM1B,GAAO,CMiMzB,uGAIoC,CAAE,OAAO,CNtL1B,GAAO,CMuL1B,yBAAyC,CAAE,OAAO,CNvW1B,GAAO,CMwW/B,8BACgC,CAAE,OAAO,CNlG1B,GAAO,CMmGtB,+BACiC,CAAE,OAAO,CN1T1B,GAAO,CM2TvB,qBAAqC,CAAE,OAAO,CNpP1B,GAAO,CMqP3B,cAA8B,CAAE,OAAO,CNtP1B,GAAO,CMuPpB,sBAAsC,CAAE,OAAO,CNxO1B,GAAO,CMyO5B,wBAAwC,CAAE,OAAO,CNR1B,GAAO,CMS9B,aAA6B,CAAE,OAAO,CNjH1B,GAAO,CMkHnB,mCACiC,CAAE,OAAO,CNiD1B,GAAO,CMhDvB,sCACsC,CAAE,OAAO,CNrJ1B,GAAO,CMsJ5B,0CACwC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ9B,kBAAkC,CAAE,OAAO,CNvO1B,GAAO,CMwOxB,sBAAsC,CAAE,OAAO,CNvX1B,GAAO,CMwX5B,iBAAiC,CAAE,OAAO,CN7O1B,GAAO,CM8OvB,oBAAoC,CAAE,OAAO,CNxJ1B,GAAO,CMyJ1B,kBAAkC,CAAE,OAAO,CNvE1B,GAAO,CMwExB,oBAAoC,CAAE,OAAO,CNtF1B,GAAO,CMuF1B,2BAA2C,CAAE,OAAO,CNtF1B,GAAO,CMuFjC,eAA+B,CAAE,OAAO,CNnb1B,GAAO,CMobrB,4CACmC,CAAE,OAAO,CNjR1B,GAAO,CMkRzB,cAA8B,CAAE,OAAO,CNI1B,GAAO,CMHpB,qBAAqC,CAAE,OAAO,CN9b1B,GAAO,CM+b3B,eAA+B,CAAE,OAAO,CN5I1B,GAAO,CM6IrB,qBAAqC,CAAE,OAAO,CN/E1B,GAAO,CMgF3B,iBAAiC,CAAE,OAAO,CNI1B,GAAO,CMHvB,eAA+B,CAAE,OAAO,CNuC1B,GAAO,CMtCrB,sBAAsC,CAAE,OAAO,CN7K1B,GAAO,CM8K5B,eAA+B,CAAE,OAAO,CN6B1B,GAAO,CM5BrB,qBAAqC,CAAE,OAAO,CNjb1B,GAAO,CMkb3B,iBAAiC,CAAE,OAAO,CNpK1B,GAAO,CMqKvB,wBAAwC,CAAE,OAAO,CNzQ1B,GAAO,CM0Q9B,kBAAkC,CAAE,OAAO,CNha1B,GAAO,CMiaxB,wBAAwC,CAAE,OAAO,CNpa1B,GAAO,CMqa9B,sBAAsC,CAAE,OAAO,CNta1B,GAAO,CMua5B,kBAAkC,CAAE,OAAO,CNxa1B,GAAO,CMyaxB,oBAAoC,CAAE,OAAO,CNta1B,GAAO,CMua1B,oBAAoC,CAAE,OAAO,CNta1B,GAAO,CMua1B,qBAAqC,CAAE,OAAO,CNjd1B,GAAO,CMkd3B,uBAAuC,CAAE,OAAO,CNjd1B,GAAO,CMkd7B,gBAAgC,CAAE,OAAO,CNtB1B,GAAO,CMuBtB,oBAAoC,CAAE,OAAO,CN9X1B,GAAO,CM+X1B,aAA6B,CAAE,OAAO,CNne1B,GAAO,CMoenB,qBAAqC,CAAE,OAAO,CNtV1B,GAAO,CMuV3B,sBAAsC,CAAE,OAAO,CN1L1B,GAAO,CM2L5B,wBAAwC,CAAE,OAAO,CNpd1B,GAAO,CMqd9B,qBAAqC,CAAE,OAAO,CNzf1B,GAAO,CM0f3B,oBAAoC,CAAE,OAAO,CN7K1B,GAAO,CM8K1B,qBAAqC,CAAE,OAAO,CNzO1B,GAAO,CM0O3B,iBAAiC,CAAE,OAAO,CNtP1B,GAAO,CMuPvB,wBAAwC,CAAE,OAAO,CNtP1B,GAAO,CMuP9B,qBAAqC,CAAE,OAAO,CNrC1B,GAAO,CMsC3B,oBAAoC,CAAE,OAAO,CNrC1B,GAAO,CMsC1B,kBAAkC,CAAE,OAAO,CN9d1B,GAAO,CM+dxB,cAA8B,CAAE,OAAO,CN5c1B,GAAO,CM6cpB,kBAAkC,CAAE,OAAO,CNtQ1B,GAAO,CMuQxB,oBAAoC,CAAE,OAAO,CN9gB1B,GAAO,CM+gB1B,aAA6B,CAAE,OAAO,CN/b1B,GAAO,CMgcnB,kDAE8B,CAAE,OAAO,CNpR1B,GAAO,CMqRpB,mBAAmC,CAAE,OAAO,CN/N1B,GAAO,COtUzB,swBAAK,CACH,WAAW,CAAE,OAAO,CACpB,y5BAAQ,CACN,WAAW,CC+BuB,aAAa,CD9B/C,OAAO,CAAE,YAAY,CACrB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,eAAe,CAAE,OAAO,CAM5B,86BAAkB,CAChB,OAAO,CAAE,YAAY,CACrB,eAAe,CAAE,OAAO,CAGxB,muEAAgB,CACd,OAAO,CAAE,MAAM,CACf,2wEAAuB,CACrB,WAAW,CAAE,KAAI,CACnB,utEAAsB,CACpB,OAAO,CAAE,YAAY,CAE3B,2iBAA2B,CACzB,OAAO,CAAE,GAAE,CfpBL,kBAAoB,CAAE,qBAAM,CAK5B,eAAiB,CAAE,qBAAM,CAezB,UAAY,CAAE,qBAAM,CeE5B,+nBAAiC,CAC/B,OAAO,CAAE,CAAC,CAGV,mtCAAuB,CACrB,SAAS,CAAE,IAAI,CACf,cAAc,CAAE,IAAI,CEpBxB,0PAAS,CACP,OAAO,CAAE,IAAqB,CAC9B,WAAW,CDayB,IAAI,CCZxC,aAAa,CDYuB,IAAI,CCXxC,UAAU,CAAE,OAAmB,CAEjC,8CAAe,CACb,KAAK,CDkC+B,IAAM,CCjC1C,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAK,CACd,KAAK,CD+B+B,IAAM,CC9B1C,UAAU,CAAE,OAAkB,CAC9B,MAAM,CAAE,KAAsB,CAC9B,OAAO,CAAE,QAA2C,CACpD,aAAa,CAAE,IAAqB,CAEtC,0ZAAyB,CACvB,UAAU,CAAE,OAAkB,CAC9B,mxCAAe,CACb,UAAU,CAAE,OAAiB,CACjC,kYAA0B,CACxB,UAAU,CAAE,OAAmB,CAC/B,ouCAAe,CACb,UAAU,CAAE,OAAoB,CAEpC,sYAAuB,CACrB,UAAU,CAAE,OAAmB,CAC/B,yuCAAe,CACb,UAAU,CAAE,OAAkB,CAElC,mZAA0B,CACxB,UAAU,CAAE,OAAuB,CACnC,swCAAe,CACb,UAAU,CAAE,OAAqB,CAErC,scAA0B,CACxB,UAAU,CDmB0B,OAAmB,CClBvD,42CAAe,CACb,KAAK,CCjD6B,OAAW,CDkD7C,UAAU,CDJwB,OAAmB,CCKvD,8dAAC,CACC,KAAK,CDsB6B,OAAW,CCpBjD,sZAAsB,CACpB,aAAa,CAAE,CAAC,CAsBlB,kBAAkB,CAChB,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,GAAG,CACX,IAAI,CAAE,CAAC,CACP,OAAO,CDG6B,GAAG,CCFvC,qBAAE,CACA,OAAO,CAAE,KAAK,CACd,KAAK,CDT6B,KAAK,CCUvC,UAAU,CAAE,WAAW,CACvB,KAAK,CDlC6B,IAAM,CCmCxC,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,2BAA0B,CACtC,OAAO,CAAE,MAAmB,CAC5B,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CACT,WAAW,CAAE,IAAI,CACjB,QAAQ,CAAE,MAAM,CjB3FZ,kBAAoB,CAAE,gBAAM,CAK5B,eAAiB,CAAE,gBAAM,CAezB,UAAY,CAAE,gBAAM,CiByExB,0CAAsB,CACpB,UAAU,CDhCsB,OAAM,CCiCxC,uCAAmB,CACjB,UAAU,CDzBsB,OAAW,CC0B7C,0CAAsB,CACpB,UAAU,CDnFsB,OAAO,CCoFzC,yCAAqB,CACnB,UAAU,CDtEsB,OAAI,CCuEtC,wBAAI,CACF,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,IAAI,CEhFd,oCAAsB,CFmFxB,kBAAkB,CAChB,MAAM,CAAE,IAAI,CACZ,GAAG,CAAE,CAAC,CACN,KAAK,CAAE,IAAI,CACX,qBAAE,CACA,KAAK,CAAE,IAAI,EG3FjB,MAAM,CACJ,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,CAAC,CACT,cAAc,CAAE,QAAQ,CACxB,eAAe,CAAE,MAAM,CACvB,MAAM,CAAE,OAAO,CACf,WAAW,CAAE,MAAM,CACnB,kBAAkB,CAAE,MAAM,CAC1B,SAAS,CAAE,OAAO,CACpB,gDAAiD,CAC/C,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACZ,gBAAgB,CACd,MAAM,CAAE,OAAO,CAEjB,IAAI,CAEF,OAAO,CAAE,YAAY,CACrB,aAAa,CAAE,GAAG,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,MAAM,CAAE,OAAO,CACf,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,iBAA6F,CACtG,KAAK,CJI+B,IAAM,CIH1C,MAAM,CAAE,yBAAyB,CACjC,gBAAgB,CJeoB,OAAM,CId1C,eAAe,CAAE,IAAI,CACrB,WAAW,CAAE,MAAM,CACnB,WAAW,CFnDyB,uDAAM,CEoD1C,UAAU,CAAE,mFAA8C,CAC1D,YAAY,CAAE,KAAK,CACnB,cAAc,CAAE,MAAM,CACtB,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,CAAC,CACP,iBAAiB,CAAE,IAAI,CpBxDjB,mBAAoB,CoByDb,IAAI,CpBpDX,gBAAiB,CoBoDV,IAAI,CpB/CX,eAAgB,CoB+CT,IAAI,CpBrCX,WAAY,CoBqCL,IAAI,CpBzDX,kBAAoB,CAAE,eAAM,CAK5B,eAAiB,CAAE,eAAM,CAezB,UAAY,CAAE,eAAM,CoByC5B,UAAU,CACR,UAAU,CAAE,OAAwB,CACpC,KAAK,CJd+B,IAAM,CIiB1C,UAAO,CACL,UAAU,CAAE,OAAqC,CACjD,KAAK,CJnB6B,IAAM,CIoB1C,UAAO,CACL,UAAU,CAAE,OAAqC,CACjD,OAAO,CAAE,CAAC,CACZ,WAAQ,CACN,UAAU,CAAE,6EAAyC,CACrD,OAAO,CAAE,iBAA6F,CACxG,YAAS,CACP,KAAK,CJ3B6B,IAAM,CI4B1C,aAAU,CACR,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAEpB,aAAa,CACX,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAChB,4DAA0B,CACxB,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAI,CACb,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAGpB,sBAAsB,CACpB,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAEX,UAAU,CACR,SAAS,CAAE,GAAG,CAEhB,SAAS,CACP,gBAAgB,CAAE,kBAAgB,CAClC,eAAO,CACL,gBAAgB,CAAE,kBAA6B,CAEnD,YAAY,CACV,gBAAgB,CAAE,kBAA2C,CAC7D,KAAK,CAAE,kBAAsB,CAC7B,kBAAO,CACL,gBAAgB,CAAE,kBAAuD,CACzE,KAAK,CFzH6B,OAAW,CE0H/C,oBAAS,CACP,KAAK,CAAE,kBAAsB,CAEjC,YAAY,CACV,gBAAgB,CAAE,kBAAiB,CACnC,kBAAO,CACL,gBAAgB,CAAE,eAA6B,CAEnD,WAAW,CACT,gBAAgB,CAAE,kBAAe,CACjC,iBAAO,CACL,gBAAgB,CAAE,kBAA4B,CAElD,YAAY,CACV,gBAAgB,CAAE,kBAAkB,CACpC,kBAAO,CACL,gBAAgB,CAAE,kBAA+B,CACrD,WAAW,CACT,gBAAgB,CJvIoB,IAAI,CIwIxC,iBAAO,CACL,gBAAgB,CAAE,kBAAoC,CAE1D,SAAS,CACP,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CJxE+B,OAAW,CIyE/C,UAAU,CAAE,IAAI,CAChB,YAAY,CAAE,sBAAsB,CACpC,eAAO,CACL,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CAAE,kBAAoC,CAC3C,UAAU,CAAE,IAAI,CAClB,gBAAQ,CACN,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CAAE,kBAAoC,CAC3C,UAAU,CAAE,IAAI,CAClB,iBAAS,CACP,KAAK,CJnG6B,OAAO,CIqG7C,mCAAoC,CAClC,cAAc,CAAE,MAAM,CAExB,aAAa,CACX,aAAa,CJ1IuB,IAAI,CduExC,KAAK,CAAE,CAAC,CACR,wCAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,mBAAO,CACL,KAAK,CAAE,IAAI,CmB3Ff,YAAY,CACV,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,YAAY,CAIvB,qCAAqC,CACnC,OAAO,CAAE,KAAK,CAChB,iBAAiB,CACf,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,GAAG,CAAE,IAAI,CACT,SAAS,CAAE,IAAI,CACf,UAAU,CL1B0B,OAAyB,CK2B7D,OAAO,CLmD6B,GAAG,CKlDvC,MAAM,CAAE,iBAAgC,CACxC,UAAU,CAAE,2BAA0B,CACtC,OAAO,CAAE,IAAqB,CAC9B,sBAAQ,CACN,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,KAAK,CHnC6B,OAAW,CGoC7C,WAAW,CAAE,MAAM,CACnB,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,MAAuB,CAChC,MAAM,CAAE,OAAO,CACf,4BAAO,CACL,UAAU,CLiCsB,OAAW,CKhC3C,KAAK,CLU2B,IAAM,CKT1C,4BAAY,CACV,UAAU,CAAE,iBAAgC,CAC5C,MAAM,CAAE,KAAuB,CACjC,2BAAW,CACT,cAAc,CAAE,IAAqB,CACrC,gDAAoB,CAClB,KAAK,CAAE,IAAI,CACf,mCAAmB,CACjB,UAAU,CAAE,OAA4B,CACxC,cAAc,CAAE,SAAS,CACzB,WAAW,CAAE,GAAG,CAChB,SAAS,CAAE,GAAG,CACd,yCAAO,CACL,UAAU,CAAE,OAA4B,CAC1C,wCAAI,CACF,KAAK,CLN2B,IAAM,CKQ5C,6CAA6C,CAC3C,MAAM,CAAE,IAAI,CACZ,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,IAAI,CACV,KAAK,CAAE,CAAC,CAGR,iDAAiB,CACf,UAAU,CLnEwB,OAAyB,CKoE3D,UAAU,CAAE,GAAG,CACjB,mDAAmB,CACjB,OAAO,CAAE,QAA2C,CACpD,yDAAO,CACL,UAAU,CLCsB,OAAW,CKA3C,KAAK,CLtB2B,IAAM,CKwB5C,+CAA+C,CAC7C,KAAK,CAAE,CAAC,CACR,IAAI,CAAE,IAAI,CACV,UAAU,CAAE,KAAK,CAGjB,yBAAQ,CACN,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,iBAA0B,CACzC,WAAW,CAAE,qBAAqB,CAClC,YAAY,CAAE,qBAAqB,CACnC,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,KAAK,CACd,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,GAAG,CACT,WAAW,CAAE,IAAI,CACnB,gDAA+B,CAC7B,IAAI,CAAE,IAAI,CCtEZ,uBAAM,CACJ,OAAO,CAAE,KAAK,CAEhB,gIAA+C,CAC7C,OAAO,CAAE,YAAY,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,CAAC,CACR,cAAc,CAAE,MAAM,CAItB,wCAAO,CACL,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,MAAM,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAA+C,CACvD,KAAK,CAAE,IAAI,CACf,4BAAW,CACT,KAAK,CAAE,IAAI,CACX,kCAAK,CACH,OAAO,CAAE,KAAK,CAChB,mCAAM,CACJ,UAAU,CAAE,GAAqB,CAEvC,QAAQ,CACN,MAAM,CAAE,CAAC,CACT,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACZ,MAAM,CACJ,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACV,WAAW,CAAE,MAAM,CACnB,aAAa,CN/BuB,IAAI,CMgCxC,SAAS,CAAE,IAAI,CACf,YAAY,CAAE,IAAI,CACpB,KAAK,CACH,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,cAAa,CACrB,KAAK,CNR+B,IAAU,CMS9C,SAAS,CAAE,GAAG,CAEhB,qBAAuB,CACrB,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,CAAC,CACT,cAAc,CAAE,QAAQ,CACxB,eAAe,CAAE,MAAM,CAGzB,iBAAiB,CACf,aAAa,CNhDuB,IAAI,CduExC,KAAK,CAAE,CAAC,CqBrGR,SAAS,CCCC,IAAQ,CDChB,WAAI,CAAE,IAAI,CACV,YAAK,CAAE,IAAI,CrBkGb,KAAK,CAAE,CAAC,CACR,gDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,uBAAO,CACL,KAAK,CAAE,IAAI,CALb,gDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,uBAAO,CACL,KAAK,CAAE,IAAI,CoBzBf,uDAAyD,CACvD,OAAO,CAAE,IAAI,CACb,KAAK,CN/C+B,OAAI,CMoDxC,mGAA+C,CAC7C,cAAc,CAAE,IAAqB,CACrC,wHAAM,CACJ,KAAK,CAAE,IAAI,CAEX,0tEAAqP,CACnP,KAAK,CAAE,IAAI,CACnB,+BAA+B,CGlF3B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,IAAuC,CCnB5C,YAAoB,CAAE,CAAC,CDqBzB,0CAAa,CACX,YAAoB,CAAE,CAAC,CHgE/B,iCAAiC,CGtF7B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,SAAuC,CAE9C,4CAAa,CACX,YAAoB,CAAE,CAAC,CCA7B,iDAAwB,CACtB,YAAoB,CAAE,CAAC,CAEvB,mDAA0B,CACxB,KAAK,CALY,IAAkC,CJqEzD,iCAAiC,CG1F7B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,SAAuC,CAE9C,4CAAa,CACX,YAAoB,CAAE,CAAC,CCA7B,iDAAwB,CACtB,YAAoB,CAAE,CAAC,CAEvB,mDAA0B,CACxB,KAAK,CALY,IAAkC,CJ0EzD,uDAAuD,CACrD,MAAM,CAAE,SAA2B,CACnC,SAAS,CAAE,GAAG,CAEhB,oBAAoB,CAClB,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,SAA2B,CACnC,SAAS,CAAE,GAAG,CAOZ,osBAAqP,CACnP,KAAK,CAAE,IAAI,CAIjB,uBAAuB,CACrB,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,KAAK,CACnB,KAAK,CAAE,IAAI,CACX,cAAc,CAAE,MAAM,CACtB,SAAS,CAAE,GAAG,CAEhB,gBAAgB,CACd,OAAO,CAAE,KAAK,CACd,KAAK,CN7H+B,IAAI,CM8HxC,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,QAAO,CACnB,UAAU,CAAE,MAAM,CAClB,kBAAC,CACC,SAAS,CAAE,OAAO,CAClB,UAAU,CAAE,MAAM,CAClB,aAAa,CAAE,GAAqB,CACtC,6BAAY,CACV,aAAa,CAAE,CAAC,CA4DpB,KAAK,CACH,WAAW,CAAE,MAAM,CAGnB,6DAAmD,CACjD,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CACf,WAAW,CJ/MuB,uDAAM,CIgNxC,SAAS,CAAE,OAAO,CACpB,gSAAqP,CACnP,kBAAkB,CAAE,IAAI,CACxB,OAAO,CAAE,GAAqB,CAC9B,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAA6B,CACrC,SAAS,CAAE,GAAG,CACd,WAAW,CJvNuB,uDAAM,CIwNxC,UAAU,CAAE,oBAAmC,CAC/C,aAAa,CAAE,CAAC,CtBxNZ,kBAAoB,CAAE,kBAAM,CAK5B,eAAiB,CAAE,kBAAM,CAezB,UAAY,CAAE,kBAAM,CsBuM1B,4BAAwB,CACtB,OAAO,CAAE,iBAAkB,CAC7B,eAAW,CACT,MAAM,CAAE,OAAO,CACjB,0CAAmC,CtB/N7B,kBAAoB,CsBgOZ,UAAU,CtB3NlB,eAAiB,CsB2NT,UAAU,CtB5MlB,UAAY,CsB4MJ,UAAU,CACtB,OAAO,CAAE,CAAC,CACV,YAAY,CAAE,QAAO,CACrB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,IAAI,CACd,oBAAgB,CtBrOV,kBAAoB,CsBsOZ,UAAU,CtBjOlB,eAAiB,CsBiOT,UAAU,CtBlNlB,UAAY,CsBkNJ,UAAU,CACtB,kGAA6D,CAC3D,kBAAkB,CAAE,IAAI,CAC5B,oXAAyU,CACvU,OAAO,CAAE,CAAC,CACV,OAAO,CAAE,cAAc,CACvB,YAAY,CNxLsB,IAAU,CMyL9C,oBAAgB,CACd,YAAY,CAAE,eAA8B,CAC9C,+EAAqE,CACnE,OAAO,CAAE,gBAAsB,CAC/B,OAAO,CAAE,gBAAgB,CAC3B,4aAAiY,CAC/X,MAAM,CAAE,WAAW,CACnB,gBAAgB,CAAE,OAAmC,CAEzD,+DAAiE,CAC/D,KAAK,CNzN+B,OAAI,CM0NxC,MAAM,CAAE,iBAAc,CACxB,iFAAmF,CACjF,YAAY,CN5NwB,OAAI,CM8NxC,yHAA+G,CAC7G,aAAa,CN/NqB,OAAI,CMiO1C,oBAAoB,CAClB,OAAO,CAAE,IAAqB,CAC9B,SAAS,CAAE,IAAI,CAKjB,QAAQ,CACN,QAAQ,CAAE,IAAI,CACd,cAAc,CAAE,GAAG,CACnB,KAAK,CAAE,IAAI,CACX,WAAW,CJ3QyB,uDAAM,CI4Q5C,eAAgB,CACd,OAAO,CAAE,aAAgB,CACzB,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAA6B,CACrC,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,oBAAmC,CtBhRzC,kBAAoB,CAAE,kBAAM,CAK5B,eAAiB,CAAE,kBAAM,CAezB,UAAY,CAAE,kBAAM,CsB+P5B,MAAM,CACJ,MAAM,CAAE,cAA6B,CACrC,gBAAgB,CNpOoB,IAAM,CMqO1C,gBAAW,CACT,MAAM,CAAE,IAAI,CAChB,2BAA4B,CAC1B,OAAO,CAAE,CAAC,CACZ,uFAA2F,CACzF,MAAM,CAAE,WAAW,CACnB,gBAAgB,CAAE,OAAmC,CAKrD,8DAAuD,CACrD,MAAM,CAAE,WAAW,CACvB,sBAAuB,CACrB,MAAM,CAAE,KAAuB,CAE/B,KAAK,CJzS+B,OAAW,CI0S/C,OAAO,CAAE,KAAK,CACd,kCAAK,CACH,cAAc,CAAE,QAAQ,CAI5B,uBAAuB,CACrB,OAAO,CAAE,YAAY,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,CAAC,CACR,cAAc,CAAE,MAAM,CAuBxB,iCAAkC,CAChC,WAAW,CAAE,MAAM,CACnB,OAAO,CAAE,GAAqB,CAC9B,qEAAiB,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CACd,gBAAgB,CNjRkB,OAAmB,CMkRrD,MAAM,CAAE,cAA6B,CACrC,KAAK,CN7U6B,IAAI,CM+U1C,kCAAkC,CAChC,WAAW,CAAE,CAAC,CAChB,kCAAkC,CAChC,YAAY,CAAE,CAAC,CAcjB,UAAU,CACR,KAAK,CAAE,IAAuB,CAC9B,MAAM,CAAE,IAAqB,CAC7B,MAAM,CAAE,MAAwB,CAChC,QAAQ,CAAE,QAAQ,CAClB,aAAa,CAAE,GAAG,CAClB,UAAU,CNrW0B,IAAI,CMsWxC,MAAM,CAAE,OAAO,CtB5WT,kBAAoB,CAAE,oBAAM,CAK5B,eAAiB,CAAE,oBAAM,CAezB,UAAY,CAAE,oBAAM,CsB0V1B,iBAAQ,CACN,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,EAAE,CACX,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,GAAG,CAClB,UAAU,CNhXwB,IAAI,CMiXtC,IAAI,CAAE,IAAI,CACV,GAAG,CAAE,IAAI,CtBvXL,kBAAoB,CAAE,oBAAM,CAK5B,eAAiB,CAAE,oBAAM,CAezB,UAAY,CAAE,oBAAM,CsBqW1B,gBAAO,CACL,OAAO,CAAE,OAAO,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAqB,CAC3B,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,IAAI,CACf,KAAK,CNzX6B,IAAI,CM0X1C,iBAAiB,CACf,UAAU,CAAE,OAAmB,CAC/B,wBAAQ,CACN,IAAI,CN5W8B,IAAI,CM6WtC,UAAU,CNtUwB,OAAM,CMuU1C,uBAAO,CACL,OAAO,CAAE,MAAM,CAEnB,8CAA+C,CAC7C,MAAM,CAAE,WAAW,CAiDnB,wGAAyB,CACvB,KAAK,CN7Z6B,OAAI,CM+ZtC,81BAAqP,CACnP,MAAM,CAAE,iBAAc,CAC1B,iDAAQ,CACN,MAAM,CAAE,iBAAc,CAE1B,mBAAmB,CACjB,WAAW,CAAE,MAAM,CACnB,qCAAiB,CACf,OAAO,CAAE,aAAgB,CACzB,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CAClB,gEAAgE,CAC9D,KAAK,CN3Y+B,OAAM,CM8Y5C,+DAA+D,CAC7D,KAAK,CN/a+B,OAAI,CMkb1C,gEAAgE,CAC9D,KAAK,CNlc+B,OAAO,CMqc7C,6DAA6D,CAC3D,KAAK,CN9Y+B,OAAW,CMoZjD,UAAU,CtB3dF,iBAAoB,CAAE,aAAM,CAK5B,cAAiB,CAAE,aAAM,CAKzB,aAAgB,CAAE,aAAM,CAKxB,YAAe,CAAE,aAAM,CAKvB,SAAY,CAAE,aAAM,CsByc5B,WAAW,CtB7dH,iBAAoB,CAAE,cAAM,CAK5B,cAAiB,CAAE,cAAM,CAKzB,aAAgB,CAAE,cAAM,CAKxB,YAAe,CAAE,cAAM,CAKvB,SAAY,CAAE,cAAM,CsB2c5B,WAAW,CtB/dH,iBAAoB,CAAE,cAAM,CAK5B,cAAiB,CAAE,cAAM,CAKzB,aAAgB,CAAE,cAAM,CAKxB,YAAe,CAAE,cAAM,CAKvB,SAAY,CAAE,cAAM,CsB6c5B,OAAO,CtBjeC,iBAAoB,CAAE,UAAM,CAK5B,cAAiB,CAAE,UAAM,CAKzB,aAAgB,CAAE,UAAM,CAKxB,YAAe,CAAE,UAAM,CAKvB,SAAY,CAAE,UAAM,CsB+c1B,iBAAW,CtBneL,iBAAoB,CsBoeL,wBAAwB,CtB/dvC,cAAiB,CsB+dF,wBAAwB,CtB1dvC,aAAgB,CsB0dD,wBAAwB,CtBrdvC,YAAe,CsBqdA,wBAAwB,CtBhdvC,SAAY,CsBgdG,wBAAwB,CAC7C,kBAAY,CtBreN,iBAAoB,CsBseL,yBAAyB,CtBjexC,cAAiB,CsBieF,yBAAyB,CtB5dxC,aAAgB,CsB4dD,yBAAyB,CtBvdxC,YAAe,CsBudA,yBAAyB,CtBldxC,SAAY,CsBkdG,yBAAyB,CAC9C,kBAAY,CtBveN,iBAAoB,CsBweL,yBAAyB,CtBnexC,cAAiB,CsBmeF,yBAAyB,CtB9dxC,aAAgB,CsB8dD,yBAAyB,CtBzdxC,YAAe,CsBydA,yBAAyB,CtBpdxC,SAAY,CsBodG,yBAAyB,CAEhD,yCAAyC,CAErC,8BAAqB,CACnB,MAAM,CAAE,SAAS,CAEjB,8ZAAqP,CACnP,aAAa,CAAE,KAAK,CACpB,OAAO,CAAE,KAAK,CAClB,cAAK,CACH,aAAa,CAAE,KAAK,CACpB,OAAO,CAAE,KAAK,CAEhB,kYAAqO,CACnO,aAAa,CAAE,CAAC,CAElB,wCAAuB,CACrB,aAAa,CAAE,KAAK,CACpB,UAAU,CAAE,IAAI,CAChB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACb,4BAAW,CACT,MAAM,CAAE,WAAW,CACvB,iEAAmE,CACjE,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,KAAuB,EH5ehC,oCAAsB,CQhC1B,YAAY,CAER,OAAO,CAAE,IAAI,ER8Bb,oCAAsB,CQ5B1B,YAAY,CAER,OAAO,CAAE,IAAI,EAEjB,WAAW,CACT,KAAK,CAAE,IAAI,CAEb,YAAY,CACV,KAAK,CAAE,KAAK,CAEd,WAAW,CACT,KAAK,CAAE,IAAI,CC4Cb,mEAAS,CACP,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CACjB,WAAW,CAAE,IAAI,CACjB,aAAa,CZ/BuB,IAAI,CYgCxC,2FAAO,CACL,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,6BAAkB,CACxB,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,CACpB,yJAAM,CACJ,SAAS,CZjByB,GAAG,CYkBrC,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,OAAO,CZnB2B,QAAmC,CYoBvE,iOAA8B,CAC5B,iBAAiB,CAAE,CAAC,CACtB,qFAAK,CACH,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,IAAI,CAChB,cAAc,CAAE,MAAM,CACtB,WAAW,CAAE,MAAM,CACnB,8FAAE,CACA,WAAW,CZnDqB,IAAI,CYoDpC,aAAa,CAAE,iBAA6B,CAChD,4EAAE,CACA,gBAAgB,CAAE,WAAW,CAC7B,cAAc,CAAE,MAAM,CAE1B,kFAAc,CACZ,WAAW,CAAE,IAAuB,CACpC,mHAAY,CACV,aAAa,CAAE,CAAC,CACpB,4HAA4B,CAC1B,KAAK,CAAE,EAAE,CACT,aAAa,CAAE,CAAC,CAChB,uXAA0C,CACxC,MAAM,CAAE,CAAC,CAEb,mBAAmB,CACjB,KAAK,CZxD+B,IAAwB,CYyD5D,SAAS,CAAE,GAAG,CAChB,kBAAkB,CAChB,KAAK,CZ3D+B,IAAwB,CY4D5D,SAAS,CAAE,GAAG,CAIhB,2HAAyD,CACvD,gBAAgB,CZpCoB,OAAmB,CYsCzD,gBAAgB,CACd,gBAAgB,CZvCoB,OAAmB,CY4CzD,kDAAsB,CACpB,MAAM,CAAE,iBAA6B,CACrC,wDAAE,CACA,aAAa,CAAE,iBAA6B,CAC5C,WAAW,CAAE,iBAA6B,CAC5C,gGAAwB,CACtB,mBAAmB,CAAE,CAAC,CAE1B,kBAAkB,CAChB,MAAM,CAAE,iBAA6B,CAGrC,0BAAE,CACA,aAAa,CAAE,iBAA6B,CAC9C,8CAAwB,CACtB,mBAAmB,CAAE,CAAC,CAGxB,2CAAwB,CACtB,mBAAmB,CAAE,CAAC,CACxB,+CAAM,CACJ,YAAY,CAAE,SAAS,CACvB,aAAa,CAAE,iBAA6B,CAC9C,2CAAwB,CACtB,mBAAmB,CAAE,CAAC,CAG1B,oBAAoB,CAClB,aAAa,CZhHuB,IAAI,CYiHxC,SAAS,CAAE,IAAI,CACf,QAAQ,CAAE,IAAI,CACd,0BAAK,CACH,aAAa,CAAE,YAAY,CAC3B,2DAAM,CACJ,WAAW,CAAE,MAAM,CCzIzB,CAAC,CACC,KAAK,CbkE+B,OAAW,CajE/C,eAAe,CAAE,IAAI,CACrB,MAAM,CAAE,OAAO,CACf,OAAO,CACL,KAAK,CbgD6B,OAAwB,Ca/C5D,SAAS,CACP,KAAK,Cb6C6B,OAAO,CanB7C,IAAI,CACF,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,MAAM,CAEpB,IAAI,CACF,WAAW,CX3CyB,uDAAM,CW4C1C,WAAW,CAAE,MAAM,CACnB,KAAK,CX/C+B,OAAW,CWgD/C,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAClB,UAAU,CbnD0B,OAAO,CaqD7C,aAAa,CACX,UAAU,CAAE,IAAI,CAElB,eAAe,CACb,UAAU,CAAE,MAAM,CAEpB,cAAc,CACZ,UAAU,CAAE,KAAK,CAEnB,cAAc,CACZ,SAAS,CAAE,IAAI,CAEjB,eAAe,CACb,SAAS,CAAE,IAAI,CAEjB,oBAAqB,CACnB,SAAS,CAAE,GAAG,CAEhB,eAAe,CACb,eAAe,CAAE,YAAY,CAE/B,gBAAgB,CACd,KAAK,CAAE,kBAAkB,CAC3B,uBAAuB,CACrB,KAAK,CAAE,kBAAgC,CACzC,aAAa,CACX,KAAK,CAAE,kBAAgB,CACzB,oBAAoB,CAClB,KAAK,CAAE,kBAA8B,CACvC,gBAAgB,CACd,KAAK,CAAE,kBAAiB,CAC1B,uBAAuB,CACrB,KAAK,CAAE,kBAA+B,CACxC,eAAe,CACb,KAAK,CAAE,kBAAe,CACxB,sBAAsB,CACpB,KAAK,CAAE,kBAA6B,CACtC,gBAAgB,CACd,KAAK,CAAE,kBAAsB,CAC/B,uBAAuB,CACrB,KAAK,CAAE,kBAAoC,CAkB7C,+CAAyB,CACvB,UAAU,CAAE,CAAC,CACb,WAAW,CAAE,GAAG,CAChB,WAAW,CX9GyB,0DAAa,CWgHnD,CAAC,CACC,WAAW,Cb1FyB,IAAI,Ca2FxC,MAAM,CAAE,CAAC,CACT,SAAS,Cb/F2B,IAAI,CagGxC,aAAa,Cb7FuB,IAAI,Ca+F1C,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,yBAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,iBAA6B,CACzC,MAAM,CAAE,MAAmB,CAC3B,OAAO,CAAE,CAAC,CAEZ,sCAAI,CACF,WAAW,CAAE,MAAM,CACnB,SAAS,CAAE,IAAI,CACf,UAAU,CblG0B,IAAM,CamG1C,MAAM,CAAE,iBAAiC,CACzC,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,KAAK,CACd,WAAW,CXrJyB,wMAAQ,CWsJ5C,KAAK,Cb1H+B,OAAI,Ca2HxC,UAAU,CAAE,IAAI,CAChB,0CAAY,CACV,SAAS,CAAE,GAAG,CAmClB,wFAAmB,CACjB,UAAU,CAAE,IAAI,CAChB,WAAW,CbzKyB,IAAI,Ca0KxC,aAAa,Cb1KuB,IAAI,Ca2KxC,oGAAE,CACA,UAAU,CAAE,IAAI,CAChB,WAAW,Cb7KuB,IAAI,Ca8KtC,wJAAY,CACV,aAAa,CAAE,CAAC,CAClB,gHAAE,CACA,aAAa,CAAE,CAAC,CAClB,gHAAE,CACA,UAAU,CAAE,MAAM,CAClB,4HAAE,CACA,UAAU,CAAE,MAAM,CACtB,4HAAK,CACH,UAAU,CAAE,OAAO,CAEzB,iFAAsB,CACpB,UAAU,CAAE,OAAO,CACnB,WAAW,Cb3LyB,IAAI,Ca4LxC,aAAa,Cb5LuB,IAAI,Ca6LxC,6FAAE,CACA,UAAU,CAAE,OAAO,CACnB,WAAW,Cb/LuB,IAAI,CagMtC,iJAAY,CACV,aAAa,CAAE,CAAC,CAClB,yGAAE,CACA,aAAa,CAAE,CAAC,CAChB,qHAAE,CACA,UAAU,CAAE,IAAI,CCrOxB,kBAAkB,CAChB,MAAM,CAAE,iBAA6B,CACrC,aAAa,CAAE,IAAI,CACnB,OAAO,Cd6B6B,IAAI,Cc5BxC,WAAW,CAAE,IAAqB,CAClC,WAAW,CAAE,GAAG,CAChB,UAAU,CdoD0B,IAAM,CcnD1C,QAAQ,CAAE,QAAQ,CAClB,wBAAO,CACL,OAAO,CAAE,SAAS,CAClB,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,GAAG,CACR,IAAI,CAAE,GAAG,CACT,UAAU,CdoDwB,OAAO,CcnDzC,KAAK,CAAE,IAAoB,CAC3B,OAAO,CAAE,QAA2C,CACtD,2CAA0B,CACxB,MAAM,CAAE,iBAA6B,CACrC,aAAa,CdcqB,IAAI,CcZ1C,+GAAmC,CACjC,MAAM,CAAE,iBAA6B,CACrC,OAAO,CAAE,GAAG,CACZ,UAAU,CAAE,IAAI,CAChB,UAAU,CdkC0B,IAAM,CchC1C,MAAM,CAAE,YAAyB,CACjC,gLAAuB,CACrB,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,CAAC,CAEb,+BAA+B,CAC7B,KAAK,CAAE,IAAI,CACb,cAAc,CACZ,YAAY,CAAE,iBAA0C,CACxD,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,SAA2C,CACpD,WAAW,CZ3ByB,wMAAQ,CY4B5C,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,GAAG,CAChB,KAAK,CdI+B,OAAwB,CcH9D,2BAA2B,CACzB,WAAW,CAAE,GAAG,CAChB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,SAA2C,CACpD,WAAW,CZnCyB,wMAAQ,CYoC5C,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,GAAG,CAChB,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,IAAI,CACd,KAAK,CZ7C+B,OAAW,CYiDjD,YAAY,CACV,2IAAgE,CAC9D,WAAW,CAAE,QAAQ,ECzDzB,IAAI,CACF,gBAAgB,CAAE,IAAO,CACzB,MAAM,CAAE,OAAO,CACf,OAAO,CAAE,MAAM,CACf,OAAO,CAAE,KAAK,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,IAAI,CACF,KAAK,CAAE,OAAO,CACd,gBAAgB,CAAE,OAAO,CAC3B,EAAE,CACA,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,MAAM,CACJ,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,GAAG,CACD,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,MAAM,CACJ,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,MAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,MAAM,CACf,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACX,gBAAgB,CAAE,OAAO,CCjJ3B,kBAAkB,CAChB,OAAO,CAAE,YAAY,CACrB,uCAAsB,CACpB,KAAK,CAAE,KAAK,CACd,oBAAC,CACC,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,GAAG,CACZ,gCAAa,CACX,YAAY,CAAE,CAAC,CACrB,qBAAqB,CACnB,aAAa,CAAE,CAAC,CAChB,KAAK,ChBiC+B,OAAwB,CgBhC5D,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,YAAY,CbmBnB,oCAAsB,CafxB,qBAAqB,CACnB,OAAO,CAAE,IAAI,CACf,uCAAuC,CACrC,OAAO,CAAE,IAAI,EAEjB,YAAY,CACV,uCAAuC,CACrC,OAAO,CAAE,IAAI,ECxBjB,SAAS,CACP,QAAQ,CAAE,KAAK,CACf,GAAG,CCAO,OAAO,CDGjB,gBAAO,CACL,eAAe,CAAE,IAAI,CAEzB,cAAc,C/B+FZ,KAAK,CAAE,CAAC,CACR,0CAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,oBAAO,CACL,KAAK,CAAE,IAAI,C+BnGb,mCAAM,CACJ,OAAO,CAAE,YAAY,CACvB,uBAAQ,CACN,UAAU,CAAE,qBAAoB,CAEhC,6BAAa,CACX,WAAW,CAAE,iBAAyB,CACxC,8BAAc,CACZ,YAAY,CAAE,iBAAyB,CAC3C,gBAAC,CACC,MAAM,CAAE,IAAmB,CAC3B,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAmB,CAChC,OAAO,CAAE,MAAiB,CAG5B,oDAAiB,CACf,MAAM,CAAE,IAAmB,CAC3B,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAmB,CAChC,OAAO,CAAE,SAAS,CAClB,aAAa,CAAE,CAAC,CAChB,OAAO,CAAE,KAAK,CACd,WAAW,CAAE,IAAI,CACjB,cAAc,CAAE,SAAS,CACzB,SAAS,CAAE,GAAG,CACd,KAAK,CjBvB6B,IAAI,CiBwBtC,WAAW,CAAE,MAAM,CAErB,oBAAE,CACA,aAAa,CAAE,CAAC,CAEhB,+BAAY,CACV,UAAU,CAAE,iBAAyB,CACvC,kCAAe,CACb,aAAa,CAAE,iBAAyB,CAC1C,4BAAS,CACP,UAAU,CAAE,OAAsC,CAClD,8BAAC,CACC,KAAK,CjBNyB,IAAwB,CiBOtD,YAAY,CAAE,iBAAgD,CAC9D,OAAO,CAAE,gBAAyB,CAClC,oCAAO,CACL,UAAU,CAAE,OAAsC,CACxD,mGAAI,CACF,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,OAAO,CACnB,KAAK,CAAE,OAAO,CACd,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAElB,wCAAmB,CACjB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,WAAW,CAAE,MAAM,CAGnB,SAAS,CAAE,KAAI,CACf,WAAW,CAAE,KAAK,CAClB,KAAK,CAAE,OAAyB,CAGpC,wDAAuB,CACrB,KAAK,CfnE6B,OAAW,CeoE7C,OAAO,CAAE,gBAAmB,CAC5B,WAAW,CAAE,IAAI,CACjB,QAAQ,CAAE,QAAQ,CAClB,UAAU,CjBtEwB,OAAyB,CiBuE3D,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,iBAAgD,CAC/D,UAAU,CAAE,iBAAgD,CAC5D,YAAY,CAAE,YAAY,CAE1B,oEAAO,CACL,UAAU,CjB7EsB,OAAyB,CiB8EzD,4GAAmB,CACjB,KAAK,CjB3CyB,IAAwB,CiB4C1D,gGAAmB,CAGjB,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,KAAI,CACf,WAAW,CAAE,KAAK,CAClB,KAAK,CAAE,IAAyB,CAIlC,iHAAI,CACF,OAAO,CAAE,IAAI,CACf,iIAAc,CACZ,OAAO,CAAE,KAAK,CAGd,yCAAG,CACD,UAAU,CAAE,OAAsC,CAClD,OAAO,CAAE,gBAAyB,CACpC,uDAAiB,CACf,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,OAAsC,CAClD,OAAO,CAAE,gBAAyB,CACtC,2DAA2B,CACzB,KAAK,CjBpE2B,IAAwB,CiBqE1D,mDAAmB,CACjB,KAAK,CAAE,OAAsC,CACjD,+BAAa,CACX,SAAS,CAAE,KAAI,CAEb,yCAAG,CACD,UAAU,CAAE,OAAsC,CAClD,OAAO,CAAE,gBAAyB,CACpC,uDAAiB,CACf,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,OAAsC,CAClD,OAAO,CAAE,gBAAyB,CAClC,UAAU,CAAE,IAAI,CAChB,aAAa,CAAE,IAAI,CACvB,2DAA2B,CACzB,KAAK,CjBpF2B,IAAwB,CiBqF1D,mDAAmB,CACjB,KAAK,CAAE,OAAsC,CACjD,+BAAa,CACX,SAAS,CAAE,KAAI,CAEjB,+BAAa,CACX,OAAO,CAAE,KAAK,CAChB,uBAAK,CACH,aAAa,CAAE,CAAC,CAChB,OAAO,CAAE,IAAI,CAEb,kCAAK,CACH,OAAO,CAAE,KAAK,CAClB,4BAAU,CACR,aAAa,CAAE,CAAC,CAChB,KAAK,CjBnG6B,OAAwB,CiBoG1D,WAAW,CAAE,MAAM,CACrB,mBAAC,CACC,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,gBAAmB,CAC5B,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,QAAQ,CAClB,SAAS,CAAE,GAAG,CACd,KAAK,CjB5G6B,OAAwB,CiB6G1D,yBAAO,CACL,gBAAgB,CAAE,OAAoC,CACtD,MAAM,CAAE,OAAO,CACf,6CAAmB,CACjB,KAAK,CjBjHyB,OAAwB,CiBkH1D,0BAAQ,CACN,gBAAgB,CjB/EgB,OAAW,CiBgF3C,MAAM,CAAE,OAAO,CACf,KAAK,CjBvG2B,IAAM,CiBwGtC,8CAAmB,CACjB,KAAK,CjBzGyB,IAAM,CiB2G5C,mBAAmB,CACjB,OAAO,CjBhF6B,GAAG,CiBiFvC,gBAAgB,CjBvFoB,OAAW,CiBwF/C,UAAU,CAAE,MAAM,CAClB,OAAO,CAAE,OAAW,CACpB,OAAO,CAAE,KAAK,CACd,KAAK,CjBpK+B,OAAyB,CiBqK7D,aAAa,CAAE,OAAW,CAC1B,oCAAgB,CACd,KAAK,CAAE,IAAI,CACX,aAAa,CAAE,IAAI,CACnB,OAAO,CAAE,QAAQ,CACjB,YAAY,CAAE,OAAuB,CACvC,uBAAG,CACD,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,sBAA0B,CAClC,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,CjBvGkB,OAAW,CiBwG7C,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,IAAI,CACrB,wDAAqB,CACnB,KAAK,CjBpL6B,OAAyB,CiBqL3D,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,OAA2C,CACpD,aAAa,CAAE,OAAW,CAE1B,oEAAO,CACL,UAAU,CAAE,qBAAoB,CAClC,0EAAQ,CACN,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,MAAM,CACd,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,aAAa,CAAE,CAAC,CAChB,SAAS,CAAE,IAAI,CACf,UAAU,CAAE,WAAa,CAEzB,oFAAQ,CACN,UAAU,CAAE,MAAM,CAGxB,gCAAM,CACJ,KAAK,CjBlI6B,OAAW,CiBmI/C,2BAAC,CACC,KAAK,CjBxK6B,OAAwB,CiByK1D,iCAAO,CACL,gBAAgB,CjBtIgB,OAAW,CiBuI3C,KAAK,CjB7J2B,IAAM,CiB+J5C,gBAAgB,CjChNR,kBAAoB,CAAE,gBAAM,CAK5B,eAAiB,CAAE,gBAAM,CAezB,UAAY,CAAE,gBAAM,CiC8L1B,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,CAAC,CACV,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,CAAC,CACV,4BAAa,CACX,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,CAAC,CACZ,0BAAW,CACT,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,KAAK,CACX,OAAO,CAAE,CAAC,CACZ,2BAAY,CACV,KAAK,CAAE,KAAK,CACZ,IAAI,CAAE,IAAI,CACV,OAAO,CAAE,CAAC,CAGd,gBAAgB,CACd,UAAU,CAAE,qBAAuC,CACnD,gBAAgB,CAAE,2uCAA2uC,CAC7vC,eAAe,CAAE,SAAsB,CAEzC,gBAAgB,CACd,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEd,YAAY,CACV,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CACN,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,CAAC,CACP,cAAc,CAAE,GAAG,CACnB,KAAK,CjB5K+B,KAAK,CiB6KzC,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,IAAI,CAChB,UAAU,CjBlLsB,OAAe,CiBmL/C,OAAO,CjB5K6B,GAAG,CiB8KzC,WAAW,CACT,OAAO,CAAE,IAAI,CACb,UAAU,CjBtL0B,OAAW,CiBuL/C,KAAK,CjB7M+B,IAAM,CiB8M1C,OAAO,CAAE,gBAAuB,CAChC,QAAQ,CAAE,QAAQ,CAClB,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CAClB,SAAS,CAAE,IAAI,C/BrKf,KAAK,CAAE,CAAC,CACR,oCAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,iBAAO,CACL,KAAK,CAAE,IAAI,C+BiKb,aAAC,CACC,KAAK,CjBrN6B,IAAM,CiBsNxC,WAAW,CAAE,IAAI,CAEnB,eAAG,CACD,YAAY,CAAE,IAAqB,CACnC,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,CjBtMkB,OAAW,CiBuM7C,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,IAAI,CACrB,aAAC,CACC,SAAS,CAAE,IAAI,CACf,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,OAAO,CAEnB,oBAAoB,CAClB,WAAW,CjB9MyB,KAAK,CiB+MzC,UAAU,CjBzR0B,OAAyB,CiB0R7D,UAAU,CAAE,IAAI,CAElB,eAAe,CACb,OAAO,CAAE,eAAmB,CAC5B,MAAM,CAAE,IAAI,CACZ,SAAS,CAAE,KAAK,CAChB,MAAM,CAAE,IAAI,CAEd,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,eAAc,CAC1B,OAAO,CAAE,IAAI,CACb,OAAO,CAAE,GAAkB,CAC3B,gBAAI,CACF,OAAO,CAAE,KAAK,CAClB,MAAM,CACJ,KAAK,CjBrS+B,IAAI,CiBsSxC,QAAC,CACC,aAAa,CAAE,IAAqB,CAExC,mBAAmB,C/BhNjB,KAAK,CAAE,CAAC,CACR,oDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,yBAAO,CACL,KAAK,CAAE,IAAI,C+B8Mb,0BAAU,CACR,aAAa,CjB5RqB,IAAI,CiB6RtC,aAAa,CAAE,iBAA6B,CAC5C,cAAc,CjB9RoB,IAAI,CiB+RxC,sCAAsB,CACpB,UAAU,CAAE,iBAA6B,CACzC,WAAW,CjBjSuB,IAAI,CiBkSxC,4BAAY,CACV,SAAS,CAAE,IAAI,CACf,aAAa,CAAE,IAAqB,CACpC,OAAO,CAAE,YAAY,CACvB,wBAAQ,CACN,KAAK,CjB5R6B,IAAwB,CiB6R1D,SAAS,CAAE,GAAG,CdxSd,oCAAsB,Cc4SxB,gBAAgB,CACd,UAAU,CjBtUwB,OAAyB,CiBuU7D,WAAW,CACT,OAAO,CAAE,KAAK,CAChB,YAAY,CAER,IAAI,CAAE,MAAmB,CAG3B,kBAAO,CACL,KAAK,CAAE,GAAG,CACV,IAAI,CAAE,CAAC,CACX,oBAAoB,CAClB,WAAW,CAAE,CAAC,CACd,oCAAe,CACb,OAAO,CCzVD,OAAO,CD0Vf,0BAAO,CACL,QAAQ,CAAE,KAAK,CACf,SAAS,CAAE,IAAI,CACf,IAAI,CAAE,GAAG,CACT,GAAG,CAAE,CAAC,CACN,MAAM,CAAE,IAAI,CACZ,QAAQ,CAAE,MAAM,EdlUlB,qCAAsB,CcqUxB,oBAAoB,CAClB,UAAU,CAAE,gBAAe,CAC7B,eAAe,CACb,MAAM,CAAE,CAAC,CACT,UAAU,CjBlWwB,OAAyB,EiBoW/D,YAAY,CACV,iCAAmC,CACjC,OAAO,CAAE,IAAI,CACf,oBAAoB,CAClB,WAAW,CAAE,CAAC,EE/WlB,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,CAAC,CACP,KAAK,CnB6E+B,KAAK,CmB5EzC,KAAK,CnBE+B,OAAyB,CmBD7D,UAAU,CAAE,OAAkC,CAC9C,UAAU,CAAE,kBAAiC,CAC7C,WAAW,CjBAyB,uDAAM,CiBC1C,OAAO,CnB+E6B,GAAG,CmB9EvC,eAAC,CACC,KAAK,CnBqE6B,OAAW,CmBpE7C,eAAe,CAAE,IAAI,CACvB,8BAAgB,CACd,OAAO,CAAE,IAAI,CACf,kCAAoB,CAClB,OAAO,CAAE,IAAqB,CAC9B,gBAAgB,CAAE,OAAkC,CACpD,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,KAAK,CACjB,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,OAAO,CACf,KAAK,CnBiD6B,OAAM,CdgC1C,KAAK,CAAE,CAAC,CACR,kFAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,wCAAO,CACL,KAAK,CAAE,IAAI,CiCrFX,uqDAAG,CACD,KAAK,CnBlB2B,OAAyB,CmBmB3D,yFAAQ,CACN,KAAK,CAAE,IAAI,CACb,6CAAU,CACR,KAAK,CAAE,IAAI,CACb,kDAAiB,CACf,gBAAgB,CnBQgB,OAAI,CmBPpC,KAAK,CnB0B2B,IAAM,CmBzBxC,yDAAwB,CACtB,gBAAgB,CnBXgB,OAAO,CmBYvC,KAAK,CnBzB2B,IAAI,CmB0BxC,0CAA8B,CAC5B,OAAO,CAAE,KAAK,CAChB,iCAAmB,CACjB,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,IAAqB,CAC9B,KAAK,CnBE6B,IAAwB,CmBD1D,OAAO,CAAE,IAAI,CACb,oCAAE,CACA,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,CAAC,CACT,MAAM,CAAE,MAAM,CACd,OAAO,CAAE,CAAC,CACV,UAAU,CAAE,iBAA6C,CAC3D,oCAAE,CACA,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,CAAC,CACT,sCAAC,CACC,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,GAAqB,CAC9B,KAAK,CnBjDyB,OAAyB,CmBkD7D,uBAAW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,IAAI,CACV,MAAM,CAAE,IAAI,CACZ,SAAS,CnBkByB,KAAK,CmBjBvC,kCAAU,CACR,KAAK,CAAE,IAAI,CACb,mEAAQ,CACN,KAAK,CAAE,IAAI,CACb,qDAA+B,CAC7B,UAAU,CAAE,KAAK,CACjB,+HAAQ,CACN,KAAK,CAAE,IAAI,CACb,gEAAU,CACR,KAAK,CAAE,IAAI,CACf,4CAAoB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAuB,CAChC,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,ChBhDpB,oCAAsB,CgBmDxB,aAAa,CACX,KAAK,CAAE,GAAG,CACV,OAAO,CAAE,IAAI,CACb,mBAAO,CACL,OAAO,CAAE,KAAK,CAClB,GAAG,CACD,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,ECzEd,gBAAG,CACD,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,eAAe,CAEzB,uBAAU,CACR,aAAa,CpBUqB,IAAI,CoBRxC,oCAAuB,CACrB,UAAU,CAAE,MAAM,CAGpB,qDAAoC,CAClC,aAAa,CpBGqB,IAAI,CoBQxC,uBAAU,CACR,WAAW,CpBTuB,IAAI,CoBUtC,WAAW,CpBVuB,IAAI,CoBWtC,aAAa,CpBXqB,IAAI,CoBiBtC,kTAAK,CACH,aAAa,CAAE,CAAC,CAKlB,qCAAQ,CACN,YAAY,CAAE,GAAG,CAUrB,8BAAiB,CACf,YAAY,CAAE,eAAc,CAC5B,mEAAM,CACJ,UAAU,CAAE,sBAAsB,CAClC,YAAY,CAAE,0BAAyB,CAG3C,0EAAiD,CAC/C,UAAU,CAAE,WAAW,CACzB,0EAAiD,CAC/C,UAAU,CAAE,WAAW,CAGzB,qDAA4B,CAC1B,aAAa,CAAE,IAAqB,CACtC,wBAAW,CACT,WAAW,CpBlDuB,IAAI,CoBqDxC,yBAAY,CACV,WAAW,CAAE,IAAI,CACjB,aAAa,CAAE,IAAqB,CACtC,yBAAY,CACV,KAAK,ClBnF6B,OAAW,CkBoF/C,yBAAY,CACV,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,iBAA2C,CACrD,wBAAW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,iBAA2C,CACrD,0BAAa,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,KAAK,CAMd,4QAAW,CACT,OAAO,CAAE,IAAI,CACb,UAAU,CAAE,MAAM,CAClB,SAAS,CAAE,IAAI,CAEf,kUAAO,CACL,UAAU,CAAE,OAAO,CACnB,OAAO,CAAE,GAAO,CAChB,WAAW,CAAE,WAAW,CACxB,OAAO,CAAE,YAAY,CACzB,kUAAmB,CACjB,OAAO,CAAE,YAAY,CAGzB,qBAAQ,CACN,KAAK,CAAE,KAAK,CACZ,KAAK,CAAE,GAAG,CACV,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,aAAuC,CAC/C,OAAO,CpB3F2B,IAAI,CoB4FtC,UAAU,CpBpDwB,OAAmB,CoBqDrD,MAAM,CAAE,iBAA6B,CAErC,yEAAS,CACP,SAAS,CAAE,GAAG,CAChB,2BAAK,CACH,aAAa,CAAE,CAAC,CAClB,oCAAc,CACZ,OAAO,CAAE,KAAK,CACd,WAAW,ClB5HqB,0DAAa,CkB6H7C,WAAW,CAAE,IAAI,CACjB,UAAU,CpBnFsB,OAAmB,CoBoFnD,OAAO,CAAE,QAA2C,CACpD,MAAM,CAAE,KAAkB,CAC1B,aAAa,CpB1GmB,IAAI,CoB2GpC,SAAS,CAAE,IAAI,CAEnB,yBAAY,CACV,UAAU,CpBvHwB,OAAO,CoBwHzC,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAuB,CAGlC,iEAAwC,CACtC,cAAc,CAAE,KAAK,CACrB,SAAS,CAAE,GAAG,CAIhB,yEAAgD,CAC9C,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,IAAI,CACZ,KAAK,CpB/I6B,IAAI,CoBgJtC,+JAAM,CACJ,MAAM,CAAE,IAAI,CACZ,gBAAgB,CAAE,sBAAsB,CACxC,WAAW,CAAE,MAAM,CACrB,2FAAQ,CACN,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAChB,cAAc,CAAE,GAAG,CAOvB,6BAAgB,CAEd,MAAM,CAAE,IAAI,CACZ,gCAAE,CACA,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,GAAG,CAClB,uCAAW,CACT,OAAO,CAAE,YAAY,CACrB,UAAU,CAAE,GAAG,CACjB,yCAAW,CACT,aAAa,CAAE,IAAI,CACnB,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,MAAM,CACrB,yCAAW,CACT,UAAU,CAAE,IAAI,CAChB,YAAY,CAAE,CAAC,CAGnB,iDAAQ,CAEN,KAAK,CpBtL6B,IAAI,CoBuLtC,wHAAO,CACL,SAAS,CAAE,eAAe,CAC1B,WAAW,CAAE,MAAM,CAErB,2HAAU,CACR,WAAW,CAAE,IAAI,CAErB,uDAAY,CACV,KAAK,CpBzH6B,OAAW,CoB0H/C,eAAE,CACA,aAAa,CpB3KqB,IAAI,CoB4KtC,kBAAE,CACA,WAAW,CAAE,IAAI,CAEnB,6EAAgB,CACd,aAAa,CAAE,eAAgC,CAEjD,kBAAE,CACA,MAAM,CAAE,aAA4C,CAMxD,8BAAiB,CACf,aAAa,CpB1LqB,IAAI,CoB4LtC,iCAAE,CACA,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,KAAuB,CAC/B,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,OAAmB,CAC/B,KAAK,CpBlJ2B,OAAW,CoBmJ3C,UAAU,CAAE,iBAA6B,CACzC,OAAO,CAAE,GAAqB,CAC9B,QAAQ,CAAE,QAAQ,CAClB,wCAAQ,CACN,KAAK,CAAE,OAAmB,CAC5B,6CAAW,CACT,KAAK,ClBnOyB,OAAW,CkBoOzC,SAAS,CAAE,eAAe,CAE9B,oCAAK,CACH,aAAa,CAAE,GAAqB,CACpC,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,cAAuB,CACpC,UAAU,CAAE,OAAa,CACzB,KAAK,CpBtM2B,IAAwB,CoBuMxD,gDAAW,CACT,KAAK,ClB7OyB,OAAW,CkB8OzC,SAAS,CAAE,eAAe,CAC9B,6CAAc,CACZ,UAAU,CAAE,CAAC,CAEf,uGAAQ,CACN,WAAW,CAAE,IAAI,CACjB,oRAA2B,CACzB,gBAAgB,CAAE,WAAW,CAC7B,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,SAAS,CAAE,eAAe,CAC5B,kIAAU,CACR,WAAW,CAAE,IAAI,CAErB,wCAAS,CACP,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,KAAK,CACd,KAAK,CpB3P2B,IAAI,CoB4PpC,WAAW,CAAE,IAAI,CACnB,wCAAS,CACP,OAAO,CAAE,YAAY,CACrB,aAAa,CAAE,GAAG,CAEtB,uDAA8B,CAC5B,OAAO,CAAE,YAAY,CACrB,KAAK,CpBtM6B,OAAM,CoBuMxC,SAAS,CAAE,GAAG,CACd,YAAY,CpB/OsB,IAAI,CoBgPxC,2BAAc,CACZ,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,KAAK,CACd,qBAAQ,CACN,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CAEnB,mDAAa,CACX,UAAU,CAAE,OAAO,CACnB,OAAO,CAAE,OAAO,CAChB,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,KAAK,CAAE,OAAO,CACd,MAAM,CAAE,OAAO,CACf,WAAW,CAAE,OAAO,CAIlB,mGAAQ,CACN,YAAY,CAAE,GAAG,CjBnQrB,oCAAsB,CiBwQtB,qBAAQ,CACN,KAAK,CAAE,IAAI,ECzSjB,wBAAwB,CACtB,KAAK,CnBK+B,OAAW,CmBHjD,KAAK,CACH,UAAU,CAAE,MAAM,YCHlB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,qEAAoB,YAGzB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,yGAAyB,YAG9B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,6FAAqB,YAG1B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,oFAAkB,YAGvB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,gHAA4B,YAGjC,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,uGAAyB",
-"sources": ["../../../bower_components/neat/app/assets/stylesheets/grid/_grid.scss","../../../bower_components/bourbon/dist/addons/_prefixer.scss","../../../bower_components/wyrm/sass/wyrm_core/_reset.sass","../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/font-awesome/scss/_path.scss","../../../bower_components/font-awesome/scss/_core.scss","../../../bower_components/font-awesome/scss/_larger.scss","../../../bower_components/font-awesome/scss/_fixed-width.scss","../../../bower_components/font-awesome/scss/_list.scss","../../../bower_components/font-awesome/scss/_variables.scss","../../../bower_components/font-awesome/scss/_bordered-pulled.scss","../../../bower_components/font-awesome/scss/_spinning.scss","../../../bower_components/font-awesome/scss/_rotated-flipped.scss","../../../bower_components/font-awesome/scss/_mixins.scss","../../../bower_components/font-awesome/scss/_stacked.scss","../../../bower_components/font-awesome/scss/_icons.scss","../../../bower_components/wyrm/sass/wyrm_core/_font_icon_defaults.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../bower_components/wyrm/sass/wyrm_core/_alert.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss","../../../bower_components/wyrm/sass/wyrm_core/_button.sass","../../../bower_components/wyrm/sass/wyrm_core/_dropdown.sass","../../../bower_components/wyrm/sass/wyrm_core/_form.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_outer-container.scss","../../../bower_components/neat/app/assets/stylesheets/settings/_grid.scss","../../../bower_components/neat/app/assets/stylesheets/grid/_span-columns.scss","../../../bower_components/wyrm/sass/wyrm_core/_neat_extra.sass","../../../bower_components/wyrm/sass/wyrm_core/_generic.sass","../../../bower_components/wyrm/sass/wyrm_core/_table.sass","../../../bower_components/wyrm/sass/wyrm_core/_type.sass","../../../bower_components/wyrm/sass/wyrm_addons/pygments/_pygments.sass","../../../bower_components/wyrm/sass/wyrm_addons/pygments/_pygments_light.sass","../../../sass/_theme_breadcrumbs.sass","../../../sass/_theme_layout.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_private.scss","../../../sass/_theme_badge.sass","../../../sass/_theme_rst.sass","../../../sass/_theme_mathjax.sass","../../../sass/_theme_font_local.sass"],
-"names": [],
-"file": "theme.css"
-}
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf
deleted file mode 100644
index 8b0f54e47e..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf
deleted file mode 100644
index 360a232dd0..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata.ttf
deleted file mode 100644
index 4b8a36d249..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Inconsolata.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf
deleted file mode 100644
index e8b9bf6a20..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf
deleted file mode 100644
index 7608bc3e0f..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf
deleted file mode 100644
index e6ed0de530..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf
deleted file mode 100644
index 141d6c08c8..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot
deleted file mode 100644
index 7c79c6a6bc..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg
deleted file mode 100644
index 45fdf33830..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg
+++ /dev/null
@@ -1,414 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata></metadata>
-<defs>
-<font id="fontawesomeregular" horiz-adv-x="1536" >
-<font-face units-per-em="1792" ascent="1536" descent="-256" />
-<missing-glyph horiz-adv-x="448" />
-<glyph unicode=" " horiz-adv-x="448" />
-<glyph unicode="&#x09;" horiz-adv-x="448" />
-<glyph unicode="&#xa0;" horiz-adv-x="448" />
-<glyph unicode="&#xa8;" horiz-adv-x="1792" />
-<glyph unicode="&#xa9;" horiz-adv-x="1792" />
-<glyph unicode="&#xae;" horiz-adv-x="1792" />
-<glyph unicode="&#xb4;" horiz-adv-x="1792" />
-<glyph unicode="&#xc6;" horiz-adv-x="1792" />
-<glyph unicode="&#x2000;" horiz-adv-x="768" />
-<glyph unicode="&#x2001;" />
-<glyph unicode="&#x2002;" horiz-adv-x="768" />
-<glyph unicode="&#x2003;" />
-<glyph unicode="&#x2004;" horiz-adv-x="512" />
-<glyph unicode="&#x2005;" horiz-adv-x="384" />
-<glyph unicode="&#x2006;" horiz-adv-x="256" />
-<glyph unicode="&#x2007;" horiz-adv-x="256" />
-<glyph unicode="&#x2008;" horiz-adv-x="192" />
-<glyph unicode="&#x2009;" horiz-adv-x="307" />
-<glyph unicode="&#x200a;" horiz-adv-x="85" />
-<glyph unicode="&#x202f;" horiz-adv-x="307" />
-<glyph unicode="&#x205f;" horiz-adv-x="384" />
-<glyph unicode="&#x2122;" horiz-adv-x="1792" />
-<glyph unicode="&#x221e;" horiz-adv-x="1792" />
-<glyph unicode="&#x2260;" horiz-adv-x="1792" />
-<glyph unicode="&#xe000;" horiz-adv-x="500" d="M0 0z" />
-<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
-<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
-<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
-<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
-<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
-<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
-<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
-<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
-<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
-<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
-<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
-<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
-<glyph unicode="&#xf016;" horiz-adv-x="1280" d="M128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280zM768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z " />
-<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
-<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
-<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
-<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
-<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
-<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
-<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
-<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
-<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
-<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
-<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
-<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
-<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
-<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
-<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
-<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q73 -1 153.5 -2t119 -1.5t52.5 -0.5l29 2q-32 95 -92 241q-53 132 -92 211zM21 -128h-21l2 79q22 7 80 18q89 16 110 31q20 16 48 68l237 616l280 724h75h53l11 -21l205 -480q103 -242 124 -297q39 -102 96 -235q26 -58 65 -164q24 -67 65 -149 q22 -49 35 -57q22 -19 69 -23q47 -6 103 -27q6 -39 6 -57q0 -14 -1 -26q-80 0 -192 8q-93 8 -189 8q-79 0 -135 -2l-200 -11l-58 -2q0 45 4 78l131 28q56 13 68 23q12 12 12 27t-6 32l-47 114l-92 228l-450 2q-29 -65 -104 -274q-23 -64 -23 -84q0 -31 17 -43 q26 -21 103 -32q3 0 13.5 -2t30 -5t40.5 -6q1 -28 1 -58q0 -17 -2 -27q-66 0 -349 20l-48 -8q-81 -14 -167 -14z" />
-<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q76 -32 140 -32q131 0 216 41t122 113q38 70 38 181q0 114 -41 180q-58 94 -141 126q-80 32 -247 32q-74 0 -101 -10v-144l-1 -173l3 -270q0 -15 12 -44zM541 761q43 -7 109 -7q175 0 264 65t89 224q0 112 -85 187q-84 75 -255 75q-52 0 -130 -13q0 -44 2 -77 q7 -122 6 -279l-1 -98q0 -43 1 -77zM0 -128l2 94q45 9 68 12q77 12 123 31q17 27 21 51q9 66 9 194l-2 497q-5 256 -9 404q-1 87 -11 109q-1 4 -12 12q-18 12 -69 15q-30 2 -114 13l-4 83l260 6l380 13l45 1q5 0 14 0.5t14 0.5q1 0 21.5 -0.5t40.5 -0.5h74q88 0 191 -27 q43 -13 96 -39q57 -29 102 -76q44 -47 65 -104t21 -122q0 -70 -32 -128t-95 -105q-26 -20 -150 -77q177 -41 267 -146q92 -106 92 -236q0 -76 -29 -161q-21 -62 -71 -117q-66 -72 -140 -108q-73 -36 -203 -60q-82 -15 -198 -11l-197 4q-84 2 -298 -11q-33 -3 -272 -11z" />
-<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q4 1 77 20q76 19 116 39q29 37 41 101l27 139l56 268l12 64q8 44 17 84.5t16 67t12.5 46.5t9 30.5t3.5 11.5l29 157l16 63l22 135l8 50v38q-41 22 -144 28q-28 2 -38 4l19 103l317 -14q39 -2 73 -2q66 0 214 9q33 2 68 4.5t36 2.5q-2 -19 -6 -38 q-7 -29 -13 -51q-55 -19 -109 -31q-64 -16 -101 -31q-12 -31 -24 -88q-9 -44 -13 -82q-44 -199 -66 -306l-61 -311l-38 -158l-43 -235l-12 -45q-2 -7 1 -27q64 -15 119 -21q36 -5 66 -10q-1 -29 -7 -58q-7 -31 -9 -41q-18 0 -23 -1q-24 -2 -42 -2q-9 0 -28 3q-19 4 -145 17 l-198 2q-41 1 -174 -11q-74 -7 -98 -9z" />
-<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l215 -1h293l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -42.5 2t-103.5 -1t-111 -1 q-34 0 -67 -5q-10 -97 -8 -136l1 -152v-332l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-88 0 -233 -14q-48 -4 -70 -4q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q8 192 6 433l-5 428q-1 62 -0.5 118.5t0.5 102.5t-2 57t-6 15q-6 5 -14 6q-38 6 -148 6q-43 0 -100 -13.5t-73 -24.5q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1744 128q33 0 42 -18.5t-11 -44.5 l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80z" />
-<glyph unicode="&#xf035;" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l446 -1h318l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -58.5 2t-138.5 -1t-128 -1 q-94 0 -127 -5q-10 -97 -8 -136l1 -152v52l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-82 0 -233 -13q-45 -5 -70 -5q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q6 137 6 433l-5 44q0 265 -2 278q-2 11 -6 15q-6 5 -14 6q-38 6 -148 6q-50 0 -168.5 -14t-132.5 -24q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1505 113q26 -20 26 -49t-26 -49l-162 -126 q-26 -20 -44.5 -11t-18.5 42v80h-1024v-80q0 -33 -18.5 -42t-44.5 11l-162 126q-26 20 -26 49t26 49l162 126q26 20 44.5 11t18.5 -42v-80h1024v80q0 33 18.5 42t44.5 -11z" />
-<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
-<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
-<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
-<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
-<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
-<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
-<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
-<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
-<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
-<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
-<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
-<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
-<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
-<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
-<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
-<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
-<glyph unicode="&#xf053;" horiz-adv-x="1152" d="M742 -37l-652 651q-37 37 -37 90.5t37 90.5l652 651q37 37 90.5 37t90.5 -37l75 -75q37 -37 37 -90.5t-37 -90.5l-486 -486l486 -485q37 -38 37 -91t-37 -90l-75 -75q-37 -37 -90.5 -37t-90.5 37z" />
-<glyph unicode="&#xf054;" horiz-adv-x="1152" d="M1099 704q0 -52 -37 -91l-652 -651q-37 -37 -90 -37t-90 37l-76 75q-37 39 -37 91q0 53 37 90l486 486l-486 485q-37 39 -37 91q0 53 37 90l76 75q36 38 90 38t90 -38l652 -651q37 -37 37 -90z" />
-<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
-<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
-<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
-<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
-<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
-<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
-<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
-<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
-<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
-<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
-<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
-<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
-<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
-<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
-<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
-<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
-<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
-<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
-<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf077;" horiz-adv-x="1664" d="M1611 320q0 -53 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-486 485l-486 -485q-36 -38 -90 -38t-90 38l-75 75q-38 36 -38 90q0 53 38 91l651 651q37 37 90 37q52 0 91 -37l650 -651q38 -38 38 -91z" />
-<glyph unicode="&#xf078;" horiz-adv-x="1664" d="M1611 832q0 -53 -37 -90l-651 -651q-38 -38 -91 -38q-54 0 -90 38l-651 651q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l486 -486l486 486q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
-<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
-<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
-<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
-<glyph unicode="&#xf080;" horiz-adv-x="1920" d="M512 512v-384h-256v384h256zM896 1024v-896h-256v896h256zM1280 768v-640h-256v640h256zM1664 1152v-1024h-256v1024h256zM1792 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5z M1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf082;" d="M1307 618l23 219h-198v109q0 49 15.5 68.5t71.5 19.5h110v219h-175q-152 0 -218 -72t-66 -213v-131h-131v-219h131v-635h262v635h175zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
-<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
-<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
-<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
-<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
-<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
-<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
-<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
-<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
-<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
-<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
-<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
-<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
-<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
-<glyph unicode="&#xf09a;" horiz-adv-x="768" d="M511 980h257l-30 -284h-227v-824h-341v824h-170v284h170v171q0 182 86 275.5t283 93.5h227v-284h-142q-39 0 -62.5 -6.5t-34 -23.5t-13.5 -34.5t-3 -49.5v-142z" />
-<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
-<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
-<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
-<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
-<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
-<glyph unicode="&#xf0a2;" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM183 128h1298q-164 181 -246.5 411.5t-82.5 484.5q0 256 -320 256t-320 -256q0 -254 -82.5 -484.5t-246.5 -411.5zM1664 128q0 -52 -38 -90t-90 -38 h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
-<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
-<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
-<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
-<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
-<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
-<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
-<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
-<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
-<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
-<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
-<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
-<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
-<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
-<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
-<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
-<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
-<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
-<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
-<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
-<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
-<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
-<glyph unicode="&#xf0d4;" d="M678 -57q0 -38 -10 -71h-380q-95 0 -171.5 56.5t-103.5 147.5q24 45 69 77.5t100 49.5t107 24t107 7q32 0 49 -2q6 -4 30.5 -21t33 -23t31 -23t32 -25.5t27.5 -25.5t26.5 -29.5t21 -30.5t17.5 -34.5t9.5 -36t4.5 -40.5zM385 294q-234 -7 -385 -85v433q103 -118 273 -118 q32 0 70 5q-21 -61 -21 -86q0 -67 63 -149zM558 805q0 -100 -43.5 -160.5t-140.5 -60.5q-51 0 -97 26t-78 67.5t-56 93.5t-35.5 104t-11.5 99q0 96 51.5 165t144.5 69q66 0 119 -41t84 -104t47 -130t16 -128zM1536 896v-736q0 -119 -84.5 -203.5t-203.5 -84.5h-468 q39 73 39 157q0 66 -22 122.5t-55.5 93t-72 71t-72 59.5t-55.5 54.5t-22 59.5q0 36 23 68t56 61.5t65.5 64.5t55.5 93t23 131t-26.5 145.5t-75.5 118.5q-6 6 -14 11t-12.5 7.5t-10 9.5t-10.5 17h135l135 64h-437q-138 0 -244.5 -38.5t-182.5 -133.5q0 126 81 213t207 87h960 q119 0 203.5 -84.5t84.5 -203.5v-96h-256v256h-128v-256h-256v-128h256v-256h128v256h256z" />
-<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M876 71q0 21 -4.5 40.5t-9.5 36t-17.5 34.5t-21 30.5t-26.5 29.5t-27.5 25.5t-32 25.5t-31 23t-33 23t-30.5 21q-17 2 -50 2q-54 0 -106 -7t-108 -25t-98 -46t-69 -75t-27 -107q0 -68 35.5 -121.5t93 -84t120.5 -45.5t127 -15q59 0 112.5 12.5t100.5 39t74.5 73.5 t27.5 110zM756 933q0 60 -16.5 127.5t-47 130.5t-84 104t-119.5 41q-93 0 -144 -69t-51 -165q0 -47 11.5 -99t35.5 -104t56 -93.5t78 -67.5t97 -26q97 0 140.5 60.5t43.5 160.5zM625 1408h437l-135 -79h-135q71 -45 110 -126t39 -169q0 -74 -23 -131.5t-56 -92.5t-66 -64.5 t-56 -61t-23 -67.5q0 -26 16.5 -51t43 -48t58.5 -48t64 -55.5t58.5 -66t43 -85t16.5 -106.5q0 -160 -140 -282q-152 -131 -420 -131q-59 0 -119.5 10t-122 33.5t-108.5 58t-77 89t-30 121.5q0 61 37 135q32 64 96 110.5t145 71t155 36t150 13.5q-64 83 -64 149q0 12 2 23.5 t5 19.5t8 21.5t7 21.5q-40 -5 -70 -5q-149 0 -255.5 98t-106.5 246q0 140 95 250.5t234 141.5q94 20 187 20zM1664 1152v-128h-256v-256h-128v256h-256v128h256v256h128v-256h256z" />
-<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
-<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
-<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
-<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
-<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
-<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
-<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
-<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
-<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
-<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
-<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
-<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
-<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
-<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
-<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
-<glyph unicode="&#xf0f3;" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1664 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5 q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
-<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0f6;" horiz-adv-x="1280" d="M1024 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1024 608v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280z M768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z" />
-<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
-<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
-<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
-<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
-<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
-<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
-<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
-<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
-<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
-<glyph unicode="&#xf110;" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
-<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
-<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
-<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
-<glyph unicode="&#xf116;" horiz-adv-x="1792" />
-<glyph unicode="&#xf117;" horiz-adv-x="1792" />
-<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
-<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
-<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
-<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
-<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
-<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
-<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
-<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
-<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
-<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
-<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
-<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
-<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
-<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
-<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
-<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
-<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
-<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
-<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
-<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
-<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
-<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
-<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
-<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
-<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
-<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
-<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
-<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
-<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
-<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
-<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
-<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
-<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
-<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
-<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
-<glyph unicode="&#xf15b;" horiz-adv-x="1280" d="M1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
-<glyph unicode="&#xf15c;" horiz-adv-x="1280" d="M1024 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1024 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28 t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
-<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
-<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
-<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
-<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
-<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
-<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
-<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
-<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
-<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
-<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
-<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
-<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
-<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
-<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
-<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M390 1408h219v-388h364v-241h-364v-394q0 -136 14 -172q13 -37 52 -60q50 -31 117 -31q117 0 232 76v-242q-102 -48 -178 -65q-77 -19 -173 -19q-105 0 -186 27q-78 25 -138 75q-58 51 -79 105q-22 54 -22 161v539h-170v217q91 30 155 84q64 55 103 132q39 78 54 196z " />
-<glyph unicode="&#xf174;" d="M1123 127v181q-88 -56 -174 -56q-51 0 -88 23q-29 17 -39 45q-11 30 -11 129v295h274v181h-274v291h-164q-11 -90 -40 -147t-78 -99q-48 -40 -116 -63v-163h127v-404q0 -78 17 -121q17 -42 59 -78q43 -37 104 -57q62 -20 140 -20q67 0 129 14q57 13 134 49zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
-<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
-<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
-<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
-<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
-<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
-<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
-<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
-<glyph unicode="&#xf180;" horiz-adv-x="1664" d="M1483 512l-587 -587q-52 -53 -127.5 -53t-128.5 53l-587 587q-53 53 -53 128t53 128l587 587q53 53 128 53t128 -53l265 -265l-398 -399l-188 188q-42 42 -99 42q-59 0 -100 -41l-120 -121q-42 -40 -42 -99q0 -58 42 -100l406 -408q30 -28 67 -37l6 -4h28q60 0 99 41 l619 619l2 -3q53 -53 53 -128t-53 -128zM1406 1138l120 -120q14 -15 14 -36t-14 -36l-730 -730q-17 -15 -37 -15v0q-4 0 -6 1q-18 2 -30 14l-407 408q-14 15 -14 36t14 35l121 120q13 15 35 15t36 -15l252 -252l574 575q15 15 36 15t36 -15z" />
-<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
-<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
-<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
-<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
-<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
-<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
-<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
-<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
-<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
-<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf197;" horiz-adv-x="1792" />
-<glyph unicode="&#xf198;" horiz-adv-x="1792" />
-<glyph unicode="&#xf199;" horiz-adv-x="1792" />
-<glyph unicode="&#xf19a;" horiz-adv-x="1792" />
-<glyph unicode="&#xf19b;" horiz-adv-x="1792" />
-<glyph unicode="&#xf19c;" horiz-adv-x="1792" />
-<glyph unicode="&#xf19d;" horiz-adv-x="1792" />
-<glyph unicode="&#xf19e;" horiz-adv-x="1792" />
-<glyph unicode="&#xf500;" horiz-adv-x="1792" />
-</font>
-</defs></svg> \ No newline at end of file
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf
deleted file mode 100644
index e89738de5e..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff b/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff
deleted file mode 100644
index 8c1748aab7..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js b/lib/spack/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js
deleted file mode 100644
index f65d479747..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
- * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
- */
-;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d<e;d++)u[c[d]]=c[d]in k;return u.list&&(u.list=!!b.createElement("datalist")&&!!a.HTMLDataListElement),u}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,f,h,i=a.length;d<i;d++)k.setAttribute("type",f=a[d]),e=k.type!=="text",e&&(k.value=l,k.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(f)&&k.style.WebkitAppearance!==c?(g.appendChild(k),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(k,null).WebkitAppearance!=="textfield"&&k.offsetHeight!==0,g.removeChild(k)):/^(search|tel)$/.test(f)||(/^(url|email)$/.test(f)?e=k.checkValidity&&k.checkValidity()===!1:e=k.value!=l)),t[a[d]]=!!e;return t}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var d="2.6.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k=b.createElement("input"),l=":)",m={}.toString,n=" -webkit- -moz- -o- -ms- ".split(" "),o="Webkit Moz O ms",p=o.split(" "),q=o.toLowerCase().split(" "),r={svg:"http://www.w3.org/2000/svg"},s={},t={},u={},v=[],w=v.slice,x,y=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["&#173;",'<style id="s',h,'">',a,"</style>"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="<svg/>",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e<g;e++)d.createElement(f[e]);return d}function p(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return r.shivMethods?n(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+l().join().replace(/\w+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(r,b.frag)}function q(a){a||(a=b);var c=m(a);return r.shivCSS&&!f&&!c.hasCSS&&(c.hasCSS=!!k(a,"article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}")),j||p(a,c),a}var c=a.html5||{},d=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,e=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,f,g="_html5shiv",h=0,i={},j;(function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(".").pop().split("?").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&"css"==i.url.split(".").pop().split("?").shift()?"c":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/static/js/theme.js b/lib/spack/docs/_themes/sphinx_rtd_theme/static/js/theme.js
deleted file mode 100644
index 749e58f400..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/static/js/theme.js
+++ /dev/null
@@ -1,113 +0,0 @@
-function toggleCurrent (elem) {
- var parent_li = elem.closest('li');
- parent_li.siblings('li.current').removeClass('current');
- parent_li.siblings().find('li.current').removeClass('current');
- parent_li.find('> ul li.current').removeClass('current');
- parent_li.toggleClass('current');
-}
-
-$(document).ready(function() {
- // Shift nav in mobile when clicking the menu.
- $(document).on('click', "[data-toggle='wy-nav-top']", function() {
- $("[data-toggle='wy-nav-shift']").toggleClass("shift");
- $("[data-toggle='rst-versions']").toggleClass("shift");
- });
- // Nav menu link click operations
- $(document).on('click', ".wy-menu-vertical .current ul li a", function() {
- var target = $(this);
- // Close menu when you click a link.
- $("[data-toggle='wy-nav-shift']").removeClass("shift");
- $("[data-toggle='rst-versions']").toggleClass("shift");
- // Handle dynamic display of l3 and l4 nav lists
- toggleCurrent(target);
- if (typeof(window.SphinxRtdTheme) != 'undefined') {
- window.SphinxRtdTheme.StickyNav.hashChange();
- }
- });
- $(document).on('click', "[data-toggle='rst-current-version']", function() {
- $("[data-toggle='rst-versions']").toggleClass("shift-up");
- });
- // Make tables responsive
- $("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
-
- // Add expand links to all parents of nested ul
- $('.wy-menu-vertical ul').siblings('a').each(function () {
- var link = $(this);
- expand = $('<span class="toctree-expand"></span>');
- expand.on('click', function (ev) {
- toggleCurrent(link);
- ev.stopPropagation();
- return false;
- });
- link.prepend(expand);
- });
-});
-
-// Sphinx theme state
-window.SphinxRtdTheme = (function (jquery) {
- var stickyNav = (function () {
- var navBar,
- win,
- winScroll = false,
- linkScroll = false,
- winPosition = 0,
- enable = function () {
- init();
- reset();
- win.on('hashchange', reset);
-
- // Set scrolling
- win.on('scroll', function () {
- if (!linkScroll) {
- winScroll = true;
- }
- });
- setInterval(function () {
- if (winScroll) {
- winScroll = false;
- var newWinPosition = win.scrollTop(),
- navPosition = navBar.scrollTop(),
- newNavPosition = navPosition + (newWinPosition - winPosition);
- navBar.scrollTop(newNavPosition);
- winPosition = newWinPosition;
- }
- }, 25);
- },
- init = function () {
- navBar = jquery('nav.wy-nav-side:first');
- win = jquery(window);
- },
- reset = function () {
- // Get anchor from URL and open up nested nav
- var anchor = encodeURI(window.location.hash);
- if (anchor) {
- try {
- var link = $('.wy-menu-vertical')
- .find('[href="' + anchor + '"]');
- $('.wy-menu-vertical li.toctree-l1 li.current')
- .removeClass('current');
- link.closest('li.toctree-l2').addClass('current');
- link.closest('li.toctree-l3').addClass('current');
- link.closest('li.toctree-l4').addClass('current');
- }
- catch (err) {
- console.log("Error expanding nav for anchor", err);
- }
- }
- },
- hashChange = function () {
- linkScroll = true;
- win.one('hashchange', function () {
- linkScroll = false;
- });
- };
- jquery(init);
- return {
- enable: enable,
- hashChange: hashChange
- };
- }());
- return {
- StickyNav: stickyNav
- };
-}($));
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/theme.conf b/lib/spack/docs/_themes/sphinx_rtd_theme/theme.conf
deleted file mode 100644
index b71548b2af..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/theme.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-[theme]
-inherit = basic
-stylesheet = css/theme.css
-
-[options]
-typekit_id = hiw1hhg
-analytics_id =
-sticky_navigation = False
-logo_only =
diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/versions.html b/lib/spack/docs/_themes/sphinx_rtd_theme/versions.html
deleted file mode 100644
index 8b3eb79d25..0000000000
--- a/lib/spack/docs/_themes/sphinx_rtd_theme/versions.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% if READTHEDOCS %}
-{# Add rst-badge after rst-versions for small badge style. #}
- <div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
- <span class="rst-current-version" data-toggle="rst-current-version">
- <span class="fa fa-book"> Read the Docs</span>
- v: {{ current_version }}
- <span class="fa fa-caret-down"></span>
- </span>
- <div class="rst-other-versions">
- <dl>
- <dt>Versions</dt>
- {% for slug, url in versions %}
- <dd><a href="{{ url }}">{{ slug }}</a></dd>
- {% endfor %}
- </dl>
- <dl>
- <dt>Downloads</dt>
- {% for type, url in downloads %}
- <dd><a href="{{ url }}">{{ type }}</a></dd>
- {% endfor %}
- </dl>
- <dl>
- <dt>On Read the Docs</dt>
- <dd>
- <a href="//{{ PRODUCTION_DOMAIN }}/projects/{{ slug }}/?fromdocs={{ slug }}">Project Home</a>
- </dd>
- <dd>
- <a href="//{{ PRODUCTION_DOMAIN }}/builds/{{ slug }}/?fromdocs={{ slug }}">Builds</a>
- </dd>
- </dl>
- <hr/>
- Free document hosting provided by <a href="http://www.readthedocs.org">Read the Docs</a>.
-
- </div>
- </div>
-{% endif %}
-
diff --git a/lib/spack/docs/basic_usage.rst b/lib/spack/docs/basic_usage.rst
index bb426b4378..7eda320029 100644
--- a/lib/spack/docs/basic_usage.rst
+++ b/lib/spack/docs/basic_usage.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _basic-usage:
===========
@@ -596,6 +601,9 @@ name or compiler specifier to their left in the spec.
If the compiler spec is omitted, Spack will choose a default compiler
based on site policies.
+
+.. _basic-variants:
+
^^^^^^^^
Variants
^^^^^^^^
@@ -681,11 +689,12 @@ Compiler environment variables and additional RPATHs
In the exceptional case a compiler requires setting special environment
variables, like an explicit library load path. These can bet set in an
-extra section in the compiler configuration. The user can also specify
-additional ``RPATHs`` that the compiler will add to all executables
-generated by that compiler. This is useful for forcing certain compilers
-to RPATH their own runtime libraries, so that executables will run
-without the need to set ``LD_LIBRARY_PATH``.
+extra section in the compiler configuration (the supported environment
+modification commands are: ``set``, ``unset``, ``append-path``, and
+``prepend-path``). The user can also specify additional ``RPATHs`` that the
+compiler will add to all executables generated by that compiler. This is
+useful for forcing certain compilers to RPATH their own runtime libraries, so
+that executables will run without the need to set ``LD_LIBRARY_PATH``.
.. code-block:: yaml
@@ -698,12 +707,29 @@ without the need to set ``LD_LIBRARY_PATH``.
f77: /opt/gcc/bin/gfortran
fc: /opt/gcc/bin/gfortran
environment:
+ unset:
+ BAD_VARIABLE: # The colon is required but the value must be empty
set:
- LD_LIBRARY_PATH : /opt/gcc/lib
+ GOOD_VARIABLE_NUM: 1
+ GOOD_VARIABLE_STR: good
+ prepend-path:
+ PATH: /path/to/binutils
+ append-path:
+ LD_LIBRARY_PATH: /opt/gcc/lib
extra_rpaths:
- /path/to/some/compiler/runtime/directory
- /path/to/some/other/compiler/runtime/directory
+
+.. note::
+
+ The section `environment` is interpreted as an ordered dictionary, which
+ means two things. First, environment modification are applied in the order
+ they are specified in the configuration file. Second, you cannot express
+ environment modifications that require mixing different commands, i.e. you
+ cannot `set` one variable, than `prepend-path` to another one, and than
+ again `set` a third one.
+
^^^^^^^^^^^^^^^^^^^^^^^
Architecture specifiers
^^^^^^^^^^^^^^^^^^^^^^^
@@ -950,11 +976,11 @@ directly when you run ``python``:
ImportError: No module named numpy
>>>
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Extensions & Environment Modules
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^
+Using Extensions
+^^^^^^^^^^^^^^^^
-There are two ways to get ``numpy`` working in Python. The first is
+There are three ways to get ``numpy`` working in Python. The first is
to use :ref:`shell-support`. You can simply ``use`` or ``load`` the
module for the extension, and it will be added to the ``PYTHONPATH``
in your current shell.
@@ -976,15 +1002,26 @@ or, for dotkit:
Now ``import numpy`` will succeed for as long as you keep your current
session open.
-^^^^^^^^^^^^^^^^^^^^^
-Activating Extensions
-^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Activating Extensions in a View
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The second way to use extensions is to create a view, which merges the
+python installation along with the extensions into a single prefix.
+See :ref:`filesystem-views` for a more in-depth description of views and
+:ref:`cmd-spack-view` for usage of the ``spack view`` command.
-It is often desirable to have certain packages *always* available as
-part of a Python installation. Spack offers a more permanent solution
-for this case. Instead of requiring users to load particular
-environment modules, you can *activate* the package within the Python
-installation:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Activating Extensions Globally
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As an alternative to creating a merged prefix with Python and its extensions,
+and prior to support for views, Spack has provided a means to install the
+extension into the Spack installation prefix for the extendee. This has
+typically been useful since extendable packages typically search their own
+installation path for addons by default.
+
+Global activations are performed with the ``spack activate`` command:
.. _cmd-spack-activate:
@@ -1044,11 +1081,11 @@ the ``py-numpy`` into the prefix of the ``python`` package. To the
python interpreter, it looks like ``numpy`` is installed in the
``site-packages`` directory.
-The only limitation of activation is that you can only have a *single*
+The only limitation of global activation is that you can only have a *single*
version of an extension activated at a time. This is because multiple
versions of the same extension would conflict if symbolically linked
into the same prefix. Users who want a different version of a package
-can still get it by using environment modules, but they will have to
+can still get it by using environment modules or views, but they will have to
explicitly load their preferred version.
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1093,22 +1130,43 @@ several variants:
Filesystem requirements
-----------------------
-Spack currently needs to be run from a filesystem that supports
+By default, Spack needs to be run from a filesystem that supports
``flock`` locking semantics. Nearly all local filesystems and recent
-versions of NFS support this, but parallel filesystems may be mounted
-without ``flock`` support enabled. You can determine how your
-filesystems are mounted with ``mount -p``. The output for a Lustre
+versions of NFS support this, but parallel filesystems or NFS volumes may
+be configured without ``flock`` support enabled. You can determine how
+your filesystems are mounted with ``mount``. The output for a Lustre
filesystem might look like this:
.. code-block:: console
- $ mount -l | grep lscratch
- pilsner-mds1-lnet0@o2ib100:/lsd on /p/lscratchd type lustre (rw,nosuid,noauto,_netdev,lazystatfs,flock)
- porter-mds1-lnet0@o2ib100:/lse on /p/lscratche type lustre (rw,nosuid,noauto,_netdev,lazystatfs,flock)
+ $ mount | grep lscratch
+ mds1-lnet0@o2ib100:/lsd on /p/lscratchd type lustre (rw,nosuid,lazystatfs,flock)
+ mds2-lnet0@o2ib100:/lse on /p/lscratche type lustre (rw,nosuid,lazystatfs,flock)
+
+Note the ``flock`` option on both Lustre mounts.
+
+If you do not see this or a similar option for your filesystem, you have
+a few options. First, you can move your Spack installation to a
+filesystem that supports locking. Second, you could ask your system
+administrator to enable ``flock`` for your filesystem.
+
+If none of those work, you can disable locking in one of two ways:
+
+ 1. Run Spack with the ``-L`` or ``--disable-locks`` option to disable
+ locks on a call-by-call basis.
+ 2. Edit :ref:`config.yaml <config-yaml>` and set the ``locks`` option
+ to ``false`` to always disable locking.
+
+.. warning::
+
+ If you disable locking, concurrent instances of Spack will have no way
+ to avoid stepping on each other. You must ensure that there is only
+ **one** instance of Spack running at a time. Otherwise, Spack may end
+ up with a corrupted database file, or you may not be able to see all
+ installed packages in commands like ``spack find``.
-Note the ``flock`` option on both Lustre mounts. If you do not see
-this or a similar option for your filesystem, you may need ot ask your
-system administrator to enable ``flock``.
+ If you are unfortunate enough to run into this situation, you may be
+ able to fix it by running ``spack reindex``.
This issue typically manifests with the error below:
diff --git a/lib/spack/docs/binary_caches.rst b/lib/spack/docs/binary_caches.rst
index c7eed69a6e..1400b0c9f7 100644
--- a/lib/spack/docs/binary_caches.rst
+++ b/lib/spack/docs/binary_caches.rst
@@ -1,7 +1,12 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _binary_caches:
============
-Build caches
+Build Caches
============
Some sites may encourage users to set up their own test environments
diff --git a/lib/spack/docs/build_settings.rst b/lib/spack/docs/build_settings.rst
index 0f935aa1ce..da2730baa1 100644
--- a/lib/spack/docs/build_settings.rst
+++ b/lib/spack/docs/build_settings.rst
@@ -1,14 +1,20 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _build-settings:
-======================================
-Build customization
-======================================
+===================
+Build Customization
+===================
Spack allows you to customize how your software is built through the
``packages.yaml`` file. Using it, you can make Spack prefer particular
-implementations of virtual dependencies (e.g., compilers, MPI, or BLAS),
+implementations of virtual dependencies (e.g., MPI or BLAS/LAPACK),
or you can make it prefer to build with particular compilers. You can
-also tell Spack to use *external* installations of certain software.
+also tell Spack to use *external* software installations already
+present on your system.
At a high level, the ``packages.yaml`` file is structured like this:
@@ -23,14 +29,14 @@ At a high level, the ``packages.yaml`` file is structured like this:
all:
# settings that apply to all packages.
-So you can either set build preferences *specifically* for one package,
-or you can specify that certain settings should apply to all packages.
+So you can either set build preferences specifically for *one* package,
+or you can specify that certain settings should apply to *all* packages.
The types of settings you can customize are described in detail below.
Spack's build defaults are in the default
``etc/spack/defaults/packages.yaml`` file. You can override them in
``~/.spack/packages.yaml`` or ``etc/spack/packages.yaml``. For more
-details on how this works, see :ref:`configuration-scopes`
+details on how this works, see :ref:`configuration-scopes`.
.. _sec-external-packages:
@@ -56,11 +62,12 @@ directory. Here's an example of an external configuration:
openmpi@1.4.3%gcc@4.4.7 arch=linux-x86_64-debian7+debug: /opt/openmpi-1.4.3-debug
openmpi@1.6.5%intel@10.1 arch=linux-x86_64-debian7: /opt/openmpi-1.6.5-intel
-This example lists three installations of OpenMPI, one built with gcc,
-one built with gcc and debug information, and another built with Intel.
+This example lists three installations of OpenMPI, one built with GCC,
+one built with GCC and debug information, and another built with Intel.
If Spack is asked to build a package that uses one of these MPIs as a
-dependency, it will use the the pre-installed OpenMPI in
-the given directory. Packages.yaml can also be used to specify modules
+dependency, it will use the pre-installed OpenMPI in
+the given directory. ``packages.yaml`` can also be used to specify modules
+to load instead of the installation prefixes.
Each ``packages.yaml`` begins with a ``packages:`` token, followed
by a list of package names. To specify externals, add a ``paths`` or ``modules``
@@ -77,9 +84,9 @@ though the package and compiler may not ever be built.
The packages configuration can tell Spack to use an external location
for certain package versions, but it does not restrict Spack to using
-external packages. In the above example, if an OpenMPI 1.8.4 became
-available Spack may choose to start building and linking with that version
-rather than continue using the pre-installed OpenMPI versions.
+external packages. In the above example, since newer versions of OpenMPI
+are available, Spack will choose to start building and linking with the
+latest version rather than continue using the pre-installed OpenMPI versions.
To prevent this, the ``packages.yaml`` configuration also allows packages
to be flagged as non-buildable. The previous example could be modified to
@@ -115,12 +122,12 @@ Concretization Preferences
--------------------------
Spack can be configured to prefer certain compilers, package
-versions, depends_on, and variants during concretization.
+versions, dependencies, and variants during concretization.
The preferred configuration can be controlled via the
-``~/.spack/packages.yaml`` file for user configuations, or the
+``~/.spack/packages.yaml`` file for user configurations, or the
``etc/spack/packages.yaml`` site configuration.
-Here's an example packages.yaml file that sets preferred packages:
+Here's an example ``packages.yaml`` file that sets preferred packages:
.. code-block:: yaml
@@ -133,17 +140,17 @@ Here's an example packages.yaml file that sets preferred packages:
all:
compiler: [gcc@4.4.7, gcc@4.6:, intel, clang, pgi]
providers:
- mpi: [mvapich, mpich, openmpi]
+ mpi: [mvapich2, mpich, openmpi]
At a high level, this example is specifying how packages should be
-concretized. The opencv package should prefer using gcc 4.9 and
+concretized. The opencv package should prefer using GCC 4.9 and
be built with debug options. The gperftools package should prefer version
-2.2 over 2.4. Every package on the system should prefer mvapich for
-its MPI and gcc 4.4.7 (except for opencv, which overrides this by preferring gcc 4.9).
+2.2 over 2.4. Every package on the system should prefer mvapich2 for
+its MPI and GCC 4.4.7 (except for opencv, which overrides this by preferring GCC 4.9).
These options are used to fill in implicit defaults. Any of them can be overwritten
on the command line if explicitly requested.
-Each packages.yaml file begins with the string ``packages:`` and
+Each ``packages.yaml`` file begins with the string ``packages:`` and
package names are specified on the next level. The special string ``all``
applies settings to each package. Underneath each package name is
one or more components: ``compiler``, ``variants``, ``version``,
@@ -164,5 +171,54 @@ gcc to pgi will thus be preferred over the xlc compiler.
The syntax for the ``provider`` section differs slightly from other
concretization rules. A provider lists a value that packages may
-``depend_on`` (e.g, mpi) and a list of rules for fulfilling that
+``depend_on`` (e.g, MPI) and a list of rules for fulfilling that
dependency.
+
+.. _package_permissions:
+
+-------------------
+Package Permissions
+-------------------
+
+Spack can be configured to assign permissions to the files installed
+by a package.
+
+In the ``packages.yaml`` file under ``permissions``, the attributes
+``read``, ``write``, and ``group`` control the package
+permissions. These attributes can be set per-package, or for all
+packages under ``all``. If permissions are set under ``all`` and for a
+specific package, the package-specific settings take precedence.
+
+The ``read`` and ``write`` attributes take one of ``user``, ``group``,
+and ``world``.
+
+.. code-block:: yaml
+
+ packages:
+ all:
+ permissions:
+ write: group
+ group: spack
+ my_app:
+ permissions:
+ read: group
+ group: my_team
+
+The permissions settings describe the broadest level of access to
+installations of the specified packages. The execute permissions of
+the file are set to the same level as read permissions for those files
+that are executable. The default setting for ``read`` is ``world``,
+and for ``write`` is ``user``. In the example above, installations of
+``my_app`` will be installed with user and group permissions but no
+world permissions, and owned by the group ``my_team``. All other
+packages will be installed with user and group write privileges, and
+world read privileges. Those packages will be owned by the group
+``spack``.
+
+The ``group`` attribute assigns a Unix-style group to a package. All
+files installed by the package will be owned by the assigned group,
+and the sticky group bit will be set on the install prefix and all
+directories inside the install prefix. This will ensure that even
+manually placed files within the install prefix are owned by the
+assigned group. If no group is assigned, Spack will allow the OS
+default behavior to go as expected.
diff --git a/lib/spack/docs/build_systems.rst b/lib/spack/docs/build_systems.rst
new file mode 100644
index 0000000000..eb8d3f6ab2
--- /dev/null
+++ b/lib/spack/docs/build_systems.rst
@@ -0,0 +1,89 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
+.. _build-systems:
+
+=============
+Build Systems
+=============
+
+Spack defines a number of classes which understand how to use common
+`build systems <https://en.wikipedia.org/wiki/List_of_build_automation_software>`_
+(Makefiles, CMake, etc.). Spack package definitions can inherit these
+classes in order to streamline their builds.
+
+This guide provides information specific to each particular build system.
+It assumes that you've read the :ref:`packaging-guide` and expands
+on these ideas for each distinct build system that Spack supports:
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Make-based
+
+ build_systems/makefilepackage
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Make-incompatible
+
+ build_systems/sconspackage
+ build_systems/wafpackage
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Build-script generation
+
+ build_systems/autotoolspackage
+ build_systems/cmakepackage
+ build_systems/mesonpackage
+ build_systems/qmakepackage
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Language-specific
+
+ build_systems/octavepackage
+ build_systems/perlpackage
+ build_systems/pythonpackage
+ build_systems/rpackage
+ build_systems/rubypackage
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Other
+
+ build_systems/cudapackage
+ build_systems/intelpackage
+ build_systems/custompackage
+
+For reference, the :py:mod:`Build System API docs <spack.build_systems>`
+provide a list of build systems and methods/attributes that can be
+overridden. If you are curious about the implementation of a particular
+build system, you can view the source code by running:
+
+.. code-block:: console
+
+ $ spack edit --build-system autotools
+
+
+This will open up the ``AutotoolsPackage`` definition in your favorite
+editor. In addition, if you are working with a less common build system
+like QMake, SCons, or Waf, it may be useful to see examples of other
+packages. You can quickly find examples by running:
+
+.. code-block:: console
+
+ $ cd var/spack/repos/builtin/packages
+ $ grep -l QMakePackage */package.py
+
+
+You can then view these packages with ``spack edit``.
+
+This guide is intended to supplement the
+:py:mod:`Build System API docs <spack.build_systems>` with examples of
+how to override commonly used methods. It also provides rules of thumb
+and suggestions for package developers who are unfamiliar with a
+particular build system.
diff --git a/lib/spack/docs/build_systems/Autoconf-automake-process.svg b/lib/spack/docs/build_systems/Autoconf-automake-process.svg
new file mode 100644
index 0000000000..13eb36a80e
--- /dev/null
+++ b/lib/spack/docs/build_systems/Autoconf-automake-process.svg
@@ -0,0 +1,840 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by graphviz version 2.30.1 (20130303.0813)
+ -->
+
+<!-- Title: autotools Pages: 1 -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="515pt"
+ height="936pt"
+ viewBox="0.00 0.00 515.00 936.00"
+ id="svg3335"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="Autoconf-automake-process.svg">
+ <metadata
+ id="metadata3645">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3643" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1309"
+ inkscape:window-height="744"
+ id="namedview3641"
+ showgrid="false"
+ inkscape:zoom="0.70163371"
+ inkscape:cx="271.30388"
+ inkscape:cy="758.87622"
+ inkscape:window-x="57"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3335" />
+ <polygon
+ style="fill:#ffffff;stroke:#ffffff"
+ id="polygon3340"
+ points="512,-932 512,5 -4,5 -4,5 -4,-932 "
+ transform="translate(4,932)" />
+ <g
+ class="node"
+ id="node1"
+ transform="translate(4,932)">
+ <title
+ id="title3343">configure.ac</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;opacity:1;fill-opacity:0.08627451"
+ id="polygon3345"
+ points="114.75,-818 209.25,-818 209.25,-854 209.25,-854 114.75,-854 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3347"
+ font-size="14.00"
+ y="-832.29999"
+ x="162">configure.ac</text>
+ </g>
+ <g
+ class="node"
+ id="node5"
+ transform="translate(4,932)">
+ <title
+ id="title3350">aclocal</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="39.469101"
+ sodipodi:cy="-762"
+ sodipodi:cx="66"
+ d="m 105.4691,-762 c 0,9.94113 -17.670917,18 -39.4691,18 -21.798183,0 -39.469101,-8.05887 -39.469101,-18 0,-9.94113 17.670918,-18 39.469101,-18 21.798183,0 39.4691,8.05887 39.4691,18 z"
+ id="ellipse3352"
+ ry="18"
+ rx="39.469101"
+ cy="-762"
+ cx="66" />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3354"
+ font-size="14.00"
+ y="-758.29999"
+ x="66">aclocal</text>
+ </g>
+ <g
+ class="edge"
+ id="edge3"
+ transform="translate(4,932)">
+ <title
+ id="title3357">configure.ac-&gt;aclocal</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3359"
+ d="m 139.249,-817.937 c -13.626,10.22 -31.049,23.287 -45.4828,34.112" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3361"
+ points="89.6641,-780.748 93.6641,-783.748 93.6641,-783.748 93.6641,-783.748 89.6641,-780.748 90.9641,-787.348 85.6641,-777.748 85.6641,-777.748 85.6641,-777.748 96.3642,-780.148 " />
+ </g>
+ <g
+ class="node"
+ id="node6"
+ transform="translate(4,932)">
+ <title
+ id="title3364">autoconf</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="46.219101"
+ sodipodi:cy="-614"
+ sodipodi:cx="130"
+ d="m 176.2191,-614 c 0,9.94113 -20.693,18 -46.2191,18 -25.5261,0 -46.219101,-8.05887 -46.219101,-18 0,-9.94113 20.693001,-18 46.219101,-18 25.5261,0 46.2191,8.05887 46.2191,18 z"
+ id="ellipse3366"
+ ry="18"
+ rx="46.219101"
+ cy="-614"
+ cx="130" />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3368"
+ font-size="14.00"
+ y="-610.29999"
+ x="130">autoconf</text>
+ </g>
+ <g
+ class="edge"
+ id="edge4"
+ transform="translate(4,932)">
+ <title
+ id="title3371">configure.ac-&gt;autoconf</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3373"
+ d="m 159.489,-817.737 c -5.538,38.073 -18.837,129.506 -25.518,175.436" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3375"
+ points="133.219,-637.131 133.939,-642.079 133.939,-642.079 133.939,-642.079 133.219,-637.131 129.486,-642.726 132.499,-632.183 132.499,-632.183 132.499,-632.183 138.392,-641.431 " />
+ </g>
+ <g
+ class="node"
+ id="node7"
+ transform="translate(4,932)">
+ <title
+ id="title3378">autoheader</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="57.292702"
+ sodipodi:cy="-762"
+ sodipodi:cx="220"
+ d="m 277.2927,-762 c 0,9.94113 -25.65081,18 -57.2927,18 -31.64189,0 -57.2927,-8.05887 -57.2927,-18 0,-9.94113 25.65081,-18 57.2927,-18 31.64189,0 57.2927,8.05887 57.2927,18 z"
+ id="ellipse3380"
+ ry="18"
+ rx="57.292702"
+ cy="-762"
+ cx="220" />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3382"
+ font-size="14.00"
+ y="-758.29999"
+ x="220">autoheader</text>
+ </g>
+ <g
+ class="edge"
+ id="edge5"
+ transform="translate(4,932)">
+ <title
+ id="title3385">configure.ac-&gt;autoheader</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3387"
+ d="m 175.745,-817.937 c 7.223,8.967 16.212,20.125 24.197,30.038" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3389"
+ points="203.217,-783.834 200.08,-787.728 200.08,-787.728 200.08,-787.728 203.217,-783.834 196.576,-784.905 206.353,-779.941 206.353,-779.941 206.353,-779.941 203.585,-790.551 " />
+ </g>
+ <g
+ class="node"
+ id="node8"
+ transform="translate(4,932)">
+ <title
+ id="title3392">automake</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="50.542702"
+ sodipodi:cy="-614"
+ sodipodi:cx="309"
+ d="m 359.5427,-614 c 0,9.94113 -22.62874,18 -50.5427,18 -27.91396,0 -50.5427,-8.05887 -50.5427,-18 0,-9.94113 22.62874,-18 50.5427,-18 27.91396,0 50.5427,8.05887 50.5427,18 z"
+ id="ellipse3394"
+ ry="18"
+ rx="50.542702"
+ cy="-614"
+ cx="309" />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3396"
+ font-size="14.00"
+ y="-610.29999"
+ x="309">automake</text>
+ </g>
+ <g
+ class="edge"
+ id="edge6"
+ transform="translate(4,932)">
+ <title
+ id="title3399">configure.ac-&gt;automake</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3401"
+ d="m 209.463,-825.823 c 26.664,7.68 58.18,21.469 76.537,45.823 30.292,40.188 30.031,101.971 26.756,137.428" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3403"
+ points="312.206,-637.438 312.739,-642.41 312.739,-642.41 312.739,-642.41 312.206,-637.438 308.265,-642.889 311.674,-632.467 311.674,-632.467 311.674,-632.467 317.213,-641.93 " />
+ </g>
+ <g
+ class="node"
+ id="node2"
+ transform="translate(4,932)">
+ <title
+ id="title3406">autoscan</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="48.1437"
+ sodipodi:cy="-910"
+ sodipodi:cx="162"
+ d="m 210.1437,-910 c 0,9.94113 -21.55467,18 -48.1437,18 -26.58903,0 -48.1437,-8.05887 -48.1437,-18 0,-9.94113 21.55467,-18 48.1437,-18 26.58903,0 48.1437,8.05887 48.1437,18 z"
+ id="ellipse3408"
+ ry="18"
+ rx="48.1437"
+ cy="-910"
+ cx="162" />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3410"
+ font-size="14.00"
+ y="-906.29999"
+ x="162">autoscan</text>
+ </g>
+ <g
+ class="edge"
+ id="edge1"
+ transform="translate(4,932)">
+ <title
+ id="title3413">autoscan-&gt;configure.ac</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3415"
+ d="m 162,-891.937 c 0,6.716 0,14.661 0,22.392" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3417"
+ points="156.75,-869.441 167.25,-869.441 167.25,-869.441 162,-854.441 " />
+ </g>
+ <g
+ class="node"
+ id="node3"
+ transform="translate(4,932)">
+ <title
+ id="title3420">Makefile.am</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3422"
+ points="333,-670 425,-670 425,-706 425,-706 333,-706 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3424"
+ font-size="14.00"
+ y="-684.29999"
+ x="379">Makefile.am</text>
+ </g>
+ <g
+ class="edge"
+ id="edge10"
+ transform="translate(4,932)">
+ <title
+ id="title3427">Makefile.am-&gt;automake</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3429"
+ d="m 362.411,-669.937 c -9.021,9.279 -20.323,20.903 -30.204,31.067" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3431"
+ points="328.474,-635.03 331.959,-638.615 331.959,-638.615 331.959,-638.615 328.474,-635.03 328.732,-641.752 324.988,-631.445 324.988,-631.445 324.988,-631.445 335.185,-635.478 " />
+ </g>
+ <g
+ class="node"
+ id="node9"
+ transform="translate(4,932)">
+ <title
+ id="title3434">aclocal.m4</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3436"
+ points="21.75,-670 106.25,-670 106.25,-706 106.25,-706 21.75,-706 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3438"
+ font-size="14.00"
+ y="-684.29999"
+ x="64">aclocal.m4</text>
+ </g>
+ <g
+ class="edge"
+ id="edge7"
+ transform="translate(4,932)">
+ <title
+ id="title3441">aclocal-&gt;aclocal.m4</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3443"
+ d="m 65.526,-743.937 c -0.1865,6.716 -0.4072,14.661 -0.622,22.392" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3445"
+ points="59.6531,-721.581 70.149,-721.289 70.149,-721.289 64.4845,-706.441 " />
+ </g>
+ <g
+ class="node"
+ id="node12"
+ transform="translate(4,932)">
+ <title
+ id="title3448">configure</title>
+ <ellipse
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ sodipodi:ry="72"
+ sodipodi:rx="72"
+ sodipodi:cy="-486"
+ sodipodi:cx="130"
+ d="m 202,-486 c 0,39.7645 -32.2355,72 -72,72 -39.764502,0 -72,-32.2355 -72,-72 0,-39.7645 32.235498,-72 72,-72 39.7645,0 72,32.2355 72,72 z"
+ id="ellipse3450"
+ ry="72"
+ rx="72"
+ cy="-486"
+ cx="130" />
+ <polyline
+ style="fill:none;stroke:#000000"
+ id="polyline3452"
+ points="177.621,-540 82.3792,-540 " />
+ <polyline
+ style="fill:none;stroke:#000000"
+ id="polyline3454"
+ points="177.621,-432 82.3792,-432 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3456"
+ font-size="14.00"
+ y="-482.29999"
+ x="130">configure</text>
+ </g>
+ <g
+ class="edge"
+ id="edge13"
+ transform="translate(4,932)">
+ <title
+ id="title3459">autoconf-&gt;configure</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3461"
+ d="m 130,-595.744 c 0,6.397 0,14.16 0,22.563" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3463"
+ points="124.75,-573.051 135.25,-573.051 135.25,-573.051 130,-558.051 " />
+ </g>
+ <g
+ class="node"
+ id="node10"
+ transform="translate(7.9661017,932)">
+ <title
+ id="title3466">config.h.in</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3468"
+ points="260.25,-670 260.25,-706 260.25,-706 179.75,-706 179.75,-670 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3470"
+ font-size="14.00"
+ y="-684.29999"
+ x="220">config.h.in</text>
+ </g>
+ <g
+ class="edge"
+ id="edge8"
+ transform="translate(4,932)">
+ <title
+ id="title3473">autoheader-&gt;config.h.in</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3475"
+ d="m 220,-743.937 c 0,6.716 0,14.661 0,22.392" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3477"
+ points="214.75,-721.441 225.25,-721.441 225.25,-721.441 220,-706.441 " />
+ </g>
+ <g
+ class="node"
+ id="node11"
+ transform="translate(4,932)">
+ <title
+ id="title3480">Makefile.in</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3482"
+ points="260.75,-468 343.25,-468 343.25,-504 343.25,-504 260.75,-504 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3484"
+ font-size="14.00"
+ y="-482.29999"
+ x="302">Makefile.in</text>
+ </g>
+ <g
+ class="edge"
+ id="edge11"
+ transform="translate(4,932)">
+ <title
+ id="title3487">automake-&gt;Makefile.in</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3489"
+ d="m 308.041,-595.744 c -1.089,19.604 -2.89,52.031 -4.243,76.384" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3491"
+ points="298.537,-519.315 309.021,-518.733 309.021,-518.733 302.947,-504.047 " />
+ </g>
+ <g
+ class="edge"
+ id="edge12"
+ transform="translate(4,932)">
+ <title
+ id="title3494">aclocal.m4-&gt;autoconf</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3496"
+ d="m 79.6411,-669.937 c 8.5054,9.279 19.1615,20.903 28.4789,31.067" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3498"
+ points="111.547,-635.131 108.168,-638.816 108.168,-638.816 108.168,-638.816 111.547,-635.131 104.851,-635.776 114.925,-631.445 114.925,-631.445 114.925,-631.445 111.485,-641.857 " />
+ </g>
+ <g
+ class="edge"
+ id="edge9"
+ transform="translate(4,932)">
+ <title
+ id="title3501">config.h.in-&gt;automake</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3503"
+ d="m 241.092,-669.937 c 12.174,9.849 27.617,22.342 40.698,32.925" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3505"
+ points="285.693,-633.855 281.806,-637 281.806,-637 281.806,-637 285.693,-633.855 278.975,-633.501 289.58,-630.71 289.58,-630.71 289.58,-630.71 284.636,-640.498 " />
+ </g>
+ <g
+ class="node"
+ id="node15"
+ transform="translate(4,932)">
+ <title
+ id="title3508">config.status</title>
+ <ellipse
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ sodipodi:ry="63.088799"
+ sodipodi:rx="63.066601"
+ sodipodi:cy="-313"
+ sodipodi:cx="230"
+ d="m 293.0666,-313 c 0,34.84298 -28.23588,63.0888 -63.0666,63.0888 -34.83072,0 -63.0666,-28.24582 -63.0666,-63.0888 0,-34.84298 28.23588,-63.0888 63.0666,-63.0888 34.83072,0 63.0666,28.24582 63.0666,63.0888 z"
+ id="ellipse3510"
+ ry="63.088799"
+ rx="63.066601"
+ cy="-313"
+ cx="230" />
+ <polyline
+ style="fill:none;stroke:#000000"
+ id="polyline3512"
+ points="271.668,-360.283 188.332,-360.283 " />
+ <polyline
+ style="fill:none;stroke:#000000"
+ id="polyline3514"
+ points="271.668,-265.717 188.332,-265.717 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3516"
+ font-size="14.00"
+ y="-309.29999"
+ x="230">config.status</text>
+ </g>
+ <g
+ class="edge"
+ id="edge14"
+ transform="translate(4,932)">
+ <title
+ id="title3519">config.h.in-&gt;config.status</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3521"
+ d="m 227.40968,-670.00576 c 1.335,49.807 -1.72568,195.00376 0.65132,283.69476"
+ sodipodi:nodetypes="cc" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3523"
+ points="228.202,-381.047 228.068,-386.045 228.068,-386.045 228.068,-386.045 228.202,-381.047 223.57,-385.925 228.336,-376.049 228.336,-376.049 228.336,-376.049 232.567,-386.166 " />
+ </g>
+ <g
+ class="edge"
+ id="edge15"
+ transform="translate(4,932)">
+ <title
+ id="title3526">Makefile.in-&gt;config.status</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3528"
+ d="m 294.833,-467.979 c -8.579,20.376 -23.463,55.724 -36.807,87.417" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3530"
+ points="256.067,-375.909 258.007,-380.517 258.007,-380.517 258.007,-380.517 256.067,-375.909 253.86,-382.264 254.127,-371.301 254.127,-371.301 254.127,-371.301 262.155,-378.771 " />
+ </g>
+ <g
+ class="edge"
+ id="edge16"
+ transform="translate(4,932)">
+ <title
+ id="title3533">configure-&gt;config.status</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3535"
+ d="m 166.102,-423.265 c 8.055,13.774 16.633,28.443 24.803,42.413" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3537"
+ points="186.478,-378.022 195.542,-383.323 195.542,-383.323 198.582,-367.724 " />
+ </g>
+ <g
+ class="node"
+ id="node13"
+ transform="translate(4,932)">
+ <title
+ id="title3540">config.h</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3542"
+ points="110.75,-176 177.25,-176 177.25,-212 177.25,-212 110.75,-212 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3544"
+ font-size="14.00"
+ y="-190.3"
+ x="144">config.h</text>
+ </g>
+ <g
+ class="node"
+ id="node18"
+ transform="translate(4,932)">
+ <title
+ id="title3547">make</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="33.220901"
+ sodipodi:cy="-106"
+ sodipodi:cx="230"
+ d="m 263.2209,-106 c 0,9.941125 -14.8735,18 -33.2209,18 -18.3474,0 -33.2209,-8.058875 -33.2209,-18 0,-9.94113 14.8735,-18 33.2209,-18 18.3474,0 33.2209,8.05887 33.2209,18 z"
+ id="ellipse3549"
+ ry="18"
+ rx="33.220901"
+ cy="-106"
+ cx="230" />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3551"
+ font-size="14.00"
+ y="-102.3"
+ x="230">make</text>
+ </g>
+ <g
+ class="edge"
+ id="edge21"
+ transform="translate(4,932)">
+ <title
+ id="title3554">config.h-&gt;make</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3556"
+ d="m 161.403,-175.597 c 13.375,13.375 31.944,31.944 46.39,46.39" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3558"
+ points="211.386,-125.614 207.85,-129.15 207.85,-129.15 207.85,-129.15 211.386,-125.614 204.668,-125.968 214.922,-122.078 214.922,-122.078 214.922,-122.078 211.032,-132.332 " />
+ </g>
+ <g
+ class="node"
+ id="node14"
+ transform="translate(4,932)">
+ <title
+ id="title3561">Makefile</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3563"
+ points="195.75,-176 264.25,-176 264.25,-212 264.25,-212 195.75,-212 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3565"
+ font-size="14.00"
+ y="-190.3"
+ x="230">Makefile</text>
+ </g>
+ <g
+ class="edge"
+ id="edge22"
+ transform="translate(4,932)">
+ <title
+ id="title3568">Makefile-&gt;make</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3570"
+ d="m 230,-175.597 c 0,11.851 0,27.78 0,41.305" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3572"
+ points="230,-129.084 230,-134.084 230,-134.084 230,-134.084 230,-129.084 225.5,-134.084 230,-124.084 230,-124.084 230,-124.084 234.5,-134.084 " />
+ </g>
+ <g
+ class="edge"
+ id="edge18"
+ transform="translate(4,932)">
+ <title
+ id="title3575">config.status-&gt;config.h</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3577"
+ d="m 193.029,-261.702 c -9.358,12.731 -19.105,25.992 -27.42,37.304" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3579"
+ points="161.268,-227.357 169.729,-221.138 169.729,-221.138 156.615,-212.162 " />
+ </g>
+ <g
+ class="edge"
+ id="edge19"
+ transform="translate(4,932)">
+ <title
+ id="title3582">config.status-&gt;Makefile</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3584"
+ d="m 230,-249.732 c 0,7.628 0,15.171 0,22.106" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3586"
+ points="224.75,-227.368 235.25,-227.368 235.25,-227.368 230,-212.368 " />
+ </g>
+ <g
+ class="node"
+ id="node20"
+ transform="translate(4,932)">
+ <title
+ id="title3589">input file</title>
+ <polygon
+ style="fill:#0000f0;stroke:#000000;fill-opacity:0.08627451"
+ id="polygon3591"
+ points="393,-176 461,-176 461,-212 461,-212 393,-212 " />
+ <text
+ style="font-size:14px;font-style:italic;text-anchor:start;font-family:URW Palladio L"
+ id="text3593"
+ font-size="14.00"
+ font-style="italic"
+ y="-191.3"
+ x="401.5">input file</text>
+ </g>
+ <g
+ class="node"
+ id="node19"
+ transform="translate(4,932)">
+ <title
+ id="title3596">executable</title>
+ <polygon
+ style="fill:#00c800;stroke:#000000;fill-opacity:0.19607843"
+ id="polygon3598"
+ points="192.75,0 267.25,0 267.25,-36 267.25,-36 192.75,-36 " />
+ <text
+ style="font-size:14px;font-style:italic;text-anchor:start;font-family:URW Palladio L"
+ id="text3600"
+ font-size="14.00"
+ font-style="italic"
+ y="-15.3"
+ x="201">executable</text>
+ </g>
+ <g
+ class="edge"
+ id="edge24"
+ transform="translate(4,932)">
+ <title
+ id="title3603">make-&gt;executable</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3605"
+ d="m 230,-87.5966 c 0,10.4427 0,24.0522 0,36.3931" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3607"
+ points="224.75,-51.084 235.25,-51.084 235.25,-51.084 230,-36.084 " />
+ </g>
+ <g
+ class="node"
+ id="node21"
+ transform="translate(4,932)">
+ <title
+ id="title3610">process</title>
+ <ellipse
+ style="fill:none;stroke:#000000"
+ sodipodi:ry="18"
+ sodipodi:rx="37.070099"
+ sodipodi:cy="-106"
+ sodipodi:cx="427"
+ d="m 464.0701,-106 c 0,9.941125 -16.59685,18 -37.0701,18 -20.47325,0 -37.0701,-8.058875 -37.0701,-18 0,-9.94113 16.59685,-18 37.0701,-18 20.47325,0 37.0701,8.05887 37.0701,18 z"
+ id="ellipse3612"
+ ry="18"
+ rx="37.070099"
+ cy="-106"
+ cx="427" />
+ <text
+ style="font-size:14px;font-style:italic;text-anchor:start;font-family:URW Palladio L"
+ id="text3614"
+ font-size="14.00"
+ font-style="italic"
+ y="-103.3"
+ x="407">process</text>
+ </g>
+ <g
+ class="edge"
+ id="edge26"
+ transform="translate(4,932)">
+ <title
+ id="title3617">input file-&gt;process</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:12,1;stroke-dashoffset:0"
+ inkscape:connector-curvature="0"
+ id="path3619"
+ d="m 427,-175.597 c 0,11.851 0,27.78 0,41.305" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3621"
+ points="427,-129.084 427,-134.084 427,-134.084 427,-134.084 427,-129.084 422.5,-134.084 427,-124.084 427,-124.084 427,-124.084 431.5,-134.084 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3623"
+ font-size="14.00"
+ y="-146.3"
+ x="467"> influences  </text>
+ </g>
+ <g
+ class="node"
+ id="node22"
+ transform="translate(4,932)">
+ <title
+ id="title3626">output file</title>
+ <polygon
+ style="fill:#00c800;stroke:#000000;fill-opacity:0.19607843"
+ id="polygon3628"
+ points="389.75,0 464.25,0 464.25,-36 464.25,-36 389.75,-36 " />
+ <text
+ style="font-size:14px;font-style:italic;text-anchor:start;font-family:URW Palladio L"
+ id="text3630"
+ font-size="14.00"
+ font-style="italic"
+ y="-15.3"
+ x="398">output file</text>
+ </g>
+ <g
+ class="edge"
+ id="edge27"
+ transform="translate(4,932)">
+ <title
+ id="title3633">process-&gt;output file</title>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0"
+ id="path3635"
+ d="m 427,-87.5966 c 0,10.4427 0,24.0522 0,36.3931" />
+ <polygon
+ style="fill:#000000;stroke:#000000"
+ id="polygon3637"
+ points="421.75,-51.084 432.25,-51.084 432.25,-51.084 427,-36.084 " />
+ <text
+ style="font-size:14px;text-anchor:middle;font-family:Liberation Sans"
+ id="text3639"
+ font-size="14.00"
+ y="-58.299999"
+ x="458.5"> creates  </text>
+ </g>
+</svg>
diff --git a/lib/spack/docs/build_systems/autotoolspackage.rst b/lib/spack/docs/build_systems/autotoolspackage.rst
new file mode 100644
index 0000000000..ce22fd832b
--- /dev/null
+++ b/lib/spack/docs/build_systems/autotoolspackage.rst
@@ -0,0 +1,305 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _autotoolspackage:
+
+----------------
+AutotoolsPackage
+----------------
+
+Autotools is a GNU build system that provides a build-script generator.
+By running the platform-independent ``./configure`` script that comes
+with the package, you can generate a platform-dependent Makefile.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``AutotoolsPackage`` base class comes with the following phases:
+
+#. ``autoreconf`` - generate the configure script
+#. ``configure`` - generate the Makefiles
+#. ``build`` - build the package
+#. ``install`` - install the package
+
+Most of the time, the ``autoreconf`` phase will do nothing, but if the
+package is missing a ``configure`` script, ``autoreconf`` will generate
+one for you.
+
+The other phases run:
+
+.. code-block:: console
+
+ $ ./configure --prefix=/path/to/installation/prefix
+ $ make
+ $ make check # optional
+ $ make install
+ $ make installcheck # optional
+
+
+Of course, you may need to add a few arguments to the ``./configure``
+line.
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+The most important file for an Autotools-based package is the ``configure``
+script. This script is automatically generated by Autotools and generates
+the appropriate Makefile when run.
+
+.. warning::
+
+ Watch out for fake Autotools packages!
+
+ Autotools is a very popular build system, and many people are used to the
+ classic steps to install a package:
+
+ .. code-block:: console
+
+ $ ./configure
+ $ make
+ $ make install
+
+
+ For this reason, some developers will write their own ``configure``
+ scripts that have nothing to do with Autotools. These packages may
+ not accept the same flags as other Autotools packages, so it is
+ better to use the ``Package`` base class and create a
+ :ref:`custom build system <custompackage>`. You can tell if a package
+ uses Autotools by running ``./configure --help`` and comparing the output
+ to other known Autotools packages. You should also look for files like:
+
+ * ``configure.ac``
+ * ``configure.in``
+ * ``Makefile.am``
+
+ Packages that don't use Autotools aren't likely to have these files.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Whether or not your package requires Autotools to install depends on
+how the source code is distributed. Most of the time, when developers
+distribute tarballs, they will already contain the ``configure`` script
+necessary for installation. If this is the case, your package does not
+require any Autotools dependencies.
+
+However, a basic rule of version control systems is to never commit
+code that can be generated. The source code repository itself likely
+does not have a ``configure`` script. Developers typically write
+(or auto-generate) a ``configure.ac`` script that contains configuration
+preferences and a ``Makefile.am`` script that contains build instructions.
+Then, ``autoconf`` is used to convert ``configure.ac`` into ``configure``,
+while ``automake`` is used to convert ``Makefile.am`` into ``Makefile.in``.
+``Makefile.in`` is used by ``configure`` to generate a platform-dependent
+``Makefile`` for you. The following diagram provides a high-level overview
+of the process:
+
+.. figure:: Autoconf-automake-process.*
+ :target: https://commons.wikimedia.org/w/index.php?curid=15581407
+
+ `GNU autoconf and automake process for generating makefiles <https://commons.wikimedia.org/wiki/File:Autoconf-automake-process.svg>`_
+ by `Jdthood` under `CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0/deed.en>`_
+
+If a ``configure`` script is not present in your tarball, you will
+need to generate one yourself. Luckily, Spack already has an ``autoreconf``
+phase to do most of the work for you. By default, the ``autoreconf``
+phase runs:
+
+.. code-block:: console
+
+ $ libtoolize
+ $ aclocal
+ $ autoreconf --install --verbose --force
+
+All you need to do is add a few Autotools dependencies to the package.
+Most stable releases will come with a ``configure`` script, but if you
+check out a commit from the ``develop`` branch, you would want to add:
+
+.. code-block:: python
+
+ depends_on('autoconf', type='build', when='@develop')
+ depends_on('automake', type='build', when='@develop')
+ depends_on('libtool', type='build', when='@develop')
+ depends_on('m4', type='build', when='@develop')
+
+In some cases, developers might need to distribute a patch that modifies
+one of the files used to generate ``configure`` or ``Makefile.in``.
+In this case, these scripts will need to be regenerated. It is
+preferable to regenerate these manually using the patch, and then
+create a new patch that directly modifies ``configure``. That way,
+Spack can use the secondary patch and additional build system
+dependencies aren't necessary.
+
+""""""""""""""""
+force_autoreconf
+""""""""""""""""
+
+If for whatever reason you really want to add the original patch
+and tell Spack to regenerate ``configure``, you can do so using the
+following setting:
+
+.. code-block:: python
+
+ force_autoreconf = True
+
+This line tells Spack to wipe away the existing ``configure`` script
+and generate a new one. If you only need to do this for a single
+version, this can be done like so:
+
+.. code-block:: python
+
+ @property
+ def force_autoreconf(self):
+ return self.version == Version('1.2.3'):
+
+^^^^^^^^^^^^^^^^^^^^^^^
+Finding configure flags
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Once you have a ``configure`` script present, the next step is to
+determine what option flags are available. These flags can be found
+by running:
+
+.. code-block:: console
+
+ $ ./configure --help
+
+``configure`` will display a list of valid flags separated into
+some or all of the following sections:
+
+* Configuration
+* Installation directories
+* Fine tuning of the installation directories
+* Program names
+* X features
+* System types
+* **Optional Features**
+* **Optional Packages**
+* **Some influential environment variables**
+
+For the most part, you can ignore all but the last 3 sections.
+The "Optional Features" sections lists flags that enable/disable
+features you may be interested in. The "Optional Packages" section
+often lists dependencies and the flags needed to locate them. The
+"environment variables" section lists environment variables that the
+build system uses to pass flags to the compiler and linker.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Addings flags to configure
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For most of the flags you encounter, you will want a variant to
+optionally enable/disable them. You can then optionally pass these
+flags to the ``configure`` call by overriding the ``configure_args``
+function like so:
+
+.. code-block:: python
+
+ def configure_args(self):
+ args = []
+
+ if '+mpi' in self.spec:
+ args.append('--enable-mpi')
+ else:
+ args.append('--disable-mpi')
+
+ return args
+
+Note that we are explicitly disabling MPI support if it is not
+requested. This is important, as many Autotools packages will enable
+options by default if the dependencies are found, and disable them
+otherwise. We want Spack installations to be as deterministic as possible.
+If two users install a package with the same variants, the goal is that
+both installations work the same way. See `here <https://www.linux.com/news/best-practices-autotools>`__
+and `here <https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Automagic_dependencies>`__
+for a rationale as to why these so-called "automagic" dependencies
+are a problem.
+
+By default, Autotools installs packages to ``/usr``. We don't want this,
+so Spack automatically adds ``--prefix=/path/to/installation/prefix``
+to your list of ``configure_args``. You don't need to add this yourself.
+
+^^^^^^^^^^^^^^^^
+Helper functions
+^^^^^^^^^^^^^^^^
+
+You may have noticed that most of the Autotools flags are of the form
+``--enable-foo``, ``--disable-bar``, ``--with-baz=<prefix>``, or
+``--without-baz``. Since these flags are so common, Spack provides a
+couple of helper functions to make your life easier.
+
+TODO: document ``with_or_without`` and ``enable_or_disable``.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Configure script in a sub-directory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Occasionally, developers will hide their source code and ``configure``
+script in a subdirectory like ``src``. If this happens, Spack won't
+be able to automatically detect the build system properly when running
+``spack create``. You will have to manually change the package base
+class and tell Spack where the ``configure`` script resides. You can
+do this like so:
+
+.. code-block:: python
+
+ configure_directory = 'src'
+
+^^^^^^^^^^^^^^^^^^^^^^
+Building out of source
+^^^^^^^^^^^^^^^^^^^^^^
+
+Some packages like ``gcc`` recommend building their software in a
+different directory than the source code to prevent build pollution.
+This can be done using the ``build_directory`` variable:
+
+.. code-block:: python
+
+ build_directory = 'spack-build'
+
+By default, Spack will build the package in the same directory that
+contains the ``configure`` script
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build and install targets
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For most Autotools packages, the usual:
+
+.. code-block:: console
+
+ $ configure
+ $ make
+ $ make install
+
+is sufficient to install the package. However, if you need to run
+make with any other targets, for example, to build an optional
+library or build the documentation, you can add these like so:
+
+.. code-block:: python
+
+ build_targets = ['all', 'docs']
+ install_targets = ['install', 'docs']
+
+^^^^^^^
+Testing
+^^^^^^^
+
+Autotools-based packages typically provide unit testing via the
+``check`` and ``installcheck`` targets. If you build your software
+with ``spack install --test=root``, Spack will check for the presence
+of a ``check`` or ``test`` target in the Makefile and run
+``make check`` for you. After installation, it will check for an
+``installcheck`` target and run ``make installcheck`` if it finds one.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the Autotools build system, see:
+https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html
diff --git a/lib/spack/docs/build_systems/cmakepackage.rst b/lib/spack/docs/build_systems/cmakepackage.rst
new file mode 100644
index 0000000000..b627ddb84b
--- /dev/null
+++ b/lib/spack/docs/build_systems/cmakepackage.rst
@@ -0,0 +1,279 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _cmakepackage:
+
+------------
+CMakePackage
+------------
+
+Like Autotools, CMake is a widely-used build-script generator. Designed
+by Kitware, CMake is the most popular build system for new C, C++, and
+Fortran projects, and many older projects are switching to it as well.
+
+Unlike Autotools, CMake can generate build scripts for builders other
+than Make: Ninja, Visual Studio, etc. It is therefore cross-platform,
+whereas Autotools is Unix-only.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``CMakePackage`` base class comes with the following phases:
+
+#. ``cmake`` - generate the Makefile
+#. ``build`` - build the package
+#. ``install`` - install the package
+
+By default, these phases run:
+
+.. code-block:: console
+
+ $ mkdir spack-build
+ $ cd spack-build
+ $ cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/installation/prefix
+ $ make
+ $ make test # optional
+ $ make install
+
+
+A few more flags are passed to ``cmake`` by default, including flags
+for setting the build type and flags for locating dependencies. Of
+course, you may need to add a few arguments yourself.
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+A CMake-based package can be identified by the presence of a
+``CMakeLists.txt`` file. This file defines the build flags that can be
+passed to the cmake invocation, as well as linking instructions. If
+you are familiar with CMake, it can prove very useful for determining
+dependencies and dependency version requirements.
+
+One thing to look for is the ``cmake_minimum_required`` function:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 2.8.12)
+
+
+This means that CMake 2.8.12 is the earliest release that will work.
+You should specify this in a ``depends_on`` statement.
+
+CMake-based packages may also contain ``CMakeLists.txt`` in subdirectories.
+This modularization helps to manage complex builds in a hierarchical
+fashion. Sometimes these nested ``CMakeLists.txt`` require additional
+dependencies not mentioned in the top-level file.
+
+There's also usually a ``cmake`` or ``CMake`` directory containing
+additional macros, find scripts, etc. These may prove useful in
+determining dependency version requirements.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Every package that uses the CMake build system requires a ``cmake``
+dependency. Since this is always the case, the ``CMakePackage`` base
+class already contains:
+
+.. code-block:: python
+
+ depends_on('cmake', type='build')
+
+
+If you need to specify a particular version requirement, you can
+override this in your package:
+
+.. code-block:: python
+
+ depends_on('cmake@2.8.12:', type='build')
+
+
+^^^^^^^^^^^^^^^^^^^
+Finding cmake flags
+^^^^^^^^^^^^^^^^^^^
+
+To get a list of valid flags that can be passed to ``cmake``, run the
+following command in the directory that contains ``CMakeLists.txt``:
+
+.. code-block:: console
+
+ $ cmake . -LAH
+
+
+CMake will start by checking for compilers and dependencies. Eventually
+it will begin to list build options. You'll notice that most of the
+build options at the top are prefixed with ``CMAKE_``. You can safely
+ignore most of these options as Spack already sets them for you. This
+includes flags needed to locate dependencies, RPATH libraries, set the
+installation directory, and set the build type.
+
+The rest of the flags are the ones you should consider adding to your
+package. They often include flags to enable/disable support for certain
+features and locate specific dependencies. One thing you'll notice that
+makes CMake different from Autotools is that CMake has an understanding
+of build flag hierarchy. That is, certain flags will not display unless
+their parent flag has been selected. For example, flags to specify the
+``lib`` and ``include`` directories for a package might not appear
+unless CMake found the dependency it was looking for. You may need to
+manually specify certain flags to explore the full depth of supported
+build flags, or check the ``CMakeLists.txt`` yourself.
+
+^^^^^^^^^^^^^^^^^^^^^
+Adding flags to cmake
+^^^^^^^^^^^^^^^^^^^^^
+
+To add additional flags to the ``cmake`` call, simply override the
+``cmake_args`` function:
+
+.. code-block:: python
+
+ def cmake_args(self):
+ args = []
+
+ if '+hdf5' in self.spec:
+ args.append('-DDETECT_HDF5=ON')
+ else:
+ args.append('-DDETECT_HDF5=OFF')
+
+ return args
+
+
+^^^^^^^^^^
+Generators
+^^^^^^^^^^
+
+CMake and Autotools are build-script generation tools; they "generate"
+the Makefiles that are used to build a software package. CMake actually
+supports multiple generators, not just Makefiles. Another common
+generator is Ninja. To switch to the Ninja generator, simply add:
+
+.. code-block:: python
+
+ generator = 'Ninja'
+
+
+``CMakePackage`` defaults to "Unix Makefiles". If you switch to the
+Ninja generator, make sure to add:
+
+.. code-block:: python
+
+ depends_on('ninja', type='build')
+
+to the package as well. Aside from that, you shouldn't need to do
+anything else. Spack will automatically detect that you are using
+Ninja and run:
+
+.. code-block:: console
+
+ $ cmake .. -G Ninja
+ $ ninja
+ $ ninja install
+
+Spack currently only supports "Unix Makefiles" and "Ninja" as valid
+generators, but it should be simple to add support for alternative
+generators. For more information on CMake generators, see:
+https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html
+
+^^^^^^^^^^^^^^^^
+CMAKE_BUILD_TYPE
+^^^^^^^^^^^^^^^^
+
+Every CMake-based package accepts a ``-DCMAKE_BUILD_TYPE`` flag to
+dictate which level of optimization to use. In order to ensure
+uniformity across packages, the ``CMakePackage`` base class adds
+a variant to control this:
+
+.. code-block:: python
+
+ variant('build_type', default='RelWithDebInfo',
+ description='CMake build type',
+ values=('Debug', 'Release', 'RelWithDebInfo', 'MinSizeRel'))
+
+However, not every CMake package accepts all four of these options.
+Grep the ``CMakeLists.txt`` file to see if the default values are
+missing or replaced. For example, the
+`dealii <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/dealii/package.py>`_
+package overrides the default variant with:
+
+.. code-block:: python
+
+ variant('build_type', default='DebugRelease',
+ description='The build type to build',
+ values=('Debug', 'Release', 'DebugRelease'))
+
+For more information on ``CMAKE_BUILD_TYPE``, see:
+https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+CMakeLists.txt in a sub-directory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Occasionally, developers will hide their source code and ``CMakeLists.txt``
+in a subdirectory like ``src``. If this happens, Spack won't
+be able to automatically detect the build system properly when running
+``spack create``. You will have to manually change the package base
+class and tell Spack where ``CMakeLists.txt`` resides. You can do this
+like so:
+
+.. code-block:: python
+
+ root_cmakelists_dir = 'src'
+
+
+Note that this path is relative to the root of the extracted tarball,
+not to the ``build_directory``. It defaults to the current directory.
+
+^^^^^^^^^^^^^^^^^^^^^^
+Building out of source
+^^^^^^^^^^^^^^^^^^^^^^
+
+By default, Spack builds every ``CMakePackage`` in a ``spack-build``
+sub-directory. If, for whatever reason, you would like to build in a
+different sub-directory, simply override ``build_directory`` like so:
+
+.. code-block:: python
+
+ build_directory = 'my-build'
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build and install targets
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For most CMake packages, the usual:
+
+.. code-block:: console
+
+ $ cmake
+ $ make
+ $ make install
+
+is sufficient to install the package. However, if you need to run
+make with any other targets, for example, to build an optional
+library or build the documentation, you can add these like so:
+
+.. code-block:: python
+
+ build_targets = ['all', 'docs']
+ install_targets = ['install', 'docs']
+
+^^^^^^^
+Testing
+^^^^^^^
+
+CMake-based packages typically provide unit testing via the
+``test`` target. If you build your software with ``--test=root``,
+Spack will check for the presence of a ``test`` target in the
+Makefile and run ``make test`` for you. If you want to run a
+different test instead, simply override the ``check`` method.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the CMake build system, see:
+https://cmake.org/cmake/help/latest/
diff --git a/lib/spack/docs/build_systems/cudapackage.rst b/lib/spack/docs/build_systems/cudapackage.rst
new file mode 100644
index 0000000000..1eed57e669
--- /dev/null
+++ b/lib/spack/docs/build_systems/cudapackage.rst
@@ -0,0 +1,43 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _cudapackage:
+
+-----------
+CudaPackage
+-----------
+
+Different from other packages, ``CudaPackage`` does not represent a build
+system. Instead its goal is to simplify and unify usage of ``CUDA`` in other
+packages.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Provided variants and dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``CudaPackage`` provides ``cuda`` variant (default to ``off``) to enable/disable
+``CUDA``, and ``cuda_arch`` variant to optionally specify the architecture.
+It also declares dependencies on the ``CUDA`` package ``depends_on('cuda@...')``
+based on the architecture as well as specifies conflicts for certain compiler versions.
+
+^^^^^
+Usage
+^^^^^
+
+In order to use it, just add another base class to your package, for example:
+
+.. code-block:: python
+
+ class MyPackage(CMakePackage, CudaPackage):
+ ...
+ def cmake_args(self):
+ spec = self.spec
+ if '+cuda' in spec:
+ options.append('-DWITH_CUDA=ON')
+ cuda_arch = spec.variants['cuda_arch'].value
+ if cuda_arch is not None:
+ options.append('-DCUDA_FLAGS=-arch=sm_{0}'.format(cuda_arch[0]))
+ else:
+ options.append('-DWITH_CUDA=OFF')
diff --git a/lib/spack/docs/build_systems/custompackage.rst b/lib/spack/docs/build_systems/custompackage.rst
new file mode 100644
index 0000000000..d02c9c1a0a
--- /dev/null
+++ b/lib/spack/docs/build_systems/custompackage.rst
@@ -0,0 +1,209 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _custompackage:
+
+--------------------
+Custom Build Systems
+--------------------
+
+While the build systems listed above should meet your needs for the
+vast majority of packages, some packages provide custom build scripts.
+This guide is intended for the following use cases:
+
+* Packaging software with its own custom build system
+* Adding support for new build systems
+
+If you want to add support for a new build system, a good place to
+start is to look at the definitions of other build systems. This guide
+focuses mostly on how Spack's build systems work.
+
+In this guide, we will be using the
+`perl <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/perl/package.py>`_ and
+`cmake <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/cmake/package.py>`_
+packages as examples. ``perl``'s build system is a hand-written
+``Configure`` shell script, while ``cmake`` bootstraps itself during
+installation. Both of these packages require custom build systems.
+
+^^^^^^^^^^
+Base class
+^^^^^^^^^^
+
+If your package does not belong to any of the aforementioned build
+systems that Spack already supports, you should inherit from the
+``Package`` base class. ``Package`` is a simple base class with a
+single phase: ``install``. If your package is simple, you may be able
+to simply write an ``install`` method that gets the job done. However,
+if your package is more complex and installation involves multiple
+steps, you should add separate phases as mentioned in the next section.
+
+If you are creating a new build system base class, you should inherit
+from ``PackageBase``. This is the superclass for all build systems in
+Spack.
+
+^^^^^^
+Phases
+^^^^^^
+
+The most important concept in Spack's build system support is the idea
+of phases. Each build system defines a set of phases that are necessary
+to install the package. They usually follow some sort of "configure",
+"build", "install" guideline, but any of those phases may be missing
+or combined with another phase.
+
+If you look at the ``perl`` package, you'll see:
+
+.. code-block:: python
+
+ phases = ['configure', 'build', 'install']
+
+Similarly, ``cmake`` defines:
+
+.. code-block:: python
+
+ phases = ['bootstrap', 'build', 'install']
+
+If we look at the ``cmake`` example, this tells Spack's ``PackageBase``
+class to run the ``bootstrap``, ``build``, and ``install`` functions
+in that order. It is now up to you to define these methods.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Phase and phase_args functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If we look at ``perl``, we see that it defines a ``configure`` method:
+
+.. code-block:: python
+
+ def configure(self, spec, prefix):
+ configure = Executable('./Configure')
+ configure(*self.configure_args())
+
+There is also a corresponding ``configure_args`` function that handles
+all of the arguments to pass to ``Configure``, just like in
+``AutotoolsPackage``. Comparatively, the ``build`` and ``install``
+phases are pretty simple:
+
+.. code-block:: python
+
+ def build(self, spec, prefix):
+ make()
+
+ def install(self, spec, prefix):
+ make('install')
+
+The ``cmake`` package looks very similar, but with a ``bootstrap``
+function instead of ``configure``:
+
+.. code-block:: python
+
+ def bootstrap(self, spec, prefix):
+ bootstrap = Executable('./bootstrap')
+ bootstrap(*self.bootstrap_args())
+
+ def build(self, spec, prefix):
+ make()
+
+ def install(self, spec, prefix):
+ make('install')
+
+Again, there is a ``boostrap_args`` function that determines the
+correct bootstrap flags to use.
+
+^^^^^^^^^^^^^^^^^^^^
+run_before/run_after
+^^^^^^^^^^^^^^^^^^^^
+
+Occasionally, you may want to run extra steps either before or after
+a given phase. This applies not just to custom build systems, but to
+existing build systems as well. You may need to patch a file that is
+generated by configure, or install extra files in addition to what
+``make install`` copies to the installation prefix. This is where
+``@run_before`` and ``@run_after`` come in.
+
+These Python decorators allow you to write functions that are called
+before or after a particular phase. For example, in ``perl``, we see:
+
+.. code-block:: python
+
+ @run_after('install')
+ def install_cpanm(self):
+ spec = self.spec
+
+ if '+cpanm' in spec:
+ with working_dir(join_path('cpanm', 'cpanm')):
+ perl = spec['perl'].command
+ perl('Makefile.PL')
+ make()
+ make('install')
+
+This extra step automatically installs ``cpanm`` in addition to the
+base Perl installation.
+
+^^^^^^^^^^^^^^^^^^^^^
+on_package_attributes
+^^^^^^^^^^^^^^^^^^^^^
+
+The ``run_before``/``run_after`` logic discussed above becomes
+particularly powerful when combined with the ``@on_package_attributes``
+decorator. This decorator allows you to conditionally run certain
+functions depending on the attributes of that package. The most
+common example is conditional testing. Many unit tests are prone to
+failure, even when there is nothing wrong with the installation.
+Unfortunately, non-portable unit tests and tests that are
+"supposed to fail" are more common than we would like. Instead of
+always running unit tests on installation, Spack lets users
+conditionally run tests with the ``--test=root`` flag.
+
+If we wanted to define a function that would conditionally run
+if and only if this flag is set, we would use the following line:
+
+.. code-block:: python
+
+ @on_package_attributes(run_tests=True)
+
+^^^^^^^
+Testing
+^^^^^^^
+
+Let's put everything together and add unit tests to our package.
+In the ``perl`` package, we can see:
+
+.. code-block:: python
+
+ @run_after('build')
+ @on_package_attributes(run_tests=True)
+ def test(self):
+ make('test')
+
+As you can guess, this runs ``make test`` *after* building the package,
+if and only if testing is requested. Again, this is not specific to
+custom build systems, it can be added to existing build systems as well.
+
+Ideally, every package in Spack will have some sort of test to ensure
+that it was built correctly. It is up to the package authors to make
+sure this happens. If you are adding a package for some software and
+the developers list commands to test the installation, please add these
+tests to your ``package.py``.
+
+.. warning::
+
+ The order of decorators matters. The following ordering:
+
+ .. code-block:: python
+
+ @run_after('install')
+ @on_package_attributes(run_tests=True)
+
+ works as expected. However, if you reverse the ordering:
+
+ .. code-block:: python
+
+ @on_package_attributes(run_tests=True)
+ @run_after('install')
+
+ the tests will always be run regardless of whether or not
+ ``--test=root`` is requested. See https://github.com/spack/spack/issues/3833
+ for more information
diff --git a/lib/spack/docs/build_systems/intelpackage.rst b/lib/spack/docs/build_systems/intelpackage.rst
new file mode 100644
index 0000000000..6a1be0519b
--- /dev/null
+++ b/lib/spack/docs/build_systems/intelpackage.rst
@@ -0,0 +1,1060 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _intelpackage:
+
+------------
+IntelPackage
+------------
+
+.. contents::
+
+^^^^^^^^^^^^^^^^^^^^^^^^
+Intel packages in Spack
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Spack can install and use several software development products offered by Intel.
+Some of these are available under no-cost terms, others require a paid license.
+All share the same basic steps for configuration, installation, and, where
+applicable, license management. The Spack Python class ``IntelPackage`` implements
+these steps.
+
+Spack interacts with Intel tools in several routes, like it does for any
+other package:
+
+.. _`route 1`:
+
+1. Accept system-provided tools after you declare them to Spack as *external packages*.
+
+.. _`route 2`:
+
+2. Install the products for you as *internal packages* in Spack.
+
+.. _`route 3`:
+
+3. *Use* the packages, regardless of installation route, to install what we'll
+ call *client packages* for you, this being Spack's primary purpose.
+
+An auxiliary route follows from route 2, as it would for most Spack
+packages, namely:
+
+.. _`route 4`:
+
+4. Make Spack-installed Intel tools available outside of Spack for ad-hoc use,
+ typically through Spack-managed modulefiles.
+
+This document covers routes 1 through 3.
+
+
+""""""""""""""""""""""""""""""""""
+Packages under no-cost license
+""""""""""""""""""""""""""""""""""
+
+Intel's standalone performance library products, notably MKL and MPI, are
+available for use under a `simplified license
+<https://software.intel.com/en-us/license/intel-simplified-software-license>`_
+since 2017 [fn1]_. They are packaged in Spack as:
+
+* ``intel-mkl`` -- Math Kernel Library (linear algebra and FFT),
+* ``intel-mpi`` -- The Intel-MPI implementation (derived from MPICH),
+* ``intel-ipp`` -- Primitives for image-, signal-, and data-processing,
+* ``intel-daal`` -- Machine learning and data analytics.
+
+Some earlier versions of these libraries were released under a paid license.
+For these older versions, the license must be available at installation time of
+the products and during compilation of client packages.
+
+The library packages work well with the Intel compilers but do not require them
+-- those packages can just as well be used with other compilers. The Intel
+compiler invocation commands offer custom options to simplify linking Intel
+libraries (sometimes considerably), but Spack always uses fairly explicit
+linkage anyway.
+
+
+""""""""""""""""""
+Licensed packages
+""""""""""""""""""
+
+Intel's core software development products that provide compilers, analyzers,
+and optimizers do require a paid license. In Spack, they are packaged as:
+
+* ``intel-parallel-studio`` -- the entire suite of compilers and libraries,
+* ``intel`` -- a subset containing just the compilers and the Intel-MPI runtime [fn2]_.
+
+..
+ TODO: Confirm and possible change(!) the scope of MPI components (runtime
+ vs. devel) in current (and previous?) *cluster/professional/composer*
+ editions, i.e., presence in downloads, possibly subject to license
+ coverage(!); see `disussion in PR #4300
+ <https://github.com/spack/spack/pull/4300#issuecomment-305582898>`_. [NB:
+ An "mpi" subdirectory is not indicative of the full MPI SDK being present
+ (i.e., ``mpicc``, ..., and header files). The directory may just as well
+ contain only the MPI runtime (``mpirun`` and shared libraries) .]
+ See also issue #8632.
+
+The license is needed at installation time and to compile client packages, but
+never to merely run any resulting binaries. The license status for a given
+Spack package is normally specified in the *package code* through directives like
+`license_required` (see :ref:`Licensed software <license>`).
+For the Intel packages, however, the *class code* provides these directives (in
+exchange of forfeiting a measure of OOP purity) and takes care of idiosyncasies
+like historic version dependence.
+
+The libraries that are provided in the standalone packages are also included in the
+all-encompassing ``intel-parallel-studio``. To complicate matters a bit, that
+package is sold in 3 "editions", of which only the upper-tier ``cluster``
+edition supports *compiling* MPI applications, and hence only that edition can
+provide the ``mpi`` virtual package. (As mentioned [fn2]_, all editions
+provide support for *running* MPI applications.)
+
+The edition forms the leading part of the version number for Spack's
+``intel*`` packages discussed here. This differs from the primarily numeric
+version numbers seen with most other Spack packages. For example, we have:
+
+
+.. code-block:: console
+
+ $ spack info intel-parallel-studio
+ ...
+ Preferred version:
+ professional.2018.3 http:...
+
+ Safe versions:
+ professional.2018.3 http:...
+ ...
+ composer.2018.3 http:...
+ ...
+ cluster.2018.3 http:...
+ ...
+ ...
+
+The full studio suite, capable of compiling MPI applications, currently
+requires about 12 GB of disk space when installed (see section `Install steps
+for packages with compilers and libraries`_ for detailed instructions).
+If you need to save disk space or installation time, you could install the
+``intel`` compilers-only subset (0.6 GB) and just the library packages you
+need, for example ``intel-mpi`` (0.5 GB) and ``intel-mkl`` (2.5 GB).
+
+
+""""""""""""""""""""
+Unrelated packages
+""""""""""""""""""""
+
+The following packages do not use the Intel installer and are not in class ``IntelPackage``
+that is discussed here:
+
+* ``intel-gpu-tools`` -- Test suite and low-level tools for the Linux `Direct
+ Rendering Manager <https://en.wikipedia.org/wiki/Direct_Rendering_Manager>`_
+* ``intel-mkl-dnn`` -- Math Kernel Library for Deep Neural Networks (``CMakePackage``)
+* ``intel-xed`` -- X86 machine instructions encoder/decoder
+* ``intel-tbb`` -- Standalone version of Intel Threading Building Blocks. Note that
+ a TBB runtime version is included with ``intel-mkl``, and development
+ versions are provided by the packages ``intel-parallel-studio`` (all
+ editions) and its ``intel`` subset.
+
+""""""""""""""""""""""""""""""""""""""""""
+Configuring Spack to use Intel licenses
+""""""""""""""""""""""""""""""""""""""""""
+
+If you wish to integrate licensed Intel products into Spack as external packages
+(`route 1`_ above) we assume that their license configuration is in place and
+is working [fn3]_. In this case, skip to section `Integration of Intel tools
+installed external to Spack`_.
+
+If you plan to have Spack install licensed products for you (`route 2`_ above),
+the Intel product installer that Spack will run underneath must have access to
+a license that is either provided by a *license server* or as a *license file*.
+The installer may be able to locate a license that is already configured on
+your system. If it cannot, you must configure Spack to provide either the
+server location or the license file.
+
+For authoritative information on Intel licensing, see:
+
+* https://software.intel.com/en-us/faq/licensing
+* https://software.intel.com/en-us/articles/how-do-i-manage-my-licenses
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Pointing to an existing license server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Installing and configuring a license server is outside the scope of Spack. We
+assume that:
+
+* Your system administrator has a license server running.
+* The license server offers valid licenses for the Intel packages of interest.
+* You can access these licenses under the user id running Spack.
+
+Be aware of the difference between (a) installing and configuring a license
+server, and (b) configuring client software to *use* a server's
+so-called floating licenses. We are concerned here with (b) only. The
+process of obtaining a license from a server for temporary use is called
+"checking out a license". For that, a client application such as the Intel
+package installer or a compiler needs to know the host name and port number of
+one or more license servers that it may query [fn4]_.
+
+Follow one of three methods to `point client software to a floating license server
+<https://software.intel.com/en-us/articles/licensing-setting-up-the-client-floating-license>`_.
+Ideally, your license administrator will already have implemented one that can
+be used unchanged in Spack: Look for the environment variable
+``INTEL_LICENSE_FILE`` or for files
+``/opt/intel/licenses/*.lic`` that contain::
+
+ SERVER hostname hostid_or_ANY portnum
+ USE_SERVER
+
+The relevant tokens, among possibly others, are the ``USE_SERVER`` line,
+intended specifically for clients, and one or more ``SERVER`` lines above it
+which give the network address.
+
+If you cannot find pre-existing ``/opt/intel/licenses/*.lic`` files and the
+``INTEL_LICENSE_FILE`` environment variable is not set (even after you loaded
+any relevant modulefiles), ask your license administrator for the server
+address(es) and place them in a "global" license file within your Spack
+directory tree `as shown below <Spack-managed file_>`_).
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Installing a standalone license file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you purchased a user-specific license, follow `Intel's instructions
+<https://software.intel.com/en-us/faq/licensing#license-management>`_
+to "activate" it for your serial number, then download the resulting license file.
+If needed, `request to have the file re-sent
+<https://software.intel.com/en-us/articles/resend-license-file>`_ to you.
+
+Intel's license files are text files that contain tokens in the proprietary
+"FLEXlm" format and whose name ends in ``.lic``.
+Intel installers and compilers look for license files in several locations when they run.
+Place your license by one of the following means, in order of decreasing preference:
+
+* Default directory
+
+ Install your license file in the directory ``/opt/intel/licenses/`` if you
+ have write permission to it. This directory is inspected by all Intel tools
+ and is therefore preferred, as no further configuration will be needed.
+ Create the directory if it does not yet exist. For the file name, either
+ keep the downloaded name or use another suitably plain yet descriptive
+ name that ends in ``.lic``. Adjust file permissions for access by licensed
+ users.
+
+
+* Directory given in environment variable
+
+ If you cannot use the default directory, but your system already has set the
+ environment variable ``INTEL_LICENSE_FILE`` independent from Spack [fn5]_,
+ then, if you have the necessary write permissions, place your license file in
+ one of the directories mentioned in this environment variable. Adjust file
+ permissions to match licensed users.
+
+ .. tip::
+
+ If your system has not yet set and used the environment variable
+ ``INTEL_LICENSE_FILE``, you could start using it with the ``spack
+ install`` stage of licensed tools and subsequent client packages. You
+ would, however, be in a bind to always set that variable in the same
+ manner, across updates and re-installations, and perhaps accommodate
+ additions to it. As this may be difficult in the long run, we recommend
+ that you do *not* attempt to start using the variable solely for Spack.
+
+.. _`Spack-managed file`:
+
+* Spack-managed file
+
+ The first time Spack encounters an Intel package that requires a license, it
+ will initialize a Spack-global Intel-specific license file for you, as a
+ template with instructional comments, and bring up an editor [fn6]_. Spack
+ will do this *even if you have a working license elsewhere* on the system.
+
+ * To proceed with an externally configured license, leave the newly templated
+ file as is (containing comments only) and close the editor. You do not need
+ to touch the file again.
+
+ * To configure your own standalone license, copy the contents of your
+ downloaded license file into the opened file, save it, and close the editor.
+
+ * To use a license server (i.e., a floating network license) that is not
+ already configured elsewhere on the system, supply your license server
+ address(es) in the form of ``SERVER`` and ``USE_SERVER`` lines at the
+ *beginning of the file* [fn7]_, in the format shown in section `Pointing to
+ an existing license server`_. Save the file and close the editor.
+
+ To revisit and manually edit this file, such as prior to a subsequent
+ installation attempt, find it at
+ ``$SPACK_ROOT/etc/spack/licenses/intel/intel.lic`` .
+
+ Spack will place symbolic links to this file in each directory where licensed
+ Intel binaries were installed. If you kept the template unchanged, Intel tools
+ will simply ignore it.
+
+
+.. _integrate-external-intel:
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Integration of Intel tools installed *external* to Spack
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section discusses `route 1`_ from the introduction.
+
+A site that already uses Intel tools, especially licensed ones, will likely
+have some versions already installed on the system, especially at a time when
+Spack is just being introduced. It will be useful to make such previously
+installed tools available for use by Spack as they are. How to do this varies
+depending on the type of the tools:
+
+""""""""""""""""""""""""""""""""""
+Integrating external compilers
+""""""""""""""""""""""""""""""""""
+
+For Spack to use external Intel compilers, you must tell it both *where* to
+find them and *when* to use them. The present section documents the "where"
+aspect, involving ``compilers.yaml`` and, in most cases, long absolute paths.
+The "when" aspect actually relates to `route 3`_ and requires explicitly
+stating the compiler as a spec component (in the form ``foo %intel`` or ``foo
+%intel@compilerversion``) when installing client packages or altering Spack's
+compiler default in ``packages.yaml``.
+See section `Selecting Intel compilers <Selecting Intel compilers_>`_ for details.
+
+To integrate a new set of externally installed Intel compilers into Spack
+follow section
+:ref:`Compiler configuration <compiler-config>`.
+Briefly, prepare your shell environment like you would if you were to use these
+compilers normally, i.e., typically by a ``module load ...`` or a shell
+``source ...`` command, then use ``spack compiler find`` to make Spack aware of
+these compilers. This will create a new entry in a suitably scoped and possibly new
+``compilers.yaml`` file. You could certainly create such a compiler entry
+manually, but this is error-prone due to the indentation and different data
+types involved.
+
+The Intel compilers need and use the system's native GCC compiler (``gcc`` on
+most systems, ``clang`` on macOS) to provide certain functionality, notably to
+support C++. To provide a different GCC compiler for the Intel tools, or more
+generally set persistent flags for all invocations of the Intel compilers, locate
+the ``compilers.yaml`` entry that defines your Intel compiler, and, using a
+text editor, change one or both of the following:
+
+1. At the ``modules:`` tag, add a ``gcc`` module to the list.
+2. At the ``flags:`` tag, add ``cflags:``, ``cxxflags:``, and ``fflags:`` key-value entries.
+
+Consult the examples under
+:ref:`Compiler configuration <compiler-config>`
+and
+:ref:`Vendor-Specific Compiler Configuration <vendor-specific-compiler-configuration>`
+in the Spack documentation.
+When done, validate your compiler definition by running
+``spack compiler info intel@compilerversion`` (replacing ``compilerversion`` by
+the version that you defined).
+
+Be aware that both the GCC integration and persistent compiler flags can also be
+affected by an advanced third method:
+
+3. A modulefile that provides the Intel compilers for you
+ could, for the benefit of users outside of Spack, implicitly
+ integrate a specific ``gcc`` version via compiler flag environment variables
+ or (hopefully not) via a sneaky extra ``PATH`` addition.
+
+Next, visit section `Selecting Intel Compilers`_ to learn how to tell
+Spack to use the newly configured compilers.
+
+""""""""""""""""""""""""""""""""""
+Integrating external libraries
+""""""""""""""""""""""""""""""""""
+
+Configure external library-type packages (as opposed to compilers)
+in the files ``$SPACK_ROOT/etc/spack/packages.yaml`` or
+``~/.spack/packages.yaml``, following the Spack documentation under
+:ref:`External Packages <sec-external-packages>`.
+
+Similar to ``compilers.yaml``, the ``packages.yaml`` files define a package
+external to Spack in terms of a Spack spec and resolve each such spec via
+either the ``paths`` or ``modules`` tokens to a specific pre-installed package
+version on the system. Since Intel tools generally need environment variables
+to interoperate, which cannot be conveyed in a mere ``paths`` specification,
+the ``modules`` token will be more sensible to use. It resolves the Spack-side
+spec to a modulefile generated and managed outside of Spack's purview,
+which Spack will load internally and transiently when the corresponding spec is
+called upon to compile client packages.
+
+Unlike for compilers, where ``spack find compilers [spec]`` generates an entry
+in an existing or new ``compilers.yaml`` file, Spack does not offer a command
+to generate an entirely new ``packages.yaml`` entry. You must create
+new entries yourself in a text editor, though the command ``spack config
+[--scope=...] edit packages`` can help with selecting the proper file.
+See section
+:ref:`Configuration Scopes <configuration-scopes>`
+for an explanation about the different files
+and section
+:ref:`Build customization <build-settings>`
+for specifics and examples for ``packages.yaml`` files.
+
+.. If your system administrator did not provide modules for pre-installed Intel
+ tools, you could do well to ask for them, because installing multiple copies
+ of the Intel tools, as is wont to happen once Spack is in the picture, is
+ bound to stretch disk space and patience thin. If you *are* the system
+ administrator and are still new to modules, then perhaps it's best to follow
+ the `next section <Installing Intel tools within Spack_>`_ and install the tools
+ solely within Spack.
+
+The following example integrates packages embodied by hypothetical
+external modulefiles ``intel-mkl/18/...`` into
+Spack as packages ``intel-mkl@...``:
+
+.. code-block:: console
+
+ $ spack config edit packages
+
+Make sure the file begins with:
+
+.. code-block:: yaml
+
+ packages:
+
+Adapt the following example. Be sure to maintain the indentation:
+
+.. code-block:: yaml
+
+ # other content ...
+
+ intel-mkl:
+ modules:
+ intel-mkl@2018.2.199 arch=linux-centos6-x86_64: intel-mkl/18/18.0.2
+ intel-mkl@2018.3.222 arch=linux-centos6-x86_64: intel-mkl/18/18.0.3
+
+The version numbers for the ``intel-mkl`` specs defined here correspond to file
+and directory names that Intel uses for its products because they were adopted
+and declared as such within Spack's package repository. You can inspect the
+versions known to your current Spack installation by:
+
+.. code-block:: console
+
+ $ spack info intel-mkl
+
+Using the same version numbers for external packages as for packages known
+internally is useful for clarity, but not strictly necessary. Moreover, with a
+``packages.yaml`` entry, you can go beyond internally known versions.
+
+.. _compiler-neutral-package:
+
+Note that the Spack spec in the example does not contain a compiler
+specification. This is intentional, as the Intel library packages can be used
+unmodified with different compilers.
+
+A slightly more advanced example illustrates how to provide
+:ref:`variants <basic-variants>`
+and how to use the ``buildable: False`` directive to prevent Spack from installing
+other versions or variants of the named package through its normal internal
+mechanism.
+
+.. code-block:: yaml
+
+ packages:
+ intel-parallel-studio:
+ modules:
+ intel-parallel-studio@cluster.2018.2.199 +mkl+mpi+ipp+tbb+daal arch=linux-centos6-x86_64: intel/18/18.0.2
+ intel-parallel-studio@cluster.2018.3.222 +mkl+mpi+ipp+tbb+daal arch=linux-centos6-x86_64: intel/18/18.0.3
+ buildable: False
+
+One additional example illustrates the use of ``paths:`` instead of
+``modules:``, useful when external modulefiles are not available or not
+suitable:
+
+.. code-block:: yaml
+
+ packages:
+ intel-parallel-studio:
+ paths:
+ intel-parallel-studio@cluster.2018.2.199 +mkl+mpi+ipp+tbb+daal: /opt/intel
+ intel-parallel-studio@cluster.2018.3.222 +mkl+mpi+ipp+tbb+daal: /opt/intel
+ buildable: False
+
+Note that for the Intel packages discussed here, the directory values in the
+``paths:`` entries must be the high-level and typically version-less
+"installation directory" that has been used by Intel's product installer.
+Such a directory will typically accumulate various product versions. Amongst
+them, Spack will select the correct version-specific product directory based on
+the ``@version`` spec component that each path is being defined for.
+
+For further background and details, see
+:ref:`External Packages <sec-external-packages>`.
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Installing Intel tools *within* Spack
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section discusses `route 2`_ from the introduction.
+
+When a system does not yet have Intel tools installed already, or the installed
+versions are undesirable, Spack can install these tools like any regular Spack
+package for you and, with appropriate pre- and post-install configuration, use its
+compilers and/or libraries to install client packages.
+
+.. _intel-install-studio:
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Install steps for packages with compilers and libraries
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+The packages ``intel-parallel-studio`` and ``intel`` (which is a subset of the
+former) are many-in-one products that contain both compilers and a set of
+library packages whose scope depends on the edition.
+Because they are general products geared towards shell environments,
+it can be somewhat involved to integrate these packages at their full extent
+into Spack.
+
+Note: To install library-only packages like ``intel-mkl``, ``intel-mpi``, and ``intel-daal``
+follow `the next section <intel-install-libs_>`_ instead.
+
+1. Review the section `Configuring spack to use intel licenses`_.
+
+.. _intel-compiler-anticipation:
+
+2. To install a version of ``intel-parallel-studio`` that provides Intel
+ compilers at a version that you have *not yet declared in Spack*,
+ the following preparatory steps are recommended:
+
+ A. Determine the compiler spec that the new ``intel-parallel-studio`` package
+ will provide, as follows: From the package version, combine the last two
+ digits of the version year, a literal "0" (zero), and the version component
+ that immediately follows the year.
+
+ ========================================== ======================
+ Package version Compiler spec provided
+ ------------------------------------------ ----------------------
+ ``intel-parallel-studio@edition.YYyy.u`` ``intel@yy.0.u``
+ ========================================== ======================
+
+ Example: The package ``intel-parallel-studio@cluster.2018.3`` will provide
+ the compiler with spec ``intel@18.0.3``.
+
+ .. _`config-compiler-anticipated`:
+
+ B. Add a new compiler section with the newly anticipated version at the
+ end of a ``compilers.yaml`` file in a suitable scope. For example, run:
+
+ .. code-block:: console
+
+ $ spack config --scope=user/linux edit compilers
+
+ and append a stub entry:
+
+ .. code-block:: yaml
+
+ - compiler:
+ target: x86_64
+ operating_system: centos6
+ modules: []
+ spec: intel@18.0.3
+ paths:
+ cc: stub
+ cxx: stub
+ f77: stub
+ fc: stub
+
+ Replace ``18.0.3`` with the version that you determined in the preceeding
+ step. The contents under ``paths:`` do not matter yet.
+
+ You are right to ask: "Why on earth is that necessary?" [fn8]_.
+ The answer lies in Spack striving for strict compiler consistency.
+ Consider what happens without such a pre-declared compiler stub:
+ Say, you ask Spack to install a particular version
+ ``intel-parallel-studio@edition.V``. Spack will apply an unrelated compiler
+ spec to concretize and install your request, resulting in
+ ``intel-parallel-studio@edition.V %X``. That compiler ``%X`` is not going to
+ be the version that this new package itself provides. Rather, it would
+ typically be ``%gcc@...`` in a default Spack installation or possibly indeed
+ ``%intel@...``, but at a version that precedes ``V``.
+
+ The problem comes to the fore as soon as you try to use any virtual ``mkl``
+ or ``mpi`` packages that you would expect to now be provided by
+ ``intel-parallel-studio@edition.V``. Spack will indeed see those virtual
+ packages, but only as being tied to the compiler that the package
+ ``intel-parallel-studio@edition.V`` was concretized with *at installation*.
+ If you were to install a client package with the new compilers now available
+ to you, you would naturally run ``spack install foo +mkl %intel@V``, yet
+ Spack will either complain about ``mkl%intel@V`` being missing (because it
+ only knows about ``mkl%X``) or it will go and attempt to install *another
+ instance* of ``intel-parallel-studio@edition.V %intel@V`` so as to match the
+ compiler spec ``%intel@V`` that you gave for your client package ``foo``.
+ This will be unexpected and will quickly get annoying because each
+ reinstallation takes up time and extra disk space.
+
+ To escape this trap, put the compiler stub declaration shown here in place,
+ then use that pre-declared compiler spec to install the actual package, as
+ shown next. This approach works because during installation only the
+ package's own self-sufficient installer will be used, not any compiler.
+
+ .. _`verify-compiler-anticipated`:
+
+3. Verify that the compiler version provided by the new ``studio`` version
+ would be used as expected if you were to compile a client package:
+
+ .. code-block:: console
+
+ $ spack spec zlib %intel
+
+ If the version does not match, explicitly state the anticipated compiler version, e.g.:
+
+ .. code-block:: console
+
+ $ spack spec zlib %intel@18.0.3
+
+ if there are problems, review and correct the compiler's ``compilers.yaml``
+ entry, be it still in stub form or already complete (as it would be for a
+ re-installation).
+
+4. Install the new ``studio`` package using Spack's regular ``install``
+ command.
+ It may be wise to provide the anticipated compiler (`see above
+ <verify-compiler-anticipated_>`_) as an explicit concretization
+ element:
+
+ .. code-block:: console
+
+ $ spack install intel-parallel-studio@cluster.2018.3 %intel@18.0.3
+
+5. Follow the same steps as under `Integrating external compilers`_ to tell
+ Spack the minutiae for actually using those compilers with client packages.
+ If you placed a stub entry in a ``compilers.yaml`` file, now is the time to
+ edit it and fill in the particulars.
+
+ * Under ``paths:``, give the full paths to the actual compiler binaries (``icc``,
+ ``ifort``, etc.) located within the Spack installation tree, in all their
+ unsightly length [fn9]_.
+
+ To determine the full path to the C compiler, adapt and run:
+
+ .. code-block:: console
+
+ $ find `spack location -i intel-parallel-studio@cluster.2018.3` \
+ -name icc -type f -ls
+
+ If you get hits for both ``intel64`` and ``ia32``, you almost certainly will
+ want to use the ``intel64`` variant. The ``icpc`` and ``ifort`` compilers
+ will be located in the same directory as ``icc``.
+
+ * Use the ``modules:`` and/or ``cflags:`` tokens to specify a suitable accompanying
+ ``gcc`` version to help pacify picky client packages that ask for C++
+ standards more recent than supported by your system-provided ``gcc`` and its
+ ``libstdc++.so``.
+
+ * To set the Intel compilers for default use in Spack, instead of the usual ``%gcc``,
+ follow section `Selecting Intel compilers`_.
+
+.. tip::
+
+ Compiler packages like ``intel-parallel-studio`` can easily be above 10 GB
+ in size, which can tax the disk space available for temporary files on
+ small, busy, or restricted systems (like virtual machines). The Intel
+ installer will stop and report insufficient space as::
+
+ ==> './install.sh' '--silent' 'silent.cfg'
+ ...
+ Missing critical prerequisite
+ -- Not enough disk space
+
+ As first remedy, clean Spack's existing staging area:
+
+ .. code-block:: console
+
+ $ spack clean --stage
+
+ then retry installing the large package. Spack normally cleans staging
+ directories but certain failures may prevent it from doing so.
+
+ If the error persists, tell Spack to use an alternative location for
+ temporary files:
+
+ 1. Run ``df -h`` to identify an alternative location on your system.
+
+ 2. Tell Spack to use that location for staging. Do **one** of the following:
+
+ * Run Spack with the environment variable ``TMPDIR`` altered for just a
+ single command. For example, to use your ``$HOME`` directory:
+
+ .. code-block:: console
+
+ $ TMPDIR="$HOME/spack-stage" spack install ....
+
+ This example uses Bourne shell syntax. Adapt for other shells as needed.
+
+ * Alternatively, customize
+ Spack's ``build_stage`` :ref:`configuration setting <config-overrides>`.
+
+ .. code-block:: console
+
+ $ spack config edit config
+
+ Append:
+
+ .. code-block:: yaml
+
+ config:
+ build_stage:
+ - /home/$user/spack-stage
+
+ Do not duplicate the ``config:`` line if it already is present.
+ Adapt the location, which here is the same as in the preceeding example.
+
+ 3. Retry installing the large package.
+
+
+.. _intel-install-libs:
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Install steps for library-only packages
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+To install library-only packages like ``intel-mkl``, ``intel-mpi``, and ``intel-daal``
+follow the steps given here.
+For packages that contain a compiler, follow `the previous section
+<intel-install-studio_>`_ instead.
+
+1. For pre-2017 product releases, review the section `Configuring Spack to use Intel licenses`_.
+
+2. Inspect the package spec. Specify an explicit compiler if necessary, e.g.:
+
+ .. code-block:: console
+
+ $ spack spec intel-mpi@2018.3.199
+ $ spack spec intel-mpi@2018.3.199 %intel
+
+ Check that the package will use the compiler flavor and version that you expect.
+
+3. Install the package normally within Spack. Use the same spec as in the
+ previous command, i.e., as general or as specific as needed:
+
+ .. code-block:: console
+
+ $ spack install intel-mpi@2018.3.199
+ $ spack install intel-mpi@2018.3.199 %intel@18
+
+4. To prepare the new packages for use with client packages,
+ follow `Selecting libraries to satisfy virtual packages`_.
+
+
+""""""""""""""""
+Debug notes
+""""""""""""""""
+
+* You can trigger a wall of additional diagnostics using Spack options, e.g.:
+
+ .. code-block:: console
+
+ $ spack --debug -v install intel-mpi
+
+ The ``--debug`` option can also be useful while installing client
+ packages `(see below) <Using Intel tools in Spack to install client
+ packages_>`_ to confirm the integration of the Intel tools in Spack, notably
+ MKL and MPI.
+
+* The ``.spack/`` subdirectory of an installed ``IntelPackage`` will contain,
+ besides Spack's usual archival items, a copy of the ``silent.cfg`` file that
+ was passed to the Intel installer:
+
+ .. code-block:: console
+
+ $ grep COMPONENTS ...intel-mpi...<hash>/.spack/silent.cfg
+ COMPONENTS=ALL
+
+* If an installation error occurs, Spack will normally clean up and remove a
+ partially installed target directory. You can direct Spack to keep it using
+ ``--keep-prefix``, e.g.:
+
+ .. code-block:: console
+
+ $ spack install --keep-prefix intel-mpi
+
+ You must, however, *remove such partial installations* prior to subsequent
+ installation attempts. Otherwise, the Intel installer will behave
+ incorrectly.
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Using Intel tools in Spack to install client packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Finally, this section pertains to `route 3`_ from the introduction.
+
+Once Intel tools are installed within Spack as external or internal packages
+they can be used as intended for installing client packages.
+
+
+.. _`select-intel-compilers`:
+
+""""""""""""""""""""""""""
+Selecting Intel compilers
+""""""""""""""""""""""""""
+
+Select Intel compilers to compile client packages, like any compiler in Spack,
+by one of the following means:
+
+* Request the Intel compilers explicitly in the client spec, e.g.:
+
+ .. code-block:: console
+
+ $ spack install libxc@3.0.0%intel
+
+
+* Alternatively, request Intel compilers implicitly by concretization preferences.
+ Configure the order of compilers in the appropriate ``packages.yaml`` file,
+ under either an ``all:`` or client-package-specific entry, in a
+ ``compiler:`` list. Consult the Spack documentation for
+ :ref:`Configuring Package Preferences <configs-tutorial-package-prefs>`
+ and
+ :ref:`Concretization Preferences <concretization-preferences>`.
+
+Example: ``etc/spack/packages.yaml`` might simply contain:
+
+.. code-block:: yaml
+
+ packages:
+ all:
+ compiler: [ intel, gcc, ]
+
+To be more specific, you can state partial or full compiler version numbers,
+for example:
+
+.. code-block:: yaml
+
+ packages:
+ all:
+ compiler: [ intel@18, intel@17, gcc@4.4.7, gcc@4.9.3, gcc@7.3.0, ]
+
+
+
+""""""""""""""""""""""""""""""""""""""""""""""""
+Selecting libraries to satisfy virtual packages
+""""""""""""""""""""""""""""""""""""""""""""""""
+
+Intel packages, whether integrated into Spack as external packages or
+installed within Spack, can be called upon to satisfy the requirement of a
+client package for a library that is available from different providers.
+The relevant virtual packages for Intel are ``blas``, ``lapack``,
+``scalapack``, and ``mpi``.
+
+In both integration routes, Intel packages can have optional
+:ref:`variants <basic-variants>`
+which alter the list of virtual packages they can satisfy. For Spack-external
+packages, the active variants are a combination of the defaults declared in
+Spack's package repository and the spec it is declared as in ``packages.yaml``.
+Needless to say, those should match the components that are actually present in
+the external product installation. Likewise, for Spack-internal packages, the
+active variants are determined, persistently at installation time, from the
+defaults in the repository and the spec selected to be installed.
+
+To have Intel packages satisfy virtual package requests for all or selected
+client packages, edit the ``packages.yaml`` file. Customize, either in the
+``all:`` or a more specific entry, a ``providers:`` dictionary whose keys are
+the virtual packages and whose values are the Spack specs that satisfy the
+virtual package, in order of decreasing preference. To learn more about the
+``providers:`` settings, see the Spack tutorial for
+:ref:`Configuring Package Preferences <configs-tutorial-package-prefs>`
+and the section
+:ref:`Concretization Preferences <concretization-preferences>`.
+
+Example: The following fairly minimal example for ``packages.yaml`` shows how
+to exclusively use the standalone ``intel-mkl`` package for all the linear
+algebra virtual packages in Spack, and ``intel-mpi`` as the preferred MPI
+implementation. Other providers can still be chosen on a per-package basis.
+
+.. code-block:: yaml
+
+ packages:
+ all:
+ providers:
+ mpi: [intel-mpi]
+ blas: [intel-mkl]
+ lapack: [intel-mkl]
+ scalapack: [intel-mkl]
+
+If you have access to the ``intel-parallel-studio@cluster`` edition, you can
+use instead:
+
+.. code-block:: yaml
+
+ all:
+ providers:
+ mpi: [intel-parallel-studio+mpi]
+ # Note: +mpi vs. +mkl
+ blas: [intel-parallel-studio+mkl]
+ lapack: [intel-parallel-studio+mkl]
+ scalapack: [intel-parallel-studio+mkl]
+
+If you installed ``intel-parallel-studio`` within Spack ("`route 2`_"), make
+sure you followed the `special installation step
+<intel-compiler-anticipation_>`_ to ensure that its virtual packages match the
+compilers it provides.
+
+
+""""""""""""""""""""""""""""""""""""""""""""
+Using Intel tools as explicit dependency
+""""""""""""""""""""""""""""""""""""""""""""
+
+With the proper installation as detailed above, no special steps should be
+required when a client package specifically (and thus deliberately) requests an
+Intel package as dependency, this being one of the target use cases for Spack.
+
+
+"""""""""""""""""""""""""""""""""""""""""""""""
+Tips for configuring client packages to use MKL
+"""""""""""""""""""""""""""""""""""""""""""""""
+
+The Math Kernel Library (MKL) is provided by several Intel packages, currently
+``intel-parallel-studio`` when variant ``+mkl`` is active (it is by default)
+and the standalone ``intel-mkl``. Because of these different provider packages,
+a *virtual* ``mkl`` package is declared in Spack.
+
+* To use MKL-specific APIs in a client package:
+
+ Declare a dependency on ``mkl``, rather than a specific provider like
+ ``intel-mkl``. Declare the dependency either absolutely or conditionally
+ based on variants that your package might have declared:
+
+ .. code-block:: python
+
+ # Examples for absolute and conditional dependencies:
+ depends_on('mkl')
+ depends_on('mkl', when='+mkl')
+ depends_on('mkl', when='fftw=mkl')
+
+ The ``MKLROOT`` environment variable (part of the documented API) will be set
+ during all stages of client package installation, and is available to both
+ the Spack packaging code and the client code.
+
+* To use MKL as provider for BLAS, LAPACK, or ScaLAPACK:
+
+ The packages that provide ``mkl`` also provide the narrower
+ virtual ``blas``, ``lapack``, and ``scalapack`` packages.
+ See the relevant :ref:`Packaging Guide section <blas_lapack_scalapack>`
+ for an introduction.
+ To portably use these virtual packages, construct preprocessor and linker
+ option strings in your package configuration code using the package functions
+ ``.headers`` and ``.libs`` in conjunction with utility functions from the
+ following classes:
+
+ * :py:class:`llnl.util.filesystem.FileList`,
+ * :py:class:`llnl.util.filesystem.HeaderList`,
+ * :py:class:`llnl.util.filesystem.LibraryList`.
+
+ .. tip::
+ *Do not* use constructs like ``.prefix.include`` or ``.prefix.lib``, with
+ Intel or any other implementation of ``blas``, ``lapack``, and
+ ``scalapack``.
+
+ For example, for an
+ :ref:`AutotoolsPackage <autotoolspackage>`
+ use ``.libs.ld_flags`` to transform the library file list into linker options
+ passed to ``./configure``:
+
+ .. code-block:: python
+
+ def configure_args(self):
+ args = []
+ ...
+ args.append('--with-blas=%s' % self.spec['blas'].libs.ld_flags)
+ args.append('--with-lapack=%s' % self.spec['lapack'].libs.ld_flags)
+ ...
+
+ .. tip::
+ Even though ``.ld_flags`` will return a string of multiple words, *do not*
+ use quotes for options like ``--with-blas=...`` because Spack passes them
+ to ``./configure`` without invoking a shell.
+
+ Likewise, in a
+ :ref:`MakefilePackage <makefilepackage>`
+ or similiar package that does not use AutoTools you may need to provide include
+ and link options for use on command lines or in environment variables.
+ For example, to generate an option string of the form ``-I<dir>``, use:
+
+ .. code-block:: python
+
+ self.spec['blas'].headers.include_flags
+
+ and to generate linker options (``-L<dir> -llibname ...``), use the same as above,
+
+ .. code-block:: python
+
+ self.spec['blas'].libs.ld_flags
+
+ See
+ :ref:`MakefilePackage <makefilepackage>`
+ and more generally the
+ :ref:`Packaging Guide <blas_lapack_scalapack>`
+ for background and further examples.
+
+
+^^^^^^^^^^
+Footnotes
+^^^^^^^^^^
+
+.. [fn1] Strictly speaking, versions from ``2017.2`` onward.
+
+.. [fn2] The package ``intel`` intentionally does not have a ``+mpi`` variant since
+ it is meant to be small. The native installer will always add MPI *runtime*
+ components because it follows defaults defined in the download package, even
+ when ``intel-parallel-studio ~mpi`` has been requested.
+
+ For ``intel-parallel-studio +mpi``, the class function
+ :py:func:``.IntelPackage.pset_components``
+ will include ``"intel-mpi intel-imb"`` in a list of component patterns passed
+ to the Intel installer. The installer will extend each pattern word with an
+ implied glob-like ``*`` to resolve it to package names that are
+ *actually present in the product BOM*.
+ As a side effect, this pattern approach accommodates occasional package name
+ changes, e.g., capturing both ``intel-mpirt`` and ``intel-mpi-rt`` .
+
+.. [fn3] How could the external installation have succeeded otherwise?
+
+.. [fn4] According to Intel's documentation, there is supposedly a way to install a
+ product using a network license even `when a FLEXlm server is not running
+ <https://software.intel.com/en-us/articles/licensing-setting-up-the-client-floating-license>`_:
+ Specify the license in the form ``port@serverhost`` in the
+ ``INTEL_LICENSE_FILE`` environment variable. All other means of specifying a
+ network license require that the license server be up.
+
+.. [fn5] Despite the name, ``INTEL_LICENSE_FILE`` can hold several and diverse entries.
+ They can be either directories (presumed to contain ``*.lic`` files), file
+ names, or network locations in the form ``port@host`` (on Linux and Mac),
+ with all items separated by ":" (on Linux and Mac).
+
+.. [fn6] Should said editor turn out to be ``vi``, you better be in a position
+ to know how to use it.
+
+.. [fn7] Comment lines in FLEXlm files, indicated by ``#`` as the first
+ non-whitespace character on the line, are generally allowed anywhere in the file.
+ There `have been reports <https://github.com/spack/spack/issues/6534>`_,
+ however, that as of 2018, ``SERVER`` and ``USE_SERVER`` lines must precede
+ any comment lines.
+
+..
+ .. [fnX] The name component ``intel`` of the compiler spec is separate from (in
+ a different namespace than) the names of the Spack packages
+ ``intel-parallel-studio`` and ``intel``. Both of the latter provide the former.
+
+.. [fn8] Spack's close coupling of installed packages to compilers, which both
+ necessitates the detour for installing ``intel-parallel-studio``, and
+ largely limits any of its provided virtual packages to a single compiler, heavily
+ favors `recommending to install Intel Parallel Studio outside of Spack
+ <integrate-external-intel_>`_ and declare it for Spack in ``packages.yaml``
+ by a `compiler-less spec <compiler-neutral-package_>`_.
+
+.. [fn9] With some effort, you can convince Spack to use shorter paths.
+
+ .. warning:: Altering the naming scheme means that Spack will lose track of
+ all packages it has installed for you so far.
+ That said, the time is right for this kind of customization
+ when you are defining a new set of compilers.
+
+ The relevant tunables are:
+
+ 1. Set the ``install_tree`` location in ``config.yaml``
+ (:ref:`see doc <config-yaml>`).
+ 2. Set the hash length in ``install-path-scheme``, also in ``config.yaml``
+ (:ref:`q.v. <config-yaml>`).
+ 3. You will want to set the *same* hash length for
+ :ref:`tcl module files <modules-naming-scheme>`
+ if you have Spack produce them for you, under ``naming_scheme`` in
+ ``modules.yaml``. Other module dialects cannot be altered in this manner.
diff --git a/lib/spack/docs/build_systems/makefilepackage.rst b/lib/spack/docs/build_systems/makefilepackage.rst
new file mode 100644
index 0000000000..dbb8686cc3
--- /dev/null
+++ b/lib/spack/docs/build_systems/makefilepackage.rst
@@ -0,0 +1,309 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _makefilepackage:
+
+---------------
+MakefilePackage
+---------------
+
+The most primitive build system a package can use is a plain Makefile.
+Makefiles are simple to write for small projects, but they usually
+require you to edit the Makefile to set platform and compiler-specific
+variables.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``MakefilePackage`` base class comes with 3 phases:
+
+#. ``edit`` - edit the Makefile
+#. ``build`` - build the project
+#. ``install`` - install the project
+
+By default, ``edit`` does nothing, but you can override it to replace
+hard-coded Makefile variables. The ``build`` and ``install`` phases
+run:
+
+.. code-block:: console
+
+ $ make
+ $ make install
+
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+The main file that matters for a ``MakefilePackage`` is the Makefile.
+This file will be named one of the following ways:
+
+* GNUmakefile (only works with GNU Make)
+* Makefile (most common)
+* makefile
+
+Some Makefiles also *include* other configuration files. Check for an
+``include`` directive in the Makefile.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Spack assumes that the operating system will have a valid ``make`` utility
+installed already, so you don't need to add a dependency on ``make``.
+However, if the package uses a ``GNUmakefile`` or the developers recommend
+using GNU Make, you should add a dependency on ``gmake``:
+
+.. code-block:: python
+
+ depends_on('gmake', type='build')
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Types of Makefile packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Most of the work involved in packaging software that uses Makefiles
+involves overriding or replacing hard-coded variables. Many packages
+make the mistake of hard-coding compilers, usually for GCC or Intel.
+This is fine if you happen to be using that particular compiler, but
+Spack is designed to work with *any* compiler, and you need to ensure
+that this is the case.
+
+Depending on how the Makefile is designed, there are 4 common strategies
+that can be used to set or override the appropriate variables:
+
+"""""""""""""""""""""
+Environment variables
+"""""""""""""""""""""
+
+Make has multiple types of
+`assignment operators <https://www.gnu.org/software/make/manual/make.html#Setting>`_.
+Some Makefiles use ``=`` to assign variables. The only way to override
+these variables is to edit the Makefile or override them on the
+command-line. However, Makefiles that use ``?=`` for assignment honor
+environment variables. Since Spack already sets ``CC``, ``CXX``, ``F77``,
+and ``FC``, you won't need to worry about setting these variables. If
+there are any other variables you need to set, you can do this in the
+``edit`` method:
+
+.. code-block:: python
+
+ def edit(self, spec, prefix):
+ env['PREFIX'] = prefix
+ env['BLASLIB'] = spec['blas'].libs.ld_flags
+
+
+`cbench <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/cbench/package.py>`_
+is a good example of a simple package that does this, while
+`esmf <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/esmf/package.py>`_
+is a good example of a more complex package.
+
+""""""""""""""""""""""
+Command-line arguments
+""""""""""""""""""""""
+
+If the Makefile ignores environment variables, the next thing to try
+is command-line arguments. You can do this by overriding the
+``build_targets`` attribute. If you don't need access to the spec,
+you can do this like so:
+
+.. code-block:: python
+
+ build_targets = ['CC=cc']
+
+
+If you do need access to the spec, you can create a property like so:
+
+.. code-block:: python
+
+ @property
+ def build_targets(self):
+ spec = self.spec
+
+ return [
+ 'CC=cc',
+ 'BLASLIB={0}'.format(spec['blas'].libs.ld_flags),
+ ]
+
+
+`cloverleaf <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/cloverleaf/package.py>`_
+is a good example of a package that uses this strategy.
+
+"""""""""""""
+Edit Makefile
+"""""""""""""
+
+Some Makefiles are just plain stubborn and will ignore command-line
+variables. The only way to ensure that these packages build correctly
+is to directly edit the Makefile. Spack provides a ``FileFilter`` class
+and a ``filter_file`` method to help with this. For example:
+
+.. code-block:: python
+
+ def edit(self, spec, prefix):
+ makefile = FileFilter('Makefile')
+
+ makefile.filter('CC = gcc', 'CC = cc')
+ makefile.filter('CXX = g++', 'CC = c++')
+
+
+`stream <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/stream/package.py>`_
+is a good example of a package that involves editing a Makefile to set
+the appropriate variables.
+
+"""""""""""
+Config file
+"""""""""""
+
+More complex packages often involve Makefiles that *include* a
+configuration file. These configuration files are primarily composed
+of variables relating to the compiler, platform, and the location of
+dependencies or names of libraries. Since these config files are
+dependent on the compiler and platform, you will often see entire
+directories of examples for common compilers and architectures. Use
+these examples to help determine what possible values to use.
+
+If the config file is long and only contains one or two variables
+that need to be modified, you can use the technique above to edit
+the config file. However, if you end up needing to modify most of
+the variables, it may be easier to write a new file from scratch.
+
+If each variable is independent of each other, a dictionary works
+well for storing variables:
+
+.. code-block:: python
+
+ def edit(self, spec, prefix):
+ config = {
+ 'CC': 'cc',
+ 'MAKE': 'make',
+ }
+
+ if '+blas' in spec:
+ config['BLAS_LIBS'] = spec['blas'].libs.joined()
+
+ with open('make.inc', 'w') as inc:
+ for key in config:
+ inc.write('{0} = {1}\n'.format(key, config[key]))
+
+
+`elk <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/elk/package.py>`_
+is a good example of a package that uses a dictionary to store
+configuration variables.
+
+If the order of variables is important, it may be easier to store
+them in a list:
+
+.. code-block:: python
+
+ def edit(self, spec, prefix):
+ config = [
+ 'INSTALL_DIR = {0}'.format(prefix),
+ 'INCLUDE_DIR = $(INSTALL_DIR)/include',
+ 'LIBRARY_DIR = $(INSTALL_DIR)/lib',
+ ]
+
+ with open('make.inc', 'w') as inc:
+ for var in config:
+ inc.write('{0}\n'.format(var))
+
+
+`hpl <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/hpl/package.py>`_
+is a good example of a package that uses a list to store
+configuration variables.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Variables to watch out for
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following is a list of common variables to watch out for. The first
+two sections are
+`implicit variables <https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html>`_
+defined by Make and will always use the same name, while the rest are
+user-defined variables and may vary from package to package.
+
+* **Compilers**
+
+ This includes variables such as ``CC``, ``CXX``, ``F77``, ``F90``,
+ and ``FC``, as well as variables related to MPI compiler wrappers,
+ like ``MPICC`` and friends.
+
+* **Compiler flags**
+
+ This includes variables for specific compilers, like ``CFLAGS``,
+ ``CXXFLAGS``, ``F77FLAGS``, ``F90FLAGS``, ``FCFLAGS``, and ``CPPFLAGS``.
+ These variables are often hard-coded to contain flags specific to a
+ certain compiler. If these flags don't work for every compiler,
+ you may want to consider filtering them.
+
+* **Variables that enable or disable features**
+
+ This includes variables like ``MPI``, ``OPENMP``, ``PIC``, and
+ ``DEBUG``. These flags often require you to create a variant
+ so that you can either build with or without MPI support, for
+ example. These flags are often compiler-dependent. You should
+ replace them with the appropriate compiler flags, such as
+ ``self.compiler.openmp_flag`` or ``self.compiler.pic_flag``.
+
+* **Platform flags**
+
+ These flags control the type of architecture that the executable
+ is compiler for. Watch out for variables like ``PLAT`` or ``ARCH``.
+
+* **Dependencies**
+
+ Look out for variables that sound like they could be used to
+ locate dependencies, such as ``JAVA_HOME``, ``JPEG_ROOT``, or
+ ``ZLIBDIR``. Also watch out for variables that control linking,
+ such as ``LIBS``, ``LDFLAGS``, and ``INCLUDES``. These variables
+ need to be set to the installation prefix of a dependency, or
+ to the correct linker flags to link to that dependency.
+
+* **Installation prefix**
+
+ If your Makefile has an ``install`` target, it needs some way of
+ knowing where to install. By default, many packages install to
+ ``/usr`` or ``/usr/local``. Since many Spack users won't have
+ sudo privileges, it is imperative that each package is installed
+ to the proper prefix. Look for variables like ``PREFIX`` or
+ ``INSTALL``.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Makefiles in a sub-directory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Not every package places their Makefile in the root of the package
+tarball. If the Makefile is in a sub-directory like ``src``, you
+can tell Spack where to locate it like so:
+
+.. code-block:: python
+
+ build_directory = 'src'
+
+
+^^^^^^^^^^^^^^^^^^^
+Manual installation
+^^^^^^^^^^^^^^^^^^^
+
+Not every Makefile includes an ``install`` target. If this is the
+case, you can override the default ``install`` method to manually
+install the package:
+
+.. code-block:: python
+
+ def install(self, spec, prefix):
+ mkdir(prefix.bin)
+ install('foo', prefix.bin)
+ install_tree('lib', prefix.lib)
+
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on reading and writing Makefiles, see:
+https://www.gnu.org/software/make/manual/make.html
diff --git a/lib/spack/docs/build_systems/mesonpackage.rst b/lib/spack/docs/build_systems/mesonpackage.rst
new file mode 100644
index 0000000000..4b30ac5df0
--- /dev/null
+++ b/lib/spack/docs/build_systems/mesonpackage.rst
@@ -0,0 +1,90 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _mesonpackage:
+
+------------
+MesonPackage
+------------
+
+Much like Autotools and CMake, Meson is a build system. But it is
+meant to be both fast and as user friendly as possible. GNOME's goal
+is to port modules to use the Meson build system.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``MesonPackage`` base class comes with the following phases:
+
+#. ``meson`` - generate ninja files
+#. ``build`` - build the project
+#. ``install`` - install the project
+
+By default, these phases run:
+
+.. code-block:: console
+
+ $ mkdir spack-build
+ $ cd spack-build
+ $ meson .. --prefix=/path/to/installation/prefix
+ $ ninja
+ $ ninja test # optional
+ $ ninja install
+
+
+Any of these phases can be overridden in your package as necessary.
+There is also a ``check`` method that looks for a ``test`` target
+in the build file. If a ``test`` target exists and the user runs:
+
+.. code-block:: console
+
+ $ spack install --test=root <meson-package>
+
+
+Spack will run ``ninja test`` after the build phase.
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+Packages that use the Meson build system can be identified by the
+presence of a ``meson.build`` file. This file declares things
+like build instructions and dependencies.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+At the bare minimum, packages that use the Meson build system need
+``meson`` and ```ninja``` dependencies. Since this is always the case,
+the ``MesonPackage`` base class already contains:
+
+.. code-block:: python
+
+ depends_on('meson', type='build')
+ depends_on('ninja', type='build')
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to meson
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you need to pass any arguments to the ``meson`` call, you can
+override the ``meson_args`` method like so:
+
+.. code-block:: python
+
+ def meson_args(self):
+ return ['--default-library=both']
+
+
+This method can be used to pass flags as well as variables.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the Meson build system, see:
+https://mesonbuild.com/index.html
diff --git a/lib/spack/docs/build_systems/octavepackage.rst b/lib/spack/docs/build_systems/octavepackage.rst
new file mode 100644
index 0000000000..f63089406c
--- /dev/null
+++ b/lib/spack/docs/build_systems/octavepackage.rst
@@ -0,0 +1,52 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _octavepackage:
+
+-------------
+OctavePackage
+-------------
+
+Octave has its own build system for installing packages.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``OctavePackage`` base class has a single phase:
+
+#. ``install`` - install the package
+
+By default, this phase runs the following command:
+
+.. code-block:: console
+
+ $ octave '--eval' 'pkg prefix <prefix>; pkg install <archive_file>'
+
+
+Beware that uninstallation is not implemented at the moment. After uninstalling
+a package via Spack, you also need to manually uninstall it from Octave via
+``pkg uninstall <package_name>``.
+
+^^^^^^^^^^^^^^^^^^^^^^^
+Finding Octave packages
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Most Octave packages are listed at https://octave.sourceforge.io/packages.php.
+
+^^^^^^^^^^^^
+Dependencies
+^^^^^^^^^^^^
+
+Usually, the homepage of a package will list dependencies, i.e.
+``Dependencies: Octave >= 3.6.0 struct >= 1.0.12``. The same information should
+be available in the ``DESCRIPTION`` file in the root of each archive.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External Documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the Octave build system, see:
+https://octave.org/doc/v4.4.0/Installing-and-Removing-Packages.html
diff --git a/lib/spack/docs/build_systems/perlpackage.rst b/lib/spack/docs/build_systems/perlpackage.rst
new file mode 100644
index 0000000000..3f36a4eb2f
--- /dev/null
+++ b/lib/spack/docs/build_systems/perlpackage.rst
@@ -0,0 +1,212 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _perlpackage:
+
+-----------
+PerlPackage
+-----------
+
+Much like Octave, Perl has its own language-specific
+build system.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``PerlPackage`` base class comes with 3 phases that can be overridden:
+
+#. ``configure`` - configure the package
+#. ``build`` - build the package
+#. ``install`` - install the package
+
+Perl packages have 2 common modules used for module installation:
+
+"""""""""""""""""""""""
+``ExtUtils::MakeMaker``
+"""""""""""""""""""""""
+
+The ``ExtUtils::MakeMaker`` module is just what it sounds like, a module
+designed to generate Makefiles. It can be identified by the presence of
+a ``Makefile.PL`` file, and has the following installation steps:
+
+.. code-block:: console
+
+ $ perl Makefile.PL INSTALL_BASE=/path/to/installation/prefix
+ $ make
+ $ make test # optional
+ $ make install
+
+
+"""""""""""""""""
+``Module::Build``
+"""""""""""""""""
+
+The ``Module::Build`` module is a pure-Perl build system, and can be
+identified by the presence of a ``Build.PL`` file. It has the following
+installation steps:
+
+.. code-block:: console
+
+ $ perl Build.PL --install_base /path/to/installation/prefix
+ $ ./Build
+ $ ./Build test # optional
+ $ ./Build install
+
+
+If both ``Makefile.PL`` and ``Build.PL`` files exist in the package,
+Spack will use ``Makefile.PL`` by default. If your package uses a
+different module, ``PerlPackage`` will need to be extended to support
+it.
+
+``PerlPackage`` automatically detects which build steps to use, so there
+shouldn't be much work on the package developer's side to get things
+working.
+
+^^^^^^^^^^^^^^^^^^^^^
+Finding Perl packages
+^^^^^^^^^^^^^^^^^^^^^
+
+Most Perl modules are hosted on CPAN - The Comprehensive Perl Archive
+Network. If you need to find a package for ``XML::Parser``, for example,
+you should search for "CPAN XML::Parser".
+
+Some CPAN pages are versioned. Check for a link to the
+"Latest Release" to make sure you have the latest version.
+
+^^^^^^^^^^^^
+Package name
+^^^^^^^^^^^^
+
+When you use ``spack create`` to create a new Perl package, Spack will
+automatically prepend ``perl-`` to the front of the package name. This
+helps to keep Perl modules separate from other packages. The same
+naming scheme is used for other language extensions, like Python and R.
+
+^^^^^^^^^^^
+Description
+^^^^^^^^^^^
+
+Most CPAN pages have a short description under "NAME" and a longer
+description under "DESCRIPTION". Use whichever you think is more
+useful while still being succinct.
+
+^^^^^^^^
+Homepage
+^^^^^^^^
+
+In the top-right corner of the CPAN page, you'll find a "permalink"
+for the package. This should be used instead of the current URL, as
+it doesn't contain the version number and will always link to the
+latest release.
+
+^^^
+URL
+^^^
+
+If you haven't found it already, the download URL is on the right
+side of the page below the permalink. Search for "Download".
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Every ``PerlPackage`` obviously depends on Perl at build and run-time,
+so ``PerlPackage`` contains:
+
+.. code-block:: python
+
+ extends('perl')
+
+ depends_on('perl', type=('build', 'run'))
+
+
+If your package requires a specific version of Perl, you should
+specify this.
+
+Although newer versions of Perl include ``ExtUtils::MakeMaker`` and
+``Module::Build`` as "core" modules, you may want to add dependencies
+on ``perl-extutils-makemaker`` and ``perl-module-build`` anyway. Many
+people add Perl as an external package, and we want the build to work
+properly. If your package uses ``Makefile.PL`` to build, add:
+
+.. code-block:: python
+
+ depends_on('perl-extutils-makemaker', type='build')
+
+
+If your package uses ``Build.PL`` to build, add:
+
+.. code-block:: python
+
+ depends_on('perl-module-build', type='build')
+
+
+^^^^^^^^^^^^^^^^^
+Perl dependencies
+^^^^^^^^^^^^^^^^^
+
+Below the download URL, you will find a "Dependencies" link, which
+takes you to a page listing all of the dependencies of the package.
+Packages listed as "Core module" don't need to be added as dependencies,
+but all direct dependencies should be added. Don't add dependencies of
+dependencies. These should be added as dependencies to the dependency,
+not to your package.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to configure
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Packages that have non-Perl dependencies often use command-line
+variables to specify their installation directory. You can pass
+arguments to ``Makefile.PL`` or ``Build.PL`` by overriding
+``configure_args`` like so:
+
+.. code-block:: python
+
+ def configure_args(self):
+ expat = self.spec['expat'].prefix
+
+ return [
+ 'EXPATLIBPATH={0}'.format(expat.lib),
+ 'EXPATINCPATH={0}'.format(expat.include),
+ ]
+
+
+^^^^^^^^^^^^^^^^^^^^^
+Alternatives to Spack
+^^^^^^^^^^^^^^^^^^^^^
+
+If you need to maintain a stack of Perl modules for a user and don't
+want to add all of them to Spack, a good alternative is ``cpanm``.
+If Perl is already installed on your system, it should come with a
+``cpan`` executable. To install ``cpanm``, run the following command:
+
+.. code-block:: console
+
+ $ cpan App::cpanminus
+
+
+Now, you can install any Perl module you want by running:
+
+.. code-block:: console
+
+ $ cpanm Module::Name
+
+
+Obviously, these commands can only be run if you have root privileges.
+Furthermore, ``cpanm`` is not capable of installing non-Perl dependencies.
+If you need to install to your home directory or need to install a module
+with non-Perl dependencies, Spack is a better option.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+You can find more information on installing Perl modules from source
+at: http://www.perlmonks.org/?node_id=128077
+
+More generic Perl module installation instructions can be found at:
+http://www.cpan.org/modules/INSTALL.html
diff --git a/lib/spack/docs/build_systems/pythonpackage.rst b/lib/spack/docs/build_systems/pythonpackage.rst
new file mode 100644
index 0000000000..61aef00c50
--- /dev/null
+++ b/lib/spack/docs/build_systems/pythonpackage.rst
@@ -0,0 +1,747 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _pythonpackage:
+
+-------------
+PythonPackage
+-------------
+
+Python packages and modules have their own special build system.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``PythonPackage`` base class provides the following phases that
+can be overridden:
+
+* ``build``
+* ``build_py``
+* ``build_ext``
+* ``build_clib``
+* ``build_scripts``
+* ``clean``
+* ``install``
+* ``install_lib``
+* ``install_headers``
+* ``install_scripts``
+* ``install_data``
+* ``sdist``
+* ``register``
+* ``bdist``
+* ``bdist_dumb``
+* ``bdist_rpm``
+* ``bdist_wininst``
+* ``upload``
+* ``check``
+
+These are all standard ``setup.py`` commands and can be found by running:
+
+.. code-block:: console
+
+ $ python setup.py --help-commands
+
+
+By default, only the ``build`` and ``install`` phases are run:
+
+#. ``build`` - build everything needed to install
+#. ``install`` - install everything from build directory
+
+If for whatever reason you need to run more phases, simply modify your
+``phases`` list like so:
+
+.. code-block:: python
+
+ phases = ['build_ext', 'install', 'bdist']
+
+
+Each phase provides a function ``<phase>`` that runs:
+
+.. code-block:: console
+
+ $ python -s setup.py --no-user-cfg <phase>
+
+
+Each phase also has a ``<phase_args>`` function that can pass arguments to
+this call. All of these functions are empty except for the ``install_args``
+function, which passes ``--prefix=/path/to/installation/prefix``. There is
+also some additional logic specific to setuptools and eggs.
+
+If you need to run a phase that is not a standard ``setup.py`` command,
+you'll need to define a function for it like so:
+
+.. code-block:: python
+
+ phases = ['configure', 'build', 'install']
+
+ def configure(self, spec, prefix):
+ self.setup_py('configure')
+
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+Python packages can be identified by the presence of a ``setup.py`` file.
+This file is used by package managers like ``pip`` to determine a
+package's dependencies and the version of dependencies required, so if
+the ``setup.py`` file is not accurate, the package will not build properly.
+For this reason, the ``setup.py`` file should be fairly reliable. If the
+documentation and ``setup.py`` disagree on something, the ``setup.py``
+file should be considered to be the truth. As dependencies are added or
+removed, the documentation is much more likely to become outdated than
+the ``setup.py``.
+
+^^^^^^^^^^^^^^^^^^^^^^^
+Finding Python packages
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The vast majority of Python packages are hosted on PyPI - The Python
+Package Index. ``pip`` only supports packages hosted on PyPI, making
+it the only option for developers who want a simple installation.
+Search for "PyPI <package-name>" to find the download page. Note that
+some pages are versioned, and the first result may not be the newest
+version. Click on the "Latest Version" button to the top right to see
+if a newer version is available. The download page is usually at:
+https://pypi.org/project/<package-name>
+
+^^^^^^^^^^^
+Description
+^^^^^^^^^^^
+
+The top of the PyPI downloads page contains a description of the
+package. The first line is usually a short description, while there
+may be a several line "Project Description" that follows. Choose whichever
+is more useful. You can also get these descriptions on the command-line
+using:
+
+.. code-block:: console
+
+ $ python setup.py --description
+ $ python setup.py --long-description
+
+
+^^^^^^^^
+Homepage
+^^^^^^^^
+
+Package developers use ``setup.py`` to upload new versions to PyPI.
+The ``setup`` method often passes metadata like ``homepage`` to PyPI.
+This metadata is displayed on the left side of the download page.
+Search for the text "Homepage" under "Project links" to find it. You
+should use this page instead of the PyPI page if they differ. You can
+also get the homepage on the command-line by running:
+
+.. code-block:: console
+
+ $ python setup.py --url
+
+
+^^^
+URL
+^^^
+
+You may have noticed that Spack allows you to add multiple versions of
+the same package without adding multiple versions of the download URL.
+It does this by guessing what the version string in the URL is and
+replacing this with the requested version. Obviously, if Spack cannot
+guess the version correctly, or if non-version-related things change
+in the URL, Spack cannot substitute the version properly.
+
+Once upon a time, PyPI offered nice, simple download URLs like:
+https://pypi.python.org/packages/source/n/numpy/numpy-1.13.1.zip
+
+As you can see, the version is 1.13.1. It probably isn't hard to guess
+what URL to use to download version 1.12.0, and Spack was perfectly
+capable of performing this calculation.
+
+However, PyPI switched to a new download URL format:
+https://pypi.python.org/packages/c0/3a/40967d9f5675fbb097ffec170f59c2ba19fc96373e73ad47c2cae9a30aed/numpy-1.13.1.zip#md5=2c3c0f4edf720c3a7b525dacc825b9ae
+
+and more recently:
+https://files.pythonhosted.org/packages/b0/2b/497c2bb7c660b2606d4a96e2035e92554429e139c6c71cdff67af66b58d2/numpy-1.14.3.zip
+
+As you can imagine, it is impossible for Spack to guess what URL to
+use to download version 1.12.0 given this URL. There is a solution,
+however. PyPI offers a new hidden interface for downloading
+Python packages that does not include a hash in the URL:
+https://pypi.io/packages/source/n/numpy/numpy-1.13.1.zip
+
+This URL redirects to the files.pythonhosted.org URL. The general syntax for
+this pypi.io URL is:
+https://pypi.io/packages/source/<first-letter-of-name>/<name>/<name>-<version>.<extension>
+
+Please use the pypi.io URL instead of the pypi.python.org URL. If both
+``.tar.gz`` and ``.zip`` versions are available, ``.tar.gz`` is preferred.
+If some releases offer both ``.tar.gz`` and ``.zip`` versions, but some
+only offer ``.zip`` versions, use ``.zip``.
+
+"""""""""""""""
+PyPI vs. GitHub
+"""""""""""""""
+
+Many packages are hosted on PyPI, but are developed on GitHub and other
+version control systems. The tarball can be downloaded from either
+location, but PyPI is preferred for the following reasons:
+
+#. PyPI contains the bare minimum of files to install the package.
+
+ You may notice that the tarball you download from PyPI does not
+ have the same checksum as the tarball you download from GitHub.
+ When a developer uploads a new release to PyPI, it doesn't contain
+ every file in the repository, only the files necessary to install
+ the package. PyPI tarballs are therefore smaller.
+
+#. PyPI is the official source for package managers like ``pip``.
+
+ Let's be honest, ``pip`` is much more popular than Spack. If the
+ GitHub tarball contains a file not present in the PyPI tarball that
+ causes a bug, the developers may not realize this for quite some
+ time. If the bug was in a file contained in the PyPI tarball, users
+ would notice the bug much more quickly.
+
+#. GitHub release may be a beta version.
+
+ When a developer releases a new version of a package on GitHub,
+ it may not be intended for most users. Until that release also
+ makes its way to PyPI, it should be assumed that the release is
+ not yet ready for general use.
+
+#. The checksum for a GitHub release may change.
+
+ Unfortunately, some developers have a habit of patching releases
+ without incrementing the version number. This results in a change
+ in tarball checksum. Package managers like Spack that use checksums
+ to verify the integrity of a download tarball grind to a halt when
+ the checksum for a known version changes. Most of the time, the
+ change is intentional, and contains a needed bug fix. However,
+ sometimes the change indicates a download source that has been
+ compromised, and a tarball that contains a virus. If this happens,
+ you must contact the developers to determine which is the case.
+ PyPI is nice because it makes it physically impossible to
+ re-release the same version of a package with a different checksum.
+
+There are some reasons to prefer downloading from GitHub:
+
+#. The GitHub tarball may contain unit tests
+
+ As previously mentioned, the PyPI tarball contains the bare minimum
+ of files to install the package. Unless explicitly specified by the
+ developers, it will not contain development files like unit tests.
+ If you desire to run the unit tests during installation, you should
+ use the GitHub tarball instead.
+
+#. Spack does not yet support ``spack versions`` and ``spack checksum``
+ with PyPI URLs
+
+ These commands work just fine with GitHub URLs. This is a minor
+ annoyance, not a reason to prefer GitHub over PyPI.
+
+If you really want to run these unit tests, no one will stop you from
+submitting a PR for a new package that downloads from GitHub.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+There are a few dependencies common to the ``PythonPackage`` build system.
+
+""""""
+Python
+""""""
+
+Obviously, every ``PythonPackage`` needs Python at build-time to run
+``python setup.py build && python setup.py install``. Python is also
+needed at run-time if you want to import the module. Due to backwards
+incompatible changes between Python 2 and 3, it is very important to
+specify which versions of Python are supported. If the documentation
+mentions that Python 3 is required, this can be specified as:
+
+.. code-block:: python
+
+ depends_on('python@3:', type=('build', 'run')
+
+
+If Python 2 is required, this would look like:
+
+.. code-block:: python
+
+ depends_on('python@:2', type=('build', 'run')
+
+
+If Python 2.7 is the only version that works, you can use:
+
+.. code-block:: python
+
+ depends_on('python@2.7:2.8', type=('build', 'run')
+
+
+The documentation may not always specify supported Python versions.
+Another place to check is in the ``setup.py`` file. Look for a line
+containing ``python_requires``. An example from
+`py-numpy <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-numpy/package.py>`_
+looks like:
+
+.. code-block:: python
+
+ python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*'
+
+
+More commonly, you will find a version check at the top of the file:
+
+.. code-block:: python
+
+ if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 4):
+ raise RuntimeError("Python version 2.7 or >= 3.4 required.")
+
+
+This can be converted to Spack's spec notation like so:
+
+.. code-block:: python
+
+ depends_on('python@2.7:2.8,3.4:', type=('build', 'run'))
+
+
+""""""""""
+setuptools
+""""""""""
+
+Originally, the Python language had a single build system called
+distutils, which is built into Python. Distutils provided a common
+framework for package authors to describe their project and how it
+should be built. However, distutils was not without limitations.
+Most notably, there was no way to list a project's dependencies
+with distutils. Along came setuptools, a non-builtin build system
+designed to overcome the limitations of distutils. Both projects
+use a similar API, making the transition easy while adding much
+needed functionality. Today, setuptools is used in around 75% of
+the Python packages in Spack.
+
+Since setuptools isn't built-in to Python, you need to add it as a
+dependency. To determine whether or not a package uses setuptools,
+search the file for an import statement like:
+
+.. code-block:: python
+
+ import setuptools
+
+
+or:
+
+.. code-block:: python
+
+ from setuptools import setup
+
+
+Some packages are designed to work with both setuptools and distutils,
+so you may find something like:
+
+.. code-block:: python
+
+ try:
+ from setuptools import setup
+ except ImportError:
+ from distutils.core import setup
+
+
+This uses setuptools if available, and falls back to distutils if not.
+In this case, you would still want to add a setuptools dependency, as
+it offers us more control over the installation.
+
+Unless specified otherwise, setuptools is usually a build-only dependency.
+That is, it is needed to install the software, but is not needed at
+run-time. This can be specified as:
+
+.. code-block:: python
+
+ depends_on('py-setuptools', type='build')
+
+
+""""""
+cython
+""""""
+
+Compared to compiled languages, interpreted languages like Python can
+be quite a bit slower. To work around this, some Python developers
+rewrite computationally demanding sections of code in C, a process
+referred to as "cythonizing". In order to build these package, you
+need to add a build dependency on cython:
+
+.. code-block:: python
+
+ depends_on('py-cython', type='build')
+
+
+Look for references to "cython" in the ``setup.py`` to determine
+whether or not this is necessary. Cython may be optional, but
+even then you should list it as a required dependency. Spack is
+designed to compile software, and is meant for HPC facilities
+where speed is crucial. There is no reason why someone would not
+want an optimized version of a library instead of the pure-Python
+version.
+
+^^^^^^^^^^^^^^^^^^^
+Python dependencies
+^^^^^^^^^^^^^^^^^^^
+
+When you install a package with ``pip``, it reads the ``setup.py``
+file in order to determine the dependencies of the package.
+If the dependencies are not yet installed, ``pip`` downloads them
+and installs them for you. This may sound convenient, but Spack
+cannot rely on this behavior for two reasons:
+
+#. Spack needs to be able to install packages on air-gapped networks.
+
+ If there is no internet connection, ``pip`` can't download the
+ package dependencies. By explicitly listing every dependency in
+ the ``package.py``, Spack knows what to download ahead of time.
+
+#. Duplicate installations of the same dependency may occur.
+
+ Spack supports *activation* of Python extensions, which involves
+ symlinking the package installation prefix to the Python installation
+ prefix. If your package is missing a dependency, that dependency
+ will be installed to the installation directory of the same package.
+ If you try to activate the package + dependency, it may cause a
+ problem if that package has already been activated.
+
+For these reasons, you must always explicitly list all dependencies.
+Although the documentation may list the package's dependencies,
+often the developers assume people will use ``pip`` and won't have to
+worry about it. Always check the ``setup.py`` to find the true
+dependencies.
+
+If the package relies on ``distutils``, it may not explicitly list its
+dependencies. Check for statements like:
+
+.. code-block:: python
+
+ try:
+ import numpy
+ except ImportError:
+ raise ImportError("numpy must be installed prior to installation")
+
+
+Obviously, this means that ``py-numpy`` is a dependency.
+
+If the package uses ``setuptools``, check for the following clues:
+
+* ``install_requires``
+
+ These packages are required for installation.
+
+* ``extra_requires``
+
+ These packages are optional dependencies that enable additional
+ functionality. You should add a variant that optionally adds these
+ dependencies.
+
+* ``test_requires``
+
+ These are packages that are required to run the unit tests for the
+ package. These dependencies can be specified using the
+ ``type='test'`` dependency type.
+
+In the root directory of the package, you may notice a
+``requirements.txt`` file. It may look like this file contains a list
+of all of the package's dependencies. Don't be fooled. This file is
+used by tools like Travis to install the pre-requisites for the
+package... and a whole bunch of other things. It often contains
+dependencies only needed for unit tests, like:
+
+* mock
+* nose
+* pytest
+
+It can also contain dependencies for building the documentation, like
+sphinx. If you can't find any information about the package's
+dependencies, you can take a look in ``requirements.txt``, but be sure
+not to add test or documentation dependencies.
+
+""""""""""
+setuptools
+""""""""""
+
+Setuptools is a bit of a special case. If a package requires setuptools
+at run-time, how do they express this? They could add it to
+``install_requires``, but setuptools is imported long before this and
+needed to read this line. And since you can't install the package
+without setuptools, the developers assume that setuptools will already
+be there, so they never mention when it is required. We don't want to
+add run-time dependencies if they aren't needed, so you need to
+determine whether or not setuptools is needed. Grep the installation
+directory for any files containing a reference to ``setuptools`` or
+``pkg_resources``. Both modules come from ``py-setuptools``.
+``pkg_resources`` is particularly common in scripts in ``prefix/bin``.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to setup.py
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The default build and install phases should be sufficient to install
+most packages. However, you may want to pass additional flags to
+either phase.
+
+You can view the available options for a particular phase with:
+
+.. code-block:: console
+
+ $ python setup.py <phase> --help
+
+
+Each phase provides a ``<phase_args>`` function that can be used to
+pass arguments to that phase. For example,
+`py-numpy <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-numpy/package.py>`_
+adds:
+
+.. code-block:: python
+
+ def build_args(self, spec, prefix):
+ args = []
+
+ # From NumPy 1.10.0 on it's possible to do a parallel build.
+ if self.version >= Version('1.10.0'):
+ # But Parallel build in Python 3.5+ is broken. See:
+ # https://github.com/spack/spack/issues/7927
+ # https://github.com/scipy/scipy/issues/7112
+ if spec['python'].version < Version('3.5'):
+ args = ['-j', str(make_jobs)]
+
+ return args
+
+
+^^^^^^^
+Testing
+^^^^^^^
+
+``PythonPackage`` provides a couple of options for testing packages.
+
+""""""""""""
+Import tests
+""""""""""""
+
+Just because a package successfully built does not mean that it built
+correctly. The most reliable test of whether or not the package was
+correctly installed is to attempt to import all of the modules that
+get installed. To get a list of modules, run the following command
+in the source directory:
+
+.. code-block:: console
+
+ $ python
+ >>> import setuptools
+ >>> setuptools.find_packages()
+ ['numpy', 'numpy._build_utils', 'numpy.compat', 'numpy.core', 'numpy.distutils', 'numpy.doc', 'numpy.f2py', 'numpy.fft', 'numpy.lib', 'numpy.linalg', 'numpy.ma', 'numpy.matrixlib', 'numpy.polynomial', 'numpy.random', 'numpy.testing', 'numpy.core.code_generators', 'numpy.distutils.command', 'numpy.distutils.fcompiler']
+
+
+Large, complex packages like ``numpy`` will return a long list of
+packages, while other packages like ``six`` will return an empty list.
+``py-six`` installs a single ``six.py`` file. In Python packaging lingo,
+a "package" is a directory containing files like:
+
+.. code-block:: none
+
+ foo/__init__.py
+ foo/bar.py
+ foo/baz.py
+
+
+whereas a "module" is a single Python file. Since ``find_packages``
+only returns packages, you'll have to determine the correct module
+names yourself. You can now add these packages and modules to the
+package like so:
+
+.. code-block:: python
+
+ import_modules = ['six']
+
+
+When you run ``spack install --test=root py-six``, Spack will attempt
+to import the ``six`` module after installation.
+
+These tests most often catch missing dependencies and non-RPATHed
+libraries. Make sure not to add modules/packages containing the word
+"test", as these likely won't end up in installation directory.
+
+""""""""""
+Unit tests
+""""""""""
+
+The package you want to install may come with additional unit tests.
+By default, Spack runs:
+
+.. code-block:: console
+
+ $ python setup.py test
+
+
+if it detects that the ``setup.py`` file supports a ``test`` phase.
+You can add additional build-time or install-time tests by overriding
+``test`` and ``installtest``, respectively. For example, ``py-numpy``
+adds:
+
+.. code-block:: python
+
+ def install_test(self):
+ with working_dir('..'):
+ python('-c', 'import numpy; numpy.test("full", verbose=2)')
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setup file in a sub-directory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In order to be compatible with package managers like ``pip``, the package
+is required to place its ``setup.py`` in the root of the tarball. However,
+not every Python package cares about ``pip`` or PyPI. If you are installing
+a package that is not hosted on PyPI, you may find that it places its
+``setup.py`` in a sub-directory. To handle this, add the directory containing
+``setup.py`` to the package like so:
+
+.. code-block:: python
+
+ build_directory = 'source'
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Alternate names for setup.py
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As previously mentioned, packages need to call their setup script ``setup.py``
+in order to be compatible with package managers like ``pip``. However, some
+packages like
+`py-meep <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-meep/package.py>`_ and
+`py-adios <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-adios/package.py>`_
+come with multiple setup scripts, one for a serial build and another for a
+parallel build. You can override the default name to use like so:
+
+.. code-block:: python
+
+ def setup_file(self):
+ return 'setup-mpi.py' if '+mpi' in self.spec else 'setup.py'
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+PythonPackage vs. packages that use Python
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+There are many packages that make use of Python, but packages that depend
+on Python are not necessarily ``PythonPackages``.
+
+"""""""""""""""""""""""
+Choosing a build system
+"""""""""""""""""""""""
+
+First of all, you need to select a build system. ``spack create`` usually
+does this for you, but if for whatever reason you need to do this manually,
+choose ``PythonPackage`` if and only if the package contains a ``setup.py``
+file.
+
+"""""""""""""""""""""""
+Choosing a package name
+"""""""""""""""""""""""
+
+Selecting the appropriate package name is a little more complicated
+than choosing the build system. By default, ``spack create`` will
+prepend ``py-`` to the beginning of the package name if it detects
+that the package uses the ``PythonPackage`` build system. However, there
+are occasionally packages that use ``PythonPackage`` that shouldn't
+start with ``py-``. For example:
+
+* busco
+* easybuild
+* httpie
+* mercurial
+* scons
+* snakemake
+
+The thing these packages have in common is that they are command-line
+tools that just so happen to be written in Python. Someone who wants
+to install ``mercurial`` with Spack isn't going to realize that it is
+written in Python, and they certainly aren't going to assume the package
+is called ``py-mercurial``. For this reason, we manually renamed the
+package to ``mercurial``.
+
+Likewise, there are occasionally packages that don't use the
+``PythonPackage`` build system but should still be prepended with ``py-``.
+For example:
+
+* py-genders
+* py-py2cairo
+* py-pygobject
+* py-pygtk
+* py-pyqt
+* py-pyserial
+* py-sip
+* py-xpyb
+
+These packages are primarily used as Python libraries, not as
+command-line tools. You may see C/C++ packages that have optional
+Python language-bindings, such as:
+
+* antlr
+* cantera
+* conduit
+* pagmo
+* vtk
+
+Don't prepend these kind of packages with ``py-``. When in doubt,
+think about how this package will be used. Is it primarily a Python
+library that will be imported in other Python scripts? Or is it a
+command-line tool, or C/C++/Fortran program with optional Python
+modules? The former should be prepended with ``py-``, while the
+latter should not.
+
+""""""""""""""""""""""
+extends vs. depends_on
+""""""""""""""""""""""
+
+This is very similar to the naming dilemma above, with a slight twist.
+As mentioned in the :ref:`Packaging Guide <packaging_extensions>`,
+``extends`` and ``depends_on`` are very similar, but ``extends`` adds
+the ability to *activate* the package. Activation involves symlinking
+everything in the installation prefix of the package to the installation
+prefix of Python. This allows the user to import a Python module without
+having to add that module to ``PYTHONPATH``.
+
+When deciding between ``extends`` and ``depends_on``, the best rule of
+thumb is to check the installation prefix. If Python libraries are
+installed to ``prefix/lib/python2.7/site-packages`` (where 2.7 is the
+MAJOR.MINOR version of Python you used to install the package), then
+you should use ``extends``. If Python libraries are installed elsewhere
+or the only files that get installed reside in ``prefix/bin``, then
+don't use ``extends``, as symlinking the package wouldn't be useful.
+
+^^^^^^^^^^^^^^^^^^^^^
+Alternatives to Spack
+^^^^^^^^^^^^^^^^^^^^^
+
+PyPI has hundreds of thousands of packages that are not yet in Spack,
+and ``pip`` may be a perfectly valid alternative to using Spack. The
+main advantage of Spack over ``pip`` is its ability to compile
+non-Python dependencies. It can also build cythonized versions of a
+package or link to an optimized BLAS/LAPACK library like MKL,
+resulting in calculations that run orders of magnitude faster.
+Spack does not offer a significant advantage to other python-management
+systems for installing and using tools like flake8 and sphinx.
+But if you need packages with non-Python dependencies like
+numpy and scipy, Spack will be very valuable to you.
+
+Anaconda is another great alternative to Spack, and comes with its own
+``conda`` package manager. Like Spack, Anaconda is capable of compiling
+non-Python dependencies. Anaconda contains many Python packages that
+are not yet in Spack, and Spack contains many Python packages that are
+not yet in Anaconda. The main advantage of Spack over Anaconda is its
+ability to choose a specific compiler and BLAS/LAPACK or MPI library.
+Spack also has better platform support for supercomputers. On the
+other hand, Anaconda offers Windows support.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on Python packaging, see:
+https://packaging.python.org/
diff --git a/lib/spack/docs/build_systems/qmakepackage.rst b/lib/spack/docs/build_systems/qmakepackage.rst
new file mode 100644
index 0000000000..f54b80f8d3
--- /dev/null
+++ b/lib/spack/docs/build_systems/qmakepackage.rst
@@ -0,0 +1,116 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _qmakepackage:
+
+------------
+QMakePackage
+------------
+
+Much like Autotools and CMake, QMake is a build-script generator
+designed by the developers of Qt. In its simplest form, Spack's
+``QMakePackage`` runs the following steps:
+
+.. code-block:: console
+
+ $ qmake
+ $ make
+ $ make check # optional
+ $ make install
+
+
+QMake does not appear to have a standardized way of specifying
+the installation directory, so you may have to set environment
+variables or edit ``*.pro`` files to get things working properly.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``QMakePackage`` base class comes with the following phases:
+
+#. ``qmake`` - generate Makefiles
+#. ``build`` - build the project
+#. ``install`` - install the project
+
+By default, these phases run:
+
+.. code-block:: console
+
+ $ qmake
+ $ make
+ $ make install
+
+
+Any of these phases can be overridden in your package as necessary.
+There is also a ``check`` method that looks for a ``check`` target
+in the Makefile. If a ``check`` target exists and the user runs:
+
+.. code-block:: console
+
+ $ spack install --test=root <qmake-package>
+
+
+Spack will run ``make check`` after the build phase.
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+Packages that use the QMake build system can be identified by the
+presence of a ``<project-name>.pro`` file. This file declares things
+like build instructions and dependencies.
+
+One thing to look for is the ``minQtVersion`` function:
+
+.. code-block:: none
+
+ minQtVersion(5, 6, 0)
+
+
+This means that Qt 5.6.0 is the earliest release that will work.
+You should specify this in a ``depends_on`` statement.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+At the bare minimum, packages that use the QMake build system need a
+``qt`` dependency. Since this is always the case, the ``QMakePackage``
+base class already contains:
+
+.. code-block:: python
+
+ depends_on('qt', type='build')
+
+
+If you want to specify a particular version requirement, or need to
+link to the ``qt`` libraries, you can override this in your package:
+
+.. code-block:: python
+
+ depends_on('qt@5.6.0:')
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to qmake
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you need to pass any arguments to the ``qmake`` call, you can
+override the ``qmake_args`` method like so:
+
+.. code-block:: python
+
+ def qmake_args(self):
+ return ['-recursive']
+
+
+This method can be used to pass flags as well as variables.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the QMake build system, see:
+http://doc.qt.io/qt-5/qmake-manual.html
diff --git a/lib/spack/docs/build_systems/rpackage.rst b/lib/spack/docs/build_systems/rpackage.rst
new file mode 100644
index 0000000000..5e44b2135e
--- /dev/null
+++ b/lib/spack/docs/build_systems/rpackage.rst
@@ -0,0 +1,346 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _rpackage:
+
+--------
+RPackage
+--------
+
+Like Python, R has its own built-in build system.
+
+The R build system is remarkably uniform and well-tested.
+This makes it one of the easiest build systems to create
+new Spack packages for.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``RPackage`` base class has a single phase:
+
+#. ``install`` - install the package
+
+By default, this phase runs the following command:
+
+.. code-block:: console
+
+ $ R CMD INSTALL --library=/path/to/installation/prefix/rlib/R/library .
+
+
+^^^^^^^^^^^^^^^^^^
+Finding R packages
+^^^^^^^^^^^^^^^^^^
+
+The vast majority of R packages are hosted on CRAN - The Comprehensive
+R Archive Network. If you are looking for a particular R package, search
+for "CRAN <package-name>" and you should quickly find what you want.
+If it isn't on CRAN, try Bioconductor, another common R repository.
+
+For the purposes of this tutorial, we will be walking through
+`r-caret <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/r-caret/package.py>`_
+as an example. If you search for "CRAN caret", you will quickly find what
+you are looking for at https://cran.r-project.org/web/packages/caret/index.html.
+If you search for "Package source", you will find the download URL for
+the latest release. Use this URL with ``spack create`` to create a new
+package.
+
+^^^^^^^^^^^^
+Package name
+^^^^^^^^^^^^
+
+The first thing you'll notice is that Spack prepends ``r-`` to the front
+of the package name. This is how Spack separates R package extensions
+from the rest of the packages in Spack. Without this, we would end up
+with package name collisions more frequently than we would like. For
+instance, there are already packages for both:
+
+* ``ape`` and ``r-ape``
+* ``curl`` and ``r-curl``
+* ``gmp`` and ``r-gmp``
+* ``jpeg`` and ``r-jpeg``
+* ``openssl`` and ``r-openssl``
+* ``uuid`` and ``r-uuid``
+* ``xts`` and ``r-xts``
+
+Many popular programs written in C/C++ are later ported to R as a
+separate project.
+
+^^^^^^^^^^^
+Description
+^^^^^^^^^^^
+
+The first thing you'll need to add to your new package is a description.
+The top of the homepage for ``caret`` lists the following description:
+
+ caret: Classification and Regression Training
+
+ Misc functions for training and plotting classification and regression models.
+
+You can either use the short description (first line), long description
+(second line), or both depending on what you feel is most appropriate.
+
+^^^^^^^^
+Homepage
+^^^^^^^^
+
+If you look at the bottom of the page, you'll see:
+
+ Linking:
+
+ Please use the canonical form https://CRAN.R-project.org/package=caret to link to this page.
+
+Please uphold the wishes of the CRAN admins and use
+https://CRAN.R-project.org/package=caret as the homepage instead of
+https://cran.r-project.org/web/packages/caret/index.html. The latter may
+change without notice.
+
+^^^
+URL
+^^^
+
+As previously mentioned, the download URL for the latest release can be
+found by searching "Package source" on the homepage.
+
+^^^^^^^^
+List URL
+^^^^^^^^
+
+CRAN maintains a single webpage containing the latest release of every
+single package: https://cran.r-project.org/src/contrib/
+
+Of course, as soon as a new release comes out, the version you were using
+in your package is no longer available at that URL. It is moved to an
+archive directory. If you search for "Old sources", you will find:
+https://cran.r-project.org/src/contrib/Archive/caret
+
+If you only specify the URL for the latest release, your package will
+no longer be able to fetch that version as soon as a new release comes
+out. To get around this, add the archive directory as a ``list_url``.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As an extension of the R ecosystem, your package will obviously depend
+on R to build and run. Normally, we would use ``depends_on`` to express
+this, but for R packages, we use ``extends``. ``extends`` is similar to
+``depends_on``, but adds an additional feature: the ability to "activate"
+the package by symlinking it to the R installation directory. Since
+every R package needs this, the ``RPackage`` base class contains:
+
+.. code-block:: python
+
+ extends('r')
+ depends_on('r', type=('build', 'run'))
+
+
+Take a close look at the homepage for ``caret``. If you look at the
+"Depends" section, you'll notice that ``caret`` depends on "R (≥ 2.10)".
+You should add this to your package like so:
+
+.. code-block:: python
+
+ depends_on('r@2.10:', type=('build', 'run'))
+
+
+^^^^^^^^^^^^^^
+R dependencies
+^^^^^^^^^^^^^^
+
+R packages are often small and follow the classic Unix philosophy
+of doing one thing well. They are modular and usually depend on
+several other packages. You may find a single package with over a
+hundred dependencies. Luckily, CRAN packages are well-documented
+and list all of their dependencies in the following sections:
+
+* Depends
+* Imports
+* LinkingTo
+
+As far as Spack is concerned, all 3 of these dependency types
+correspond to ``type=('build', 'run')``, so you don't have to worry
+about them. If you are curious what they mean,
+https://github.com/spack/spack/issues/2951 has a pretty good summary:
+
+ ``Depends`` is required and will cause those R packages to be *attached*,
+ that is, their APIs are exposed to the user. ``Imports`` *loads* packages
+ so that *the package* importing these packages can access their APIs,
+ while *not* being exposed to the user. When a user calls ``library(foo)``
+ s/he *attaches* package ``foo`` and all of the packages under ``Depends``.
+ Any function in one of these package can be called directly as ``bar()``.
+ If there are conflicts, user can also specify ``pkgA::bar()`` and
+ ``pkgB::bar()`` to distinguish between them. Historically, there was only
+ ``Depends`` and ``Suggests``, hence the confusing names. Today, maybe
+ ``Depends`` would have been named ``Attaches``.
+
+ The ``LinkingTo`` is not perfect and there was recently an extensive
+ discussion about API/ABI among other things on the R-devel mailing
+ list among very skilled R developers:
+
+ * https://stat.ethz.ch/pipermail/r-devel/2016-December/073505.html
+ * https://stat.ethz.ch/pipermail/r-devel/2017-January/073647.html
+
+Some packages also have a fourth section:
+
+* Suggests
+
+These are optional, rarely-used dependencies that a user might find
+useful. You should **NOT** add these dependencies to your package.
+R packages already have enough dependencies as it is, and adding
+optional dependencies can really slow down the concretization
+process. They can also introduce circular dependencies.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Core, recommended, and non-core packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you look at "Depends", "Imports", and "LinkingTo", you will notice
+3 different types of packages:
+
+"""""""""""""
+Core packages
+"""""""""""""
+
+If you look at the ``caret`` homepage, you'll notice a few dependencies
+that don't have a link to the package, like ``methods``, ``stats``, and
+``utils``. These packages are part of the core R distribution and are
+tied to the R version installed. You can basically consider these to be
+"R itself". These are so essential to R so it would not make sense that
+they could be updated via CRAN. If so, you would basically get a different
+version of R. Thus, they're updated when R is updated.
+
+You can find a list of these core libraries at:
+https://github.com/wch/r-source/tree/trunk/src/library
+
+""""""""""""""""""""
+Recommended packages
+""""""""""""""""""""
+
+When you install R, there is an option called ``--with-recommended-packages``.
+This flag causes the R installation to include a few "Recommended" packages
+(legacy term). They are for historical reasons quite tied to the core R
+distribution, developed by the R core team or people closely related to it.
+The R core distribution "knows" about these package, but they are indeed
+distributed via CRAN. Because they're distributed via CRAN, they can also be
+updated between R version releases.
+
+Spack explicitly adds the ``--without-recommended-packages`` flag to prevent
+the installation of these packages. Due to the way Spack handles package
+activation (symlinking packages to the R installation directory),
+pre-existing recommended packages will cause conflicts for already-existing
+files. We could either not include these recommended packages in Spack and
+require them to be installed through ``--with-recommended-packages``, or
+we could not install them with R and let users choose the version of the
+package they want to install. We chose the latter.
+
+Since these packages are so commonly distributed with the R system, many
+developers may assume these packages exist and fail to list them as
+dependencies. Watch out for this.
+
+You can find a list of these recommended packages at:
+https://github.com/wch/r-source/blob/trunk/share/make/vars.mk
+
+"""""""""""""""""
+Non-core packages
+"""""""""""""""""
+
+These are packages that are neither "core" nor "recommended". There are more
+than 10,000 of these packages hosted on CRAN alone.
+
+For each of these package types, if you see that a specific version is
+required, for example, "lattice (≥ 0.20)", please add this information to
+the dependency:
+
+.. code-block:: python
+
+ depends_on('r-lattice@0.20:', type=('build', 'run'))
+
+
+^^^^^^^^^^^^^^^^^^
+Non-R dependencies
+^^^^^^^^^^^^^^^^^^
+
+Some packages depend on non-R libraries for linking. Check out the
+`r-stringi <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/r-stringi/package.py>`_
+package for an example: https://CRAN.R-project.org/package=stringi.
+If you search for the text "SystemRequirements", you will see:
+
+ ICU4C (>= 52, optional)
+
+This is how non-R dependencies are listed. Make sure to add these
+dependencies. The default dependency type should suffice.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to the installation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Some R packages provide additional flags that can be passed to
+``R CMD INSTALL``, often to locate non-R dependencies.
+`r-rmpi <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/r-rmpi/package.py>`_
+is an example of this, and flags for linking to an MPI library. To pass
+these to the installation command, you can override ``configure_args``
+like so:
+
+.. code-block:: python
+
+ def configure_args(self, spec, prefix):
+ mpi_name = spec['mpi'].name
+
+ # The type of MPI. Supported values are:
+ # OPENMPI, LAM, MPICH, MPICH2, or CRAY
+ if mpi_name == 'openmpi':
+ Rmpi_type = 'OPENMPI'
+ elif mpi_name == 'mpich':
+ Rmpi_type = 'MPICH2'
+ else:
+ raise InstallError('Unsupported MPI type')
+
+ return [
+ '--with-Rmpi-type={0}'.format(Rmpi_type),
+ '--with-mpi={0}'.format(spec['mpi'].prefix),
+ ]
+
+
+There is a similar ``configure_vars`` function that can be overridden
+to pass variables to the build.
+
+^^^^^^^^^^^^^^^^^^^^^
+Alternatives to Spack
+^^^^^^^^^^^^^^^^^^^^^
+
+CRAN hosts over 10,000 R packages, most of which are not in Spack. Many
+users may not need the advanced features of Spack, and may prefer to
+install R packages the normal way:
+
+.. code-block:: console
+
+ $ R
+ > install.packages("ggplot2")
+
+
+R will search CRAN for the ``ggplot2`` package and install all necessary
+dependencies for you. If you want to update all installed R packages to
+the latest release, you can use:
+
+.. code-block:: console
+
+ > update.packages(ask = FALSE)
+
+
+This works great for users who have internet access, but those on an
+air-gapped cluster will find it easier to let Spack build a download
+mirror and install these packages for you.
+
+Where Spack really shines is its ability to install non-R dependencies
+and link to them properly, something the R installation mechanism
+cannot handle.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on installing R packages, see:
+https://stat.ethz.ch/R-manual/R-devel/library/utils/html/INSTALL.html
diff --git a/lib/spack/docs/build_systems/rubypackage.rst b/lib/spack/docs/build_systems/rubypackage.rst
new file mode 100644
index 0000000000..70e23f6d50
--- /dev/null
+++ b/lib/spack/docs/build_systems/rubypackage.rst
@@ -0,0 +1,16 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _rubypackage:
+
+-----------
+RubyPackage
+-----------
+
+Like Perl, Python, and R, Ruby has its own build system for
+installing Ruby gems.
+
+This build system is a work-in-progress. See
+https://github.com/spack/spack/pull/3127 for more information.
diff --git a/lib/spack/docs/build_systems/sconspackage.rst b/lib/spack/docs/build_systems/sconspackage.rst
new file mode 100644
index 0000000000..d87702b9dc
--- /dev/null
+++ b/lib/spack/docs/build_systems/sconspackage.rst
@@ -0,0 +1,306 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _sconspackage:
+
+------------
+SConsPackage
+------------
+
+SCons is a general-purpose build system that does not rely on
+Makefiles to build software. SCons is written in Python, and handles
+all building and linking itself.
+
+As far as build systems go, SCons is very non-uniform. It provides a
+common framework for developers to write build scripts, but the build
+scripts themselves can vary drastically. Some developers add subcommands
+like:
+
+.. code-block:: console
+
+ $ scons clean
+ $ scons build
+ $ scons test
+ $ scons install
+
+
+Others don't add any subcommands. Some have configuration options that
+can be specified through variables on the command line. Others don't.
+
+^^^^^^
+Phases
+^^^^^^
+
+As previously mentioned, SCons allows developers to add subcommands like
+``build`` and ``install``, but by default, installation usually looks like:
+
+.. code-block:: console
+
+ $ scons
+ $ scons install
+
+
+To facilitate this, the ``SConsPackage`` base class provides the
+following phases:
+
+#. ``build`` - build the package
+#. ``install`` - install the package
+
+Package developers often add unit tests that can be invoked with
+``scons test`` or ``scons check``. Spack provides a ``test`` method
+to handle this. Since we don't know which one the package developer
+chose, the ``test`` method does nothing by default, but can be easily
+overridden like so:
+
+.. code-block:: python
+
+ def test(self):
+ scons('check')
+
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+SCons packages can be identified by their ``SConstruct`` files. These
+files handle everything from setting up subcommands and command-line
+options to linking and compiling.
+
+One thing to look for is the ``EnsureSConsVersion`` function:
+
+.. code-block:: none
+
+ EnsureSConsVersion(2, 3, 0)
+
+
+This means that SCons 2.3.0 is the earliest release that will work.
+You should specify this in a ``depends_on`` statement.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+At the bare minimum, packages that use the SCons build system need a
+``scons`` dependency. Since this is always the case, the ``SConsPackage``
+base class already contains:
+
+.. code-block:: python
+
+ depends_on('scons', type='build')
+
+
+If you want to specify a particular version requirement, you can override
+this in your package:
+
+.. code-block:: python
+
+ depends_on('scons@2.3.0:', type='build')
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Finding available options
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The first place to start when looking for a list of valid options to
+build a package is ``scons --help``. Some packages like
+`kahip <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/kahip/package.py>`_
+don't bother overwriting the default SCons help message, so this isn't
+very useful, but other packages like
+`serf <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/serf/package.py>`_
+print a list of valid command-line variables:
+
+.. code-block:: console
+
+ $ scons --help
+ scons: Reading SConscript files ...
+ Checking for GNU-compatible C compiler...yes
+ scons: done reading SConscript files.
+
+ PREFIX: Directory to install under ( /path/to/PREFIX )
+ default: /usr/local
+ actual: /usr/local
+
+ LIBDIR: Directory to install architecture dependent libraries under ( /path/to/LIBDIR )
+ default: $PREFIX/lib
+ actual: /usr/local/lib
+
+ APR: Path to apr-1-config, or to APR's install area ( /path/to/APR )
+ default: /usr
+ actual: /usr
+
+ APU: Path to apu-1-config, or to APR's install area ( /path/to/APU )
+ default: /usr
+ actual: /usr
+
+ OPENSSL: Path to OpenSSL's install area ( /path/to/OPENSSL )
+ default: /usr
+ actual: /usr
+
+ ZLIB: Path to zlib's install area ( /path/to/ZLIB )
+ default: /usr
+ actual: /usr
+
+ GSSAPI: Path to GSSAPI's install area ( /path/to/GSSAPI )
+ default: None
+ actual: None
+
+ DEBUG: Enable debugging info and strict compile warnings (yes|no)
+ default: False
+ actual: False
+
+ APR_STATIC: Enable using a static compiled APR (yes|no)
+ default: False
+ actual: False
+
+ CC: Command name or path of the C compiler
+ default: None
+ actual: gcc
+
+ CFLAGS: Extra flags for the C compiler (space-separated)
+ default: None
+ actual:
+
+ LIBS: Extra libraries passed to the linker, e.g. "-l<library1> -l<library2>" (space separated)
+ default: None
+ actual: None
+
+ LINKFLAGS: Extra flags for the linker (space-separated)
+ default: None
+ actual:
+
+ CPPFLAGS: Extra flags for the C preprocessor (space separated)
+ default: None
+ actual: None
+
+ Use scons -H for help about command-line options.
+
+
+More advanced packages like
+`cantera <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/cantera/package.py>`_
+use ``scons --help`` to print a list of subcommands:
+
+.. code-block:: console
+
+ $ scons --help
+ scons: Reading SConscript files ...
+
+ SCons build script for Cantera
+
+ Basic usage:
+ 'scons help' - print a description of user-specifiable options.
+
+ 'scons build' - Compile Cantera and the language interfaces using
+ default options.
+
+ 'scons clean' - Delete files created while building Cantera.
+
+ '[sudo] scons install' - Install Cantera.
+
+ '[sudo] scons uninstall' - Uninstall Cantera.
+
+ 'scons test' - Run all tests which did not previously pass or for which the
+ results may have changed.
+
+ 'scons test-reset' - Reset the passing status of all tests.
+
+ 'scons test-clean' - Delete files created while running the tests.
+
+ 'scons test-help' - List available tests.
+
+ 'scons test-NAME' - Run the test named "NAME".
+
+ 'scons <command> dump' - Dump the state of the SCons environment to the
+ screen instead of doing <command>, e.g.
+ 'scons build dump'. For debugging purposes.
+
+ 'scons samples' - Compile the C++ and Fortran samples.
+
+ 'scons msi' - Build a Windows installer (.msi) for Cantera.
+
+ 'scons sphinx' - Build the Sphinx documentation
+
+ 'scons doxygen' - Build the Doxygen documentation
+
+
+You'll notice that cantera provides a ``scons help`` subcommand. Running
+``scons help`` prints a list of valid command-line variables.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to scons
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now that you know what arguments the project accepts, you can add them to
+the package build phase. This is done by overriding ``build_args`` like so:
+
+.. code-block:: python
+
+ def build_args(self, spec, prefix):
+ args = [
+ 'PREFIX={0}'.format(prefix),
+ 'ZLIB={0}'.format(spec['zlib'].prefix),
+ ]
+
+ if '+debug' in spec:
+ args.append('DEBUG=yes')
+ else:
+ args.append('DEBUG=no')
+
+ return args
+
+
+``SConsPackage`` also provides an ``install_args`` function that you can
+override to pass additional arguments to ``scons install``.
+
+^^^^^^^^^^^^^^^^^
+Compiler wrappers
+^^^^^^^^^^^^^^^^^
+
+By default, SCons builds all packages in a separate execution environment,
+and doesn't pass any environment variables from the user environment.
+Even changes to ``PATH`` are not propagated unless the package developer
+does so.
+
+This is particularly troublesome for Spack's compiler wrappers, which depend
+on environment variables to manage dependencies and linking flags. In many
+cases, SCons packages are not compatible with Spack's compiler wrappers,
+and linking must be done manually.
+
+First of all, check the list of valid options for anything relating to
+environment variables. For example, cantera has the following option:
+
+.. code-block:: none
+
+ * env_vars: [ string ]
+ Environment variables to propagate through to SCons. Either the
+ string "all" or a comma separated list of variable names, e.g.
+ 'LD_LIBRARY_PATH,HOME'.
+ - default: 'LD_LIBRARY_PATH,PYTHONPATH'
+
+
+In the case of cantera, using ``env_vars=all`` allows us to use
+Spack's compiler wrappers. If you don't see an option related to
+environment variables, try using Spack's compiler wrappers by passing
+``spack_cc``, ``spack_cxx``, and ``spack_fc`` via the ``CC``, ``CXX``,
+and ``FC`` arguments, respectively. If you pass them to the build and
+you see an error message like:
+
+.. code-block:: none
+
+ Spack compiler must be run from Spack! Input 'SPACK_PREFIX' is missing.
+
+
+you'll know that the package isn't compatible with Spack's compiler
+wrappers. In this case, you'll have to use the path to the actual
+compilers, which are stored in ``self.compiler.cc`` and friends.
+Note that this may involve passing additional flags to the build to
+locate dependencies, a task normally done by the compiler wrappers.
+serf is an example of a package with this limitation.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the SCons build system, see:
+http://scons.org/documentation.html
diff --git a/lib/spack/docs/build_systems/wafpackage.rst b/lib/spack/docs/build_systems/wafpackage.rst
new file mode 100644
index 0000000000..10a458f59e
--- /dev/null
+++ b/lib/spack/docs/build_systems/wafpackage.rst
@@ -0,0 +1,129 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _wafpackage:
+
+----------
+WafPackage
+----------
+
+Like SCons, Waf is a general-purpose build system that does not rely
+on Makefiles to build software.
+
+^^^^^^
+Phases
+^^^^^^
+
+The ``WafPackage`` base class comes with the following phases:
+
+#. ``configure`` - configure the project
+#. ``build`` - build the project
+#. ``install`` - install the project
+
+By default, these phases run:
+
+.. code-block:: console
+
+ $ python waf configure --prefix=/path/to/installation/prefix
+ $ python waf build
+ $ python waf install
+
+
+Each of these are standard Waf commands and can be found by running:
+
+.. code-block:: console
+
+ $ python waf --help
+
+
+Each phase provides a ``<phase>`` function that runs:
+
+.. code-block:: console
+
+ $ python waf -j<jobs> <phase>
+
+
+where ``<jobs>`` is the number of parallel jobs to build with. Each phase
+also has a ``<phase_args>`` function that can pass arguments to this call.
+All of these functions are empty except for the ``configure_args``
+function, which passes ``--prefix=/path/to/installation/prefix``.
+
+^^^^^^^
+Testing
+^^^^^^^
+
+``WafPackage`` also provides ``test`` and ``installtest`` methods,
+which are run after the ``build`` and ``install`` phases, respectively.
+By default, these phases do nothing, but you can override them to
+run package-specific unit tests. For example, the
+`py-py2cairo <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-py2cairo/package.py>`_
+package uses:
+
+.. code-block:: python
+
+ def installtest(self):
+ with working_dir('test'):
+ pytest = which('py.test')
+ pytest()
+
+
+^^^^^^^^^^^^^^^
+Important files
+^^^^^^^^^^^^^^^
+
+Each Waf package comes with a custom ``waf`` build script, written in
+Python. This script contains instructions to build the project.
+
+The package also comes with a ``wscript`` file. This file is used to
+override the default ``configure``, ``build``, and ``install`` phases
+to customize the Waf project. It also allows developers to override
+the default ``./waf --help`` message. Check this file to find useful
+information about dependencies and the minimum versions that are
+supported.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Build system dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``WafPackage`` does not require ``waf`` to build. ``waf`` is only
+needed to create the ``./waf`` script. Since ``./waf`` is a Python
+script, Python is needed to build the project. ``WafPackage`` adds
+the following dependency automatically:
+
+.. code-block:: python
+
+ depends_on('python@2.5:', type='build')
+
+
+Waf only supports Python 2.5 and up.
+
+^^^^^^^^^^^^^^^^^^^^^^^^
+Passing arguments to waf
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+As previously mentioned, each phase comes with a ``<phase_args>``
+function that can be used to pass arguments to that particular
+phase. For example, if you need to pass arguments to the build
+phase, you can use:
+
+.. code-block:: python
+
+ def build_args(self, spec, prefix):
+ args = []
+
+ if self.run_tests:
+ args.append('--test')
+
+ return args
+
+
+A list of valid options can be found by running ``./waf --help``.
+
+^^^^^^^^^^^^^^^^^^^^^^
+External documentation
+^^^^^^^^^^^^^^^^^^^^^^
+
+For more information on the Waf build system, see:
+https://waf.io/book/
diff --git a/lib/spack/docs/command_index.in b/lib/spack/docs/command_index.in
index 6520352b42..7f1f35c744 100644
--- a/lib/spack/docs/command_index.in
+++ b/lib/spack/docs/command_index.in
@@ -1,9 +1,9 @@
-=============
-Command Index
-=============
+=================
+Command Reference
+=================
-This is an alphabetical list of commands with links to the places they
-appear in the documentation.
+This is a reference for all commands in the Spack command line interface.
+The same information is available through :ref:`spack-help`.
-.. hlist::
- :columns: 3
+Commands that also have sections in the main documentation have a link to
+"More documentation".
diff --git a/lib/spack/docs/conf.py b/lib/spack/docs/conf.py
index 94d301f6d9..5212b4cc30 100644
--- a/lib/spack/docs/conf.py
+++ b/lib/spack/docs/conf.py
@@ -1,28 +1,9 @@
-# flake8: noqa
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+# flake8: noqa
# -*- coding: utf-8 -*-
#
# Spack documentation build configuration file, created by
@@ -42,7 +23,13 @@ import re
import shutil
import subprocess
from glob import glob
-from sphinx.apidoc import main as sphinx_apidoc
+
+# Since Sphinx 1.7, sphinx.apidoc has been moved to sphinx.ext.apidoc
+# sphinx.apidoc is deprecated and will be removed in Sphinx 2.0
+try:
+ from sphinx.ext.apidoc import main as sphinx_apidoc
+except ImportError:
+ from sphinx.apidoc import main as sphinx_apidoc
# -- Spack customizations -----------------------------------------------------
@@ -68,26 +55,32 @@ os.environ['COLIFY_SIZE'] = '25x120'
#
# Generate package list using spack command
#
-with open('package_list.rst', 'w') as plist_file:
+with open('package_list.html', 'w') as plist_file:
subprocess.Popen(
- [spack_root + '/bin/spack', 'list', '--format=rst'], stdout=plist_file)
+ [spack_root + '/bin/spack', 'list', '--format=html'],
+ stdout=plist_file)
#
# Find all the `cmd-spack-*` references and add them to a command index
#
-command_names = []
+import spack
+import spack.cmd
+command_names = spack.cmd.all_commands()
+documented_commands = set()
for filename in glob('*rst'):
with open(filename) as f:
for line in f:
- match = re.match('.. _(cmd-spack-.*):', line)
+ match = re.match('.. _cmd-(spack-.*):', line)
if match:
- command_names.append(match.group(1).strip())
+ documented_commands.add(match.group(1).strip())
+os.environ['COLUMNS'] = '120'
shutil.copy('command_index.in', 'command_index.rst')
with open('command_index.rst', 'a') as index:
- index.write('\n')
- for cmd in sorted(command_names):
- index.write(' * :ref:`%s`\n' % cmd)
+ subprocess.Popen(
+ [spack_root + '/bin/spack', 'commands', '--format=rst'] + list(
+ documented_commands),
+ stdout=index)
#
# Run sphinx-apidoc
@@ -105,28 +98,6 @@ apidoc_args = [
sphinx_apidoc(apidoc_args + ['../spack'])
sphinx_apidoc(apidoc_args + ['../llnl'])
-#
-# Exclude everything in spack.__all__ from indexing. All of these
-# symbols are imported from elsewhere in spack; their inclusion in
-# __all__ simply allows package authors to use `from spack import *`.
-# Excluding them ensures they're only documented in their "real" module.
-#
-# This also avoids issues where some of these symbols shadow core spack
-# modules. Sphinx will complain about duplicate docs when this happens.
-#
-import fileinput, spack
-handling_spack = False
-for line in fileinput.input('spack.rst', inplace=1):
- if handling_spack:
- if not line.startswith(' :noindex:'):
- print(' :noindex: %s' % ' '.join(spack.__all__))
- handling_spack = False
-
- if line.startswith('.. automodule::'):
- handling_spack = (line == '.. automodule:: spack\n')
-
- sys.stdout.write(line)
-
# Enable todo items
todo_include_todos = True
@@ -180,16 +151,16 @@ master_doc = 'index'
# General information about the project.
project = u'Spack'
-copyright = u'2013-2017, Lawrence Livermore National Laboratory.'
+copyright = u'2013-2018, Lawrence Livermore National Laboratory.'
# 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 = str(spack.spack_version.up_to(2))
+version = '.'.join(str(s) for s in spack.spack_version_info[:2])
# The full version, including alpha/beta/rc tags.
-release = str(spack.spack_version.up_to(2))
+release = spack.spack_version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -238,7 +209,7 @@ html_theme = 'sphinx_rtd_theme'
html_theme_options = { 'logo_only' : True }
# Add any paths that contain custom themes here, relative to this directory.
-html_theme_path = ["_themes"]
+# html_theme_path = ["_themes"]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
diff --git a/lib/spack/docs/config_yaml.rst b/lib/spack/docs/config_yaml.rst
index da760f05e3..c02929d8c1 100644
--- a/lib/spack/docs/config_yaml.rst
+++ b/lib/spack/docs/config_yaml.rst
@@ -1,8 +1,13 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _config-yaml:
-====================================
-Basic settings in ``config.yaml``
-====================================
+==============
+Basic Settings
+==============
Spack's basic configuration options are set in ``config.yaml``. You can
see the default settings by looking at
@@ -79,8 +84,8 @@ See :ref:`modules` for details.
--------------------
Spack is designed to run out of a user home directory, and on many
-systems the home directory is a (slow) network filesystem. On most systems,
-building in a temporary filesystem results in faster builds than building
+systems the home directory is a (slow) network file system. On most systems,
+building in a temporary file system results in faster builds than building
in the home directory. Usually, there is also more space available in
the temporary location than in the home directory. So, Spack tries to
create build stages in temporary space.
@@ -151,6 +156,17 @@ to ``false`` to disable these checks. Disabling this can expose you to
attacks. Use at your own risk.
--------------------
+``locks``
+--------------------
+
+When set to ``true``, concurrent instances of Spack will use locks to
+avoid modifying the install tree, database file, etc. If false, Spack
+will disable all locking, but you must **not** run concurrent instances
+of Spack. For file systems that don't support locking, you should set
+this to ``false`` and run one Spack at a time, but otherwise we recommend
+enabling locks.
+
+--------------------
``dirty``
--------------------
@@ -180,3 +196,22 @@ to 4, for example, commands like ``spack install`` will run ``make -j4``
instead of hogging every core.
To build all software in serial, set ``build_jobs`` to 1.
+
+--------------------
+``ccache``
+--------------------
+
+When set to ``true`` Spack will use ccache to cache compiles. This is
+useful specifically in two cases: (1) when using ``spack setup``, and (2)
+when building the same package with many different variants. The default is
+``false``.
+
+When enabled, Spack will look inside your ``PATH`` for a ``ccache``
+executable and stop if it is not found. Some systems come with
+``ccache``, but it can also be installed using ``spack install
+ccache``. ``ccache`` comes with reasonable defaults for cache size
+and location. (See the *Configuration settings* section of ``man
+ccache`` to learn more about the default settings and how to change
+them). Please note that we currently disable ccache's ``hash_dir``
+feature to avoid an issue with the stage directory (see
+https://github.com/LLNL/spack/pull/3761#issuecomment-294352232).
diff --git a/lib/spack/docs/configuration.rst b/lib/spack/docs/configuration.rst
index f1648eb4e0..2ff1987ba8 100644
--- a/lib/spack/docs/configuration.rst
+++ b/lib/spack/docs/configuration.rst
@@ -1,8 +1,13 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _configuration:
-==============================
-Configuration Files in Spack
-==============================
+===================
+Configuration Files
+===================
Spack has many configuration files. Here is a quick list of them, in
case you want to skip directly to specific docs:
@@ -14,9 +19,9 @@ case you want to skip directly to specific docs:
* :ref:`packages.yaml <build-settings>`
* :ref:`repos.yaml <repositories>`
--------------------------
+-----------
YAML Format
--------------------------
+-----------
Spack configuration files are written in YAML. We chose YAML because
it's human readable, but also versatile in that it supports dictionaries,
@@ -29,44 +34,52 @@ Here is an example ``config.yaml`` file:
config:
install_tree: $spack/opt/spack
module_roots:
- lmod: $spack/share/spack/lmod
+ lmod: $spack/share/spack/lmod
build_stage:
- $tempdir
- /nfs/tmp2/$user
-Each spack configuration files is nested under a top-level section
+Each Spack configuration file is nested under a top-level section
corresponding to its name. So, ``config.yaml`` starts with ``config:``,
-and ``mirrors.yaml`` starts with ``mirrors:``, etc.
+``mirrors.yaml`` starts with ``mirrors:``, etc.
.. _configuration-scopes:
--------------------------
+--------------------
Configuration Scopes
--------------------------
+--------------------
Spack pulls configuration data from files in several directories. There
-are four configuration scopes. From lowest to highest:
+are six configuration scopes. From lowest to highest:
#. **defaults**: Stored in ``$(prefix)/etc/spack/defaults/``. These are
the "factory" settings. Users should generally not modify the settings
here, but should override them in other configuration scopes. The
defaults here will change from version to version of Spack.
-#. **system**: Stored in ``/etc/spack``. These are settings for this
+#. **system**: Stored in ``/etc/spack/``. These are settings for this
machine, or for all machines on which this file system is
mounted. The site scope can be used for settings idiosyncratic to a
particular machine, such as the locations of compilers or external
packages. These settings are presumably controlled by someone with
- root access on the machine.
+ root access on the machine. They override the defaults scope.
-#. **site**: Stored in ``$(prefix)/etc/spack/``. Settings here affect
- only *this instance* of Spack, and they override defaults. The site
- scope can can be used for per-project settings (one spack instance per
- project) or for site-wide settings on a multi-user machine (e.g., for
- a common spack instance).
+#. **site**: Stored in ``$(prefix)/etc/spack/``. Settings here affect
+ only *this instance* of Spack, and they override the defaults and system
+ scopes. The site scope can can be used for per-project settings (one
+ Spack instance per project) or for site-wide settings on a multi-user
+ machine (e.g., for a common Spack instance).
#. **user**: Stored in the home directory: ``~/.spack/``. These settings
- affect all instances of Spack and take the highest precedence.
+ affect all instances of Spack and take higher precedence than site,
+ system, or defaults scopes.
+
+#. **custom**: Stored in a custom directory specified by ``--config-scope``.
+ If multiple scopes are listed on the command line, they are ordered
+ from lowest to highest precedence.
+
+#. **command line**: Build settings specified on the command line take
+ precedence over all other scopes.
Each configuration directory may contain several configuration files,
such as ``config.yaml``, ``compilers.yaml``, or ``mirrors.yaml``. When
@@ -75,76 +88,175 @@ lower-precedence settings.
Commands that modify scopes (e.g., ``spack compilers``, ``spack repo``,
etc.) take a ``--scope=<name>`` parameter that you can use to control
-which scope is modified. By default they modify the highest-precedence
+which scope is modified. By default, they modify the highest-precedence
scope.
+.. _custom-scopes:
+
+^^^^^^^^^^^^^
+Custom scopes
+^^^^^^^^^^^^^
+
+In addition to the ``defaults``, ``system``, ``site``, and ``user``
+scopes, you may add configuration scopes directly on the command
+line with the ``--config-scope`` argument, or ``-C`` for short.
+
+For example, the following adds two configuration scopes, named
+``scopea`` and ``scopeb``, to a ``spack spec`` command:
+
+.. code-block:: console
+
+ $ spack -C ~/myscopes/scopea -C ~/myscopes/scopeb spec ncurses
+
+Custom scopes come *after* the ``spack`` command and *before* the
+subcommand, and they specify a single path to a directory full of
+configuration files. You can add the same configuration files to that
+directory that you can add to any other scope (``config.yaml``,
+``packages.yaml``, etc.).
+
+If multiple scopes are provided:
+
+#. Each must be preceded with the ``--config-scope`` or ``-C`` flag.
+#. They must be ordered from lowest to highest precedence.
+
+"""""""""""""""""""""""""""""""""""""""""""
+Example: scopes for release and development
+"""""""""""""""""""""""""""""""""""""""""""
+
+Suppose that you need to support simultaneous building of release and
+development versions of ``mypackage``, where ``mypackage`` -> ``A`` -> ``B``.
+You could create The following files:
+
+.. code-block:: yaml
+ :caption: ~/myscopes/release/packages.yaml
+
+ packages:
+ mypackage:
+ version: [1.7]
+ A:
+ version: [2.3]
+ B:
+ version: [0.8]
+
+.. code-block:: yaml
+ :caption: ~/myscopes/develop/packages.yaml
+
+ packages:
+ mypackage:
+ version: [develop]
+ A:
+ version: [develop]
+ B:
+ version: [develop]
+
+You can switch between ``release`` and ``develop`` configurations using
+configuration arguments. You would type ``spack -C ~/myscopes/release``
+when you want to build the designated release versions of ``mypackage``,
+``A``, and ``B``, and you would type ``spack -C ~/myscopes/develop`` when
+you want to build all of these packages at the ``develop`` version.
+
+"""""""""""""""""""""""""""""""
+Example: swapping MPI providers
+"""""""""""""""""""""""""""""""
+
+Suppose that you need to build two software packages, ``packagea`` and
+``packageb``. ``packagea`` is Python 2-based and ``packageb`` is Python
+3-based. ``packagea`` only builds with OpenMPI and ``packageb`` only builds
+with MPICH. You can create different configuration scopes for use with
+``packagea`` and ``packageb``:
+
+.. code-block:: yaml
+ :caption: ~/myscopes/packgea/packages.yaml
+
+ packages:
+ python:
+ version: [2.7.11]
+ all:
+ providers:
+ mpi: [openmpi]
+
+.. code-block:: yaml
+ :caption: ~/myscopes/packageb/packages.yaml
+
+ packages:
+ python:
+ version: [3.5.2]
+ all:
+ providers:
+ mpi: [mpich]
+
+
.. _platform-scopes:
--------------------------
-Platform-specific scopes
--------------------------
-
-For each scope above, there can *also* be platform-specific settings.
-For example, on Blue Gene/Q machines, Spack needs to know the location
-of cross-compilers for the compute nodes. This configuration is in
-``etc/spack/defaults/bgq/compilers.yaml``. It will take precedence
-over settings in the ``defaults`` scope, but can still be overridden
-by settings in ``system``, ``system/bgq``, ``site``, ``site/bgq``,
-``user``, or ``user/bgq``. So, the full scope precedence is:
-
-1. ``defaults``
-2. ``defaults/<platform>``
-3. ``system``
-4. ``system/<platform>``
-5. ``site``
-6. ``site/<platform>``
-7. ``user``
-8. ``user/<platform>``
+------------------------
+Platform-specific Scopes
+------------------------
+
+For each scope above, there can also be platform-specific settings.
+For example, on most platforms, GCC is the preferred compiler.
+However, on macOS (darwin), Clang often works for more packages,
+and is set as the default compiler. This configuration is set in
+``$(prefix)/etc/spack/defaults/darwin/packages.yaml``. It will take
+precedence over settings in the ``defaults`` scope, but can still be
+overridden by settings in ``system``, ``system/darwin``, ``site``,
+``site/darwin``, ``user``, ``user/darwin``, ``custom``, or
+``custom/darwin``. So, the full scope precedence is:
+
+#. ``defaults``
+#. ``defaults/<platform>``
+#. ``system``
+#. ``system/<platform>``
+#. ``site``
+#. ``site/<platform>``
+#. ``user``
+#. ``user/<platform>``
+#. ``custom``
+#. ``custom/<platform>``
You can get the name to use for ``<platform>`` by running ``spack arch
--platform``. The system config scope has a ``<platform>`` section for
sites at which ``/etc`` is mounted on multiple heterogeneous machines.
--------------------------
-Scope precedence
--------------------------
+----------------
+Scope Precedence
+----------------
When spack queries for configuration parameters, it searches in
-higher-precedence scopes first. So, settings in a higher-precedence file
-can override those with the same key in a lower-precedence one. For
+higher-precedence scopes first. So, settings in a higher-precedence file
+can override those with the same key in a lower-precedence one. For
list-valued settings, Spack *prepends* higher-precedence settings to
lower-precedence settings. Completely ignoring higher-level configuration
options is supported with the ``::`` notation for keys (see
:ref:`config-overrides` below).
-^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^
Simple keys
-^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^
-Let's look at an example of overriding a single key in a Spack file. If
+Let's look at an example of overriding a single key in a Spack file. If
your configurations look like this:
-**defaults** scope:
-
.. code-block:: yaml
+ :caption: $(prefix)/etc/spack/defaults/config.yaml
config:
install_tree: $spack/opt/spack
module_roots:
- lmod: $spack/share/spack/lmod
+ lmod: $spack/share/spack/lmod
build_stage:
- $tempdir
- /nfs/tmp2/$user
-**site** scope:
.. code-block:: yaml
+ :caption: ~/.spack/config.yaml
config:
install_tree: /some/other/directory
+
Spack will only override ``install_tree`` in the ``config`` section, and
-will take the site preferences for other settings. You can see the
+will take the site preferences for other settings. You can see the
final, combined configuration with the ``spack config get <configtype>``
command:
@@ -155,11 +267,11 @@ command:
config:
install_tree: /some/other/directory
module_roots:
- lmod: $spack/share/spack/lmod
+ lmod: $spack/share/spack/lmod
build_stage:
- $tempdir
- /nfs/tmp2/$user
- $ _
+
.. _config-overrides:
@@ -167,14 +279,14 @@ command:
Overriding entire sections
^^^^^^^^^^^^^^^^^^^^^^^^^^
-Above, the site ``config.yaml`` only overrides specific settings in the
-default ``config.yaml``. Sometimes, it is useful to *completely*
-override lower-precedence settings. To do this, you can use *two* colons
-at the end of a key in a configuration file. For example, if the
-**site** ``config.yaml`` above looks like this:
+Above, the user ``config.yaml`` only overrides specific settings in the
+default ``config.yaml``. Sometimes, it is useful to *completely*
+override lower-precedence settings. To do this, you can use *two* colons
+at the end of a key in a configuration file. For example:
.. code-block:: yaml
:emphasize-lines: 1
+ :caption: ~/.spack/config.yaml
config::
install_tree: /some/other/directory
@@ -188,35 +300,36 @@ Spack will ignore all lower-precedence configuration under the
config:
install_tree: /some/other/directory
-^^^^^^^^^^^^^^^^^^^^^^
+
+^^^^^^^^^^^^^^^^^^^^
List-valued settings
-^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^
-Let's revisit the ``config.yaml`` example one more time. The
+Let's revisit the ``config.yaml`` example one more time. The
``build_stage`` setting's value is an ordered list of directories:
-**defaults**
-
.. code-block:: yaml
+ :caption: $(prefix)/etc/spack/defaults/config.yaml
build_stage:
- $tempdir
- /nfs/tmp2/$user
+
Suppose the user configuration adds its *own* list of ``build_stage``
paths:
-**user**
-
.. code-block:: yaml
+ :caption: ~/.spack/config.yaml
build_stage:
- /lustre-scratch/$user
- ~/mystage
-Spack will first look at the paths in the site ``config.yaml``, then the
-paths in the user's ``~/.spack/config.yaml``. The list in the
-higher-precedence scope is *prepended* to the defaults. ``spack config
+
+Spack will first look at the paths in the defaults ``config.yaml``, then the
+paths in the user's ``~/.spack/config.yaml``. The list in the
+higher-precedence scope is *prepended* to the defaults. ``spack config
get config`` shows the result:
.. code-block:: console
@@ -226,27 +339,27 @@ get config`` shows the result:
config:
install_tree: /some/other/directory
module_roots:
- lmod: $spack/share/spack/lmod
+ lmod: $spack/share/spack/lmod
build_stage:
- /lustre-scratch/$user
- ~/mystage
- $tempdir
- /nfs/tmp2/$user
- $ _
+
As in :ref:`config-overrides`, the higher-precedence scope can
-*completely* override the lower-precedence scope using `::`. So if the
+*completely* override the lower-precedence scope using ``::``. So if the
user config looked like this:
-**user**
-
.. code-block:: yaml
:emphasize-lines: 1
+ :caption: ~/.spack/config.yaml
build_stage::
- /lustre-scratch/$user
- ~/mystage
+
The merged configuration would look like this:
.. code-block:: console
@@ -256,57 +369,163 @@ The merged configuration would look like this:
config:
install_tree: /some/other/directory
module_roots:
- lmod: $spack/share/spack/lmod
+ lmod: $spack/share/spack/lmod
build_stage:
- /lustre-scratch/$user
- ~/mystage
- $ _
+
.. _config-file-variables:
-------------------------------
-Config file variables
-------------------------------
+---------------------
+Config File Variables
+---------------------
-Spack understands several variables which can be used in config file paths
-where ever they appear. There are three sets of these variables, Spack specific
-variables, environment variables, and user path variables. Spack specific
-variables and environment variables both are indicated by prefixing the variable
-name with ``$``. User path variables are indicated at the start of the path with
-``~`` or ``~user``. Let's discuss each in turn.
+Spack understands several variables which can be used in config file
+paths wherever they appear. There are three sets of these variables:
+Spack-specific variables, environment variables, and user path
+variables. Spack-specific variables and environment variables are both
+indicated by prefixing the variable name with ``$``. User path variables
+are indicated at the start of the path with ``~`` or ``~user``.
^^^^^^^^^^^^^^^^^^^^^^^^
-Spack Specific Variables
+Spack-specific variables
^^^^^^^^^^^^^^^^^^^^^^^^
Spack understands several special variables. These are:
- * ``$spack``: path to the prefix of this spack installation
- * ``$tempdir``: default system temporary directory (as specified in
- Python's `tempfile.tempdir
- <https://docs.python.org/2/library/tempfile.html#tempfile.tempdir>`_
- variable.
- * ``$user``: name of the current user
+* ``$spack``: path to the prefix of this Spack installation
+* ``$tempdir``: default system temporary directory (as specified in
+ Python's `tempfile.tempdir
+ <https://docs.python.org/2/library/tempfile.html#tempfile.tempdir>`_
+ variable.
+* ``$user``: name of the current user
Note that, as with shell variables, you can write these as ``$varname``
or with braces to distinguish the variable from surrounding characters:
-``${varname}``. Their names are also case insensitive meaning that ``$SPACK``
-works just as well as ``$spack``. These special variables are also
-substituted first, so any environment variables with the same name will not
-be used.
+``${varname}``. Their names are also case insensitive, meaning that
+``$SPACK`` works just as well as ``$spack``. These special variables are
+substituted first, so any environment variables with the same name will
+not be used.
+
+^^^^^^^^^^^^^^^^^^^^^
+Environment variables
+^^^^^^^^^^^^^^^^^^^^^
+
+After Spack-specific variables are evaluated, environment variables are
+expanded. These are formatted like Spack-specific variables, e.g.,
+``${varname}``. You can use this to insert environment variables in your
+Spack configuration.
^^^^^^^^^^^^^^^^^^^^^
-Environment Variables
+User home directories
^^^^^^^^^^^^^^^^^^^^^
-Spack then uses ``os.path.expandvars`` to expand any remaining environment
-variables.
+Spack performs Unix-style tilde expansion on paths in configuration
+files. This means that tilde (``~``) will expand to the current user's
+home directory, and ``~user`` will expand to a specified user's home
+directory. The ``~`` must appear at the beginning of the path, or Spack
+will not expand it.
+
+----------------------------
+Seeing Spack's Configuration
+----------------------------
+
+With so many scopes overriding each other, it can sometimes be difficult
+to understand what Spack's final configuration looks like.
-^^^^^^^^^^^^^^
-User Variables
-^^^^^^^^^^^^^^
+Spack provides two useful ways to view the final "merged" version of any
+configuration file: ``spack config get`` and ``spack config blame``.
+
+.. _cmd-spack-config-get:
+
+^^^^^^^^^^^^^^^^^^^^
+``spack config get``
+^^^^^^^^^^^^^^^^^^^^
+
+``spack config get`` shows a fully merged configuration file, taking into
+account all scopes. For example, to see the fully merged
+``config.yaml``, you can type:
+
+.. code-block:: console
+
+ $ spack config get config
+ config:
+ debug: false
+ checksum: true
+ verify_ssl: true
+ dirty: false
+ build_jobs: 8
+ install_tree: $spack/opt/spack
+ template_dirs:
+ - $spack/templates
+ directory_layout: ${ARCHITECTURE}/${COMPILERNAME}-${COMPILERVER}/${PACKAGE}-${VERSION}-${HASH}
+ module_roots:
+ tcl: $spack/share/spack/modules
+ lmod: $spack/share/spack/lmod
+ dotkit: $spack/share/spack/dotkit
+ build_stage:
+ - $tempdir
+ - /nfs/tmp2/$user
+ - $spack/var/spack/stage
+ source_cache: $spack/var/spack/cache
+ misc_cache: ~/.spack/cache
+ locks: true
+
+Likewise, this will show the fully merged ``packages.yaml``:
+
+.. code-block:: console
+
+ $ spack config get packages
+
+You can use this in conjunction with the ``-C`` / ``--config-scope`` argument to
+see how your scope will affect Spack's configuration:
+
+.. code-block:: console
+
+ $ spack -C /path/to/my/scope config get packages
+
+
+.. _cmd-spack-config-blame:
+
+^^^^^^^^^^^^^^^^^^^^^^
+``spack config blame``
+^^^^^^^^^^^^^^^^^^^^^^
+
+``spack config blame`` functions much like ``spack config get``, but it
+shows exactly which configuration file each preference came from. If you
+do not know why Spack is behaving a certain way, this can help you track
+down the problem:
+
+.. code-block:: console
-Spack also uses the ``os.path.expanduser`` function on the path to expand
-any user tilde paths such as ``~`` or ``~user``. These tilde paths must appear
-at the beginning of the path or ``os.path.expanduser`` will not properly
-expand them.
+ $ spack --insecure -C ./my-scope -C ./my-scope-2 config blame config
+ ==> Warning: You asked for --insecure. Will NOT check SSL certificates.
+ --- config:
+ _builtin debug: False
+ /home/myuser/spack/etc/spack/defaults/config.yaml:72 checksum: True
+ command_line verify_ssl: False
+ ./my-scope-2/config.yaml:2 dirty: False
+ _builtin build_jobs: 8
+ ./my-scope/config.yaml:2 install_tree: /path/to/some/tree
+ /home/myuser/spack/etc/spack/defaults/config.yaml:23 template_dirs:
+ /home/myuser/spack/etc/spack/defaults/config.yaml:24 - $spack/templates
+ /home/myuser/spack/etc/spack/defaults/config.yaml:28 directory_layout: ${ARCHITECTURE}/${COMPILERNAME}-${COMPILERVER}/${PACKAGE}-${VERSION}-${HASH}
+ /home/myuser/spack/etc/spack/defaults/config.yaml:32 module_roots:
+ /home/myuser/spack/etc/spack/defaults/config.yaml:33 tcl: $spack/share/spack/modules
+ /home/myuser/spack/etc/spack/defaults/config.yaml:34 lmod: $spack/share/spack/lmod
+ /home/myuser/spack/etc/spack/defaults/config.yaml:35 dotkit: $spack/share/spack/dotkit
+ /home/myuser/spack/etc/spack/defaults/config.yaml:49 build_stage:
+ /home/myuser/spack/etc/spack/defaults/config.yaml:50 - $tempdir
+ /home/myuser/spack/etc/spack/defaults/config.yaml:51 - /nfs/tmp2/$user
+ /home/myuser/spack/etc/spack/defaults/config.yaml:52 - $spack/var/spack/stage
+ /home/myuser/spack/etc/spack/defaults/config.yaml:57 source_cache: $spack/var/spack/cache
+ /home/myuser/spack/etc/spack/defaults/config.yaml:62 misc_cache: ~/.spack/cache
+ /home/myuser/spack/etc/spack/defaults/config.yaml:86 locks: True
+
+You can see above that the ``build_jobs`` and ``debug`` settings are
+built in and are not overridden by a configuration file. The
+``verify_ssl`` setting comes from the ``--insceure`` option on the
+command line. ``dirty`` and ``install_tree`` come from the custom
+scopes ``./my-scope`` and ``./my-scope-2``, and all other configuration
+options come from the default configuration files that ship with Spack.
diff --git a/lib/spack/docs/contribution_guide.rst b/lib/spack/docs/contribution_guide.rst
index 6ee55c2f66..11b826da13 100644
--- a/lib/spack/docs/contribution_guide.rst
+++ b/lib/spack/docs/contribution_guide.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _contribution-guide:
==================
@@ -34,13 +39,30 @@ Continuous Integration
Spack uses `Travis CI <https://travis-ci.org/spack/spack>`_ for Continuous Integration
testing. This means that every time you submit a pull request, a series of tests will
-be run to make sure you didn't accidentally introduce any bugs into Spack. Your PR
-will not be accepted until it passes all of these tests. While you can certainly wait
+be run to make sure you didn't accidentally introduce any bugs into Spack. **Your PR
+will not be accepted until it passes all of these tests.** While you can certainly wait
for the results of these tests after submitting a PR, we recommend that you run them
locally to speed up the review process.
+.. note::
+
+ Oftentimes, Travis will fail for reasons other than a problem with your PR.
+ For example, apt-get, pip, or homebrew will fail to download one of the
+ dependencies for the test suite, or a transient bug will cause the unit tests
+ to timeout. If Travis fails, click the "Details" link and click on the test(s)
+ that is failing. If it doesn't look like it is failing for reasons related to
+ your PR, you have two options. If you have write permissions for the Spack
+ repository, you should see a "Restart job" button on the right-hand side. If
+ not, you can close and reopen your PR to rerun all of the tests. If the same
+ test keeps failing, there may be a problem with your PR. If you notice that
+ every recent PR is failing with the same error message, it may be that Travis
+ is down or one of Spack's dependencies put out a new release that is causing
+ problems. If this is the case, please file an issue.
+
+
If you take a look in ``$SPACK_ROOT/.travis.yml``, you'll notice that we test
-against Python 2.6, 2.7, and 3.3-3.6. We currently perform 3 types of tests:
+against Python 2.6, 2.7, and 3.4-3.7 on both macOS and Linux. We currently
+perform 3 types of tests:
^^^^^^^^^^
Unit Tests
@@ -80,6 +102,13 @@ tests, run:
A more detailed list of available unit tests can be found by running
``spack test --long-list``.
+By default, ``pytest`` captures the output of all unit tests. If you add print
+statements to a unit test and want to see the output, simply run:
+
+.. code-block:: console
+
+ $ spack test -s -k architecture
+
Unit tests are crucial to making sure bugs aren't introduced into Spack. If you
are modifying core Spack libraries or adding new functionality, please consider
adding new unit tests or strengthening existing tests.
@@ -87,7 +116,7 @@ adding new unit tests or strengthening existing tests.
.. note::
There is also a ``run-unit-tests`` script in ``share/spack/qa`` that
- runs the unit tests. Afterwards, it reports back to Coverage with the
+ runs the unit tests. Afterwards, it reports back to Codecov with the
percentage of Spack that is covered by unit tests. This script is
designed for Travis CI. If you want to run the unit tests yourself, we
suggest you use ``spack test``.
@@ -154,20 +183,27 @@ However, if you aren't compliant with PEP 8, flake8 will complain:
Most of the error messages are straightforward, but if you don't understand what
they mean, just ask questions about them when you submit your PR. The line numbers
-will change if you add or delete lines, so simply run ``run-flake8-tests`` again
+will change if you add or delete lines, so simply run ``spack flake8`` again
to update them.
.. tip::
Try fixing flake8 errors in reverse order. This eliminates the need for
- multiple runs of ``flake8`` just to re-compute line numbers and makes it
- much easier to fix errors directly off of the Travis output.
+ multiple runs of ``spack flake8`` just to re-compute line numbers and
+ makes it much easier to fix errors directly off of the Travis output.
.. warning::
- Flake8 requires setuptools in order to run. If you installed ``py-flake8``
- with Spack, make sure to add ``py-setuptools`` to your ``PYTHONPATH``.
- Otherwise, you will get an error message like:
+ Flake8 and ``pep8-naming`` require a number of dependencies in order
+ to run. If you installed ``py-flake8`` and ``py-pep8-naming``, the
+ easiest way to ensure the right packages are on your ``PYTHONPATH`` is
+ to run::
+
+ spack activate py-flake8
+ spack activate pep8-naming
+
+ so that all of the dependencies are symlinked to a central
+ location. If you see an error message like:
.. code-block:: console
@@ -176,6 +212,8 @@ to update them.
from pkg_resources import load_entry_point
ImportError: No module named pkg_resources
+ that means Flake8 couldn't find setuptools in your ``PYTHONPATH``.
+
^^^^^^^^^^^^^^^^^^^
Documentation Tests
^^^^^^^^^^^^^^^^^^^
@@ -190,6 +228,7 @@ installed with Spack:
* sphinx
* sphinxcontrib-programoutput
+* sphinx-rtd-theme
* graphviz
* git
* mercurial
@@ -199,18 +238,25 @@ installed with Spack:
Sphinx has `several required dependencies <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-sphinx/package.py>`_.
If you installed ``py-sphinx`` with Spack, make sure to add all of these
- dependencies to your ``PYTHONPATH``. The easiest way to do this is to run
- ``spack activate py-sphinx`` so that all of the dependencies are symlinked
- to a central location. If you see an error message like:
+ dependencies to your ``PYTHONPATH``. The easiest way to do this is to run:
.. code-block:: console
- Traceback (most recent call last):
- File: "/usr/bin/flake8", line 5, in <module>
- from pkg_resources import load_entry_point
- ImportError: No module named pkg_resources
+ $ spack activate py-sphinx
+ $ spack activate py-sphinx-rtd-theme
+ $ spack activate py-sphinxcontrib-programoutput
- that means Sphinx couldn't find setuptools in your ``PYTHONPATH``.
+ so that all of the dependencies are symlinked to a central location.
+ If you see an error message like:
+
+ .. code-block:: console
+
+ Extension error:
+ Could not import extension sphinxcontrib.programoutput (exception: No module named sphinxcontrib.programoutput)
+ make: *** [html] Error 1
+
+ that means Sphinx couldn't find ``py-sphinxcontrib-programoutput`` in your
+ ``PYTHONPATH``.
Once all of the dependencies are installed, you can try building the documentation:
@@ -225,11 +271,11 @@ your PR is accepted.
.. note::
- There is also a ``run-doc-tests`` script in the Quality Assurance directory.
- The only difference between running this script and running ``make`` by hand
- is that the script will exit immediately if it encounters an error or warning.
- This is necessary for Travis CI. If you made a lot of documentation changes, it
- is much quicker to run ``make`` by hand so that you can see all of the warnings
+ There is also a ``run-doc-tests`` script in ``share/spack/qa``. The only
+ difference between running this script and running ``make`` by hand is that
+ the script will exit immediately if it encounters an error or warning. This
+ is necessary for Travis CI. If you made a lot of documentation changes, it is
+ much quicker to run ``make`` by hand so that you can see all of the warnings
at once.
If you are editing the documentation, you should obviously be running the
@@ -277,6 +323,37 @@ Documentation changes can result in much more obfuscated warning messages.
If you don't understand what they mean, feel free to ask when you submit
your PR.
+--------
+Coverage
+--------
+
+Spack uses `Codecov <https://codecov.io/>`_ to generate and report unit test
+coverage. This helps us tell what percentage of lines of code in Spack are
+covered by unit tests. Although code covered by unit tests can still contain
+bugs, it is much less error prone than code that is not covered by unit tests.
+
+Codecov provides `browser extensions <https://github.com/codecov/browser-extension>`_
+for Google Chrome, Firefox, and Opera. These extensions integrate with GitHub
+and allow you to see coverage line-by-line when viewing the Spack repository.
+If you are new to Spack, a great way to get started is to write unit tests to
+increase coverage!
+
+Unlike with Travis, Codecov tests are not required to pass in order for your
+PR to be merged. If you modify core Spack libraries, we would greatly
+appreciate unit tests that cover these changed lines. Otherwise, we have no
+way of knowing whether or not your changes introduce a bug. If you make
+substantial changes to the core, we may request unit tests to increase coverage.
+
+.. note::
+
+ If the only files you modified are package files, we do not care about
+ coverage on your PR. You may notice that the Codecov tests fail even though
+ you didn't modify any core files. This means that Spack's overall coverage
+ has increased since you branched off of develop. This is a good thing!
+ If you really want to get the Codecov tests to pass, you can rebase off of
+ the latest develop, but again, this is not required.
+
+
-------------
Git Workflows
-------------
diff --git a/lib/spack/docs/developer_guide.rst b/lib/spack/docs/developer_guide.rst
index 96b4436683..926d2a360d 100644
--- a/lib/spack/docs/developer_guide.rst
+++ b/lib/spack/docs/developer_guide.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _developer_guide:
===============
@@ -119,7 +124,7 @@ etc.) but we wanted to make Spack *very* easy to use. The simple layout
spares users from the need to install Spack into a Python environment.
Many users don't have write access to a Python installation, and installing
an entire new instance of Python to bootstrap Spack would be very complicated.
-Users should not have to install install a big, complicated package to
+Users should not have to install a big, complicated package to
use the thing that's supposed to spare them from the details of big,
complicated packages. The end result is that Spack works out of the
box: clone it and add ``bin`` to your PATH and you're ready to go.
@@ -314,7 +319,7 @@ See the `Argparse documentation <https://docs.python.org/2.7/library/argparse.ht
for more details on how to add arguments.
Some commands have a set of subcommands, like ``spack compiler find`` or
-``spack module refresh``. You can add subparsers to your parser to handle
+``spack module lmod refresh``. You can add subparsers to your parser to handle
this. Check out ``spack edit --command compiler`` for an example of this.
A lot of commands take the same arguments and flags. These arguments should
diff --git a/lib/spack/docs/docker_for_developers.rst b/lib/spack/docs/docker_for_developers.rst
new file mode 100644
index 0000000000..2f1b5a949a
--- /dev/null
+++ b/lib/spack/docs/docker_for_developers.rst
@@ -0,0 +1,41 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _docker_for_developers:
+
+=====================
+Docker for Developers
+=====================
+
+This guide is intended for people who want to use our prepared docker
+environments to work on developing Spack or working on spack packages. It is
+meant to serve as the companion documentation for the :ref:`packaging-guide`.
+
+--------
+Overview
+--------
+
+To get started, all you need is the latest version of ``docker``.
+
+.. code-block:: console
+
+ $ cd share/spack/docker
+ $ source config/ubuntu.bash
+ $ ./run-image.sh
+
+This command should drop you into an interactive shell where you can run spack
+within an isolated docker container running ubuntu. The copy of spack being
+used should be tied to the working copy of your cloned git repo, so any changes
+you make should be immediately reflected in the running docker container. Feel
+free to add or modify any packages or to hack on spack, itself. Your contained
+copy of spack should immediately reflect all changes.
+
+To work within a container running a different linux distro, source one of the
+other environment files under ``config``.
+
+.. code-block:: console
+
+ $ source config/fedora.bash
+ $ ./run-image.sh
diff --git a/lib/spack/docs/features.rst b/lib/spack/docs/features.rst
index 8d7c1ec0cd..dce20d51d6 100644
--- a/lib/spack/docs/features.rst
+++ b/lib/spack/docs/features.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
================
Feature Overview
================
@@ -126,7 +131,7 @@ It doesn't take much python coding to get from there to a working
package:
.. literalinclude:: ../../../var/spack/repos/builtin/packages/libelf/package.py
- :lines: 25-
+ :lines: 6-
Spack also provides wrapper functions around common commands like
``configure``, ``make``, and ``cmake`` to make writing packages
diff --git a/lib/spack/docs/getting_started.rst b/lib/spack/docs/getting_started.rst
index 9e59b28dac..8fd0840e35 100644
--- a/lib/spack/docs/getting_started.rst
+++ b/lib/spack/docs/getting_started.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _getting_started:
===============
@@ -11,7 +16,7 @@ Prerequisites
Spack has the following minimum requirements, which must be installed
before Spack is run:
-1. Python 2 (2.6 or 2.7) or 3 (3.3 - 3.6)
+1. Python 2 (2.6 or 2.7) or 3 (3.4 - 3.7)
2. A C/C++ compiler
3. The ``git`` and ``curl`` commands.
4. If using the ``gpg`` subcommand, ``gnupg2`` is required.
@@ -163,7 +168,7 @@ compilers`` or ``spack compiler list``:
Any of these compilers can be used to build Spack packages. More on
how this is done is in :ref:`sec-specs`.
-.. _spack-compiler-add:
+.. _cmd-spack-compiler-add:
^^^^^^^^^^^^^^^^^^^^^^
``spack compiler add``
@@ -171,7 +176,7 @@ how this is done is in :ref:`sec-specs`.
An alias for ``spack compiler find``.
-.. _spack-compiler-find:
+.. _cmd-spack-compiler-find:
^^^^^^^^^^^^^^^^^^^^^^^
``spack compiler find``
@@ -202,7 +207,14 @@ installed, but you know that new compilers have been added to your
This loads the environment module for gcc-4.9.0 to add it to
``PATH``, and then it adds the compiler to Spack.
-.. _spack-compiler-info:
+.. note::
+
+ By default, spack does not fill in the ``modules:`` field in the
+ ``compilers.yaml`` file. If you are using a compiler from a
+ module, then you should add this field manually.
+ See the section on :ref:`compilers-requiring-modules`.
+
+.. _cmd-spack-compiler-info:
^^^^^^^^^^^^^^^^^^^^^^^
``spack compiler info``
@@ -320,6 +332,7 @@ by adding the following to your ``packages.yaml`` file:
all:
compiler: [gcc@4.9.3]
+.. _compilers-requiring-modules:
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compilers Requiring Modules
@@ -484,6 +497,9 @@ simple package. For example:
$ spack install zlib%gcc@5.3.0
+
+.. _vendor-specific-compiler-configuration:
+
--------------------------------------
Vendor-Specific Compiler Configuration
--------------------------------------
@@ -805,7 +821,7 @@ encountered on a Macintosh during ``spack install julia-master``:
.. code-block:: console
- ==> Trying to clone git repository:
+ ==> Cloning git repository:
https://github.com/JuliaLang/julia.git
on branch master
Cloning into 'julia'...
@@ -816,7 +832,7 @@ This problem is related to OpenSSL, and in some cases might be solved
by installing a new version of ``git`` and ``openssl``:
#. Run ``spack install git``
-#. Add the output of ``spack module loads git`` to your ``.bashrc``.
+#. Add the output of ``spack module tcl loads git`` to your ``.bashrc``.
If this doesn't work, it is also possible to disable checking of SSL
certificates by using:
@@ -861,7 +877,7 @@ or alternately:
.. code-block:: console
- $ spack module loads curl >>~/.bashrc
+ $ spack module tcl loads curl >>~/.bashrc
or if environment modules don't work:
@@ -926,75 +942,38 @@ Once ``curl`` has been installed, you can similarly install the others.
Environment Modules
"""""""""""""""""""
-In order to use Spack's generated environment modules, you must have
-installed one of *Environment Modules* or *Lmod*. On many Linux
-distributions, this can be installed from the vendor's repository. For
-example: ``yum install environment-modules`` (Fedora/RHEL/CentOS). If
-your Linux distribution does not have Environment Modules, Spack can
-build it for you!
-
-What follows are three steps describing how to install and use environment-modules with spack.
-
-#. Install ``environment-modules``.
-
- * ``spack bootstrap`` will build ``environment-modules`` for you (and may build
- other packages that are useful to the operation of Spack)
-
- * Install ``environment-modules`` using ``spack install`` with
- ``spack install environment-modules~X`` (The ``~X`` variant builds without Xorg
- dependencies, but ``environment-modules`` works fine too.)
-
-#. Add ``modulecmd`` to ``PATH`` and create a ``module`` command.
-
- * If you are using ``bash`` or ``ksh``, Spack can currently do this for you as well.
- After installing ``environment-modules`` following the step
- above, source Spack's shell integration script. This will automatically
- detect the lack of ``modulecmd`` and ``module``, and use the installed
- ``environment-modules`` from ``spack bootstrap`` or ``spack install``.
-
- .. code-block:: console
-
- # For bash/zsh users
- $ export SPACK_ROOT=/path/to/spack
- $ . $SPACK_ROOT/share/spack/setup-env.sh
+In order to use Spack's generated module files, you must have
+installed ``environment-modules`` or ``lmod``. The simplest way
+to get the latest version of either of these tools is installing
+it as part of Spack's bootstrap procedure:
+.. code-block:: console
- * If you prefer to do it manually, you can activate with the following
- script (or apply the updates to your ``.bashrc`` file manually):
+ $ spack bootstrap
- .. code-block:: sh
+.. warning::
+ At the moment ``spack bootstrap`` is only able to install ``environment-modules``.
+ Extending its capabilities to prefer ``lmod`` where possible is in the roadmap,
+ and likely to happen before the next release.
- TMP=`tempfile`
- echo >$TMP
- MODULE_HOME=`spack location --install-dir environment-modules`
- MODULE_VERSION=`ls -1 $MODULE_HOME/Modules | head -1`
- ${MODULE_HOME}/Modules/${MODULE_VERSION}/bin/add.modules <$TMP
- cp .bashrc $TMP
- echo "MODULE_VERSION=${MODULE_VERSION}" > .bashrc
- cat $TMP >>.bashrc
+Alternatively, on many Linux distributions, you can install a pre-built binary
+from the vendor's repository. On Fedora/RHEL/CentOS, for example, this can be
+done with the command:
- This is added to your ``.bashrc`` (or similar) files, enabling Environment
- Modules when you log in.
-
-#. Test that the ``module`` command is found with:
+.. code-block:: console
- .. code-block:: console
+ $ yum install environment-modules
- $ module avail
+Once you have the tool installed and available in your path, you can source
+Spack's setup file:
+.. code-block:: console
-If ``tcl`` 8.0 or later is installed on your system, you can prevent
-spack from rebuilding ``tcl`` as part of the ``environment-modules`` dependency
-stack by adding the following to your ``~/.spack/packages.yaml`` replacing
-version 8.5 with whatever version is installed on your system:
+ $ source share/spack/setup-env.sh
- .. code-block:: yaml
+This activates :ref:`shell support <shell-support>` and makes commands like
+``spack load`` available for use.
- packages:
- tcl:
- paths:
- tcl@8.5: /usr
- buildable: False
^^^^^^^^^^^^^^^^^
Package Utilities
@@ -1096,6 +1075,37 @@ they may use packages you have signed using the ``--export <keyfile>`` flag.
Secret keys may also be later exported using the
``spack gpg export <location> [<key>...]`` command.
+.. note::
+
+ Key creation speed
+ The creation of a new GPG key requires generating a lot of random numbers.
+ Depending on the entropy produced on your system, the entire process may
+ take a long time (*even appearing to hang*). Virtual machines and cloud
+ instances are particularly likely to display this behavior.
+
+ To speed it up you may install tools like ``rngd``, which is
+ usually available as a package in the host OS. On e.g. an
+ Ubuntu machine you need to give the following commands:
+
+ .. code-block:: console
+
+ $ sudo apt-get install rng-tools
+ $ sudo rngd -r /dev/urandom
+
+ before generating the keys.
+
+ Another alternative is ``haveged``, which can be installed on
+ RHEL/CentOS machines as follows:
+
+ .. code-block:: console
+
+ $ sudo yum install haveged
+ $ sudo chkconfig haveged on
+
+ `This Digital Ocean tutorial
+ <https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged>`_
+ provides a good overview of sources of randomness.
+
^^^^^^^^^^^^
Listing keys
^^^^^^^^^^^^
@@ -1226,6 +1236,13 @@ cray-mpich module into the environment. You can then be able to use whatever
environment variables, libraries, etc, that are brought into the environment
via module load.
+.. note::
+
+ For Cray-provided packages, it is best to use ``modules:`` instead of ``paths:``
+ in ``packages.yaml``, because the Cray Programming Environment heavily relies on
+ modules (e.g., loading the ``cray-mpich`` module adds MPI libraries to the
+ compiler wrapper link line).
+
You can set the default compiler that Spack can use for each compiler type.
If you want to use the Cray defaults, then set them under ``all:`` in packages.yaml.
In the compiler field, set the compiler specs in your order of preference.
@@ -1262,3 +1279,17 @@ for each compiler type for each cray modules. This ensures that for each
compiler on our system we can use that external module.
For more on external packages check out the section :ref:`sec-external-packages`.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Using Linux containers on Cray machines
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Spack uses environment variables particular to the Cray programming
+environment to determine which systems are Cray platforms. These
+environment variables may be propagated into containers that are not
+using the Cray programming environment.
+
+To ensure that Spack does not autodetect the Cray programming
+environment, unset the environment variable ``CRAYPE_VERSION``. This
+will cause Spack to treat a linux container on a Cray system as a base
+linux distro.
diff --git a/lib/spack/docs/index.rst b/lib/spack/docs/index.rst
index 2ca737bb72..c2d8a28b89 100644
--- a/lib/spack/docs/index.rst
+++ b/lib/spack/docs/index.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. Spack documentation master file, created by
sphinx-quickstart on Mon Dec 9 15:32:41 2013.
You can adapt this file completely to your liking, but it should at least
@@ -73,7 +78,9 @@ or refer to the full manual below.
contribution_guide
packaging_guide
+ build_systems
developer_guide
+ docker_for_developers
Spack API Docs <spack>
LLNL API Docs <llnl>
diff --git a/lib/spack/docs/known_issues.rst b/lib/spack/docs/known_issues.rst
index c45ababc4f..9e64cd63b4 100644
--- a/lib/spack/docs/known_issues.rst
+++ b/lib/spack/docs/known_issues.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
============
Known Issues
============
@@ -5,38 +10,6 @@ Known Issues
This is a list of known bugs in Spack. It provides ways of getting around these
problems if you encounter them.
------------------------------------------------------------------
-Default variants are not taken into account during concretization
------------------------------------------------------------------
-
-**Status:** Expected to be fixed in the next release
-
-Current concretization algorithm does not take into account default values
-of variants when adding extra constraints to the spec via CLI. For example
-you may encounter the following error when trying to specify which MPI provider
-to use:
-
-.. code-block:: console
-
- $ spack install hdf5 ^openmpi
- ==> Error: hdf5 does not depend on openmpi
-
-although the hdf5 package contains:
-
-.. code-block:: python
-
- variant('mpi', default=True, description='Enable MPI support')
- depends_on('mpi', when='+mpi')
-
-A workaround is to explicitly activate the variant related to the dependency:
-
-.. code-block:: console
-
- $ spack install hdf5+mpi ^openmpi
-
-See https://github.com/spack/spack/issues/397 for further details.
-
-
---------------------------------------------------
Variants are not properly forwarded to dependencies
---------------------------------------------------
@@ -77,26 +50,6 @@ See https://github.com/spack/spack/issues/267 and
https://github.com/spack/spack/issues/2546 for further details.
----------------------------------
-``spack extensions`` doesn't work
----------------------------------
-
-**Status:** Up for grabs if you want to try to fix it
-
-Spack provides an ``extensions`` command that lists all available extensions
-of a package, the ones that are installed, and the ones that are already
-activated. This is very useful in conjunction with ``spack activate``.
-Unfortunately, this command no longer works:
-
-.. code-block:: console
-
- $ spack extensions python
- ==> python@2.7.13%clang@8.0.0-apple~tk~ucs4 arch=darwin-sierra-x86_64 -ckrr4mg has no extensions.
-
-
-See https://github.com/spack/spack/issues/2895 for further details.
-
-
----------------------------
``spack setup`` doesn't work
----------------------------
diff --git a/lib/spack/docs/mirrors.rst b/lib/spack/docs/mirrors.rst
index 4075421e12..d273e330d0 100644
--- a/lib/spack/docs/mirrors.rst
+++ b/lib/spack/docs/mirrors.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _mirrors:
=======
@@ -69,7 +74,7 @@ packages from the internet and checksumming them.
The other three commands are for managing mirror configuration. They
control the URL(s) from which Spack downloads its packages.
-.. _spack-mirror-create:
+.. _cmd-spack-mirror-create:
-----------------------
``spack mirror create``
@@ -154,7 +159,7 @@ can supply a file with specs in it, one per line:
This is useful if there is a specific suite of software managed by
your site.
-.. _spack-mirror-add:
+.. _cmd-spack-mirror-add:
--------------------
``spack mirror add``
@@ -166,7 +171,7 @@ a directory, you can use a file URL like this one:
.. code-block:: none
- file://~/spack-mirror-2014-06-24
+ file://$HOME/spack-mirror-2014-06-24
That points to the directory on the local filesystem. If it were on a
web server, you could use a URL like this one:
@@ -178,11 +183,11 @@ You can tell your Spack installation to use that mirror like this:
.. code-block:: console
- $ spack mirror add local_filesystem file://~/spack-mirror-2014-06-24
+ $ spack mirror add local_filesystem file://$HOME/spack-mirror-2014-06-24
Each mirror has a name so that you can refer to it again later.
-.. _spack-mirror-list:
+.. _cmd-spack-mirror-list:
---------------------
``spack mirror list``
@@ -193,9 +198,9 @@ To see all the mirrors Spack knows about, run ``spack mirror list``:
.. code-block:: console
$ spack mirror list
- local_filesystem file://~/spack-mirror-2014-06-24
+ local_filesystem file:///home/username/spack-mirror-2014-06-24
-.. _spack-mirror-remove:
+.. _cmd-spack-mirror-remove:
-----------------------
``spack mirror remove``
@@ -218,7 +223,7 @@ Adding a mirror really adds a line in ``~/.spack/mirrors.yaml``:
.. code-block:: yaml
mirrors:
- local_filesystem: file://~/spack-mirror-2014-06-24
+ local_filesystem: file:///home/username/spack-mirror-2014-06-24
remote_server: https://example.com/some/web-hosted/directory/spack-mirror-2014-06-24
If you want to change the order in which mirrors are searched for
diff --git a/lib/spack/docs/module_file_support.rst b/lib/spack/docs/module_file_support.rst
index 6b874fbe97..37dd03547f 100644
--- a/lib/spack/docs/module_file_support.rst
+++ b/lib/spack/docs/module_file_support.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _modules:
=======
@@ -113,8 +118,10 @@ Modules Dotkit
========================= ==========================
And you can use the same shortened names you use everywhere else in
-Spack. For example, this will add the ``mpich`` package built with
-``gcc`` to your path:
+Spack.
+
+For example, if you are using dotkit, this will add the ``mpich``
+package built with ``gcc`` to your path:
.. code-block:: console
@@ -122,16 +129,16 @@ Spack. For example, this will add the ``mpich`` package built with
# ... wait for install ...
- $ spack use mpich %gcc@4.4.7
+ $ spack use mpich %gcc@4.4.7 # dotkit
Prepending: mpich@3.0.4%gcc@4.4.7 (ok)
$ which mpicc
~/spack/opt/linux-debian7-x86_64/gcc@4.4.7/mpich@3.0.4/bin/mpicc
-Or, similarly with modules, you could type:
+Or, similarly if you are using modules, you could type:
.. code-block:: console
- $ spack load mpich %gcc@4.4.7
+ $ spack load mpich %gcc@4.4.7 # modules
These commands will add appropriate directories to your ``PATH``,
``MANPATH``, ``CPATH``, and ``LD_LIBRARY_PATH``. When you no longer
@@ -178,9 +185,9 @@ To identify just the one built with the Intel compiler.
.. _cmd-spack-module-loads:
-^^^^^^^^^^^^^^^^^^^^^^
-``spack module loads``
-^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+``spack module tcl loads``
+^^^^^^^^^^^^^^^^^^^^^^^^^^
In some cases, it is desirable to load not just a module, but also all
the modules it depends on. This is not required for most modules
@@ -193,21 +200,13 @@ Scripts to load modules recursively may be made with the command:
.. code-block:: console
- $ spack module loads --dependencies <spec>
+ $ spack module tcl loads --dependencies <spec>
An equivalent alternative using `process substitution <http://tldp.org/LDP/abs/html/process-sub.html>`_ is:
.. code-block :: console
- $ source <( spack module loads --dependencies <spec> )
-
-.. warning::
-
- The ``spack load`` command does not currently accept the
- ``--dependencies`` flag. Use ``spack module loads`` instead, for
- now.
-
-.. See #1662
+ $ source <( spack module tcl loads --dependencies <spec> )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,12 +216,12 @@ Module Commands for Shell Scripts
Although Spack is flexible, the ``module`` command is much faster.
This could become an issue when emitting a series of ``spack load``
commands inside a shell script. By adding the ``--shell`` flag,
-``spack module find`` may also be used to generate code that can be
+``spack module tcl find`` may also be used to generate code that can be
cut-and-pasted into a shell script. For example:
.. code-block:: console
- $ spack module loads --dependencies py-numpy git
+ $ spack module tcl loads --dependencies py-numpy git
# bzip2@1.0.6%gcc@4.9.3=linux-x86_64
module load bzip2-1.0.6-gcc-4.9.3-ktnrhkrmbbtlvnagfatrarzjojmkvzsx
# ncurses@6.0%gcc@4.9.3=linux-x86_64
@@ -262,9 +261,9 @@ Module Prefixes
^^^^^^^^^^^^^^^
On some systems, modules are automatically prefixed with a certain
-string; ``spack module loads`` needs to know about that prefix when it
+string; ``spack module tcl loads`` needs to know about that prefix when it
issues ``module load`` commands. Add the ``--prefix`` option to your
-``spack module loads`` commands if this is necessary.
+``spack module tcl loads`` commands if this is necessary.
For example, consider the following on one system:
@@ -273,11 +272,11 @@ For example, consider the following on one system:
$ module avail
linux-SuSE11-x86_64/antlr-2.7.7-gcc-5.3.0-bdpl46y
- $ spack module loads antlr # WRONG!
+ $ spack module tcl loads antlr # WRONG!
# antlr@2.7.7%gcc@5.3.0~csharp+cxx~java~python arch=linux-SuSE11-x86_64
module load antlr-2.7.7-gcc-5.3.0-bdpl46y
- $ spack module loads --prefix linux-SuSE11-x86_64/ antlr
+ $ spack module tcl loads --prefix linux-SuSE11-x86_64/ antlr
# antlr@2.7.7%gcc@5.3.0~csharp+cxx~java~python arch=linux-SuSE11-x86_64
module load linux-SuSE11-x86_64/antlr-2.7.7-gcc-5.3.0-bdpl46y
@@ -290,15 +289,15 @@ installation of a package. The table below summarizes the essential
information associated with the different file formats
that can be generated by Spack:
- +-----------------------------+--------------------+-------------------------------+----------------------------------+----------------------+
- | | **Hook name** | **Default root directory** | **Default template file** | **Compatible tools** |
- +=============================+====================+===============================+==================================+======================+
- | **Dotkit** | ``dotkit`` | share/spack/dotkit | templates/modules/modulefile.dk | DotKit |
- +-----------------------------+--------------------+-------------------------------+----------------------------------+----------------------+
- | **TCL - Non-Hierarchical** | ``tcl`` | share/spack/modules | templates/modules/modulefile.tcl | Env. Modules/LMod |
- +-----------------------------+--------------------+-------------------------------+----------------------------------+----------------------+
- | **Lua - Hierarchical** | ``lmod`` | share/spack/lmod | templates/modules/modulefile.lua | LMod |
- +-----------------------------+--------------------+-------------------------------+----------------------------------+----------------------+
+ +-----------------------------+--------------------+-------------------------------+----------------------------------------------+----------------------+
+ | | **Hook name** | **Default root directory** | **Default template file** | **Compatible tools** |
+ +=============================+====================+===============================+==============================================+======================+
+ | **Dotkit** | ``dotkit`` | share/spack/dotkit | share/spack/templates/modules/modulefile.dk | DotKit |
+ +-----------------------------+--------------------+-------------------------------+----------------------------------------------+----------------------+
+ | **TCL - Non-Hierarchical** | ``tcl`` | share/spack/modules | share/spack/templates/modules/modulefile.tcl | Env. Modules/LMod |
+ +-----------------------------+--------------------+-------------------------------+----------------------------------------------+----------------------+
+ | **Lua - Hierarchical** | ``lmod`` | share/spack/lmod | share/spack/templates/modules/modulefile.lua | LMod |
+ +-----------------------------+--------------------+-------------------------------+----------------------------------------------+----------------------+
Spack ships with sensible defaults for the generation of module files, but
@@ -485,6 +484,9 @@ you will prevent the generation of module files for any package that
is compiled with ``gcc@4.4.7``, with the only exception of any ``gcc``
or any ``llvm`` installation.
+
+.. _modules-naming-scheme:
+
"""""""""""""""""""""""""""
Customize the naming scheme
"""""""""""""""""""""""""""
@@ -629,39 +631,38 @@ The allowed values for the ``autoload`` statement are either ``none``,
Maintaining Module Files
------------------------
-Spack not only provides great flexibility in the generation of module files
-and in the customization of both their layout and content, but also ships with
-a tool to ease the burden of their maintenance in production environments.
-This tool is the ``spack module`` command:
+Each type of module file has a command with the same name associated
+with it. The actions these commands permit are usually associated
+with the maintenance of a production environment. Here's, for instance,
+a sample of the features of the ``spack module tcl`` command:
-.. command-output:: spack module --help
+.. command-output:: spack module tcl --help
.. _cmd-spack-module-refresh:
-^^^^^^^^^^^^^^^^^^^^^^^^
-``spack module refresh``
-^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Refresh the set of modules
+^^^^^^^^^^^^^^^^^^^^^^^^^^
-The command that regenerates module files to update their content or
-their layout is ``module refresh``:
+The subcommand that regenerates module files to update their content or
+their layout is ``refresh``:
-.. command-output:: spack module refresh --help
+.. command-output:: spack module tcl refresh --help
A set of packages can be selected using anonymous specs for the optional
-``constraint`` positional argument. The argument ``--module-type`` identifies
-the type of module files to refresh. Optionally the entire tree can be deleted
+``constraint`` positional argument. Optionally the entire tree can be deleted
before regeneration if the change in layout is radical.
.. _cmd-spack-module-rm:
^^^^^^^^^^^^^^^^^^^
-``spack module rm``
+Delete module files
^^^^^^^^^^^^^^^^^^^
If instead what you need is just to delete a few module files, then the right
-command is ``module rm``:
+subcommand is ``rm``:
-.. command-output:: spack module rm --help
+.. command-output:: spack module tcl rm --help
.. note::
We care about your module files!
diff --git a/lib/spack/docs/package_list.rst b/lib/spack/docs/package_list.rst
new file mode 100644
index 0000000000..f112525d52
--- /dev/null
+++ b/lib/spack/docs/package_list.rst
@@ -0,0 +1,17 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _package-list:
+
+============
+Package List
+============
+
+This is a list of things you can install using Spack. It is
+automatically generated based on the packages in the latest Spack
+release.
+
+.. raw:: html
+ :file: package_list.html
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index a066aa96df..17d7cffed4 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _packaging-guide:
===============
@@ -413,27 +418,26 @@ The most straightforward way to add new versions to your package is to
add a line like this in the package class:
.. code-block:: python
- :linenos:
class Foo(Package):
- url = 'http://example.com/foo-1.0.tar.gz'
+
+ url = "http://example.com/foo-1.0.tar.gz"
+
version('8.2.1', '4136d7b4c04df68b686570afa26988ac')
- ...
+ version('8.2.0', '1c9f62f0778697a09d36121ead88e08e')
+ version('8.1.2', 'd47dd09ed7ae6e7fd6f9a816d7f5fdf6')
-Versions should be listed with the newest version first.
+Versions should be listed in descending order, from newest to oldest.
^^^^^^^^^^^^^
Date Versions
^^^^^^^^^^^^^
If you wish to use dates as versions, it is best to use the format
-``@date-yyyy-mm-dd``. This will ensure they sort in the correct
-order. If you want your date versions to be numeric (assuming they
-don't conflict with other numeric versions), you can use just
-``yyyy.mm.dd``.
+``@yyyy-mm-dd``. This will ensure they sort in the correct order.
Alternately, you might use a hybrid release-version / date scheme.
-For example, ``@1.3.2016.08.31`` would mean the version from the
+For example, ``@1.3_2016-08-31`` would mean the version from the
``1.3`` branch, as of August 31, 2016.
^^^^^^^^^^^^
@@ -442,7 +446,7 @@ Version URLs
By default, each version's URL is extrapolated from the ``url`` field
in the package. For example, Spack is smart enough to download
-version ``8.2.1.`` of the ``Foo`` package above from
+version ``8.2.1`` of the ``Foo`` package above from
http://example.com/foo-8.2.1.tar.gz.
If the URL is particularly complicated or changes based on the release,
@@ -515,44 +519,28 @@ of its versions, you can add an explicit URL for a particular version:
When you supply a custom URL for a version, Spack uses that URL
-*verbatim* and does not perform extrapolation.
-
-^^^^^^^^^^^^^^^^^^^^^
-PyPI and version URLs
-^^^^^^^^^^^^^^^^^^^^^
-
-In addition to their developer websites, many python packages are hosted at the
-`Python Package Index (PyPi) <https://pypi.python.org/pypi>`_. Although links to
-these individual files are typically `generated using a hash
-<https://bitbucket.org/pypa/pypi/issues/438>`_ it is often possible to find a
-reliable link of the format
-
-.. code-block:: sh
+*verbatim* and does not perform extrapolation. The order of precedence
+of these methods is:
- https://pypi.python.org/packages/source/<first letter of package>/<package>/<package>-<version>.<extension>
+#. package-level ``url``
+#. ``url_for_version()``
+#. version-specific ``url``
-Packages hosted on GitHub and the like are often developer versions that do not
-contain all of the files (e.g. configuration scripts) necessary to support
-compilation. For this reason it is ideal to link to a repository such as PyPi
-if possible.
-
-More recently, sources are being indexed at `pypi.io <https://pypi.io>`_ as
-well. Links obtained from this site follow a similar pattern, namely
-
-.. code-block:: sh
-
- https://pypi.io/packages/source/<first letter of package>/<package>/<package>-<version>.<extension>
-
-These links currently redirect back to `pypi.python.org
-<https://pypi.python.org>`_, but this `may change in the future
-<https://bitbucket.org/pypa/pypi/issues/438#comment-27243225>`_.
+so if your package contains a ``url_for_version()``, it can be overridden
+by a version-specific ``url``.
+If your package does not contain a package-level ``url`` or ``url_for_version()``,
+Spack can determine which URL to download from even if only some of the versions
+specify their own ``url``. Spack will use the nearest URL *before* the requested
+version. This is useful for packages that have an easy to extrapolate URL, but
+keep changing their URL format every few releases. With this method, you only
+need to specify the ``url`` when the URL changes.
^^^^^^^^^^^^^^^^^^^^^^^^
Skipping the expand step
^^^^^^^^^^^^^^^^^^^^^^^^
-Spack normally expands archives (e.g. `*.tar.gz` and `*.zip`) automatically
+Spack normally expands archives (e.g. ``*.tar.gz`` and ``*.zip``) automatically
after downloading them. If you want to skip this step (e.g., for
self-extracting executables and other custom archive types), you can add
``expand=False`` to a ``version`` directive.
@@ -560,7 +548,7 @@ self-extracting executables and other custom archive types), you can add
.. code-block:: python
version('8.2.1', '4136d7b4c04df68b686570afa26988ac',
- url='http://example.com/foo-8.2.1-special-version.tar.gz', expand=False)
+ url='http://example.com/foo-8.2.1-special-version.sh', expand=False)
When ``expand`` is set to ``False``, Spack sets the current working
directory to the directory containing the downloaded archive before it
@@ -605,7 +593,7 @@ here will suffice; for example, ``@develop``, ``@master``, ``@local``.
The following rules determine the sort order of numeric
vs. non-numeric versions:
-#. The non-numeric versions ``@develop`` is considered greatest (newest).
+#. The non-numeric version ``@develop`` is considered greatest (newest).
#. Numeric versions are all less than ``@develop`` version, and are
sorted numerically.
@@ -617,7 +605,7 @@ The logic behind this sort order is two-fold:
#. Non-numeric versions are usually used for special cases while
developing or debugging a piece of software. Keeping most of them
- less than numeric versions ensures that Spack choose numeric
+ less than numeric versions ensures that Spack chooses numeric
versions by default whenever possible.
#. The most-recent development version of a package will usually be
@@ -652,34 +640,6 @@ use:
#. If all else fails and ``@develop`` is the only matching version, it
will be used.
-^^^^^^^^^^^^^
-``spack md5``
-^^^^^^^^^^^^^
-
-If you have one or more files to checksum, you can use the ``spack md5``
-command to do it:
-
-.. code-block:: console
-
- $ spack md5 foo-8.2.1.tar.gz foo-8.2.2.tar.gz
- ==> 2 MD5 checksums:
- 4136d7b4c04df68b686570afa26988ac foo-8.2.1.tar.gz
- 1586b70a49dfe05da5fcc29ef239dce0 foo-8.2.2.tar.gz
-
-``spack md5`` also accepts one or more URLs and automatically downloads
-the files for you:
-
-.. code-block:: console
-
- $ spack md5 http://example.com/foo-8.2.1.tar.gz
- ==> Trying to fetch from http://example.com/foo-8.2.1.tar.gz
- ######################################################################## 100.0%
- ==> 1 MD5 checksum:
- 4136d7b4c04df68b686570afa26988ac foo-8.2.1.tar.gz
-
-Doing this for lots of files, or whenever a new package version is
-released, is tedious. See ``spack checksum`` below for an automated
-version of this process.
.. _cmd-spack-checksum:
@@ -707,7 +667,7 @@ example for ``libelf``:
...
0.5.2 http://www.mr511.de/software/libelf-0.5.2.tar.gz
- How many would you like to checksum? (default is 5, q to abort)
+ How many would you like to checksum? (default is 1, q to abort)
This does the same thing that ``spack create`` does, but it allows you
to go back and add new versions easily as you need them (e.g., as
@@ -833,12 +793,12 @@ But its downloads are in many different subdirectories of
homepage = "http://www.mpich.org"
url = "http://www.mpich.org/static/downloads/3.0.4/mpich-3.0.4.tar.gz"
list_url = "http://www.mpich.org/static/downloads/"
- list_depth = 2
+ list_depth = 1
By default, Spack only looks at the top-level page available at
-``list_url``. ``list_depth`` tells it to follow up to 2 levels of
-links from the top-level page. Note that here, this implies two
-levels of subdirectories, as the ``mpich`` website is structured much
+``list_url``. ``list_depth = 1`` tells it to follow up to 1 level of
+links from the top-level page. Note that here, this implies 1
+level of subdirectories, as the ``mpich`` website is structured much
like a filesystem. But ``list_depth`` really refers to link depth
when spidering the page.
@@ -851,13 +811,57 @@ Fetching from code repositories
For some packages, source code is provided in a Version Control System
(VCS) repository rather than in a tarball. Spack can fetch packages
from VCS repositories. Currently, Spack supports fetching with `Git
-<git-fetch_>`_, `Mercurial (hg) <hg-fetch_>`_, and `Subversion (SVN)
-<svn-fetch_>`_.
+<git-fetch_>`_, `Mercurial (hg) <hg-fetch_>`_, `Subversion (svn)
+<svn-fetch_>`_, and `Go <go-fetch_>`_.
+
+To fetch a package from a source repository, Spack needs to know which
+VCS to use and where to download from. Much like with ``url``, package
+authors can specify a class-level ``git``, ``hg``, ``svn``, or ``go``
+attribute containing the correct download location.
+
+Many packages developed with Git have both a Git repository as well as
+release tarballs available for download. Packages can define both a
+class-level tarball URL and VCS. For example:
+
+.. code-block:: python
+
+ class Trilinos(CMakePackage):
+
+ homepage = "https://trilinos.org/"
+ url = "https://github.com/trilinos/Trilinos/archive/trilinos-release-12-12-1.tar.gz"
+ git = "https://github.com/trilinos/Trilinos.git"
+
+ version('develop', branch='develop')
+ version('master', branch='master')
+ version('12.12.1', 'ecd4606fa332212433c98bf950a69cc7')
+ version('12.10.1', '667333dbd7c0f031d47d7c5511fd0810')
+ version('12.8.1', '9f37f683ee2b427b5540db8a20ed6b15')
+
+If a package contains both a ``url`` and ``git`` class-level attribute,
+Spack decides which to use based on the arguments to the ``version()``
+directive. Versions containing a specific branch, tag, or revision are
+assumed to be for VCS download methods, while versions containing a
+checksum are assumed to be for URL download methods.
+
+Like ``url``, if a specific version downloads from a different repository
+than the default repo, it can be overridden with a version-specific argument.
+
+.. note::
+
+ In order to reduce ambiguity, each package can only have a single VCS
+ top-level attribute in addition to ``url``. In the rare case that a
+ package uses multiple VCS, a fetch strategy can be specified for each
+ version. For example, the ``rockstar`` package contains:
+
+ .. code-block:: python
+
+ class Rockstar(MakefilePackage):
+
+ homepage = "https://bitbucket.org/gfcstanford/rockstar"
+
+ version('develop', git='https://bitbucket.org/gfcstanford/rockstar.git')
+ version('yt', hg='https://bitbucket.org/MatthewTurk/rockstar')
-To fetch a package from a source repository, you add a ``version()``
-call to your package with parameters indicating the repository URL and
-any branch, tag, or revision to fetch. See below for the parameters
-you'll need for each VCS system.
.. _git-fetch:
@@ -865,11 +869,11 @@ you'll need for each VCS system.
Git
^^^
-Git fetching is enabled with the following parameters to ``version``:
+Git fetching supports the following parameters to ``version``:
-* ``git``: URL of the git repository.
-* ``tag``: name of a tag to fetch.
-* ``branch``: name of a branch to fetch.
+* ``git``: URL of the git repository, if different than the class-level ``git``.
+* ``branch``: Name of a branch to fetch.
+* ``tag``: Name of a tag to fetch.
* ``commit``: SHA hash (or prefix) of a commit to fetch.
* ``submodules``: Also fetch submodules recursively when checking out this repository.
@@ -881,66 +885,72 @@ Default branch
.. code-block:: python
class Example(Package):
- ...
- version('develop', git='https://github.com/example-project/example.git')
- This download method is untrusted, and is not recommended.
+ git = "https://github.com/example-project/example.git"
-Tags
- To fetch from a particular tag, use the ``tag`` parameter along with
- ``git``:
+ version('develop')
+
+ This download method is untrusted, and is not recommended. Aside from HTTPS,
+ there is no way to verify that the repository has not been compromised, and
+ the commit you get when you install the package likely won't be the same
+ commit that was used when the package was first written. Additionally, the
+ default branch may change. It is best to at least specify a branch name.
+
+Branches
+ To fetch a particular branch, use the ``branch`` parameter:
.. code-block:: python
- version('1.0.1', git='https://github.com/example-project/example.git',
- tag='v1.0.1')
+ version('experimental', branch='experimental')
- This download method is untrusted, and is not recommended.
+ This download method is untrusted, and is not recommended. Branches are
+ moving targets, so the commit you get when you install the package likely
+ won't be the same commit that was used when the package was first written.
-Branches
- To fetch a particular branch, use ``branch`` instead:
+Tags
+ To fetch from a particular tag, use ``tag`` instead:
.. code-block:: python
- version('experimental', git='https://github.com/example-project/example.git',
- branch='experimental')
+ version('1.0.1', tag='v1.0.1')
- This download method is untrusted, and is not recommended.
+ This download method is untrusted, and is not recommended. Although tags
+ are generally more stable than branches, Git allows tags to be moved.
+ Many developers use tags to denote rolling releases, and may move the
+ tag when a bug is patched.
Commits
Finally, to fetch a particular commit, use ``commit``:
.. code-block:: python
- version('2014-10-08', git='https://github.com/example-project/example.git',
- commit='9d38cd4e2c94c3cea97d0e2924814acc')
+ version('2014-10-08', commit='9d38cd4e2c94c3cea97d0e2924814acc')
This doesn't have to be a full hash; you can abbreviate it as you'd
expect with git:
.. code-block:: python
- version('2014-10-08', git='https://github.com/example-project/example.git',
- commit='9d38cd')
+ version('2014-10-08', commit='9d38cd')
This download method *is trusted*. It is the recommended way to
securely download from a Git repository.
It may be useful to provide a saner version for commits like this,
- e.g. you might use the date as the version, as done above. Or you
- could just use the abbreviated commit hash. It's up to the package
- author to decide what makes the most sense.
+ e.g. you might use the date as the version, as done above. Or, if you
+ know the commit at which a release was cut, you can use the release
+ version. It's up to the package author to decide what makes the most
+ sense. Although you can use the commit hash as the version number,
+ this is not recommended, as it won't sort properly.
Submodules
-
You can supply ``submodules=True`` to cause Spack to fetch submodules
recursively along with the repository at fetch time. For more information
about git submodules see the manpage of git: ``man git-submodule``.
.. code-block:: python
- version('1.0.1', git='https://github.com/example-project/example.git',
- tag='v1.0.1', submodules=True)
+ version('1.0.1', tag='v1.0.1', submodules=True)
.. _github-fetch:
@@ -949,7 +959,7 @@ Submodules
GitHub
^^^^^^
-If a project is hosted on GitHub, *any* valid Git branch, tag or hash
+If a project is hosted on GitHub, *any* valid Git branch, tag, or hash
may be downloaded as a tarball. This is accomplished simply by
constructing an appropriate URL. Spack can checksum any package
downloaded this way, thereby producing a trusted download. For
@@ -959,7 +969,7 @@ checksum.
.. code-block:: python
version('1.9.5.1.1', 'd035e4bc704d136db79b43ab371b27d2',
- url='https://www.github.com/jswhit/pyproj/tarball/0be612cc9f972e38b50a90c946a9b353e2ab140f')
+ url='https://www.github.com/jswhit/pyproj/tarball/0be612cc9f972e38b50a90c946a9b353e2ab140f')
.. _hg-fetch:
@@ -967,34 +977,38 @@ checksum.
Mercurial
^^^^^^^^^
-Fetching with mercurial works much like `git <git-fetch>`_, but you
+Fetching with Mercurial works much like `Git <git-fetch>`_, but you
use the ``hg`` parameter.
-Default
- Add the ``hg`` parameter with no ``revision``:
+Default branch
+ Add the ``hg`` attribute with no ``revision`` passed to ``version``:
.. code-block:: python
- version('develop', hg='https://jay.grs.rwth-aachen.de/hg/example')
+ class Example(Package):
- This download method is untrusted, and is not recommended.
+ hg = "https://bitbucket.org/example-project/example"
+
+ version('develop')
+
+ This download method is untrusted, and is not recommended. As with
+ Git's default fetching strategy, there is no way to verify the
+ integrity of the download.
Revisions
- Add ``hg`` and ``revision`` parameters:
+ To fetch a particular revision, use the ``revision`` parameter:
.. code-block:: python
- version('1.0', hg='https://jay.grs.rwth-aachen.de/hg/example',
- revision='v1.0')
-
- This download method is untrusted, and is not recommended.
+ version('1.0', revision='v1.0')
Unlike ``git``, which has special parameters for different types of
revisions, you can use ``revision`` for branches, tags, and commits
- when you fetch with Mercurial.
+ when you fetch with Mercurial. Like Git, fetching specific branches
+ or tags is an untrusted download method, and is not recommended.
+ The recommended fetch strategy is to specify a particular commit
+ hash as the revision.
-As with git, you can fetch these versions using the ``spack install
-example@<version>`` command-line syntax.
.. _svn-fetch:
@@ -1002,34 +1016,70 @@ example@<version>`` command-line syntax.
Subversion
^^^^^^^^^^
-To fetch with subversion, use the ``svn`` and ``revision`` parameters:
+To fetch with subversion, use the ``svn`` and ``revision`` parameters.
Fetching the head
- Simply add an ``svn`` parameter to ``version``:
+ Simply add an ``svn`` parameter to the package:
.. code-block:: python
- version('develop', svn='https://outreach.scidac.gov/svn/libmonitor/trunk')
+ class Example(Package):
- This download method is untrusted, and is not recommended.
+ svn = "https://outreach.scidac.gov/svn/example/trunk"
+
+ version('develop')
+
+ This download method is untrusted, and is not recommended for the
+ same reasons as mentioned above.
Fetching a revision
- To fetch a particular revision, add a ``revision`` to the
- version call:
+ To fetch a particular revision, add a ``revision`` argument to the
+ version directive:
.. code-block:: python
- version('develop', svn='https://outreach.scidac.gov/svn/libmonitor/trunk',
- revision=128)
+ version('develop', revision=128)
This download method is untrusted, and is not recommended.
+ Unfortunately, Subversion has no commit hashing scheme like Git and
+ Mercurial do, so there is no way to guarantee that the download you
+ get is the same as the download used when the package was created.
+ Use at your own risk.
+
Subversion branches are handled as part of the directory structure, so
-you can check out a branch or tag by changing the ``url``.
+you can check out a branch or tag by changing the URL. If you want to
+package multiple branches, simply add a ``svn`` argument to each
+version directive.
+
+.. _go-fetch:
--------------------------------------------------
+^^
+Go
+^^
+
+Go isn't a VCS, it is a programming language with a builtin command,
+`go get <https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies>`_,
+that fetches packages and their dependencies automatically.
+It can clone a Git repository, or download from another source location.
+For example:
+
+.. code-block:: python
+
+ class ThePlatinumSearcher(Package):
+
+ homepage = "https://github.com/monochromegane/the_platinum_searcher"
+ go = "github.com/monochromegane/the_platinum_searcher/..."
+
+ version('head')
+
+Go cannot be used to fetch a particular commit or branch, it always
+downloads the head of the repository. This download method is untrusted,
+and is not recommended. Use another fetch strategy whenever possible.
+
+------------------------------------
Resources (expanding extra tarballs)
--------------------------------------------------
+------------------------------------
Some packages (most notably compilers) provide optional features if additional
resources are expanded within their source tree before building. In Spack it is
@@ -1593,6 +1643,14 @@ correct way to specify this would be:
depends_on('python@2.6.0:2.6.999')
+A spec can contain multiple version ranges separated by commas.
+For example, if you need Boost 1.59.0 or newer, but there are known
+issues with 1.64.0, 1.65.0, and 1.66.0, you can say:
+
+.. code-block:: python
+
+ depends_on('boost@1.59.0:1.63,1.65.1,1.67.0:')
+
^^^^^^^^^^^^^^^^
Dependency types
@@ -1874,18 +1932,38 @@ from being linked in at activation time.
``depends_on('python')`` and ``extends(python)`` in the same
package. ``extends`` implies ``depends_on``.
+-----
+Views
+-----
+
+As covered in :ref:`filesystem-views`, the ``spack view`` command can be
+used to symlink a number of packages into a merged prefix. The methods of
+``PackageViewMixin`` can be overridden to customize how packages are added
+to views. Generally this can be used to create copies of specific files rather
+than symlinking them when symlinking does not work. For example, ``Python``
+overrides ``add_files_to_view`` in order to create a copy of the ``python``
+binary since the real path of the Python executable is used to detect
+extensions; as a consequence python extension packages (those inheriting from
+``PythonPackage``) likewise override ``add_files_to_view`` in order to rewrite
+shebang lines which point to the Python interpreter.
+
^^^^^^^^^^^^^^^^^^^^^^^^^
Activation & deactivation
^^^^^^^^^^^^^^^^^^^^^^^^^
+Adding an extension to a view is referred to as an activation. If the view is
+maintained in the Spack installation prefix of the extendee this is called a
+global activation. Activations may involve updating some centralized state
+that is maintained by the extendee package, so there can be additional work
+for adding extensions compared with non-extension packages.
+
Spack's ``Package`` class has default ``activate`` and ``deactivate``
implementations that handle symbolically linking extensions' prefixes
-into the directory of the parent package. However, extendable
-packages can override these methods to add custom activate/deactivate
-logic of their own. For example, the ``activate`` and ``deactivate``
-methods in the Python class use the symbolic linking, but they also
-handle details surrounding Python's ``.pth`` files, and other aspects
-of Python packaging.
+into a specified view. Extendable packages can override these methods
+to add custom activate/deactivate logic of their own. For example,
+the ``activate`` and ``deactivate`` methods in the Python class handle
+symbolic linking of extensions, but they also handle details surrounding
+Python's ``.pth`` files, and other aspects of Python packaging.
Spack's extensions mechanism is designed to be extensible, so that
other packages (like Ruby, R, Perl, etc.) can provide their own
@@ -1900,7 +1978,7 @@ Let's look at Python's activate function:
This function is called on the *extendee* (Python). It first calls
``activate`` in the superclass, which handles symlinking the
-extension package's prefix into this package's prefix. It then does
+extension package's prefix into the specified view. It then does
some special handling of the ``easy-install.pth`` file, part of
Python's setuptools.
@@ -2268,6 +2346,10 @@ The classes that are currently provided by Spack are:
| :py:class:`.CMakePackage` | Specialized class for packages |
| | built using CMake |
+-------------------------------+----------------------------------+
+ | :py:class:`.CudaPackage` | A helper class for packages that |
+ | | use CUDA. It is intended to be |
+ | | used in combination with others |
+ +-------------------------------+----------------------------------+
| :py:class:`.QMakePackage` | Specialized class for packages |
| | build using QMake |
+-------------------------------+----------------------------------+
@@ -2280,6 +2362,9 @@ The classes that are currently provided by Spack are:
| :py:class:`.RPackage` | Specialized class for |
| | :py:class:`.R` extensions |
+-------------------------------+----------------------------------+
+ | :py:class:`.OctavePackage` | Specialized class for |
+ | | :py:class:`.Octave` packages |
+ +-------------------------------+----------------------------------+
| :py:class:`.PythonPackage` | Specialized class for |
| | :py:class:`.Python` extensions |
+-------------------------------+----------------------------------+
@@ -2607,15 +2692,16 @@ as arguments.
Here are the definitions of the three built-in flag handlers:
-.. code-block:: python
+ def build_system_flags(self, name, flags):
+ return (None, None, flags)
- def inject_flags(self, name, flags):
+ def inject_flags(pkg, name, flags):
return (flags, None, None)
- def env_flags(self, name, flags):
+ def env_flags(pkg, name, flags):
return (None, flags, None)
- def build_system_flags(self, name, flags):
+ def build_system_flags(pkg, name, flags):
return (None, None, flags)
.. note::
@@ -2628,10 +2714,7 @@ the built-in flag handlers,
.. code-block:: python
- flag_handler = <PackageClass>.env_flags
-
-where ``<PackageClass>`` can be any of the subclasses of PackageBase
-discussed in :ref:`installation_procedure`,
+ flag_handler = env_flags
or by implementing the flag_handler method. Suppose for a package
``Foo`` we need to pass ``cflags``, ``cxxflags``, and ``cppflags``
@@ -2657,7 +2740,7 @@ method of the ``EnvironmentModifications`` class to append values to a
list of flags whenever the flag handler is ``env_flags``. If the
package passes flags through the environment or the build system
manually (in the install method, for example), we recommend using the
-default flag handler, or removind manual references and implementing a
+default flag handler, or removing manual references and implementing a
custom flag handler method that adds the desired flags to export as
environment variables or pass to the build system. Manual flag passing
is likely to interfere with the ``env_flags`` and
@@ -2667,8 +2750,8 @@ In rare circumstances such as compiling and running small unit tests, a
package developer may need to know what are the appropriate compiler
flags to enable features like ``OpenMP``, ``c++11``, ``c++14`` and
alike. To that end the compiler classes in ``spack`` implement the
-following **properties**: ``openmp_flag``, ``cxx11_flag``,
-``cxx14_flag``, which can be accessed in a package by
+following **properties**: ``openmp_flag``, ``cxx98_flag``, ``cxx11_flag``,
+``cxx14_flag``, and ``cxx17_flag``, which can be accessed in a package by
``self.compiler.cxx11_flag`` and alike. Note that the implementation is
such that if a given compiler version does not support this feature, an
error will be produced. Therefore package developers can also use these
@@ -2679,6 +2762,8 @@ is handy when a package supports additional variants like
variant('openmp', default=True, description="Enable OpenMP support.")
+.. _blas_lapack_scalapack:
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Blas, Lapack and ScaLapack libraries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -2776,11 +2861,11 @@ Prefix Attribute Location
Of course, this only works if your file or directory is a valid Python
variable name. If your file or directory contains dashes or dots, use
-``join_path`` instead:
+``join`` instead:
.. code-block:: python
- join_path(prefix.lib, 'libz.a')
+ prefix.lib.join('libz.a')
.. _spec-objects:
diff --git a/lib/spack/docs/repositories.rst b/lib/spack/docs/repositories.rst
index 5e722e2139..699fe4a7ed 100644
--- a/lib/spack/docs/repositories.rst
+++ b/lib/spack/docs/repositories.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _repositories:
=============================
@@ -36,7 +41,7 @@ Package repositories allow you to:
1. Maintain your own packages separately from Spack;
-2. Share your packages (e.g. by hosting them in a shared file system),
+2. Share your packages (e.g., by hosting them in a shared file system),
without committing them to the built-in Spack package repository; and
3. Override built-in Spack packages with your own implementation.
@@ -72,7 +77,7 @@ paths to repositories. Each path is on a separate line starting with
- /opt/local-repo
- $spack/var/spack/repos/builtin
-When Spack interprets a spec, e.g. ``mpich`` in ``spack install mpich``,
+When Spack interprets a spec, e.g., ``mpich`` in ``spack install mpich``,
it searches these repositories in order (first to last) to resolve each
package name. In this example, Spack will look for the following
packages and use the first valid file:
@@ -142,7 +147,7 @@ packages created by the Computation directorate might use ``llnl.comp``.
Spack cannot ensure that every repository is named uniquely, but it will
prevent you from registering two repositories with the same namespace at
the same time. If you try to add a repository that has the same name as
-an existing one, e.g. ``builtin``, Spack will print a warning message.
+an existing one, e.g., ``builtin``, Spack will print a warning message.
.. _namespace-example:
@@ -445,7 +450,7 @@ Spack repo namespaces are actually Python namespaces tacked on under
``spack.pkg``. The search semantics of ``repos.yaml`` are actually
implemented using Python's built-in `sys.path
<https://docs.python.org/2/library/sys.html#sys.path>`_ search. The
-:py:mod:`spack.repository` module implements a custom `Python importer
+:py:mod:`spack.repo` module implements a custom `Python importer
<https://docs.python.org/2/library/imp.html>`_.
.. warning::
diff --git a/lib/spack/docs/requirements.txt b/lib/spack/docs/requirements.txt
index d3fe0d18d7..592060a89e 100644
--- a/lib/spack/docs/requirements.txt
+++ b/lib/spack/docs/requirements.txt
@@ -1,5 +1,6 @@
# These dependencies should be installed using pip in order
# to build the documentation.
-sphinx
+sphinx==1.7.0
sphinxcontrib-programoutput
+sphinx-rtd-theme
diff --git a/lib/spack/docs/tutorial.rst b/lib/spack/docs/tutorial.rst
index ff2a2f6870..c41f8c87d2 100644
--- a/lib/spack/docs/tutorial.rst
+++ b/lib/spack/docs/tutorial.rst
@@ -1,12 +1,17 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _spack-101:
=============================
Tutorial: Spack 101
=============================
-This is a 3-hour introduction to Spack with lectures and live demos. It
-was presented as a tutorial at `Supercomputing 2016
-<http://sc16.supercomputing.org>`_. You can use these materials to teach
+This is a full-day introduction to Spack with lectures and live demos. It
+was presented as a tutorial at `Supercomputing 2018
+<http://sc18.supercomputing.org>`_. You can use these materials to teach
a course on Spack at your own site, or you can just skip ahead and read
the live demo scripts to see how Spack is used in practice.
@@ -15,19 +20,18 @@ the live demo scripts to see how Spack is used in practice.
.. rubric:: Slides
.. figure:: tutorial/sc16-tutorial-slide-preview.png
- :target: http://llnl.github.io/spack/files/Spack-SC16-Tutorial.pdf
+ :target: http://spack.io/slides/Spack-SC18-Tutorial.pdf
:height: 72px
:align: left
:alt: Slide Preview
-`Download Slides <http://llnl.github.io/spack/files/Spack-SC16-Tutorial.pdf>`_.
+`Download Slides <http://spack.io/slides/Spack-SC18-Tutorial.pdf>`_.
-**Full citation:** Todd Gamblin, Massimiliano Culpo, Gregory Becker, Matt
-Legendre, Greg Lee, Elizabeth Fischer, and Benedikt Hegner.
+**Full citation:** Todd Gamblin, Gregory Becker, Massimiliano Culpo, Matt
+Legendre, Mario Melara, Peter Scheibel, and Adam Stewart.
`Managing HPC Software Complexity with Spack
-<http://sc16.supercomputing.org/presentation/?id=tut166&sess=sess209>`_.
-Tutorial presented at Supercomputing 2016. November 13, 2016, Salt Lake
-City, UT, USA.
+<https://sc18.supercomputing.org/presentation/?id=tut165&sess=sess252>`_.
+Tutorial presented at Supercomputing 2018. November 12, 2018, Dallas, TX, USA.
.. _sc16-live-demos:
@@ -39,9 +43,10 @@ correspond to sections in the slides above.
1. :ref:`basics-tutorial`
2. :ref:`configs-tutorial`
3. :ref:`packaging-tutorial`
- 4. :ref:`build-systems-tutorial`
- 5. :ref:`advanced-packaging-tutorial`
- 6. :ref:`modules-tutorial`
+ 4. :ref:`environments-tutorial`
+ 5. :ref:`modules-tutorial`
+ 6. :ref:`build-systems-tutorial`
+ 7. :ref:`advanced-packaging-tutorial`
Full contents:
@@ -49,6 +54,7 @@ Full contents:
tutorial_basics
tutorial_configuration
tutorial_packaging
+ tutorial_environments
+ tutorial_modules
tutorial_buildsystems
tutorial_advanced_packaging
- tutorial_modules
diff --git a/lib/spack/docs/tutorial/examples/0.package.py b/lib/spack/docs/tutorial/examples/0.package.py
index 0a42cdc802..cdc8f6a6e4 100644
--- a/lib/spack/docs/tutorial/examples/0.package.py
+++ b/lib/spack/docs/tutorial/examples/0.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
#
# This is a template package file for Spack. We've put "FIXME"
# next to all the things you'll want to change. Once you've handled
diff --git a/lib/spack/docs/tutorial/examples/1.package.py b/lib/spack/docs/tutorial/examples/1.package.py
index 308779d016..a6af7ed3e4 100644
--- a/lib/spack/docs/tutorial/examples/1.package.py
+++ b/lib/spack/docs/tutorial/examples/1.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/2.package.py b/lib/spack/docs/tutorial/examples/2.package.py
index 7980768e06..c2687a95cd 100644
--- a/lib/spack/docs/tutorial/examples/2.package.py
+++ b/lib/spack/docs/tutorial/examples/2.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/3.package.py b/lib/spack/docs/tutorial/examples/3.package.py
index b30dd900ae..1a9d76f050 100644
--- a/lib/spack/docs/tutorial/examples/3.package.py
+++ b/lib/spack/docs/tutorial/examples/3.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/4.package.py b/lib/spack/docs/tutorial/examples/4.package.py
index 116a11a0fa..c90c14b836 100644
--- a/lib/spack/docs/tutorial/examples/4.package.py
+++ b/lib/spack/docs/tutorial/examples/4.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/5.package.py b/lib/spack/docs/tutorial/examples/5.package.py
index 3e7a1f83cb..18cb846d34 100644
--- a/lib/spack/docs/tutorial/examples/5.package.py
+++ b/lib/spack/docs/tutorial/examples/5.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/Autotools/0.package.py b/lib/spack/docs/tutorial/examples/Autotools/0.package.py
index 44a157b36a..b9d2f2ca43 100644
--- a/lib/spack/docs/tutorial/examples/Autotools/0.package.py
+++ b/lib/spack/docs/tutorial/examples/Autotools/0.package.py
@@ -1,31 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
-class Mpileaks(AutoToolsPackage):
+class Mpileaks(AutotoolsPackage):
"""Tool to detect and report leaked MPI objects like MPI_Requests and
MPI_Datatypes."""
diff --git a/lib/spack/docs/tutorial/examples/Autotools/1.package.py b/lib/spack/docs/tutorial/examples/Autotools/1.package.py
index bc12c70b7f..cebe14f91b 100644
--- a/lib/spack/docs/tutorial/examples/Autotools/1.package.py
+++ b/lib/spack/docs/tutorial/examples/Autotools/1.package.py
@@ -1,31 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
-class Mpileaks(AutoToolsPackage):
+class Mpileaks(AutotoolsPackage):
"""Tool to detect and report leaked MPI objects like MPI_Requests and
MPI_Datatypes."""
diff --git a/lib/spack/docs/tutorial/examples/Cmake/0.package.py b/lib/spack/docs/tutorial/examples/Cmake/0.package.py
index 724b3fdf94..2cdf06fd69 100644
--- a/lib/spack/docs/tutorial/examples/Cmake/0.package.py
+++ b/lib/spack/docs/tutorial/examples/Cmake/0.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
#
# This is a template package file for Spack. We've put "FIXME"
# next to all the things you'll want to change. Once you've handled
diff --git a/lib/spack/docs/tutorial/examples/Cmake/1.package.py b/lib/spack/docs/tutorial/examples/Cmake/1.package.py
index dcb44260d2..4b8c35b5a3 100644
--- a/lib/spack/docs/tutorial/examples/Cmake/1.package.py
+++ b/lib/spack/docs/tutorial/examples/Cmake/1.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/Cmake/2.package.py b/lib/spack/docs/tutorial/examples/Cmake/2.package.py
index 126a841ce9..2fbff1ce08 100644
--- a/lib/spack/docs/tutorial/examples/Cmake/2.package.py
+++ b/lib/spack/docs/tutorial/examples/Cmake/2.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/Makefile/0.package.py b/lib/spack/docs/tutorial/examples/Makefile/0.package.py
index 641b6ccb8f..c6be060420 100644
--- a/lib/spack/docs/tutorial/examples/Makefile/0.package.py
+++ b/lib/spack/docs/tutorial/examples/Makefile/0.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/Makefile/1.package.py b/lib/spack/docs/tutorial/examples/Makefile/1.package.py
index 709bc71afa..184a8a137a 100644
--- a/lib/spack/docs/tutorial/examples/Makefile/1.package.py
+++ b/lib/spack/docs/tutorial/examples/Makefile/1.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/Makefile/2.package.py b/lib/spack/docs/tutorial/examples/Makefile/2.package.py
index 10aba473e3..fda0d8aae6 100644
--- a/lib/spack/docs/tutorial/examples/Makefile/2.package.py
+++ b/lib/spack/docs/tutorial/examples/Makefile/2.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial/examples/Makefile/3.package.py b/lib/spack/docs/tutorial/examples/Makefile/3.package.py
index 269ab2c454..7520ad5c27 100644
--- a/lib/spack/docs/tutorial/examples/Makefile/3.package.py
+++ b/lib/spack/docs/tutorial/examples/Makefile/3.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
@@ -43,11 +24,13 @@ class Bowtie(MakefilePackage):
makefile.filter('CC= .*', 'CC = ' + env['CC'])
makefile.filter('CXX = .*', 'CXX = ' + env['CXX'])
- def build(self, spec, prefix):
+ @property
+ def build_targets(self):
if "+tbb" in spec:
- make()
+ return []
else:
- make("NO_TBB=1")
+ return ["NO_TBB=1"]
- def install(self, spec, prefix):
- make('prefix={0}'.format(self.prefix), 'install')
+ @property
+ def install_targets(self):
+ return ['prefix={0}'.format(self.prefix), 'install']
diff --git a/lib/spack/docs/tutorial/examples/PyPackage/0.package.py b/lib/spack/docs/tutorial/examples/PyPackage/0.package.py
index 48114075a7..e06546ae9a 100644
--- a/lib/spack/docs/tutorial/examples/PyPackage/0.package.py
+++ b/lib/spack/docs/tutorial/examples/PyPackage/0.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
#
# This is a template package file for Spack. We've put "FIXME"
# next to all the things you'll want to change. Once you've handled
diff --git a/lib/spack/docs/tutorial/examples/PyPackage/1.package.py b/lib/spack/docs/tutorial/examples/PyPackage/1.package.py
index a9cbff00e2..40402a824e 100644
--- a/lib/spack/docs/tutorial/examples/PyPackage/1.package.py
+++ b/lib/spack/docs/tutorial/examples/PyPackage/1.package.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/llnl/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack import *
diff --git a/lib/spack/docs/tutorial_advanced_packaging.rst b/lib/spack/docs/tutorial_advanced_packaging.rst
index 901e75bfd7..dafc095f5b 100644
--- a/lib/spack/docs/tutorial_advanced_packaging.rst
+++ b/lib/spack/docs/tutorial_advanced_packaging.rst
@@ -1,104 +1,238 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _advanced-packaging-tutorial:
============================
Advanced Topics in Packaging
============================
-While you can quickly accomplish most common tasks with what
-was covered in :ref:`packaging-tutorial`, there are times when such
-knowledge won't suffice. Usually this happens for libraries that provide
-more than one API and need to let dependents decide which one to use
-or for packages that provide tools that are invoked at build-time,
-or in other similar situations.
+Spack tries to automatically configure packages with information from
+dependencies such that all you need to do is to list the dependencies
+(i.e., with the ``depends_on`` directive) and the build system (for example
+by deriving from :code:`CmakePackage`).
-In the following we'll dig into some of the details of package
-implementation that help us deal with these rare, but important,
-occurrences. You can rest assured that in every case Spack remains faithful to
-its philosophy: keep simple things simple, but be flexible enough when
-complex requests arise!
+However, there are many special cases. Often you need to retrieve details
+about dependencies to set package-specific configuration options, or to
+define package-specific environment variables used by the package's build
+system. This tutorial covers how to retrieve build information from
+dependencies, and how you can automatically provide important information to
+dependents in your package.
----------------------
Setup for the tutorial
----------------------
-The simplest way to follow along with this tutorial is to use our Docker image,
-which comes with Spack and various packages pre-installed:
+.. note::
-.. code-block:: console
+ If you are not using the tutorial docker image, it is recommended that you
+ do this section of the tutorial in a fresh clone of Spack
- $ docker pull alalazo/spack:advanced_packaging_tutorial
- $ docker run --rm -h advanced-packaging-tutorial -it alalazo/spack:advanced_packaging_tutorial
- root@advanced-packaging-tutorial:/#
- root@advanced-packaging-tutorial:/# spack find
- ==> 20 installed packages.
- -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- arpack-ng@3.5.0 hdf5@1.10.1 libpciaccess@0.13.5 libtool@2.4.6 m4@1.4.18 ncurses@6.0 openblas@0.2.20 openssl@1.0.2k superlu@5.2.1 xz@5.2.3
- cmake@3.9.4 hwloc@1.11.8 libsigsegv@2.11 libxml2@2.9.4 mpich@3.2 netlib-lapack@3.6.1 openmpi@3.0.0 pkg-config@0.29.2 util-macros@1.19.1 zlib@1.2.11
+The tutorial uses custom package definitions with missing sections that
+will be filled in during the tutorial. These package definitions are stored
+in a separate package repository, which can be enabled with:
-If you already started the image, you can set the ``EDITOR`` environment
-variable to your preferred editor (``vi``, ``emacs``, and ``nano`` are included in the image)
-and move directly to :ref:`specs_build_interface_tutorial`.
+.. code-block:: console
-If you choose not to use the Docker image, you can clone the Spack repository
-and build the necessary bits yourself:
+ $ spack repo add --scope=site var/spack/repos/tutorial
-.. code-block:: console
+This section of the tutorial may also require a newer version of gcc, which
+you can add with:
- $ git clone https://github.com/spack/spack.git
- Cloning into 'spack'...
- remote: Counting objects: 92731, done.
- remote: Compressing objects: 100% (1108/1108), done.
- remote: Total 92731 (delta 1964), reused 4186 (delta 1637), pack-reused 87932
- Receiving objects: 100% (92731/92731), 33.31 MiB | 64.00 KiB/s, done.
- Resolving deltas: 100% (43557/43557), done.
- Checking connectivity... done.
+.. code-block:: console
- $ cd spack
- $ git checkout tutorials/advanced_packaging
- Branch tutorials/advanced_packaging set up to track remote branch tutorials/advanced_packaging from origin.
- Switched to a new branch 'tutorials/advanced_packaging'
+ $ spack install gcc@7.2.0
+ $ spack compiler add --scope=site path/to/spack-installed-gcc/bin
-At this point you can install the software that will be used
-during the rest of the tutorial (the output of the commands is omitted
-for the sake of brevity):
+If you are using the tutorial docker image, all dependency packages
+will have been installed. Otherwise, to install these packages you can use
+the following commands:
.. code-block:: console
$ spack install openblas
$ spack install netlib-lapack
$ spack install mpich
- $ spack install openmpi
- $ spack install --only=dependencies armadillo ^openblas
- $ spack install --only=dependencies netcdf
- $ spack install --only=dependencies elpa
Now, you are ready to set your preferred ``EDITOR`` and continue with
the rest of the tutorial.
+.. note::
+
+ Several of these packages depend on an MPI implementation. You can use
+ OpenMPI if you install it from scratch, but this is slow (>10 min.).
+ A binary cache of MPICH may be provided, in which case you can force
+ the package to use it and install quickly. All tutorial examples with
+ packages that depend on MPICH include the spec syntax for building with it
-.. _specs_build_interface_tutorial:
+.. _adv_pkg_tutorial_start:
-----------------------
-Spec's build interface
-----------------------
+---------------------------------------
+Modifying a package's build environment
+---------------------------------------
+
+Spack sets up several environment variables like ``PATH`` by default to aid in
+building a package, but many packages make use of environment variables which
+convey specific information about their dependencies (e.g., ``MPICC``).
+This section covers how to update your Spack packages so that package-specific
+environment variables are defined at build-time.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Set environment variables in dependent packages at build-time
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Dependencies can set environment variables that are required when their
+dependents build. For example, when a package depends on a python extension
+like py-numpy, Spack's ``python`` package will add it to ``PYTHONPATH``
+so it is available at build time; this is required because the default setup
+that spack does is not sufficient for python to import modules.
+
+To provide environment setup for a dependent, a package can implement the
+:py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
+function. This function takes as a parameter a :py:class:`EnvironmentModifications <spack.util.environment.EnvironmentModifications>`
+object which includes convenience methods to update the environment. For
+example, an MPI implementation can set ``MPICC`` for packages that depend on it:
+
+.. code-block:: python
+
+ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
+ spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
+
+In this case packages that depend on ``mpi`` will have ``MPICC`` defined in
+their environment when they build. This section is focused on modifying the
+build-time environment represented by ``spack_env``, but it's worth noting that
+modifications to ``run_env`` are included in Spack's automatically-generated
+module files.
+
+We can practice by editing the ``mpich`` package to set the ``MPICC``
+environment variable in the build-time environment of dependent packages.
+
+.. code-block:: console
+
+ root@advanced-packaging-tutorial:/# spack edit mpich
+
+Once you're finished, the method should look like this:
+
+.. code-block:: python
+
+ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
+ spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
+ spack_env.set('MPICXX', join_path(self.prefix.bin, 'mpic++'))
+ spack_env.set('MPIF77', join_path(self.prefix.bin, 'mpif77'))
+ spack_env.set('MPIF90', join_path(self.prefix.bin, 'mpif90'))
+
+ spack_env.set('MPICH_CC', spack_cc)
+ spack_env.set('MPICH_CXX', spack_cxx)
+ spack_env.set('MPICH_F77', spack_f77)
+ spack_env.set('MPICH_F90', spack_fc)
+ spack_env.set('MPICH_FC', spack_fc)
+
+At this point we can, for instance, install ``netlib-scalapack`` with
+``mpich``:
+
+.. code-block:: console
+
+ root@advanced-packaging-tutorial:/# spack install netlib-scalapack ^mpich
+ ...
+ ==> Created stage in /usr/local/var/spack/stage/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
+ ==> No patches needed for netlib-scalapack
+ ==> Building netlib-scalapack [CMakePackage]
+ ==> Executing phase: 'cmake'
+ ==> Executing phase: 'build'
+ ==> Executing phase: 'install'
+ ==> Successfully installed netlib-scalapack
+ Fetch: 0.01s. Build: 3m 59.86s. Total: 3m 59.87s.
+ [+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
+
+
+and double check the environment logs to verify that every variable was
+set to the correct value.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Set environment variables in your own package
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Packages can modify their own build-time environment by implementing the
+:py:func:`setup_environment <spack.package.PackageBase.setup_environment>` function.
+For ``qt`` this looks like:
+
+.. code-block:: python
+
+ def setup_environment(self, spack_env, run_env):
+ spack_env.set('MAKEFLAGS', '-j{0}'.format(make_jobs))
+ run_env.set('QTDIR', self.prefix)
+
+When ``qt`` builds, ``MAKEFLAGS`` will be defined in the environment.
+
+To contrast with ``qt``'s :py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
+function:
+
+.. code-block:: python
-Spack is designed with an emphasis on assigning responsibilities
-to the appropriate entities, as this results in a clearer and more intuitive interface
-for the users.
-When it comes to packaging, one of the most fundamental guideline that
-emerged from this tenet is that:
+ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
+ spack_env.set('QTDIR', self.prefix)
- *It is a package's responsibility to know
- every software it directly depends on and to expose to others how to
- use the services it provides*.
+Let's see how it works by completing the ``elpa`` package:
-Spec's build interface is a protocol-like implementation of this guideline
-that allows packages to easily query their dependencies,
-and prescribes how they should expose their own build information.
+.. code-block:: console
+
+ root@advanced-packaging-tutorial:/# spack edit elpa
+
+In the end your method should look like:
-^^^^^^^^^^^^^^^^^^^^
-A motivating example
-^^^^^^^^^^^^^^^^^^^^
+.. code-block:: python
+
+ def setup_environment(self, spack_env, run_env):
+ spec = self.spec
+
+ spack_env.set('CC', spec['mpi'].mpicc)
+ spack_env.set('FC', spec['mpi'].mpifc)
+ spack_env.set('CXX', spec['mpi'].mpicxx)
+ spack_env.set('SCALAPACK_LDFLAGS', spec['scalapack'].libs.joined())
+
+ spack_env.append_flags('LDFLAGS', spec['lapack'].libs.search_flags)
+ spack_env.append_flags('LIBS', spec['lapack'].libs.link_flags)
+
+At this point it's possible to proceed with the installation of ``elpa ^mpich``
+
+------------------------------
+Retrieving library information
+------------------------------
+
+Although Spack attempts to help packages locate their dependency libraries
+automatically (e.g. by setting ``PKG_CONFIG_PATH`` and ``CMAKE_PREFIX_PATH``),
+a package may have unique configuration options that are required to locate
+libraries. When a package needs information about dependency libraries, the
+general approach in Spack is to query the dependencies for the locations of
+their libraries and set configuration options accordingly. By default most
+Spack packages know how to automatically locate their libraries. This section
+covers how to retrieve library information from dependencies and how to locate
+libraries when the default logic doesn't work.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Accessing dependency libraries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you need to access the libraries of a dependency, you can do so
+via the ``libs`` property of the spec, for example in the ``arpack-ng``
+package:
+
+.. code-block:: python
+
+ def install(self, spec, prefix):
+ lapack_libs = spec['lapack'].libs.joined(';')
+ blas_libs = spec['blas'].libs.joined(';')
+
+ cmake(*[
+ '-DLAPACK_LIBRARIES={0}'.format(lapack_libs),
+ '-DBLAS_LIBRARIES={0}'.format(blas_libs)
+ ], '.')
+
+Note that ``arpack-ng`` is querying virtual dependencies, which Spack
+automatically resolves to the installed implementation (e.g. ``openblas``
+for ``blas``).
We've started work on a package for ``armadillo``. You should open it,
read through the comment that starts with ``# TUTORIAL:`` and complete
@@ -135,11 +269,11 @@ is as easy as accessing the their ``libs`` attribute. Furthermore, the interface
remains the same whether you are querying regular or virtual dependencies.
At this point you can complete the installation of ``armadillo`` using ``openblas``
-as a LAPACK provider:
+as a LAPACK provider (``armadillo ^openblas ^mpich``):
.. code-block:: console
- root@advanced-packaging-tutorial:/# spack install armadillo ^openblas
+ root@advanced-packaging-tutorial:/# spack install armadillo ^openblas ^mpich
==> pkg-config is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
...
==> superlu is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/superlu-5.2.1-q2mbtw2wo4kpzis2e2n227ip2fquxrno
@@ -160,12 +294,36 @@ Hopefully the installation went fine and the code we added expanded to the right
of semicolon separated libraries (you are encouraged to open ``armadillo``'s
build logs to double check).
-If we try to build another version tied to ``netlib-lapack`` we'll
-notice that this time the installation won't complete:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Providing libraries to dependents
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Spack provides a default implementation for ``libs`` which often works
+out of the box. A user can write a package definition without having to
+implement a ``libs`` property and dependents can retrieve its libraries
+as shown in the above section. However, the default implementation assumes that
+libraries follow the naming scheme ``lib<package name>.so`` (or e.g.
+``lib<package name>.a`` for static libraries). Packages which don't
+follow this naming scheme must implement this function themselves, e.g.
+``opencv``:
+
+.. code-block:: python
+
+ @property
+ def libs(self):
+ shared = "+shared" in self.spec
+ return find_libraries(
+ "libopencv_*", root=self.prefix, shared=shared, recurse=True
+ )
+
+This issue is common for packages which implement an interface (i.e.
+virtual package providers in Spack). If we try to build another version of
+``armadillo`` tied to ``netlib-lapack`` (``armadillo ^netlib-lapack ^mpich``)
+we'll notice that this time the installation won't complete:
.. code-block:: console
- root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack
+ root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack ^mpich
==> pkg-config is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
...
==> openmpi is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f
@@ -190,8 +348,9 @@ notice that this time the installation won't complete:
See build log for details:
/usr/local/var/spack/stage/arpack-ng-3.5.0-bloz7cqirpdxj33pg7uj32zs5likz2un/arpack-ng-3.5.0/spack-build.out
-This is because ``netlib-lapack`` requires extra work, compared to ``openblas``,
-to expose its build information to other packages. Let's edit it:
+Unlike ``openblas`` which provides a library named ``libopenblas.so``,
+``netlib-lapack`` provides ``liblapack.so``, so it needs to implement
+customized library search logic. Let's edit it:
.. code-block:: console
@@ -206,15 +365,21 @@ What we need to implement is:
def lapack_libs(self):
shared = True if '+shared' in self.spec else False
return find_libraries(
- 'liblapack', root=self.prefix, shared=shared, recurse=True
+ 'liblapack', root=self.prefix, shared=shared, recursive=True
)
-i.e. a property that returns the correct list of libraries for the LAPACK interface.
-Now we can finally install ``armadillo ^netlib-lapack``:
+i.e., a property that returns the correct list of libraries for the LAPACK interface.
+
+We use the name ``lapack_libs`` rather than ``libs`` because
+``netlib-lapack`` can also provide ``blas``, and when it does it is provided
+as a separate library file. Using this name ensures that when
+dependents ask for ``lapack`` libraries, ``netlib-lapack`` will retrieve only
+the libraries associated with the ``lapack`` interface. Now we can finally
+install ``armadillo ^netlib-lapack ^mpich``:
.. code-block:: console
- root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack
+ root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack ^mpich
...
==> Building armadillo [CMakePackage]
@@ -225,62 +390,43 @@ Now we can finally install ``armadillo ^netlib-lapack``:
Fetch: 0.01s. Build: 3.75s. Total: 3.76s.
[+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/armadillo-8.100.1-sxmpu5an4dshnhickh6ykchyfda7jpyn
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-What happens at subscript time?
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Since each implementation of a virtual package is responsible for locating the
+libraries associated with the interfaces it provides, dependents do not need
+to include special-case logic for different implementations and for example
+need only ask for :code:`spec['blas'].libs`.
-The example above leaves us with a few questions. How could it be that the
-attribute:
-
-.. code-block:: python
+----------------------
+Other Packaging Topics
+----------------------
- spec['lapack'].libs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Attach attributes to other packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-stems from a property of the ``netlib-lapack`` package that has a different name?
-How is it even computed for ``openblas``, given that in its package there's no code
-that deals with finding libraries?
-The answer is that ``libs`` is one of the few properties of specs that follow the
-*build-interface protocol*. The others are currently ``command`` and ``headers``.
-These properties exist only on concrete specs that have been retrieved via the
-subscript notation.
+Build tools usually also provide a set of executables that can be used
+when another package is being installed. Spack gives you the opportunity
+to monkey-patch dependent modules and attach attributes to them. This
+helps make the packager experience as similar as possible to what would
+have been the manual installation of the same package.
-What happens is that, whenever you retrieve a spec using subscripts:
+An example here is the ``automake`` package, which overrides
+:py:func:`setup_dependent_package <spack.package.PackageBase.setup_dependent_package>`:
.. code-block:: python
- lapack = spec['lapack']
-
-the key that appears in the query (in this case ``'lapack'``) is attached to the
-returned item. When, later on, you access any of the build-interface attributes, this
-key is used to compute the result according to the following algorithm:
-
-.. code-block:: none
-
- Given any pair of <query-key> and <build-attribute>:
-
- 1. If <query-key> is the name of a virtual spec and the package
- providing it has an attribute named '<query-key>_<build-attribute>'
- return it
-
- 2. Otherwise if the package has an attribute named '<build-attribute>'
- return that
-
- 3. Otherwise use the default handler for <build-attribute>
+ def setup_dependent_package(self, module, dependent_spec):
+ # Automake is very likely to be a build dependency,
+ # so we add the tools it provides to the dependent module
+ executables = ['aclocal', 'automake']
+ for name in executables:
+ setattr(module, name, self._make_executable(name))
-Going back to our concrete case this means that, if the spec providing LAPACK
-is ``netlib-lapack``, we are returning the value computed in the ``lapack_libs``
-property. If it is ``openblas``, we are instead resorting to the default handler
-for ``libs`` (which searches for the presence of ``libopenblas`` in the
-installation prefix).
+so that every other package that depends on it can use directly ``aclocal``
+and ``automake`` with the usual function call syntax of :py:class:`Executable <spack.util.executable.Executable>`:
-.. note::
+.. code-block:: python
- Types commonly returned by build-interface attributes
- Even though there's no enforcement on it, the type of the objects returned most often when
- asking for the ``libs`` attributes is :py:class:`LibraryList <llnl.util.filesystem.LibraryList>`.
- Similarly the usual type returned for ``headers`` is :py:class:`HeaderList <llnl.util.filesystem.HeaderList>`,
- while for ``command`` is :py:class:`Executable <spack.util.executable.Executable>`. You can refer to
- these objects' API documentation to discover more about them.
+ aclocal('--force')
^^^^^^^^^^^^^^^^^^^^^^^
Extra query parameters
@@ -288,14 +434,14 @@ Extra query parameters
An advanced feature of the Spec's build-interface protocol is the support
for extra parameters after the subscript key. In fact, any of the keys used in the query
-can be followed by a comma separated list of extra parameters which can be
+can be followed by a comma-separated list of extra parameters which can be
inspected by the package receiving the request to fine-tune a response.
-Let's look at an example and try to install ``netcdf``:
+Let's look at an example and try to install ``netcdf ^mpich``:
.. code-block:: console
- root@advanced-packaging-tutorial:/# spack install netcdf
+ root@advanced-packaging-tutorial:/# spack install netcdf ^mpich
==> libsigsegv is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
==> m4 is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
...
@@ -336,12 +482,12 @@ If you followed the instructions correctly, the code added to the
libraries, root=self.prefix, shared=shared, recurse=True
)
-where we highlighted the line retrieving the extra parameters. Now we can successfully
-complete the installation of ``netcdf``:
+where we highlighted the line retrieving the extra parameters. Now we can successfully
+complete the installation of ``netcdf ^mpich``:
.. code-block:: console
- root@advanced-packaging-tutorial:/# spack install netcdf
+ root@advanced-packaging-tutorial:/# spack install netcdf ^mpich
==> libsigsegv is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
==> m4 is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
...
@@ -357,207 +503,3 @@ complete the installation of ``netcdf``:
==> Successfully installed netcdf
Fetch: 0.01s. Build: 24.61s. Total: 24.62s.
[+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.4.1.1-gk2xxhbqijnrdwicawawcll4t3c7dvoj
-
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Single package providing multiple virtual specs
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-At the close of this tutorial's subsection, it may be useful to see where the
-build-interface protocol shines the most i.e. when it comes to manage packages
-that provide more than one virtual spec. An example of a package of this kind is
-``intel-parallel-studio``, and due to its complexity we'll limit our discussion
-here to just a few considerations (without any hands-on). You can open
-the related ``package.py`` in the usual way:
-
-.. code-block:: console
-
- root@advanced-packaging-tutorial:/# spack edit intel-parallel-studio
-
-As you can see this package provides a lot of virtual specs, and thus it has
-more than one function that enters into the build-interface protocol. These
-functions will be invoked for *exactly the same spec* according to the key used
-by its dependents in the subscript query.
-
-So, for instance, the ``blas_libs`` property will be returned when
-``intel-parallel-studio`` is the BLAS provider in the current DAG and
-is retrieved by a dependent with:
-
-.. code-block:: python
-
- blas = self.spec['blas']
- blas_libs = blas.libs
-
-Within the property we inspect various aspects of the current spec:
-
-.. code-block:: python
-
- @property
- def blas_libs(self):
- spec = self.spec
- prefix = self.prefix
- shared = '+shared' in spec
-
- if '+ilp64' in spec:
- mkl_integer = ['libmkl_intel_ilp64']
- else:
- mkl_integer = ['libmkl_intel_lp64']
- ...
-
-and construct the list of library we need to return accordingly.
-
-What we achieved is that the complexity of dealing with ``intel-parallel-studio``
-is now gathered in the package itself, instead of being spread
-all over its possible dependents.
-Thus, a package that uses MPI or LAPACK doesn't care which implementation it uses,
-as each virtual dependency has
-*a uniform interface* to ask for libraries or headers and manipulate them.
-The packages that provide this virtual spec, on the other hand, have a clear
-way to differentiate their answer to the query [#uniforminterface]_.
-
-.. [#uniforminterface] Before this interface was added, each package that
- depended on MPI or LAPACK had dozens of lines of code copied from other
- packages telling it where to find the libraries and what they are called.
- With the addition of this interface, the virtual dependency itself tells
- other packages that depend on it where it can find its libraries.
-
----------------------------
-Package's build environment
----------------------------
-
-Besides Spec's build interface, Spack provides means to set environment
-variables, either for yourself or for your dependent packages, and to
-attach attributes to your dependents. We'll see them next with the help
-of a few real use cases.
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Set variables at build-time for yourself
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Spack provides a way to manipulate a package's build time and
-run time environments using the
-:py:func:`setup_environment <spack.package.PackageBase.setup_environment>` function.
-Let's try to see how it works by completing the ``elpa`` package:
-
-.. code-block:: console
-
- root@advanced-packaging-tutorial:/# spack edit elpa
-
-In the end your method should look like:
-
-.. code-block:: python
-
- def setup_environment(self, spack_env, run_env):
- spec = self.spec
-
- spack_env.set('CC', spec['mpi'].mpicc)
- spack_env.set('FC', spec['mpi'].mpifc)
- spack_env.set('CXX', spec['mpi'].mpicxx)
- spack_env.set('SCALAPACK_LDFLAGS', spec['scalapack'].libs.joined())
-
- spack_env.append_flags('LDFLAGS', spec['lapack'].libs.search_flags)
- spack_env.append_flags('LIBS', spec['lapack'].libs.link_flags)
-
-The two arguments, ``spack_env`` and ``run_env``, are both instances of
-:py:class:`EnvironmentModifications <spack.environment.EnvironmentModifications>` and
-permit you to register modifications to either the build-time or the run-time
-environment of the package, respectively.
-At this point it's possible to proceed with the installation of ``elpa``:
-
-.. code-block:: console
-
- root@advanced-packaging-tutorial:/# spack install elpa
- ==> pkg-config is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
- ==> ncurses is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.0-ukq4tccptm2rxd56d2bumqthnpcjzlez
- ...
- ==> Executing phase: 'build'
- ==> Executing phase: 'install'
- ==> Successfully installed elpa
- Fetch: 3.94s. Build: 41.93s. Total: 45.87s.
- [+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/elpa-2016.05.004-sdbfhwcexg7s2zqf52vssb762ocvklbu
-
-If you had modifications to ``run_env``, those would have appeared e.g. in the module files
-generated for the package.
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Set variables in dependencies at build-time
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Another common occurrence, particularly for packages like ``r`` and ``python``
-that support extensions and for packages that provide build tools,
-is to require *their dependents* to have some environment variables set.
-
-The mechanism is similar to what we just saw, except that we override the
-:py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
-function, which takes one additional argument, i.e. the dependent spec that needs the modified
-environment. Let's practice completing the ``mpich`` package:
-
-.. code-block:: console
-
- root@advanced-packaging-tutorial:/# spack edit mpich
-
-Once you're finished the method should look like this:
-
-.. code-block:: python
-
- def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
- spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
- spack_env.set('MPICXX', join_path(self.prefix.bin, 'mpic++'))
- spack_env.set('MPIF77', join_path(self.prefix.bin, 'mpif77'))
- spack_env.set('MPIF90', join_path(self.prefix.bin, 'mpif90'))
-
- spack_env.set('MPICH_CC', spack_cc)
- spack_env.set('MPICH_CXX', spack_cxx)
- spack_env.set('MPICH_F77', spack_f77)
- spack_env.set('MPICH_F90', spack_fc)
- spack_env.set('MPICH_FC', spack_fc)
-
-At this point we can, for instance, install ``netlib-scalapack``:
-
-.. code-block:: console
-
- root@advanced-packaging-tutorial:/# spack install netlib-scalapack ^mpich
- ...
- ==> Created stage in /usr/local/var/spack/stage/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
- ==> No patches needed for netlib-scalapack
- ==> Building netlib-scalapack [CMakePackage]
- ==> Executing phase: 'cmake'
- ==> Executing phase: 'build'
- ==> Executing phase: 'install'
- ==> Successfully installed netlib-scalapack
- Fetch: 0.01s. Build: 3m 59.86s. Total: 3m 59.87s.
- [+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
-
-
-and double check the environment logs to verify that every variable was
-set to the correct value. More complicated examples of the use of this function
-may be found in the ``r`` and ``python`` package.
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Attach attributes to other packages
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Build tools usually also provide a set of executables that can be used
-when another package is being installed. Spack gives the opportunity
-to monkey-patch dependent modules and attach attributes to them. This
-helps make the packager experience as similar as possible to what would
-have been the manual installation of the same package.
-
-An example here is the ``automake`` package, which overrides
-:py:func:`setup_dependent_package <spack.package.PackageBase.setup_dependent_package>`:
-
-.. code-block:: python
-
- def setup_dependent_package(self, module, dependent_spec):
- # Automake is very likely to be a build dependency,
- # so we add the tools it provides to the dependent module
- executables = ['aclocal', 'automake']
- for name in executables:
- setattr(module, name, self._make_executable(name))
-
-so that every other package that depends on it can use directly ``aclocal``
-and ``automake`` with the usual function call syntax of :py:class:`Executable <spack.util.executable.Executable>`:
-
-.. code-block:: python
-
- aclocal('--force') \ No newline at end of file
diff --git a/lib/spack/docs/tutorial_basics.rst b/lib/spack/docs/tutorial_basics.rst
index d74159d7f6..50c072c08e 100644
--- a/lib/spack/docs/tutorial_basics.rst
+++ b/lib/spack/docs/tutorial_basics.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _basics-tutorial:
=========================================
@@ -23,22 +28,24 @@ Installing Spack
----------------
Spack works out of the box. Simply clone spack and get going. We will
-clone Spack and immediately checkout the most recent release, v0.11.0.
+clone Spack and immediately checkout the most recent release, v0.12.
.. code-block:: console
$ git clone https://github.com/spack/spack
+ git clone https://github.com/spack/spack
Cloning into 'spack'...
- remote: Counting objects: 94561, done.
- remote: Compressing objects: 100% (121/121), done.
- remote: Total 94561 (delta 91), reused 121 (delta 48), pack-reused 94368
- Receiving objects: 100% (94561/94561), 32.44 MiB | 31.88 MiB/s, done.
- Resolving deltas: 100% (44914/44914), done.
+ remote: Enumerating objects: 68, done.
+ remote: Counting objects: 100% (68/68), done.
+ remote: Compressing objects: 100% (56/56), done.
+ remote: Total 135389 (delta 40), reused 16 (delta 9), pack-reused 135321
+ Receiving objects: 100% (135389/135389), 47.31 MiB | 1.01 MiB/s, done.
+ Resolving deltas: 100% (64414/64414), done.
Checking connectivity... done.
$ cd spack
- $ git checkout releases/v0.11.0
- Branch releases/v0.11.0 set up to track remote branch releases/v0.11.0 from origin.
- Switched to a new branch 'releases/v0.11.0'
+ $ git checkout releases/v0.12
+ Branch releases/v0.12 set up to track remote branch releases/v0.12 from origin.
+ Switched to a new branch 'releases/v0.12'
Next add Spack to your path. Spack has some nice command line
integration tools, so instead of simply appending to your ``PATH``
@@ -59,10 +66,10 @@ The ``spack list`` command shows available packages.
.. code-block:: console
$ spack list
- ==> 2177 packages.
- abinit libepoxy py-html5lib r-ncdf4
- abyss libevent py-httpbin r-network
- ack libevpath py-hypothesis r-networkd3abinit
+ ==> 2907 packages.
+ abinit libgpuarray py-espresso r-mlrmbo
+ abyss libgridxc py-espressopp r-mmwrweek
+ accfft libgtextutils py-et-xmlfile r-mnormt
...
The ``spack list`` command can also take a query string. Spack
@@ -72,10 +79,10 @@ we can view all available python packages.
.. code-block:: console
$ spack list py-
- ==> 356 packages.
- py-3to2 py-functools32 py-numpydoc py-pywavelets
- py-4suite-xml py-future py-olefile py-pyyaml
- py-abipy py-futures py-ont-fast5-api py-qtawesome
+ ==> 479 packages.
+ lumpy-sv py-funcsigs py-numpydoc py-utililib
+ perl-file-copy-recursive py-functools32 py-olefile py-pywavelets
+ py-3to2 py-future py-ont-fast5-api py-pyyaml
...
-------------------
@@ -89,43 +96,42 @@ software, simply type ``spack install <package_name>``.
$ spack install zlib
==> Installing zlib
- ==> Fetching file:///home/ubuntu/becker/buildcache/zlib/zlib-1.2.11.tar.gz
- curl: (37) Couldn't open file /home/ubuntu/becker/buildcache/zlib/zlib-1.2.11.tar.gz
- ==> Fetching from file:///home/ubuntu/becker/buildcache/zlib/zlib-1.2.11.tar.gz failed.
+ ==> Searching for binary cache of zlib
+ ==> Warning: No Spack mirrors are currently configured
+ ==> No binary for zlib found: installing from source
==> Fetching http://zlib.net/fossils/zlib-1.2.11.tar.gz
######################################################################## 100.0%
- ==> Staging archive: /home/ubuntu/test/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb/zlib-1.2.11.tar.gz
- ==> Created stage in /home/ubuntu/test/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ ==> Staging archive: /home/spack1/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb/zlib-1.2.11.tar.gz
+ ==> Created stage in /home/spack1/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> No patches needed for zlib
==> Building zlib [Package]
==> Executing phase: 'install'
==> Successfully installed zlib
- Fetch: 0.58s. Build: 1.15s. Total: 1.73s.
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ Fetch: 3.27s. Build: 2.18s. Total: 5.44s.
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
Spack can install software either from source or from a binary
cache. Packages in the binary cache are signed with GPG for
security. For the tutorial we have prepared a binary cache so you
don't have to wait on slow compilation from source. To be able to
-install from the binary cache, we will need to trust the GPG key that
-the binary cache was prepared with.
+install from the binary cache, we will need to configure Spack with
+the location of the binary cache and trust the GPG key that the binary
+cache was signed with.
.. code-block:: console
- $ spack gpg trust ~/public.key
- gpg: keybox '/home/ubuntu/test/spack/opt/spack/gpg/pubring.kbx' created
- gpg: /home/ubuntu/test/spack/opt/spack/gpg/trustdb.gpg: trustdb created
+ $ spack mirror add tutorial /mirror
+ $ spack gpg trust /mirror/public.key
+ gpg: keybox '/home/spack1/spack/opt/spack/gpg/pubring.kbx' created
+ gpg: /home/spack1/spack/opt/spack/gpg/trustdb.gpg: trustdb created
gpg: key 3B7C69B2: public key "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" imported
gpg: Total number processed: 1
gpg: imported: 1
-The AWS instances and Docker images we use for the tutorial already
-have configuration files in place so that Spack knows where to look
-for binary packages (and that's the only change we've made). You'll
-learn more about configuring Spack later in the tutorial, but for now
-you will be able to install the rest of the packages in the tutorial
-from a binary cache by specifying ``spack install --use-cache
-<package_name>``. This will install the binary cached version if it
+You'll learn more about configuring Spack later in the tutorial, but
+for now you will be able to install the rest of the packages in the
+tutorial from a binary cache using the same ``spack install``
+command. By default this will install the binary cached version if it
exists and fall back on installing from source.
Spack's spec syntax is the interface by which we can request specific
@@ -134,24 +140,28 @@ compilers.
.. code-block:: console
- $ spack install --use-cache zlib %clang
- ...
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-4.7-libsigsegv-2.11-eaqxu5mka32jpjif32rttiwebimrr2kb.spec.yaml
+ $ spack install zlib %clang
+ ==> Installing zlib
+ ==> Searching for binary cache of zlib
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64-gcc-7.2.0-texinfo-6.5-cuqnfgfhhmudqp5f7upmld6ax7pratzw.spec.yaml
+ ######################################################################## 100.0%
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64-gcc-4.7-zlib-1.2.11-bq2wtdxakpjytk2tjr7qu23i4py2fi2r.spec.yaml
######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr.spec.yaml
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-dyninst-9.3.2-bu6s2jzievsjkwtcnrtimc5b625j5omf.spec.yaml
######################################################################## 100.0%
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64-gcc-7.2.0-openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4.spec.yaml
+ ...
==> Installing zlib from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.11/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.11/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:05:02 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:08:01 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed zlib from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul
Note that this installation is located separately from the previous
one. We will discuss this in more detail later, but this is part of what
@@ -175,43 +185,35 @@ compilers.
.. code-block:: console
- $ spack install --use-cache zlib@1.2.8
+ $ spack install zlib@1.2.8
==> Installing zlib
==> Searching for binary cache of zlib
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing zlib from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:05:03 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:18:30 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed zlib from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc
- $ spack install --use-cache zlib %gcc@4.7
+ $ spack install zlib %gcc@4.7
==> Installing zlib
==> Searching for binary cache of zlib
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing zlib from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-4.7/zlib-1.2.11/linux-ubuntu16.04-x86_64-gcc-4.7-zlib-1.2.11-bq2wtdxakpjytk2tjr7qu23i4py2fi2r.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-4.7/zlib-1.2.11/linux-ubuntu16.04-x86_64-gcc-4.7-zlib-1.2.11-bq2wtdxakpjytk2tjr7qu23i4py2fi2r.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:03:00 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 04:55:30 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed zlib from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-4.7/zlib-1.2.11-bq2wtdxakpjytk2tjr7qu23i4py2fi2r
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-4.7/zlib-1.2.11-bq2wtdxakpjytk2tjr7qu23i4py2fi2r
The spec syntax also includes compiler flags. Spack accepts
``cppflags``, ``cflags``, ``cxxflags``, ``fflags``, ``ldflags``, and
@@ -221,24 +223,20 @@ into the compile line automatically by the Spack compiler wrappers.
.. code-block:: console
- $ spack install --use-cache zlib @1.2.8 cppflags=-O3
+ $ spack install zlib @1.2.8 cppflags=-O3
==> Installing zlib
==> Searching for binary cache of zlib
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-4.7-zlib-1.2.11-bq2wtdxakpjytk2tjr7qu23i4py2fi2r.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing zlib from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:03:00 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:31:54 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed zlib from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu
The ``spack find`` command is used to query installed packages. Note that
some packages appear identical with the default output. The ``-l`` flag
@@ -286,25 +284,21 @@ existing package's hash matches the desired spec.
.. code-block:: console
- $ spack install --use-cache openssl
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
- ==> Installing openssl
- ==> Searching for binary cache of openssl
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu.spec.yaml
+ $ spack install tcl
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ ==> Installing tcl
+ ==> Searching for binary cache of tcl
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> Installing tcl from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-tcl-8.6.8-qhwyccywhx2i6s7ob2gvjrjtj3rnfuqt.spack
######################################################################## 100.0%
- ==> Installing openssl from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k/linux-ubuntu16.04-x86_64-gcc-5.4.0-openssl-1.0.2k-2woov64m3n4gjtnfp722qcyemzf2qtom.spack
- ######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:03:18 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:07:15 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed openssl from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k-2woov64m3n4gjtnfp722qcyemzf2qtom
+ ==> Successfully installed tcl from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8-qhwyccywhx2i6s7ob2gvjrjtj3rnfuqt
Dependencies can be explicitly requested using the ``^`` sigil. Note that
the spec syntax is recursive. Anything we could specify about the
@@ -312,38 +306,32 @@ top-level package, we can also specify about a dependency using ``^``.
.. code-block:: console
- $ spack install --use-cache openssl ^zlib @1.2.8 %clang
+ $ spack install tcl ^zlib @1.2.8 %clang
==> Installing zlib
==> Searching for binary cache of zlib
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-openssl-1.0.2k-2woov64m3n4gjtnfp722qcyemzf2qtom.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing zlib from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.8/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-zlib-1.2.8-i426yu3o6lyau5fv5ljwsajfkqxj5rl5.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.8/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-zlib-1.2.8-i426yu3o6lyau5fv5ljwsajfkqxj5rl5.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:03:06 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:09:01 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed zlib from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.8-i426yu3o6lyau5fv5ljwsajfkqxj5rl5
- ==> Installing openssl
- ==> Searching for binary cache of openssl
- ==> Installing openssl from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/openssl-1.0.2k/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-openssl-1.0.2k-ufruk7kj2fz3oupuat2jbgc2y7hg37vy.spack
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.8-i426yu3o6lyau5fv5ljwsajfkqxj5rl5
+ ==> Installing tcl
+ ==> Searching for binary cache of tcl
+ ==> Installing tcl from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/tcl-8.6.8/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-tcl-8.6.8-6wc66etr7y6hgibp2derrdkf763exwvc.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:03:23 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:10:21 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed openssl from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/openssl-1.0.2k-ufruk7kj2fz3oupuat2jbgc2y7hg37vy
+ ==> Successfully installed tcl from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/tcl-8.6.8-6wc66etr7y6hgibp2derrdkf763exwvc
Packages can also be referred to from the command line by their package
hash. Using the ``spack find -lf`` command earlier we saw that the hash
@@ -357,27 +345,21 @@ packages share the prefix) then spack will report an error.
.. code-block:: console
- $ spack install --use-cache openssl ^/64mn
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu
- ==> Installing openssl
- ==> Searching for binary cache of openssl
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-zlib-1.2.8-i426yu3o6lyau5fv5ljwsajfkqxj5rl5.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-clang-3.8.0-2ubuntu4-openssl-1.0.2k-ufruk7kj2fz3oupuat2jbgc2y7hg37vy.spec.yaml
- ######################################################################## 100.0%
- ==> Installing openssl from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k/linux-ubuntu16.04-x86_64-gcc-5.4.0-openssl-1.0.2k-gyxmhgbam26d7y42omb7xrvkjjgmzwio.spack
+ $ spack install tcl ^/64mn
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu
+ ==> Installing tcl
+ ==> Searching for binary cache of tcl
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> Installing tcl from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-tcl-8.6.8-am4pbatrtga3etyusg2akmsvrswwxno2.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:03:12 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:11:53 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed openssl from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k-gyxmhgbam26d7y42omb7xrvkjjgmzwio
+ ==> Successfully installed tcl from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8-am4pbatrtga3etyusg2akmsvrswwxno2
The ``spack find`` command can also take a ``-d`` flag, which can show
dependency information. Note that each package has a top-level entry,
@@ -386,9 +368,9 @@ even if it also appears as a dependency.
.. code-block:: console
$ spack find -ldf
- ==> 9 installed packages.
+ ==> 9 installed packages
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
- ufruk7k openssl@1.0.2k%clang
+ 6wc66et tcl@8.6.8%clang
i426yu3 ^zlib@1.2.8%clang
i426yu3 zlib@1.2.8%clang
@@ -401,10 +383,10 @@ even if it also appears as a dependency.
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- gyxmhgb openssl@1.0.2k%gcc
+ am4pbat tcl@8.6.8%gcc
64mns5m ^zlib@1.2.8%gcc cppflags="-O3"
- 2woov64 openssl@1.0.2k%gcc
+ qhwyccy tcl@8.6.8%gcc
5nus6kn ^zlib@1.2.11%gcc
bkyl5bh zlib@1.2.8%gcc
@@ -420,197 +402,250 @@ we install it "out of the box," it will build with ``openmpi``.
.. code-block:: console
- $ spack install --use-cache hdf5
+ $ spack install hdf5
==> Installing libsigsegv
==> Searching for binary cache of libsigsegv
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-openssl-1.0.2k-gyxmhgbam26d7y42omb7xrvkjjgmzwio.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing libsigsegv from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11/linux-ubuntu16.04-x86_64-gcc-5.4.0-libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11/linux-ubuntu16.04-x86_64-gcc-5.4.0-libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:21:10 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:08:01 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed libsigsegv from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
==> Installing m4
==> Searching for binary cache of m4
==> Installing m4 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18/linux-ubuntu16.04-x86_64-gcc-5.4.0-m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18/linux-ubuntu16.04-x86_64-gcc-5.4.0-m4-1.4.18-suf5jtcfehivwfesrc5hjy72r4nukyel.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:22:03 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:24:11 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed m4 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-suf5jtcfehivwfesrc5hjy72r4nukyel
==> Installing libtool
==> Searching for binary cache of libtool
==> Installing libtool from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6/linux-ubuntu16.04-x86_64-gcc-5.4.0-libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6/linux-ubuntu16.04-x86_64-gcc-5.4.0-libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:29:09 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:12:47 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed libtool from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
- ==> Installing pkg-config
- ==> Searching for binary cache of pkg-config
- ==> Installing pkg-config from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj.spack
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
+ ==> Installing pkgconf
+ ==> Searching for binary cache of pkgconf
+ ==> Installing pkgconf from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkgconf-1.4.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-pkgconf-1.4.2-fovrh7alpft646n6mhis5mml6k6e5f4v.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:30:13 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:00:47 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed pkg-config from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
+ ==> Successfully installed pkgconf from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkgconf-1.4.2-fovrh7alpft646n6mhis5mml6k6e5f4v
==> Installing util-macros
==> Searching for binary cache of util-macros
==> Installing util-macros from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/util-macros-1.19.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/util-macros-1.19.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:30:12 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:31:54 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed util-macros from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr
==> Installing libpciaccess
==> Searching for binary cache of libpciaccess
==> Installing libpciaccess from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libpciaccess-0.13.5/linux-ubuntu16.04-x86_64-gcc-5.4.0-libpciaccess-0.13.5-5urc6tcjae26fbbd2wyfohoszhgxtbmc.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libpciaccess-0.13.5/linux-ubuntu16.04-x86_64-gcc-5.4.0-libpciaccess-0.13.5-5urc6tcjae26fbbd2wyfohoszhgxtbmc.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:23 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:09:34 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed libpciaccess from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libpciaccess-0.13.5-5urc6tcjae26fbbd2wyfohoszhgxtbmc
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libpciaccess-0.13.5-5urc6tcjae26fbbd2wyfohoszhgxtbmc
==> Installing xz
==> Searching for binary cache of xz
==> Installing xz from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/xz-5.2.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-xz-5.2.3-htnq7wqdrqtof6uxqicdj3f7oe3xz6pw.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/xz-5.2.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-xz-5.2.4-teneqii2xv5u6zl5r6qi3pwurc6pmypz.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:34 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:05:03 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed xz from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/xz-5.2.3-htnq7wqdrqtof6uxqicdj3f7oe3xz6pw
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/xz-5.2.4-teneqii2xv5u6zl5r6qi3pwurc6pmypz
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> Installing libxml2
==> Searching for binary cache of libxml2
==> Installing libxml2 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libxml2-2.9.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-libxml2-2.9.4-sxk64lvcxhqjflzesnf3ye4wakovwi45.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/libxml2-2.9.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-libxml2-2.9.8-wpexsphdmfayxqxd4up5vgwuqgu5woo7.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:23 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 04:56:04 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed libxml2 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libxml2-2.9.4-sxk64lvcxhqjflzesnf3ye4wakovwi45
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libxml2-2.9.8-wpexsphdmfayxqxd4up5vgwuqgu5woo7
+ ==> Installing ncurses
+ ==> Searching for binary cache of ncurses
+ ==> Installing ncurses from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-ncurses-6.1-3o765ourmesfrji6yeclb4wb5w54aqbh.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:04:49 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed ncurses from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.1-3o765ourmesfrji6yeclb4wb5w54aqbh
+ ==> Installing readline
+ ==> Searching for binary cache of readline
+ ==> Installing readline from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-readline-7.0-nxhwrg7xwc6nbsm2v4ezwe63l6nfidbi.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:04:56 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed readline from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0-nxhwrg7xwc6nbsm2v4ezwe63l6nfidbi
+ ==> Installing gdbm
+ ==> Searching for binary cache of gdbm
+ ==> Installing gdbm from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.14.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-gdbm-1.14.1-q4fpyuo7ouhkeq6d3oabtrppctpvxmes.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:18:34 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed gdbm from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.14.1-q4fpyuo7ouhkeq6d3oabtrppctpvxmes
+ ==> Installing perl
+ ==> Searching for binary cache of perl
+ ==> Installing perl from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.26.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-perl-5.26.2-ic2kyoadgp3dxfejcbllyplj2wf524fo.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:12:45 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed perl from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.26.2-ic2kyoadgp3dxfejcbllyplj2wf524fo
+ ==> Installing autoconf
+ ==> Searching for binary cache of autoconf
+ ==> Installing autoconf from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69/linux-ubuntu16.04-x86_64-gcc-5.4.0-autoconf-2.69-3sx2gxeibc4oasqd4o5h6lnwpcpsgd2q.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:24:03 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed autoconf from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69-3sx2gxeibc4oasqd4o5h6lnwpcpsgd2q
+ ==> Installing automake
+ ==> Searching for binary cache of automake
+ ==> Installing automake from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.16.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-automake-1.16.1-rymw7imfehycqxzj4nuy2oiw3abegooy.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:12:03 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed automake from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.16.1-rymw7imfehycqxzj4nuy2oiw3abegooy
+ ==> Installing numactl
+ ==> Searching for binary cache of numactl
+ ==> Installing numactl from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/numactl-2.0.11/linux-ubuntu16.04-x86_64-gcc-5.4.0-numactl-2.0.11-ft463odrombnxlc3qew4omckhlq7tqgc.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:30:34 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed numactl from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/numactl-2.0.11-ft463odrombnxlc3qew4omckhlq7tqgc
==> Installing hwloc
==> Searching for binary cache of hwloc
==> Installing hwloc from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hwloc-1.11.8/linux-ubuntu16.04-x86_64-gcc-5.4.0-hwloc-1.11.8-ivg4d2e6anxwin4zbld2g4qlrbuquoyg.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hwloc-1.11.9/linux-ubuntu16.04-x86_64-gcc-5.4.0-hwloc-1.11.9-43tkw5mt6huhv37vqnybqgxtkodbsava.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:32 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:08:00 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hwloc from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hwloc-1.11.8-ivg4d2e6anxwin4zbld2g4qlrbuquoyg
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hwloc-1.11.9-43tkw5mt6huhv37vqnybqgxtkodbsava
==> Installing openmpi
==> Searching for binary cache of openmpi
==> Installing openmpi from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.1.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:43:34 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:01:54 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed openmpi from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx
==> Installing hdf5
==> Searching for binary cache of hdf5
==> Installing hdf5 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.1-bovz45ms24pmfr7hlckf56bxegfc4rea.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.4-ozyvmhzdew66byarohm4p36ep7wtcuiw.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:53:08 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:23:04 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hdf5 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-bovz45ms24pmfr7hlckf56bxegfc4rea
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-ozyvmhzdew66byarohm4p36ep7wtcuiw
-Spack packages can also have variants. Boolean variants can be specified
-using the ``+`` and ``~`` or ``-`` sigils. There are two sigils for
-``False`` to avoid conflicts with shell parsing in different
-situations. Variants (boolean or otherwise) can also be specified using
-the same syntax as compiler flags. Here we can install HDF5 without MPI
-support.
+Spack packages can also have build options, called variants. Boolean
+variants can be specified using the ``+`` and ``~`` or ``-``
+sigils. There are two sigils for ``False`` to avoid conflicts with
+shell parsing in different situations. Variants (boolean or otherwise)
+can also be specified using the same syntax as compiler flags. Here
+we can install HDF5 without MPI support.
.. code-block:: console
- $ spack install --use-cache hdf5~mpi
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ $ spack install hdf5~mpi
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> Installing hdf5
==> Searching for binary cache of hdf5
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f.spec.yaml
- ######################################################################## 100.0%
- ...
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing hdf5 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.1-pa6oqzfeqzkqkzqr2375fqyt3qggx3tr.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.4-5vcv5r67vpjzenq4apyebshclelnzuja.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:53:40 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:23:24 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hdf5 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-pa6oqzfeqzkqkzqr2375fqyt3qggx3tr
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-5vcv5r67vpjzenq4apyebshclelnzuja
We might also want to install HDF5 with a different MPI
implementation. While MPI is not a package itself, packages can depend on
@@ -627,48 +662,76 @@ by any of several providers.
.. code-block:: console
- $ spack install --use-cache hdf5+hl+mpi ^mpich
+ $ spack install hdf5+hl+mpi ^mpich
+ ==> libsigsegv is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
+ ==> m4 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-suf5jtcfehivwfesrc5hjy72r4nukyel
+ ==> pkgconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkgconf-1.4.2-fovrh7alpft646n6mhis5mml6k6e5f4v
+ ==> ncurses is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.1-3o765ourmesfrji6yeclb4wb5w54aqbh
+ ==> readline is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0-nxhwrg7xwc6nbsm2v4ezwe63l6nfidbi
+ ==> gdbm is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.14.1-q4fpyuo7ouhkeq6d3oabtrppctpvxmes
+ ==> perl is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.26.2-ic2kyoadgp3dxfejcbllyplj2wf524fo
+ ==> autoconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69-3sx2gxeibc4oasqd4o5h6lnwpcpsgd2q
+ ==> automake is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.16.1-rymw7imfehycqxzj4nuy2oiw3abegooy
+ ==> libtool is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
+ ==> Installing texinfo
+ ==> Searching for binary cache of texinfo
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> Installing texinfo from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/texinfo-6.5/linux-ubuntu16.04-x86_64-gcc-5.4.0-texinfo-6.5-zs7a2pcwhq6ho2cj2x26uxfktwkpyucn.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:18:29 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed texinfo from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/texinfo-6.5-zs7a2pcwhq6ho2cj2x26uxfktwkpyucn
+ ==> Installing findutils
+ ==> Searching for binary cache of findutils
+ ==> Installing findutils from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/findutils-4.6.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-findutils-4.6.0-d4iajxsopzrlcjtasahxqeyjkjv5jx4v.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:07:17 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed findutils from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/findutils-4.6.0-d4iajxsopzrlcjtasahxqeyjkjv5jx4v
==> Installing mpich
==> Searching for binary cache of mpich
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.1-pa6oqzfeqzkqkzqr2375fqyt3qggx3tr.spec.yaml
- ######################################################################## 100.0%
==> Installing mpich from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpich-3.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpich-3.2-cymrnoowcc4vdyvdnf5ypvob4cmdadk5.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpich-3.2.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpich-3.2.1-p3f7p2r5ntrynqibosglxvhwyztiwqs5.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:45:26 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:23:57 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed mpich from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpich-3.2-cymrnoowcc4vdyvdnf5ypvob4cmdadk5
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpich-3.2.1-p3f7p2r5ntrynqibosglxvhwyztiwqs5
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> Installing hdf5
==> Searching for binary cache of hdf5
==> Installing hdf5 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.1-e4gz6f2l5ik3ijuk3alwsqplex4tbvin.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.4-xxd7syhgej6onpyfyewxqcqe7ltkt7ob.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:49:45 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:07:32 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hdf5 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-e4gz6f2l5ik3ijuk3alwsqplex4tbvin
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-xxd7syhgej6onpyfyewxqcqe7ltkt7ob
We'll do a quick check in on what we have installed so far.
.. code-block:: console
$ spack find -ldf
- ==> 23 installed packages.
+ ==> 32 installed packages
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
- ufruk7k openssl@1.0.2k%clang
+ 6wc66et tcl@8.6.8%clang
i426yu3 ^zlib@1.2.8%clang
i426yu3 zlib@1.2.8%clang
@@ -681,26 +744,48 @@ We'll do a quick check in on what we have installed so far.
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- pa6oqzf hdf5@1.10.1%gcc
+ 3sx2gxe autoconf@2.69%gcc
+ suf5jtc ^m4@1.4.18%gcc
+ fypapcp ^libsigsegv@2.11%gcc
+ ic2kyoa ^perl@5.26.2%gcc
+ q4fpyuo ^gdbm@1.14.1%gcc
+ nxhwrg7 ^readline@7.0%gcc
+ 3o765ou ^ncurses@6.1%gcc
+
+ rymw7im automake@1.16.1%gcc
+ ic2kyoa ^perl@5.26.2%gcc
+ q4fpyuo ^gdbm@1.14.1%gcc
+ nxhwrg7 ^readline@7.0%gcc
+ 3o765ou ^ncurses@6.1%gcc
+
+ d4iajxs findutils@4.6.0%gcc
+
+ q4fpyuo gdbm@1.14.1%gcc
+ nxhwrg7 ^readline@7.0%gcc
+ 3o765ou ^ncurses@6.1%gcc
+
+ 5vcv5r6 hdf5@1.10.4%gcc
5nus6kn ^zlib@1.2.11%gcc
- bovz45m hdf5@1.10.1%gcc
- yo5qkfv ^openmpi@3.0.0%gcc
- ivg4d2e ^hwloc@1.11.8%gcc
+ ozyvmhz hdf5@1.10.4%gcc
+ 3njc4q5 ^openmpi@3.1.3%gcc
+ 43tkw5m ^hwloc@1.11.9%gcc
5urc6tc ^libpciaccess@0.13.5%gcc
- sxk64lv ^libxml2@2.9.4%gcc
- htnq7wq ^xz@5.2.3%gcc
+ wpexsph ^libxml2@2.9.8%gcc
+ teneqii ^xz@5.2.4%gcc
5nus6kn ^zlib@1.2.11%gcc
+ ft463od ^numactl@2.0.11%gcc
- e4gz6f2 hdf5@1.10.1%gcc
- cymrnoo ^mpich@3.2%gcc
+ xxd7syh hdf5@1.10.4%gcc
+ p3f7p2r ^mpich@3.2.1%gcc
5nus6kn ^zlib@1.2.11%gcc
- ivg4d2e hwloc@1.11.8%gcc
+ 43tkw5m hwloc@1.11.9%gcc
5urc6tc ^libpciaccess@0.13.5%gcc
- sxk64lv ^libxml2@2.9.4%gcc
- htnq7wq ^xz@5.2.3%gcc
+ wpexsph ^libxml2@2.9.8%gcc
+ teneqii ^xz@5.2.4%gcc
5nus6kn ^zlib@1.2.11%gcc
+ ft463od ^numactl@2.0.11%gcc
5urc6tc libpciaccess@0.13.5%gcc
@@ -708,33 +793,52 @@ We'll do a quick check in on what we have installed so far.
o2pfwjf libtool@2.4.6%gcc
- sxk64lv libxml2@2.9.4%gcc
- htnq7wq ^xz@5.2.3%gcc
+ wpexsph libxml2@2.9.8%gcc
+ teneqii ^xz@5.2.4%gcc
5nus6kn ^zlib@1.2.11%gcc
- r5envx3 m4@1.4.18%gcc
+ suf5jtc m4@1.4.18%gcc
fypapcp ^libsigsegv@2.11%gcc
- cymrnoo mpich@3.2%gcc
+ p3f7p2r mpich@3.2.1%gcc
- yo5qkfv openmpi@3.0.0%gcc
- ivg4d2e ^hwloc@1.11.8%gcc
+ 3o765ou ncurses@6.1%gcc
+
+ ft463od numactl@2.0.11%gcc
+
+ 3njc4q5 openmpi@3.1.3%gcc
+ 43tkw5m ^hwloc@1.11.9%gcc
5urc6tc ^libpciaccess@0.13.5%gcc
- sxk64lv ^libxml2@2.9.4%gcc
- htnq7wq ^xz@5.2.3%gcc
+ wpexsph ^libxml2@2.9.8%gcc
+ teneqii ^xz@5.2.4%gcc
5nus6kn ^zlib@1.2.11%gcc
+ ft463od ^numactl@2.0.11%gcc
+
+ ic2kyoa perl@5.26.2%gcc
+ q4fpyuo ^gdbm@1.14.1%gcc
+ nxhwrg7 ^readline@7.0%gcc
+ 3o765ou ^ncurses@6.1%gcc
- gyxmhgb openssl@1.0.2k%gcc
+ fovrh7a pkgconf@1.4.2%gcc
+
+ nxhwrg7 readline@7.0%gcc
+ 3o765ou ^ncurses@6.1%gcc
+
+ am4pbat tcl@8.6.8%gcc
64mns5m ^zlib@1.2.8%gcc cppflags="-O3"
- 2woov64 openssl@1.0.2k%gcc
+ qhwyccy tcl@8.6.8%gcc
5nus6kn ^zlib@1.2.11%gcc
- ae2hwm7 pkg-config@0.29.2%gcc
+ zs7a2pc texinfo@6.5%gcc
+ ic2kyoa ^perl@5.26.2%gcc
+ q4fpyuo ^gdbm@1.14.1%gcc
+ nxhwrg7 ^readline@7.0%gcc
+ 3o765ou ^ncurses@6.1%gcc
milz7fm util-macros@1.19.1%gcc
- htnq7wq xz@5.2.3%gcc
+ teneqii xz@5.2.4%gcc
bkyl5bh zlib@1.2.8%gcc
@@ -756,6 +860,30 @@ DAG as a graph.
o | zlib
/
o mpich
+ o findutils
+ |\
+ | |\
+ | | |\
+ | | | |\
+ o | | | | texinfo
+ | | | o | automake
+ | |_|/| |
+ |/| | | |
+ | | | |/
+ | | | o autoconf
+ | |_|/|
+ |/| |/
+ | |/|
+ o | | perl
+ o | | gdbm
+ o | | readline
+ o | | ncurses
+ o | | pkgconf
+ / /
+ | o libtool
+ |/
+ o m4
+ o libsigsegv
You may also have noticed that there are some packages shown in the
``spack find -d`` output that we didn't install explicitly. These are
@@ -777,270 +905,237 @@ let's look at an even more complicated package.
.. code-block:: console
- $ spack install --use-cache trilinos
+ $ spack install trilinos
+ ==> Installing diffutils
+ ==> Searching for binary cache of diffutils
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> Installing diffutils from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/diffutils-3.6/linux-ubuntu16.04-x86_64-gcc-5.4.0-diffutils-3.6-2rhuivgjrna2nrxhntyde6md2khcvs34.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat Nov 10 05:30:17 2018 UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed diffutils from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/diffutils-3.6-2rhuivgjrna2nrxhntyde6md2khcvs34
==> Installing bzip2
==> Searching for binary cache of bzip2
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.1-e4gz6f2l5ik3ijuk3alwsqplex4tbvin.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpich-3.2-cymrnoowcc4vdyvdnf5ypvob4cmdadk5.spec.yaml
- ######################################################################## 100.0%
==> Installing bzip2 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/bzip2-1.0.6/linux-ubuntu16.04-x86_64-gcc-5.4.0-bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/bzip2-1.0.6/linux-ubuntu16.04-x86_64-gcc-5.4.0-bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:39:37 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:34:37 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed bzip2 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> Installing boost
==> Searching for binary cache of boost
==> Installing boost from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.65.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-boost-1.65.1-xxqnbqql5nup7rujer2ury3hsdgcumzb.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.68.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-boost-1.68.0-zbgfxapchxa4awxdwpleubfuznblxzvt.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:43:14 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 04:58:55 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed boost from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.65.1-xxqnbqql5nup7rujer2ury3hsdgcumzb
- ==> pkg-config is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
- ==> Installing ncurses
- ==> Searching for binary cache of ncurses
- ==> Installing ncurses from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-ncurses-6.0-ukq4tccptm2rxd56d2bumqthnpcjzlez.spack
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.68.0-zbgfxapchxa4awxdwpleubfuznblxzvt
+ ==> pkgconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkgconf-1.4.2-fovrh7alpft646n6mhis5mml6k6e5f4v
+ ==> ncurses is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.1-3o765ourmesfrji6yeclb4wb5w54aqbh
+ ==> readline is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0-nxhwrg7xwc6nbsm2v4ezwe63l6nfidbi
+ ==> gdbm is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.14.1-q4fpyuo7ouhkeq6d3oabtrppctpvxmes
+ ==> perl is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.26.2-ic2kyoadgp3dxfejcbllyplj2wf524fo
+ ==> Installing openssl
+ ==> Searching for binary cache of openssl
+ ==> Installing openssl from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2o/linux-ubuntu16.04-x86_64-gcc-5.4.0-openssl-1.0.2o-b4y3w3bsyvjla6eesv4vt6aplpfrpsha.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:06:38 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:24:10 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed ncurses from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.0-ukq4tccptm2rxd56d2bumqthnpcjzlez
- ==> openssl is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k-2woov64m3n4gjtnfp722qcyemzf2qtom
+ ==> Successfully installed openssl from binary cache
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2o-b4y3w3bsyvjla6eesv4vt6aplpfrpsha
==> Installing cmake
==> Searching for binary cache of cmake
==> Installing cmake from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/cmake-3.9.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-cmake-3.9.4-a2lyofsoxutyy4ihvzopizpbjubtdoem.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/cmake-3.12.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-cmake-3.12.3-otafqzhh4xnlq2mpakch7dr3tjfsrjnx.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 01:22:03 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:33:15 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed cmake from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/cmake-3.9.4-a2lyofsoxutyy4ihvzopizpbjubtdoem
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/cmake-3.12.3-otafqzhh4xnlq2mpakch7dr3tjfsrjnx
==> Installing glm
==> Searching for binary cache of glm
==> Installing glm from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/glm-0.9.7.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-glm-0.9.7.1-jnw622jwcbsymzj2fsx22omjl7tmvaws.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/glm-0.9.7.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-glm-0.9.7.1-jnw622jwcbsymzj2fsx22omjl7tmvaws.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:38 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:30:33 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed glm from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/glm-0.9.7.1-jnw622jwcbsymzj2fsx22omjl7tmvaws
- ==> libsigsegv is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
- ==> m4 is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
- ==> libtool is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
- ==> util-macros is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr
- ==> libpciaccess is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libpciaccess-0.13.5-5urc6tcjae26fbbd2wyfohoszhgxtbmc
- ==> xz is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/xz-5.2.3-htnq7wqdrqtof6uxqicdj3f7oe3xz6pw
- ==> libxml2 is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libxml2-2.9.4-sxk64lvcxhqjflzesnf3ye4wakovwi45
- ==> hwloc is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hwloc-1.11.8-ivg4d2e6anxwin4zbld2g4qlrbuquoyg
- ==> openmpi is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/glm-0.9.7.1-jnw622jwcbsymzj2fsx22omjl7tmvaws
+ ==> libsigsegv is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
+ ==> m4 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-suf5jtcfehivwfesrc5hjy72r4nukyel
+ ==> libtool is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
+ ==> util-macros is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/util-macros-1.19.1-milz7fmttmptcic2qdk5cnel7ll5sybr
+ ==> libpciaccess is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libpciaccess-0.13.5-5urc6tcjae26fbbd2wyfohoszhgxtbmc
+ ==> xz is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/xz-5.2.4-teneqii2xv5u6zl5r6qi3pwurc6pmypz
+ ==> libxml2 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libxml2-2.9.8-wpexsphdmfayxqxd4up5vgwuqgu5woo7
+ ==> autoconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69-3sx2gxeibc4oasqd4o5h6lnwpcpsgd2q
+ ==> automake is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.16.1-rymw7imfehycqxzj4nuy2oiw3abegooy
+ ==> numactl is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/numactl-2.0.11-ft463odrombnxlc3qew4omckhlq7tqgc
+ ==> hwloc is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hwloc-1.11.9-43tkw5mt6huhv37vqnybqgxtkodbsava
+ ==> openmpi is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx
==> Installing hdf5
==> Searching for binary cache of hdf5
==> Installing hdf5 from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.1-d73xxpvfxgd2z2ypmuuwtxhoxmzdglez.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-hdf5-1.10.4-oqwnui7wtovuf2id4vjwcxfmxlzjus6y.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:39:36 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:09:10 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hdf5 from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-d73xxpvfxgd2z2ypmuuwtxhoxmzdglez
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-oqwnui7wtovuf2id4vjwcxfmxlzjus6y
==> Installing openblas
==> Searching for binary cache of openblas
==> Installing openblas from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openblas-0.2.20/linux-ubuntu16.04-x86_64-gcc-5.4.0-openblas-0.2.20-4dahl6ltbpojei4s3stbqbq5iuuqlaxo.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/openblas-0.3.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-openblas-0.3.3-cyeg2yiitpuqglhvbox5gtbgsim2v5vn.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:43:22 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:32:04 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed openblas from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openblas-0.2.20-4dahl6ltbpojei4s3stbqbq5iuuqlaxo
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openblas-0.3.3-cyeg2yiitpuqglhvbox5gtbgsim2v5vn
==> Installing hypre
==> Searching for binary cache of hypre
==> Installing hypre from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.12.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hypre-2.12.1-z3rgfzqc4gu4u4qvveyo2dqqzl2j463z.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.15.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hypre-2.15.1-fshksdpecwiq7r6vawfswpboedhbisju.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:17 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:07:34 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hypre from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.12.1-z3rgfzqc4gu4u4qvveyo2dqqzl2j463z
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.15.1-fshksdpecwiq7r6vawfswpboedhbisju
==> Installing matio
==> Searching for binary cache of matio
==> Installing matio from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9/linux-ubuntu16.04-x86_64-gcc-5.4.0-matio-1.5.9-4ajrcuhdf5uktotnrfzufufy5vbd6any.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9/linux-ubuntu16.04-x86_64-gcc-5.4.0-matio-1.5.9-lmzdgssvobdljw52mtahelu2ju7osh6h.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:24 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:05:13 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed matio from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9-4ajrcuhdf5uktotnrfzufufy5vbd6any
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9-lmzdgssvobdljw52mtahelu2ju7osh6h
==> Installing metis
==> Searching for binary cache of metis
==> Installing metis from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/metis-5.1.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-metis-5.1.0-m34qytcqsvsaduxyh3wevf3kj6pbzyw6.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/metis-5.1.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-metis-5.1.0-3wnvp4ji3wwu4v4vymszrhx6naehs6jc.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:39:28 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:31:42 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed metis from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/metis-5.1.0-m34qytcqsvsaduxyh3wevf3kj6pbzyw6
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/metis-5.1.0-3wnvp4ji3wwu4v4vymszrhx6naehs6jc
==> Installing netlib-scalapack
==> Searching for binary cache of netlib-scalapack
==> Installing netlib-scalapack from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-netlib-scalapack-2.0.2-xudg7xypr63nte6ifrdsmllilxbrfiar.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-netlib-scalapack-2.0.2-wotpfwfctgfkzzn2uescucxvvbg3tm6b.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:28 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:07:22 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed netlib-scalapack from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-xudg7xypr63nte6ifrdsmllilxbrfiar
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-wotpfwfctgfkzzn2uescucxvvbg3tm6b
==> Installing mumps
==> Searching for binary cache of mumps
==> Installing mumps from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-mumps-5.1.1-5a7hgodxoze47xqd32jcxhvzctex4ezx.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-mumps-5.1.1-acsg2dzroox2swssgc5cwgkvdy6jcm5q.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:15 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:18:32 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed mumps from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1-5a7hgodxoze47xqd32jcxhvzctex4ezx
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1-acsg2dzroox2swssgc5cwgkvdy6jcm5q
==> Installing netcdf
==> Searching for binary cache of netcdf
==> Installing netcdf from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.4.1.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-netcdf-4.4.1.1-gk2xxhbqijnrdwicawawcll4t3c7dvoj.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.6.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-netcdf-4.6.1-mhm4izpogf4mrjidyskb6ewtzxdi7t6g.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:43:37 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:11:57 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed netcdf from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.4.1.1-gk2xxhbqijnrdwicawawcll4t3c7dvoj
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.6.1-mhm4izpogf4mrjidyskb6ewtzxdi7t6g
==> Installing parmetis
==> Searching for binary cache of parmetis
==> Installing parmetis from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-parmetis-4.0.3-o4qdo7aylhejov2e5ii7tagrnw6qrrlo.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-parmetis-4.0.3-uv6h3sqx6quqg22hxesi2mw2un3kw6b7.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:39:37 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:12:04 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed parmetis from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3-o4qdo7aylhejov2e5ii7tagrnw6qrrlo
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3-uv6h3sqx6quqg22hxesi2mw2un3kw6b7
==> Installing suite-sparse
==> Searching for binary cache of suite-sparse
==> Installing suite-sparse from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/suite-sparse-4.5.5/linux-ubuntu16.04-x86_64-gcc-5.4.0-suite-sparse-4.5.5-bg67crx4ltmxulnumuxjxqzrcobpmyzg.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/suite-sparse-5.3.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-suite-sparse-5.3.0-zaau4kifha2enpdcn3mjlrqym7hm7yon.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:30:31 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:22:54 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed suite-sparse from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/suite-sparse-4.5.5-bg67crx4ltmxulnumuxjxqzrcobpmyzg
- ==> Installing superlu-dist
- ==> Searching for binary cache of superlu-dist
- ==> Installing superlu-dist from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/superlu-dist-5.2.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-superlu-dist-5.2.2-gggsamgizi2dwmwxglgzbxvg6hkamhol.spack
- ######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:43:35 AM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed superlu-dist from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/superlu-dist-5.2.2-gggsamgizi2dwmwxglgzbxvg6hkamhol
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/suite-sparse-5.3.0-zaau4kifha2enpdcn3mjlrqym7hm7yon
==> Installing trilinos
==> Searching for binary cache of trilinos
==> Installing trilinos from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-trilinos-12.12.1-istwe3b43b7etgtrhcuzjem3p5gonc6h.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-trilinos-12.12.1-rlsruavxqvwk2tgxzxboclbo6ykjf54r.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 11:47:19 PM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:18:10 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed trilinos from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-istwe3b43b7etgtrhcuzjem3p5gonc6h
-Now we're starting to see the power of Spack. Trilinos has 11 top
-level dependecies, many of which have dependencies of their
-own. Installing more complex packages can take days or weeks even for
-an experienced user. Although we've done a binary installation for the
-tutorial, a source installation of trilinos using Spack takes about 3
-hours (depending on the system), but only 20 seconds of programmer
-time.
+Now we're starting to see the power of Spack. Trilinos in its default
+configuration has 23 top level dependecies, many of which have
+dependencies of their own. Installing more complex packages can take
+days or weeks even for an experienced user. Although we've done a
+binary installation for the tutorial, a source installation of
+trilinos using Spack takes about 3 hours (depending on the system),
+but only 20 seconds of programmer time.
Spack manages constistency of the entire DAG. Every MPI dependency will
be satisfied by the same configuration of MPI, etc. If we install
@@ -1049,142 +1144,116 @@ with ``mpich``:
.. code-block:: console
- $ spack install --use-cache trilinos +hdf5 ^hdf5+hl+mpi ^mpich
- ==> bzip2 is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
- ==> boost is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.65.1-xxqnbqql5nup7rujer2ury3hsdgcumzb
- ==> pkg-config is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
- ==> ncurses is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.0-ukq4tccptm2rxd56d2bumqthnpcjzlez
- ==> openssl is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k-2woov64m3n4gjtnfp722qcyemzf2qtom
- ==> cmake is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/cmake-3.9.4-a2lyofsoxutyy4ihvzopizpbjubtdoem
- ==> glm is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/glm-0.9.7.1-jnw622jwcbsymzj2fsx22omjl7tmvaws
- ==> mpich is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpich-3.2-cymrnoowcc4vdyvdnf5ypvob4cmdadk5
- ==> hdf5 is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-e4gz6f2l5ik3ijuk3alwsqplex4tbvin
- ==> openblas is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openblas-0.2.20-4dahl6ltbpojei4s3stbqbq5iuuqlaxo
+ $ spack install trilinos +hdf5 ^hdf5+hl+mpi ^mpich
+ ==> diffutils is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/diffutils-3.6-2rhuivgjrna2nrxhntyde6md2khcvs34
+ ==> bzip2 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ ==> boost is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.68.0-zbgfxapchxa4awxdwpleubfuznblxzvt
+ ==> pkgconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkgconf-1.4.2-fovrh7alpft646n6mhis5mml6k6e5f4v
+ ==> ncurses is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.1-3o765ourmesfrji6yeclb4wb5w54aqbh
+ ==> readline is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0-nxhwrg7xwc6nbsm2v4ezwe63l6nfidbi
+ ==> gdbm is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.14.1-q4fpyuo7ouhkeq6d3oabtrppctpvxmes
+ ==> perl is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.26.2-ic2kyoadgp3dxfejcbllyplj2wf524fo
+ ==> openssl is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2o-b4y3w3bsyvjla6eesv4vt6aplpfrpsha
+ ==> cmake is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/cmake-3.12.3-otafqzhh4xnlq2mpakch7dr3tjfsrjnx
+ ==> glm is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/glm-0.9.7.1-jnw622jwcbsymzj2fsx22omjl7tmvaws
+ ==> libsigsegv is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
+ ==> m4 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-suf5jtcfehivwfesrc5hjy72r4nukyel
+ ==> autoconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69-3sx2gxeibc4oasqd4o5h6lnwpcpsgd2q
+ ==> automake is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.16.1-rymw7imfehycqxzj4nuy2oiw3abegooy
+ ==> libtool is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
+ ==> texinfo is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/texinfo-6.5-zs7a2pcwhq6ho2cj2x26uxfktwkpyucn
+ ==> findutils is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/findutils-4.6.0-d4iajxsopzrlcjtasahxqeyjkjv5jx4v
+ ==> mpich is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpich-3.2.1-p3f7p2r5ntrynqibosglxvhwyztiwqs5
+ ==> hdf5 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-xxd7syhgej6onpyfyewxqcqe7ltkt7ob
+ ==> openblas is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openblas-0.3.3-cyeg2yiitpuqglhvbox5gtbgsim2v5vn
==> Installing hypre
==> Searching for binary cache of hypre
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-netcdf-4.4.1.1-gk2xxhbqijnrdwicawawcll4t3c7dvoj.spec.yaml
- ######################################################################## 100.0%
- ...
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-bzip2-1.0.6-ufczdvsqt6edesm36xiucyry7myhj7e7.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-boost-1.65.1-xxqnbqql5nup7rujer2ury3hsdgcumzb.spec.yaml
- ######################################################################## 100.0%
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing hypre from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.12.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hypre-2.12.1-3psjg2ka2qa26jtgitlil4vglqr67anj.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.15.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-hypre-2.15.1-obewuozolon7tkdg4cfxc6ae2tzkronb.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:49:37 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:34:36 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed hypre from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.12.1-3psjg2ka2qa26jtgitlil4vglqr67anj
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hypre-2.15.1-obewuozolon7tkdg4cfxc6ae2tzkronb
==> Installing matio
==> Searching for binary cache of matio
==> Installing matio from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9/linux-ubuntu16.04-x86_64-gcc-5.4.0-matio-1.5.9-3ibrutc6cs7x6ybyt5ni5n6djtq5okm2.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9/linux-ubuntu16.04-x86_64-gcc-5.4.0-matio-1.5.9-gvyqldhifflmvcrtui3b6s64jcczsxxh.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:45:26 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:25:11 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed matio from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9-3ibrutc6cs7x6ybyt5ni5n6djtq5okm2
- ==> metis is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/metis-5.1.0-m34qytcqsvsaduxyh3wevf3kj6pbzyw6
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/matio-1.5.9-gvyqldhifflmvcrtui3b6s64jcczsxxh
+ ==> metis is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/metis-5.1.0-3wnvp4ji3wwu4v4vymszrhx6naehs6jc
==> Installing netlib-scalapack
==> Searching for binary cache of netlib-scalapack
==> Installing netlib-scalapack from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-netlib-scalapack-2.0.2-p7iln2pcosw2ipyqoyr7ie6lpva2oj7r.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:49:49 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:32:20 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed netlib-scalapack from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-p7iln2pcosw2ipyqoyr7ie6lpva2oj7r
==> Installing mumps
==> Searching for binary cache of mumps
==> Installing mumps from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-mumps-5.1.1-phvk6yhkzqed6gjsbah6dnhlesdclild.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-mumps-5.1.1-cumcj5a75cagsznpjrgretxdg6okxaur.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:45:28 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:33:18 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed mumps from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1-phvk6yhkzqed6gjsbah6dnhlesdclild
- ==> libsigsegv is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
- ==> m4 is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mumps-5.1.1-cumcj5a75cagsznpjrgretxdg6okxaur
==> Installing netcdf
==> Searching for binary cache of netcdf
==> Installing netcdf from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.4.1.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-netcdf-4.4.1.1-rmx4uppnhpv6kq7bh7r46zfqevgdkkgw.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.6.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-netcdf-4.6.1-wmmx5sgwfds34v7bkkhiduar5yecrnnd.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:49:38 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:24:01 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed netcdf from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.4.1.1-rmx4uppnhpv6kq7bh7r46zfqevgdkkgw
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netcdf-4.6.1-wmmx5sgwfds34v7bkkhiduar5yecrnnd
==> Installing parmetis
==> Searching for binary cache of parmetis
==> Installing parmetis from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-parmetis-4.0.3-qk77g6aiqr3f2hsykg54zzuhlxcpdcmv.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-parmetis-4.0.3-jehtatan4y2lcobj6waoqv66jj4libtz.spack
######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:45:14 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:07:41 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed parmetis from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3-qk77g6aiqr3f2hsykg54zzuhlxcpdcmv
- ==> suite-sparse is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/suite-sparse-4.5.5-bg67crx4ltmxulnumuxjxqzrcobpmyzg
- ==> Installing superlu-dist
- ==> Searching for binary cache of superlu-dist
- ==> Installing superlu-dist from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/superlu-dist-5.2.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-superlu-dist-5.2.2-65vot2le3ezooz7tj6eveovly725o44x.spack
- ######################################################################## 100.0%
- gpg: Signature made Sat 11 Nov 2017 12:45:14 AM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed superlu-dist from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/superlu-dist-5.2.2-65vot2le3ezooz7tj6eveovly725o44x
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/parmetis-4.0.3-jehtatan4y2lcobj6waoqv66jj4libtz
+ ==> suite-sparse is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/suite-sparse-5.3.0-zaau4kifha2enpdcn3mjlrqym7hm7yon
==> Installing trilinos
==> Searching for binary cache of trilinos
==> Installing trilinos from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-trilinos-12.12.1-xupifcp5d4f53cobm6g3xzao577uzezs.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-trilinos-12.12.1-kqc52moweigxqxzwzfqajc6ocxwdwn4w.spack
######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 12:04:58 AM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:30:15 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed trilinos from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-xupifcp5d4f53cobm6g3xzao577uzezs
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-kqc52moweigxqxzwzfqajc6ocxwdwn4w
We see that every package in the trilinos DAG that depends on MPI now
@@ -1193,47 +1262,47 @@ uses ``mpich``.
.. code-block:: console
$ spack find -d trilinos
- ==> 2 installed packages.
+ ==> 2 installed packages
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
trilinos@12.12.1
- ^boost@1.65.1
+ ^boost@1.68.0
^bzip2@1.0.6
^zlib@1.2.11
^glm@0.9.7.1
- ^hdf5@1.10.1
- ^openmpi@3.0.0
- ^hwloc@1.11.8
+ ^hdf5@1.10.4
+ ^openmpi@3.1.3
+ ^hwloc@1.11.9
^libpciaccess@0.13.5
- ^libxml2@2.9.4
- ^xz@5.2.3
- ^hypre@2.12.1
- ^openblas@0.2.20
+ ^libxml2@2.9.8
+ ^xz@5.2.4
+ ^numactl@2.0.11
+ ^hypre@2.15.1
+ ^openblas@0.3.3
^matio@1.5.9
^metis@5.1.0
^mumps@5.1.1
^netlib-scalapack@2.0.2
- ^netcdf@4.4.1.1
+ ^netcdf@4.6.1
^parmetis@4.0.3
- ^suite-sparse@4.5.5
- ^superlu-dist@5.2.2
+ ^suite-sparse@5.3.0
trilinos@12.12.1
- ^boost@1.65.1
+ ^boost@1.68.0
^bzip2@1.0.6
^zlib@1.2.11
^glm@0.9.7.1
- ^hdf5@1.10.1
- ^mpich@3.2
- ^hypre@2.12.1
- ^openblas@0.2.20
+ ^hdf5@1.10.4
+ ^mpich@3.2.1
+ ^hypre@2.15.1
+ ^openblas@0.3.3
^matio@1.5.9
^metis@5.1.0
^mumps@5.1.1
^netlib-scalapack@2.0.2
- ^netcdf@4.4.1.1
+ ^netcdf@4.6.1
^parmetis@4.0.3
- ^suite-sparse@4.5.5
- ^superlu-dist@5.2.2
+ ^suite-sparse@5.3.0
+
As we discussed before, the ``spack find -d`` command shows the
dependency information as a tree. While that is often sufficient, many
@@ -1258,95 +1327,111 @@ command shows the full DAG of the dependency information.
| | | | | | | | | | |\
| | | | | | | | | | | |\
| | | | | | | | | | | | |\
- | | | | | | | | | | | | | |\
- o | | | | | | | | | | | | | | superlu-dist
- |\ \ \ \ \ \ \ \ \ \ \ \ \ \ \
- | |_|/ / / / / / / / / / / / /
- |/| | | | | | | | | | | | | |
- | |\ \ \ \ \ \ \ \ \ \ \ \ \ \
- | | |_|/ / / / / / / / / / / /
- | |/| | | | | | | | | | | | |
- | | |\ \ \ \ \ \ \ \ \ \ \ \ \
- | | | |_|/ / / / / / / / / / /
- | | |/| | | | | | | | | | | |
- | | | | |_|_|/ / / / / / / /
- | | | |/| | | | | | | | | |
- | | | | o | | | | | | | | | suite-sparse
- | | | |/| | | | | | | | | |
- | | |/|/ / / / / / / / / /
- o | | | | | | | | | | | | parmetis
- |\| | | | | | | | | | | |
- |\ \ \ \ \ \ \ \ \ \ \ \ \
- | |_|_|/ / / / / / / / / /
- |/| | | | | | | | | | | |
- | | |_|_|_|_|_|_|_|/ / /
- | |/| | | | | | | | | |
+ o | | | | | | | | | | | | | suite-sparse
+ |\ \ \ \ \ \ \ \ \ \ \ \ \ \
+ | |_|_|/ / / / / / / / / / /
+ |/| | | | | | | | | | | | |
+ | |\ \ \ \ \ \ \ \ \ \ \ \ \
+ | | |_|_|_|_|_|/ / / / / / /
+ | |/| | | | | | | | | | | |
+ | | | |_|_|_|_|_|_|_|/ / /
+ | | |/| | | | | | | | | |
+ | | | o | | | | | | | | | parmetis
+ | | |/| | | | | | | | | |
+ | |/|/| | | | | | | | | |
+ | | | |/ / / / / / / / /
| | | | | | o | | | | | mumps
- | | | |_|_|/| | | | | |
- | | |/| |_|/| | | | | |
+ | |_|_|_|_|/| | | | | |
+ |/| | | |_|/| | | | | |
| | | |/| |/ / / / / /
| | | | |/| | | | | |
| | | | o | | | | | | netlib-scalapack
- | | |_|/| | | | | | |
- | |/| |/| | | | | | |
+ | |_|_|/| | | | | | |
+ |/| | |/| | | | | | |
| | |/|/ / / / / / /
- o | | | | | | | | | metis
- |/ / / / / / / / /
+ | o | | | | | | | | metis
+ | |/ / / / / / / /
| | | | | | | o | glm
- | |_|_|_|_|_|/ /
- |/| | | | | | |
- o | | | | | | | cmake
- |\ \ \ \ \ \ \ \
- o | | | | | | | | openssl
- | | | | o | | | | netcdf
- | |_|_|/| | | | |
- |/| | |/| | | | |
- | | |/| | | | | |
- | | | | |\ \ \ \ \
- | | | | | | |_|/ /
- | | | | | |/| | |
- | | | | | | o | | matio
- | |_|_|_|_|/| | |
- |/| | | | |/ / /
- | | | | | | o | hypre
- | | | |_|_|/| |
- | | |/| |_|/ /
+ | | |_|_|_|_|/ /
+ | |/| | | | | |
+ | o | | | | | | cmake
+ | |\ \ \ \ \ \ \
+ | o | | | | | | | openssl
+ | |\ \ \ \ \ \ \ \
+ | | | | | o | | | | netcdf
+ | | |_|_|/| | | | |
+ | |/| | |/| | | | |
+ | | | | | |\ \ \ \ \
+ | | | | | | | |_|/ /
+ | | | | | | |/| | |
+ | | | | | | | o | | matio
+ | | |_|_|_|_|/| | |
+ | |/| | | | |/ / /
+ | | | | | | | o | hypre
+ | |_|_|_|_|_|/| |
+ |/| | | | |_|/ /
+ | | | | |/| | |
+ | | | | | | o | hdf5
+ | | |_|_|_|/| |
+ | |/| | | |/ /
+ | | | | |/| |
+ | | | | o | | openmpi
+ | | |_|/| | |
+ | |/| | | | |
+ | | | | |\ \ \
+ | | | | | o | | hwloc
+ | | | | |/| | |
+ | | | | | |\ \ \
+ | | | | | | |\ \ \
+ | | | | | | o | | | libxml2
+ | | |_|_|_|/| | | |
+ | |/| | | |/| | | |
+ | | | | | | | | | o boost
+ | | |_|_|_|_|_|_|/|
+ | |/| | | | | | | |
+ | o | | | | | | | | zlib
+ | / / / / / / / /
+ | | | | | o | | | xz
+ | | | | | / / /
+ | | | | | o | | libpciaccess
+ | | | | |/| | |
+ | | | | | |\ \ \
+ | | | | | o | | | util-macros
+ | | | | | / / /
+ | | | o | | | | numactl
+ | | | |\ \ \ \ \
+ | | | | |_|_|/ /
+ | | | |/| | | |
+ | | | | |\ \ \ \
+ | | | | | |_|/ /
+ | | | | |/| | |
+ | | | | | |\ \ \
+ | | | | | o | | | automake
+ | | |_|_|/| | | |
+ | |/| | | | | | |
+ | | | | | |/ / /
+ | | | | | o | | autoconf
+ | | |_|_|/| | |
+ | |/| | |/ / /
| | | |/| | |
- | | | | | o | hdf5
- | |_|_|_|/| |
- |/| | |_|/ /
- | | |/| | |
- | | o | | | openmpi
- | | o | | | hwloc
- | | |\ \ \ \
- | | | |\ \ \ \
- | | | o | | | | libxml2
- | |_|/| | | | |
- |/| |/| | | | |
- | | | | | | | o boost
- | |_|_|_|_|_|/|
- |/| | | | | | |
- o | | | | | | | zlib
- / / / / / / /
- | | o | | | | xz
- | | / / / /
- | | o | | | libpciaccess
- | |/| | | |
- | | |\ \ \ \
- | | o | | | | util-macros
- | | / / / /
- o | | | | | ncurses
- |/ / / / /
- o | | | | pkg-config
- / / / /
- | o | | openblas
- | / /
- o | | libtool
- |/ /
- o | m4
- o | libsigsegv
- /
- o bzip2
+ | o | | | | | perl
+ | o | | | | | gdbm
+ | o | | | | | readline
+ | |/ / / / /
+ | o | | | | ncurses
+ | | |_|/ /
+ | |/| | |
+ | o | | | pkgconf
+ | / / /
+ o | | | openblas
+ / / /
+ | o | libtool
+ |/ /
+ o | m4
+ o | libsigsegv
+ /
+ o bzip2
+ o diffutils
You can control how the output is displayed with a number of options.
@@ -1364,25 +1449,27 @@ complicated packages. The output can be changed to the ``graphviz``
Uninstalling Packages
---------------------
-Earlier we installed many configurations each of zlib and
-openssl. Now we will go through and uninstall some of those packages
-that we didn't really need.
+Earlier we installed many configurations each of zlib and tcl. Now we
+will go through and uninstall some of those packages that we didn't
+really need.
.. code-block:: console
- $ spack find -d openssl
- ==> 3 installed packages.
+ $ spack find -d tcl
+ ==> 3 installed packages
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
- openssl@1.0.2k
+ tcl@8.6.8
^zlib@1.2.8
+
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- openssl@1.0.2k
+ tcl@8.6.8
^zlib@1.2.8
- openssl@1.0.2k
+ tcl@8.6.8
^zlib@1.2.11
+
$ spack find zlib
==> 6 installed packages.
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
@@ -1411,15 +1498,12 @@ We can uninstall packages by spec using the same syntax as install.
==> 5 installed packages.
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
i426yu3 zlib@1.2.8%clang
-
4pt75q7 zlib@1.2.11%clang
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
bkyl5bh zlib@1.2.8%gcc
-
64mns5m zlib@1.2.8%gcc cppflags="-O3"
-
5nus6kn zlib@1.2.11%gcc
We can also uninstall packages by referring only to their hash.
@@ -1433,22 +1517,19 @@ remove packages that are required by another installed package.
==> Error: Will not uninstall zlib@1.2.8%clang@3.8.0-2ubuntu4/i426yu3
The following packages depend on it:
- -- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
- ufruk7k openssl@1.0.2k%clang
-
+ -- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
+ 6wc66et tcl@8.6.8%clang
==> Error: Use \`spack uninstall --dependents\` to uninstall these dependencies as well.
$ spack uninstall -R zlib/i426
==> The following packages will be uninstalled:
- -- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
- ufruk7k openssl@1.0.2k%clang
-
- i426yu3 zlib@1.2.8%clang+optimize+pic+shared
-
+ -- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
+ 6wc66et tcl@8.6.8%clang
+ i426yu3 zlib@1.2.8%clang+optimize+pic+shared
==> Do you want to proceed? [y/N] y
- ==> Successfully uninstalled openssl@1.0.2k%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64 /ufruk7k
+ ==> Successfully uninstalled tcl@8.6.8%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64 /6wc66et
==> Successfully uninstalled zlib@1.2.8%clang@3.8.0-2ubuntu4+optimize+pic+shared arch=linux-ubuntu16.04-x86_64 /i426yu3
Spack will not uninstall packages that are not sufficiently
@@ -1460,25 +1541,22 @@ packages at once.
$ spack uninstall trilinos
==> Error: trilinos matches multiple packages:
- -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- istwe3b trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~dtk+epetra+epetraext+exodus+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2+instantiate~instantiate_cmplx~intrepid~intrepid2+metis+ml+muelu+mumps~nox~openmp~pnetcdf~python~rol+sacado~shards+shared~stk+suite-sparse~superlu+superlu-dist+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
-
- xupifcp trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~dtk+epetra+epetraext+exodus+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2+instantiate~instantiate_cmplx~intrepid~intrepid2+metis+ml+muelu+mumps~nox~openmp~pnetcdf~python~rol+sacado~shards+shared~stk+suite-sparse~superlu+superlu-dist+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
-
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ rlsruav trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
+ kqc52mo trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
==> Error: You can either:
a) use a more specific spec, or
b) use `spack uninstall --all` to uninstall ALL matching specs.
- $ spack uninstall /istw
+ $ spack uninstall /rlsr
==> The following packages will be uninstalled:
- -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- istwe3b trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~dtk+epetra+epetraext+exodus+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2+instantiate~instantiate_cmplx~intrepid~intrepid2+metis+ml+muelu+mumps~nox~openmp~pnetcdf~python~rol+sacado~shards+shared~stk+suite-sparse~superlu+superlu-dist+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
-
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ rlsruav trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
==> Do you want to proceed? [y/N] y
- ==> Successfully uninstalled trilinos@12.12.1%gcc@5.4.0~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~dtk+epetra+epetraext+exodus+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2+instantiate~instantiate_cmplx~intrepid~intrepid2+metis+ml+muelu+mumps~nox~openmp~pnetcdf~python~rol+sacado~shards+shared~stk+suite-sparse~superlu+superlu-dist+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2 arch=linux-ubuntu16.04-x86_64 /istwe3b
+ ==> Successfully uninstalled trilinos@12.12.1%gcc@5.4.0~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2 arch=linux-ubuntu16.04-x86_64 /rlsruav
-----------------------------
Advanced ``spack find`` Usage
@@ -1497,10 +1575,10 @@ return every package which was built with ``cppflags="-O3"``.
.. code-block:: console
$ spack find ^mpich
- ==> 9 installed packages.
+ ==> 8 installed packages
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- hdf5@1.10.1 hypre@2.12.1 matio@1.5.9 mumps@5.1.1 netcdf@4.4.1.1 netlib-scalapack@2.0.2 parmetis@4.0.3 superlu-dist@5.2.2 trilinos@12.12.1
-
+ hdf5@1.10.4 matio@1.5.9 netcdf@4.6.1 parmetis@4.0.3
+ hypre@2.15.1 mumps@5.1.1 netlib-scalapack@2.0.2 trilinos@12.12.1
$ spack find cppflags=-O3
==> 1 installed packages.
@@ -1508,28 +1586,28 @@ return every package which was built with ``cppflags="-O3"``.
zlib@1.2.8
The ``find`` command can also show which packages were installed
-explicitly (rather than pulled in as a dependency) using the ``-e``
-flag. The ``-E`` flag shows implicit installs only. The ``find`` command can
+explicitly (rather than pulled in as a dependency) using the ``-x``
+flag. The ``-X`` flag shows implicit installs only. The ``find`` command can
also show the path to which a spack package was installed using the ``-p``
command.
.. code-block:: console
- $ spack find -pe
- ==> 10 installed packages.
+ $ spack find -px
+ ==> 10 installed packages
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
- zlib@1.2.11 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul
+ zlib@1.2.11 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/clang-3.8.0-2ubuntu4/zlib-1.2.11-4pt75q7qq6lygf3hgnona4lyc2uwedul
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- hdf5@1.10.1 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-pa6oqzfeqzkqkzqr2375fqyt3qggx3tr
- hdf5@1.10.1 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-bovz45ms24pmfr7hlckf56bxegfc4rea
- hdf5@1.10.1 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.1-e4gz6f2l5ik3ijuk3alwsqplex4tbvin
- openssl@1.0.2k /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k-gyxmhgbam26d7y42omb7xrvkjjgmzwio
- openssl@1.0.2k /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openssl-1.0.2k-2woov64m3n4gjtnfp722qcyemzf2qtom
- trilinos@12.12.1 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-xupifcp5d4f53cobm6g3xzao577uzezs
- zlib@1.2.8 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc
- zlib@1.2.8 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu
- zlib@1.2.11 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ hdf5@1.10.4 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-5vcv5r67vpjzenq4apyebshclelnzuja
+ hdf5@1.10.4 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-ozyvmhzdew66byarohm4p36ep7wtcuiw
+ hdf5@1.10.4 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-xxd7syhgej6onpyfyewxqcqe7ltkt7ob
+ tcl@8.6.8 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8-am4pbatrtga3etyusg2akmsvrswwxno2
+ tcl@8.6.8 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8-qhwyccywhx2i6s7ob2gvjrjtj3rnfuqt
+ trilinos@12.12.1 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-kqc52moweigxqxzwzfqajc6ocxwdwn4w
+ zlib@1.2.8 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-bkyl5bhuep6fmhuxzkmhqy25qefjcvzc
+ zlib@1.2.8 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.8-64mns5mvdacqvlashkf7v6lqrxixhmxu
+ zlib@1.2.11 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
---------------------
Customizing Compilers
@@ -1557,175 +1635,86 @@ added to the configuration.
.. code-block:: console
- $ spack install --use-cache gcc
- ==> libsigsegv is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
- ==> m4 is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
- ==> pkg-config is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
- ==> ncurses is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.0-ukq4tccptm2rxd56d2bumqthnpcjzlez
- ==> Installing readline
- ==> Searching for binary cache of readline
- ==> Finding buildcaches in /home/ubuntu/becker/buildcache/build_cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-matio-1.5.9-3ibrutc6cs7x6ybyt5ni5n6djtq5okm2.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-trilinos-12.12.1-xupifcp5d4f53cobm6g3xzao577uzezs.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-parmetis-4.0.3-qk77g6aiqr3f2hsykg54zzuhlxcpdcmv.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-superlu-dist-5.2.2-65vot2le3ezooz7tj6eveovly725o44x.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-hypre-2.12.1-3psjg2ka2qa26jtgitlil4vglqr67anj.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-mumps-5.1.1-phvk6yhkzqed6gjsbah6dnhlesdclild.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-netcdf-4.4.1.1-rmx4uppnhpv6kq7bh7r46zfqevgdkkgw.spec.yaml
- ######################################################################## 100.0%
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64-gcc-5.4.0-netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z.spec.yaml
- ######################################################################## 100.0%
- ==> Installing readline from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-readline-7.0-gizxpch53zv5ufa62a2tb5lalcqgxbuc.spack
- ######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:26:53 PM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed readline from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0-gizxpch53zv5ufa62a2tb5lalcqgxbuc
- ==> Installing gdbm
- ==> Searching for binary cache of gdbm
- ==> Installing gdbm from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.13/linux-ubuntu16.04-x86_64-gcc-5.4.0-gdbm-1.13-vdhoris6wdzzb2ykax2hz7qzgizk5h3t.spack
- ######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:26:51 PM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed gdbm from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.13-vdhoris6wdzzb2ykax2hz7qzgizk5h3t
- ==> Installing perl
- ==> Searching for binary cache of perl
- ==> Installing perl from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.24.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-perl-5.24.1-mfzwy6y5mlbqpqvti4etpe3cgkmxkpi2.spack
- ######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:27:19 PM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed perl from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.24.1-mfzwy6y5mlbqpqvti4etpe3cgkmxkpi2
- ==> Installing autoconf
- ==> Searching for binary cache of autoconf
- ==> Installing autoconf from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69/linux-ubuntu16.04-x86_64-gcc-5.4.0-autoconf-2.69-bvabhjiklhi7c5742ixzs7hubhid3ax2.spack
- ######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:27:22 PM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed autoconf from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69-bvabhjiklhi7c5742ixzs7hubhid3ax2
- ==> Installing automake
- ==> Searching for binary cache of automake
- ==> Installing automake from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.15.1/linux-ubuntu16.04-x86_64-gcc-5.4.0-automake-1.15.1-kaiefe4j2lsq6b32ncrclmbeoa5z25a5.spack
- ######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:27:21 PM UTC using RSA key ID 3B7C69B2
- gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
- ==> Successfully installed automake from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.15.1-kaiefe4j2lsq6b32ncrclmbeoa5z25a5
- ==> libtool is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
+ $ spack install gcc
+ ==> libsigsegv is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
+ ==> m4 is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-suf5jtcfehivwfesrc5hjy72r4nukyel
+ ==> pkgconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkgconf-1.4.2-fovrh7alpft646n6mhis5mml6k6e5f4v
+ ==> ncurses is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/ncurses-6.1-3o765ourmesfrji6yeclb4wb5w54aqbh
+ ==> readline is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/readline-7.0-nxhwrg7xwc6nbsm2v4ezwe63l6nfidbi
+ ==> gdbm is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gdbm-1.14.1-q4fpyuo7ouhkeq6d3oabtrppctpvxmes
+ ==> perl is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/perl-5.26.2-ic2kyoadgp3dxfejcbllyplj2wf524fo
+ ==> autoconf is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/autoconf-2.69-3sx2gxeibc4oasqd4o5h6lnwpcpsgd2q
+ ==> automake is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/automake-1.16.1-rymw7imfehycqxzj4nuy2oiw3abegooy
+ ==> libtool is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libtool-2.4.6-o2pfwjf44353ajgr42xqtvzyvqsazkgu
==> Installing gmp
==> Searching for binary cache of gmp
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing gmp from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/gmp-6.1.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-gmp-6.1.2-qc4qcfz4monpllc3nqupdo7vwinf73sw.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/gmp-6.1.2/linux-ubuntu16.04-x86_64-gcc-5.4.0-gmp-6.1.2-qc4qcfz4monpllc3nqupdo7vwinf73sw.spack
######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:12:29 PM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:18:16 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed gmp from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gmp-6.1.2-qc4qcfz4monpllc3nqupdo7vwinf73sw
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gmp-6.1.2-qc4qcfz4monpllc3nqupdo7vwinf73sw
==> Installing isl
==> Searching for binary cache of isl
==> Installing isl from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/isl-0.18/linux-ubuntu16.04-x86_64-gcc-5.4.0-isl-0.18-vttqoutnsmjpm3ogb52rninksc7hq5ax.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/isl-0.18/linux-ubuntu16.04-x86_64-gcc-5.4.0-isl-0.18-vttqoutnsmjpm3ogb52rninksc7hq5ax.spack
######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:12:28 PM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:05:19 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed isl from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/isl-0.18-vttqoutnsmjpm3ogb52rninksc7hq5ax
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/isl-0.18-vttqoutnsmjpm3ogb52rninksc7hq5ax
==> Installing mpfr
==> Searching for binary cache of mpfr
==> Installing mpfr from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpfr-3.1.5/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpfr-3.1.5-mdi6irzvxcbemt7yredzr36dvo6ty4sl.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpfr-3.1.6/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpfr-3.1.6-jnt2nnp5pmvikbw7opueajlbwbhmjxyv.spack
######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:12:30 PM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:32:07 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed mpfr from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpfr-3.1.5-mdi6irzvxcbemt7yredzr36dvo6ty4sl
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpfr-3.1.6-jnt2nnp5pmvikbw7opueajlbwbhmjxyv
==> Installing mpc
==> Searching for binary cache of mpc
==> Installing mpc from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpc-1.0.3/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpc-1.0.3-tumbpshu5hjxwextoudk5hmic6nspb3z.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpc-1.1.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-mpc-1.1.0-iuf3gc3zpgr4n4mditnxhff6x3joxi27.spack
######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:12:29 PM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:30:35 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed mpc from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpc-1.0.3-tumbpshu5hjxwextoudk5hmic6nspb3z
- ==> zlib is already installed in /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
- ==> Installing gcc
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpc-1.1.0-iuf3gc3zpgr4n4mditnxhff6x3joxi27
+ ==> zlib is already installed in /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ Installing gcc
==> Searching for binary cache of gcc
+ ==> Finding buildcaches in /mirror/build_cache
==> Installing gcc from binary cache
- ==> Fetching file:///home/ubuntu/becker/buildcache/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-gcc-7.2.0-k3vy57euyeuyvpotwf4wezfmpo3mrtrj.spack
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0/linux-ubuntu16.04-x86_64-gcc-5.4.0-gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs.spack
######################################################################## 100.0%
- gpg: Signature made Sun 12 Nov 2017 10:16:31 PM UTC using RSA key ID 3B7C69B2
+ gpg: Signature made Sat Nov 10 05:22:47 2018 UTC using RSA key ID 3B7C69B2
gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
- ==> Relocating package from
- /home/ubuntu/becker/spack/opt/spack to /home/ubuntu/test/spack/opt/spack.
==> Successfully installed gcc from binary cache
- [+] /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-k3vy57euyeuyvpotwf4wezfmpo3mrtrj
+ [+] /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs
$ spack find -p gcc
- ==> 1 installed packages.
+ spack find -p gcc
+ ==> 1 installed package
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- gcc@7.2.0 /home/ubuntu/test/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-k3vy57euyeuyvpotwf4wezfmpo3mrtrj
+ gcc@7.2.0 /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs
We can add gcc to Spack as an available compiler using the ``spack
compiler add`` command. This will allow future packages to build with
@@ -1733,7 +1722,7 @@ gcc@7.2.0.
.. code-block:: console
- $ spack compiler add /home/ubuntu/becker/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-k3vy57euyeuyvpotwf4wezfmpo3mrtrj
+ $ spack compiler add `spack location -i gcc@7.2.0`
==> Added 1 new compiler to /home/ubuntu/.spack/linux/compilers.yaml
gcc@7.2.0
==> Compilers are defined in the following files:
diff --git a/lib/spack/docs/tutorial_buildsystems.rst b/lib/spack/docs/tutorial_buildsystems.rst
index d92db13062..db31f318df 100644
--- a/lib/spack/docs/tutorial_buildsystems.rst
+++ b/lib/spack/docs/tutorial_buildsystems.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _build-systems-tutorial:
==============================
@@ -105,8 +110,8 @@ This will open the :code:`AutotoolsPackage` file in your text editor.
.. literalinclude:: ../../../lib/spack/spack/build_systems/autotools.py
:language: python
- :emphasize-lines: 42,45,62
- :lines: 40-95,259-267
+ :emphasize-lines: 33,36,54
+ :lines: 30-76,240-248
:linenos:
@@ -151,7 +156,7 @@ build system. Although this package is acceptable let's make this into an
.. literalinclude:: tutorial/examples/Autotools/0.package.py
:language: python
- :emphasize-lines: 28
+ :emphasize-lines: 9
:linenos:
We first inherit from the :code:`AutotoolsPackage` class.
@@ -163,7 +168,7 @@ to be overridden is :code:`configure_args()`.
.. literalinclude:: tutorial/examples/Autotools/1.package.py
:language: python
- :emphasize-lines: 42,43
+ :emphasize-lines: 25,26,27,28,29,30,31,32
:linenos:
Since Spack takes care of setting the prefix for us we can exclude that as
@@ -204,8 +209,8 @@ Take note of the following:
.. literalinclude:: ../../../lib/spack/spack/build_systems/makefile.py
:language: python
- :lines: 33-79,89-107
- :emphasize-lines: 48,54,61
+ :lines: 14,43-61,70-88
+ :emphasize-lines: 21,27,34
:linenos:
Similar to :code:`Autotools`, :code:`MakefilePackage` class has properties
@@ -247,7 +252,7 @@ Let's add in the rest of our details for our package:
.. literalinclude:: tutorial/examples/Makefile/1.package.py
:language: python
- :emphasize-lines: 29,30,32,33,37,39
+ :emphasize-lines: 10,11,13,14,18,20
:linenos:
As we mentioned earlier, most packages using a :code:`Makefile` have hard-coded
@@ -289,7 +294,7 @@ To fix this, we need to use the :code:`edit()` method to write our custom
.. literalinclude:: tutorial/examples/Makefile/2.package.py
:language: python
- :emphasize-lines: 42,43,44
+ :emphasize-lines: 23,24,25
:linenos:
Here we use a :code:`FileFilter` object to edit our :code:`Makefile`. It takes
@@ -302,7 +307,7 @@ Let's change the build and install phases of our package:
.. literalinclude:: tutorial/examples/Makefile/3.package.py
:language: python
- :emphasize-lines: 46, 52
+ :emphasize-lines: 28,29,30,31,32,35,36
:linenos:
Here demonstrate another strategy that we can use to manipulate our package
@@ -318,23 +323,36 @@ Let's look at a couple of other examples and go through them:
.. code-block:: console
- $ spack edit cbench
+ $ spack edit esmf
Some packages allow environment variables to be set and will honor them.
Packages that use :code:`?=` for assignment in their :code:`Makefile`
-can be set using environment variables. In our :code:`cbench` example we
+can be set using environment variables. In our :code:`esmf` example we
set two environment variables in our :code:`edit()` method:
.. code-block:: python
def edit(self, spec, prefix):
- # The location of the Cbench source tree
- env['CBENCHHOME'] = self.stage.source_path
-
- # The location that will contain all your tests and your results
- env['CBENCHTEST'] = prefix
-
- # ... more code
+ for var in os.environ:
+ if var.startswith('ESMF_'):
+ os.environ.pop(var)
+
+ # More code ...
+
+ if self.compiler.name == 'gcc':
+ os.environ['ESMF_COMPILER'] = 'gfortran'
+ elif self.compiler.name == 'intel':
+ os.environ['ESMF_COMPILER'] = 'intel'
+ elif self.compiler.name == 'clang':
+ os.environ['ESMF_COMPILER'] = 'gfortranclang'
+ elif self.compiler.name == 'nag':
+ os.environ['ESMF_COMPILER'] = 'nag'
+ elif self.compiler.name == 'pgi':
+ os.environ['ESMF_COMPILER'] = 'pgi'
+ else:
+ msg = "The compiler you are building with, "
+ msg += "'{0}', is not supported by ESMF."
+ raise InstallError(msg.format(self.compiler.name))
As you may have noticed, we didn't really write anything to the :code:`Makefile`
but rather we set environment variables that will override variables set in
@@ -355,7 +373,7 @@ Let's look at an example of this in the :code:`elk` package:
.. code-block:: python
def edit(self, spec, prefix):
- # Dictionary of configuration options
+ # Dictionary of configuration options
config = {
'MAKE': 'make',
'AR': 'ar'
@@ -470,20 +488,16 @@ In the :code:`CMakePackage` class we can override the following phases:
The :code:`CMakePackage` class also provides sensible defaults so we only need to
override :code:`cmake_args()`.
-Let's look at these defaults in the :code:`CMakePackage` class:
+Let's look at these defaults in the :code:`CMakePackage` class in the :code:`_std_args()` method:
.. code-block:: console
$ spack edit --build-system cmake
-
-And go into a bit of detail on the highlighted sections:
-
-
.. literalinclude:: ../../../lib/spack/spack/build_systems/cmake.py
:language: python
- :lines: 37-92, 94-155, 174-211
- :emphasize-lines: 57,68,86,94,96,99,100,101,102,111,117,135,136
+ :lines: 102-147
+ :emphasize-lines: 10,18,24,36,37,38,44
:linenos:
Some :code:`CMake` packages use different generators. Spack is able to support
@@ -492,16 +506,16 @@ Unix-Makefile_ generators as well as Ninja_ generators.
.. _Unix-Makefile: https://cmake.org/cmake/help/v3.4/generator/Unix%20Makefiles.html
.. _Ninja: https://cmake.org/cmake/help/v3.4/generator/Ninja.html
-Default generator is :code:`Unix Makefile`.
+If no generator is specified Spack will default to :code:`Unix Makefiles`.
Next we setup the build type. In :code:`CMake` you can specify the build type
that you want. Options include:
-1. empty
-2. Debug
-3. Release
-4. RelWithDebInfo
-5. MinSizeRel
+1. :code:`empty`
+2. :code:`Debug`
+3. :code:`Release`
+4. :code:`RelWithDebInfo`
+5. :code:`MinSizeRel`
With these options you can specify whether you want your executable to have
the debug version only, release version or the release with debug information.
@@ -509,7 +523,7 @@ Release executables tend to be more optimized than Debug. In Spack, we set
the default as RelWithDebInfo unless otherwise specified through a variant.
Spack then automatically sets up the :code:`-DCMAKE_INSTALL_PREFIX` path,
-appends the build type (RelDebInfo default), and then specifies a verbose
+appends the build type (:code:`RelWithDebInfo` default), and then specifies a verbose
:code:`Makefile`.
Next we add the :code:`rpaths` to :code:`-DCMAKE_INSTALL_RPATH:STRING`.
@@ -524,9 +538,8 @@ In the end our :code:`cmake` line will look like this (example is :code:`xrootd`
$ cmake $HOME/spack/var/spack/stage/xrootd-4.6.0-4ydm74kbrp4xmcgda5upn33co5pwddyk/xrootd-4.6.0 -G Unix Makefiles -DCMAKE_INSTALL_PREFIX:PATH=$HOME/spack/opt/spack/darwin-sierra-x86_64/clang-9.0.0-apple/xrootd-4.6.0-4ydm74kbrp4xmcgda5upn33co5pwddyk -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_FIND_FRAMEWORK:STRING=LAST -DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE -DCMAKE_INSTALL_RPATH:STRING=$HOME/spack/opt/spack/darwin-sierra-x86_64/clang-9.0.0-apple/xrootd-4.6.0-4ydm74kbrp4xmcgda5upn33co5pwddyk/lib:$HOME/spack/opt/spack/darwin-sierra-x86_64/clang-9.0.0-apple/xrootd-4.6.0-4ydm74kbrp4xmcgda5upn33co5pwddyk/lib64 -DCMAKE_PREFIX_PATH:STRING=$HOME/spack/opt/spack/darwin-sierra-x86_64/clang-9.0.0-apple/cmake-3.9.4-hally3vnbzydiwl3skxcxcbzsscaasx5
-
-Saves a lot of typing doesn't it?
-
+We can see now how :code:`CMake` takes care of a lot of the boilerplate code
+that would have to be otherwise typed in.
Let's try to recreate callpath_:
@@ -564,7 +577,7 @@ Again we fill in the details:
.. literalinclude:: tutorial/examples/Cmake/1.package.py
:language: python
:linenos:
- :emphasize-lines: 28,32,33,37,38,39,40,41,42
+ :emphasize-lines: 9,13,14,18,19,20,21,22,23
As mentioned earlier, Spack will use sensible defaults to prevent repeated code
and to make writing :code:`CMake` package files simpler.
@@ -575,7 +588,7 @@ compiler flags. We add the following options like so:
.. literalinclude:: tutorial/examples/Cmake/2.package.py
:language: python
:linenos:
- :emphasize-lines: 45,49,50
+ :emphasize-lines: 26,30,31
Now we can control our build options using :code:`cmake_args()`. If defaults are
sufficient enough for the package, we can leave this method out.
@@ -590,7 +603,7 @@ different location is found in :code:`spades`.
.. code-block:: console
- $ spack edit spade
+ $ spack edit spades
.. code-block:: python
@@ -665,6 +678,12 @@ list you can run:
check perform some checks on the package
+We can write package files for Python packages using the :code:`Package` class,
+but the class brings with it a lot of methods that are useless for Python packages.
+Instead, Spack has a :code:`PythonPackage` subclass that allows packagers
+of Python modules to be able to invoke :code:`setup.py` and use :code:`Distutils`,
+which is much more familiar to a typical python user.
+
To see the defaults that Spack has for each a methods, we will take a look
at the :code:`PythonPackage` class:
@@ -677,18 +696,11 @@ We see the following:
.. literalinclude:: ../../../lib/spack/spack/build_systems/python.py
:language: python
- :lines: 35, 161-364
+ :lines: 19,146-357
:linenos:
Each of these methods have sensible defaults or they can be overridden.
-We can write package files for Python packages using the :code:`Package` class,
-but the class brings with it a lot of methods that are useless for Python packages.
-Instead, Spack has a :code: `PythonPackage` subclass that allows packagers
-of Python modules to be able to invoke :code:`setup.py` and use :code:`Distutils`,
-which is much more familiar to a typical python user.
-
-
We will write a package file for Pandas_:
.. _pandas: https://pandas.pydata.org
@@ -783,7 +795,7 @@ for the following build systems:
3. :code:`WafPackage`
4. :code:`RPackage`
5. :code:`PerlPackage`
-6. :code:`QMake`
+6. :code:`QMakePackage`
Each of these classes have their own abstractions to help assist in writing
diff --git a/lib/spack/docs/tutorial_configuration.rst b/lib/spack/docs/tutorial_configuration.rst
index f9221be9b4..4c2ce6a314 100644
--- a/lib/spack/docs/tutorial_configuration.rst
+++ b/lib/spack/docs/tutorial_configuration.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _configs-tutorial:
======================
@@ -8,7 +13,7 @@ This tutorial will guide you through various configuration options
that allow you to customize Spack's behavior with respect to
software installation. We will first cover the configuration file
hierarchy. Then, we will cover configuration options for compilers,
-focusing on how it can be used to extend Spack's compiler auto-detection.
+focusing on how they can be used to extend Spack's compiler auto-detection.
Next, we will cover the packages configuration file, focusing on
how it can be used to override default build options as well as
specify external package installations to use. Finally, we will
@@ -31,17 +36,19 @@ Configuration Scopes
Depending on your use case, you may want to provide configuration
settings common to everyone on your team, or you may want to set
default behaviors specific to a single user account. Spack provides
-4 configuration *scopes* to handle this customization. These scopes,
+six configuration *scopes* to handle this customization. These scopes,
in order of decreasing priority, are:
-====================== ==================================
-Scope Directory
-====================== ==================================
-User configurations ``~/.spack``
-Project configurations ``$SPACK_ROOT/etc/spack``
-System configurations ``/etc/spack``
-Default configurations ``$SPACK_ROOT/etc/spack/defaults``
-====================== ==================================
+============ ===================================================
+Scope Directory
+============ ===================================================
+Command-line N/A
+Custom Custom directory, specified with ``--config-scope``
+User ``~/.spack/``
+Site ``$SPACK_ROOT/etc/spack/``
+System ``/etc/spack/``
+Defaults ``$SPACK_ROOT/etc/spack/defaults/``
+============ ===================================================
Spack's default configuration settings reside in
``$SPACK_ROOT/etc/spack/defaults``. These are useful for reference,
@@ -60,24 +67,40 @@ configuration files to the ``~/.spack`` directory. When Spack first
checked for compilers on your system, you may have noticed that it
placed your compiler configuration in this directory.
+Configuration settings can also be placed in a custom location,
+which is then specified on the command line via ``--config-scope``.
+An example use case is managing two sets of configurations, one for
+development and another for production preferences.
+
+Settings specified on the command line have precedence over all
+other configuration scopes.
+
+^^^^^^^^^^^^^^^^^^^^^^^^
+Platform-specific Scopes
+^^^^^^^^^^^^^^^^^^^^^^^^
+
Some facilities manage multiple platforms from a single shared
-filesystem. In order to handle this, each of the configuration
+file system. In order to handle this, each of the configuration
scopes listed above has two *sub-scopes*: platform-specific and
platform-independent. For example, compiler settings can be stored
in ``compilers.yaml`` configuration files in the following locations:
-- ``~/.spack/<platform>/compilers.yaml``
-- ``~/.spack/compilers.yaml``
-- ``$SPACK_ROOT/etc/spack/<platform>/compilers.yaml``
-- ``$SPACK_ROOT/etc/spack/compilers.yaml``
-- ``/etc/spack/<platform>/compilers.yaml``
-- ``/etc/spack/compilers.yaml``
-- ``$SPACK_ROOT/etc/defaults/<platform>/compilers.yaml``
-- ``$SPACK_ROOT/etc/defaults/compilers.yaml``
+#. ``~/.spack/<platform>/compilers.yaml``
+#. ``~/.spack/compilers.yaml``
+#. ``$SPACK_ROOT/etc/spack/<platform>/compilers.yaml``
+#. ``$SPACK_ROOT/etc/spack/compilers.yaml``
+#. ``/etc/spack/<platform>/compilers.yaml``
+#. ``/etc/spack/compilers.yaml``
+#. ``$SPACK_ROOT/etc/defaults/<platform>/compilers.yaml``
+#. ``$SPACK_ROOT/etc/defaults/compilers.yaml``
These files are listed in decreasing order of precedence, so files in
``~/.spack/<platform>`` will override settings in ``~/.spack``.
+-----------
+YAML Format
+-----------
+
Spack configurations are YAML dictionaries. Every configuration file
begins with a top-level dictionary that tells Spack which
configuration set it modifies. When Spack checks it's configuration,
@@ -112,7 +135,7 @@ ensures that no other compilers are used, as the user configuration
scope is the last scope searched and the ``compilers::`` line replaces
all previous configuration files information. If the same
configuration file had a single colon instead of the double colon, it
-would add the gcc version 5.4.0 compiler to whatever other compilers
+would add the GCC version 5.4.0 compiler to whatever other compilers
were listed in other configuration files.
.. _configs-tutorial-compilers:
@@ -122,8 +145,8 @@ Compiler Configuration
----------------------
For most tasks, we can use Spack with the compilers auto-detected the
-first time Spack runs on a system. As we discussed in the basic
-installation section, we can also tell Spack where compilers are
+first time Spack runs on a system. As discussed in the basic
+installation tutorial, we can also tell Spack where compilers are
located using the ``spack compiler add`` command. However, in some
circumstances we want even more fine-grained control over the
compilers available. This section will teach you how to exercise that
@@ -146,6 +169,19 @@ We will start by opening the compilers configuration file
modules: []
operating_system: ubuntu16.04
paths:
+ cc: /usr/bin/clang-3.7
+ cxx: /usr/bin/clang++-3.7
+ f77: null
+ fc: null
+ spec: clang@3.7.1-2ubuntu2
+ target: x86_64
+ - compiler:
+ environment: {}
+ extra_rpaths: []
+ flags: {}
+ modules: []
+ operating_system: ubuntu16.04
+ paths:
cc: /usr/bin/clang
cxx: /usr/bin/clang++
f77: null
@@ -159,6 +195,19 @@ We will start by opening the compilers configuration file
modules: []
operating_system: ubuntu16.04
paths:
+ cc: /usr/bin/gcc-4.7
+ cxx: /usr/bin/g++-4.7
+ f77: /usr/bin/gfortran-4.7
+ fc: /usr/bin/gfortran-4.7
+ spec: gcc@4.7
+ target: x86_64
+ - compiler:
+ environment: {}
+ extra_rpaths: []
+ flags: {}
+ modules: []
+ operating_system: ubuntu16.04
+ paths:
cc: /usr/bin/gcc
cxx: /usr/bin/g++
f77: /usr/bin/gfortran
@@ -167,27 +216,27 @@ We will start by opening the compilers configuration file
target: x86_64
-This specifies one version of the gcc compiler and one version of the
-clang compiler with no flang compiler. Now suppose we have a code that
-we want to compile with the clang compiler for C/C++ code, but with
+This specifies two versions of the GCC compiler and two versions of the
+Clang compiler with no Flang compiler. Now suppose we have a code that
+we want to compile with the Clang compiler for C/C++ code, but with
gfortran for Fortran components. We can do this by adding another entry
to the ``compilers.yaml`` file.
.. code-block:: yaml
- compiler:
- environment: {}
- extra_rpaths: []
- flags: {}
- modules: []
- operating_system: ubuntu16.04
- paths:
- cc: /usr/bin/clang
- cxx: /usr/bin/clang++
- f77: /usr/bin/gfortran
- fc: /usr/bin/gfortran
- spec: clang@3.8.0-gfortran
- target: x86_64
+ environment: {}
+ extra_rpaths: []
+ flags: {}
+ modules: []
+ operating_system: ubuntu16.04
+ paths:
+ cc: /usr/bin/clang
+ cxx: /usr/bin/clang++
+ f77: /usr/bin/gfortran
+ fc: /usr/bin/gfortran
+ spec: clang@3.8.0-gfortran
+ target: x86_64
Let's talk about the sections of this compiler entry that we've changed.
@@ -198,7 +247,7 @@ compiler for both specifications of Fortran. We've also changed the
``spec`` entry for this compiler. The ``spec`` entry is effectively the
name of the compiler for Spack. It consists of a name and a version
number, separated by the ``@`` sigil. The name must be one of the supported
-compiler names in Spack (gcc, intel, pgi, xl, xl_r, clang, nag, cce).
+compiler names in Spack (gcc, intel, pgi, xl, xl_r, clang, nag, cce, arm).
The version number can be an arbitrary string of alphanumeric characters,
as well as ``-``, ``.``, and ``_``. The ``target`` and ``operating_system``
sections we leave unchanged. These sections specify when Spack can use
@@ -209,7 +258,7 @@ We can verify that our new compiler works by invoking it now:
.. code-block:: console
- $ spack install zlib %clang@3.8.0-gfortran
+ $ spack install --no-cache zlib %clang@3.8.0-gfortran
...
@@ -217,7 +266,7 @@ This new compiler also works on Fortran codes:
.. code-block:: console
- $ spack install cfitsio %clang@3.8.0-gfortran
+ $ spack install --no-cache cfitsio %clang@3.8.0-gfortran -bzip2
...
@@ -238,19 +287,19 @@ Let's open our compilers configuration file again and add a compiler flag.
.. code-block:: yaml
- compiler:
- environment: {}
- extra_rpaths: []
- flags:
- cppflags: -g
- modules: []
- operating_system: ubuntu16.04
- paths:
- cc: /usr/bin/clang
- cxx: /usr/bin/clang++
- f77: /usr/bin/gfortran
- fc: /usr/bin/gfortran
- spec: clang@3.8.0-gfortran
- target: x86_64
+ environment: {}
+ extra_rpaths: []
+ flags:
+ cppflags: -g
+ modules: []
+ operating_system: ubuntu16.04
+ paths:
+ cc: /usr/bin/clang
+ cxx: /usr/bin/clang++
+ f77: /usr/bin/gfortran
+ fc: /usr/bin/gfortran
+ spec: clang@3.8.0-gfortran
+ target: x86_64
We can test this out using the ``spack spec`` command to show how the
@@ -273,14 +322,14 @@ spec is concretized.
^bzip2@1.0.6%clang@3.8.0-gfortran cppflags="-g" +shared arch=linux-ubuntu16.04-x86_64
-We can see that "cppflags=-g" has been added to every node in the DAG.
+We can see that ``cppflags="-g"`` has been added to every node in the DAG.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Advanced Compiler Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are three fields of the compiler configuration entry that we
-have not talked about yet.
+have not yet talked about.
The ``modules`` field of the compiler is used primarily on Cray systems,
but can be useful on any system that has compilers that are only
@@ -290,21 +339,45 @@ of the build environment for packages using that compiler.
The ``extra_rpaths`` field of the compiler configuration is used for
compilers that do not rpath all of their dependencies by
-default. Since compilers are generally installed externally to Spack,
+default. Since compilers are often installed externally to Spack,
Spack is unable to manage compiler dependencies and enforce
rpath usage. This can lead to packages not finding link dependencies
imposed by the compiler properly. For compilers that impose link
dependencies on the resulting executables that are not rpath'ed into
-the executable automatically, the ``extra_rpath`` field of the compiler
+the executable automatically, the ``extra_rpaths`` field of the compiler
configuration tells Spack which dependencies to rpath into every
executable created by that compiler. The executables will then be able
-to find the link dependencies imposed by the compiler.
+to find the link dependencies imposed by the compiler. As an example,
+this field can be set by
+
+.. code-block:: yaml
+
+ - compiler:
+ ...
+ extra_rpaths:
+ - /apps/intel/ComposerXE2017/compilers_and_libraries_2017.5.239/linux/compiler/lib/intel64_lin
+ ...
+
The ``environment`` field of the compiler configuration is used for
compilers that require environment variables to be set during build
time. For example, if your Intel compiler suite requires the
``INTEL_LICENSE_FILE`` environment variable to point to the proper
-license server, you can set this in ``compilers.yaml``.
+license server, you can set this in ``compilers.yaml`` as follows:
+
+.. code-block:: yaml
+
+ - compiler:
+ environment:
+ set:
+ INTEL_LICENSE_FILE: 1713@license4
+ ...
+
+
+In addition to ``set``, ``environment`` also supports ``unset``,
+``prepend-path``, and ``append-path``.
+
+.. _configs-tutorial-package-prefs:
-------------------------------
Configuring Package Preferences
@@ -325,8 +398,8 @@ configuration file. First, we will look at the default
This sets the default preferences for compilers and for providers of
virtual packages. To illustrate how this works, suppose we want to
-change the preferences to prefer the clang compiler and to prefer
-mpich over openmpi. Currently, we prefer gcc and openmpi
+change the preferences to prefer the Clang compiler and to prefer
+MPICH over OpenMPI. Currently, we prefer GCC and OpenMPI.
.. code-block:: console
@@ -335,20 +408,27 @@ mpich over openmpi. Currently, we prefer gcc and openmpi
--------------------------------
hdf5
- Normalized
- --------------------------------
- hdf5
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%gcc@5.4.0+cxx~debug+fortran+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
- ^openmpi@3.0.0%gcc@5.4.0~cuda fabrics= ~java schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
- ^hwloc@1.11.7%gcc@5.4.0~cuda+libxml2~pci arch=linux-ubuntu16.04-x86_64
- ^libxml2@2.9.4%gcc@5.4.0~python arch=linux-ubuntu16.04-x86_64
- ^pkg-config@0.29.2%gcc@5.4.0+internal_glib arch=linux-ubuntu16.04-x86_64
- ^xz@5.2.3%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
- ^zlib@1.2.11%gcc@5.4.0+pic+shared arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%gcc@5.4.0~cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ ^openmpi@3.1.3%gcc@5.4.0~cuda+cxx_exceptions fabrics= ~java~legacylaunchers~memchecker~pmi schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
+ ^hwloc@1.11.9%gcc@5.4.0~cairo~cuda+libxml2+pci+shared arch=linux-ubuntu16.04-x86_64
+ ^libpciaccess@0.13.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^util-macros@1.19.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^libxml2@2.9.8%gcc@5.4.0~python arch=linux-ubuntu16.04-x86_64
+ ^xz@5.2.4%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ ^numactl@2.0.11%gcc@5.4.0 patches=592f30f7f5f757dfc239ad0ffd39a9a048487ad803c26b419e0f96b8cda08c1a arch=linux-ubuntu16.04-x86_64
+ ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
Now we will open the packages configuration file and update our
@@ -378,16 +458,23 @@ overrides the default settings just for these two items.
--------------------------------
hdf5
- Normalized
- --------------------------------
- hdf5
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4+cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
- ^mpich@3.2%clang@3.8.0-2ubuntu4 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
- ^zlib@1.2.11%clang@3.8.0-2ubuntu4+pic+shared arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ ^mpich@3.2.1%clang@3.8.0-2ubuntu4 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
+ ^findutils@4.6.0%clang@3.8.0-2ubuntu4 patches=84b916c0bf8c51b7e7b28417692f0ad3e7030d1f3c248ba77c42ede5c1c5d11e,bd9e4e5cc280f9753ae14956c4e4aa17fe7a210f55dd6c84aa60b12d106d47a2 arch=linux-ubuntu16.04-x86_64
+ ^autoconf@2.69%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^m4@1.4.18%clang@3.8.0-2ubuntu4 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ ^libsigsegv@2.11%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^perl@5.26.2%clang@3.8.0-2ubuntu4+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ ^gdbm@1.14.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^readline@7.0%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^ncurses@6.1%clang@3.8.0-2ubuntu4~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ ^pkgconf@1.4.2%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^automake@1.16.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^libtool@2.4.6%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^texinfo@6.5%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.11%clang@3.8.0-2ubuntu4+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
^^^^^^^^^^^^^^^^^^^
@@ -418,16 +505,23 @@ We can check the effect of this command with ``spack spec hdf5`` again.
--------------------------------
hdf5
- Normalized
- --------------------------------
- hdf5
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4+cxx~debug~fortran~hl+mpi+pic~shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
- ^mpich@3.2%clang@3.8.0-2ubuntu4 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
- ^zlib@1.2.11%clang@3.8.0-2ubuntu4+pic~shared arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl+mpi+pic~shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ ^mpich@3.2.1%clang@3.8.0-2ubuntu4 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
+ ^findutils@4.6.0%clang@3.8.0-2ubuntu4 patches=84b916c0bf8c51b7e7b28417692f0ad3e7030d1f3c248ba77c42ede5c1c5d11e,bd9e4e5cc280f9753ae14956c4e4aa17fe7a210f55dd6c84aa60b12d106d47a2 arch=linux-ubuntu16.04-x86_64
+ ^autoconf@2.69%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^m4@1.4.18%clang@3.8.0-2ubuntu4 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ ^libsigsegv@2.11%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^perl@5.26.2%clang@3.8.0-2ubuntu4+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac ~shared+threads arch=linux-ubuntu16.04-x86_64
+ ^gdbm@1.14.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^readline@7.0%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^ncurses@6.1%clang@3.8.0-2ubuntu4~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ ^pkgconf@1.4.2%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^automake@1.16.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^libtool@2.4.6%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^texinfo@6.5%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.11%clang@3.8.0-2ubuntu4+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
So far we have only made global changes to the package preferences. As
@@ -458,15 +552,10 @@ Now hdf5 will concretize without an MPI dependency by default.
--------------------------------
hdf5
- Normalized
- --------------------------------
- hdf5
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4+cxx~debug~fortran~hl+mpi+pic~shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
- ^zlib@1.2.11%clang@3.8.0-2ubuntu4+pic~shared arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.11%clang@3.8.0-2ubuntu4+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
In general, every attribute that we can set for all packages we can
@@ -507,14 +596,9 @@ okay.
--------------------------------
hdf5
- Normalized
- --------------------------------
- hdf5
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%gcc@5.4.0~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%gcc@5.4.0~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
^zlib@1.2.8%gcc@5.4.0+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
@@ -529,14 +613,9 @@ preference of clang. If we explicitly specify clang:
--------------------------------
hdf5%clang
- Normalized
- --------------------------------
- hdf5%clang
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
^zlib@1.2.11%clang@3.8.0-2ubuntu4+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
@@ -571,14 +650,9 @@ Now Spack will be forced to choose the external zlib.
--------------------------------
hdf5%clang
- Normalized
- --------------------------------
- hdf5%clang
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl~mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
^zlib@1.2.8%gcc@5.4.0+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
@@ -616,31 +690,32 @@ build with an alternate MPI implementation.
--------------------------------
hdf5%clang+mpi
- Normalized
- --------------------------------
- hdf5%clang+mpi
- ^mpi
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl+mpi+pic~shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
- ^openmpi@3.0.0%clang@3.8.0-2ubuntu4~cuda fabrics=verbs ~java schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
- ^hwloc@1.11.8%clang@3.8.0-2ubuntu4~cuda+libxml2+pci arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ ^openmpi@3.1.3%clang@3.8.0-2ubuntu4~cuda+cxx_exceptions fabrics= ~java~legacylaunchers~memchecker~pmi schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
+ ^hwloc@1.11.9%clang@3.8.0-2ubuntu4~cairo~cuda+libxml2+pci~shared arch=linux-ubuntu16.04-x86_64
^libpciaccess@0.13.5%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
^libtool@2.4.6%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
- ^m4@1.4.18%clang@3.8.0-2ubuntu4 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00 +sigsegv arch=linux-ubuntu16.04-x86_64
+ ^m4@1.4.18%clang@3.8.0-2ubuntu4 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
^libsigsegv@2.11%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
- ^pkg-config@0.29.2%clang@3.8.0-2ubuntu4+internal_glib arch=linux-ubuntu16.04-x86_64
+ ^pkgconf@1.4.2%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
^util-macros@1.19.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
- ^libxml2@2.9.4%clang@3.8.0-2ubuntu4~python arch=linux-ubuntu16.04-x86_64
- ^xz@5.2.3%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
- ^zlib@1.2.8%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ ^libxml2@2.9.8%clang@3.8.0-2ubuntu4~python arch=linux-ubuntu16.04-x86_64
+ ^xz@5.2.4%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.8%gcc@5.4.0+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
+ ^numactl@2.0.11%clang@3.8.0-2ubuntu4 patches=592f30f7f5f757dfc239ad0ffd39a9a048487ad803c26b419e0f96b8cda08c1a arch=linux-ubuntu16.04-x86_64
+ ^autoconf@2.69%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^perl@5.26.2%clang@3.8.0-2ubuntu4+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac ~shared+threads arch=linux-ubuntu16.04-x86_64
+ ^gdbm@1.14.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^readline@7.0%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
+ ^ncurses@6.1%clang@3.8.0-2ubuntu4~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ ^automake@1.16.1%clang@3.8.0-2ubuntu4 arch=linux-ubuntu16.04-x86_64
We have only expressed a preference for mpich over other MPI
implementations, and Spack will happily build with one we haven't
-forbid it from using. We could resolve this by requesting
+forbid it from building. We could resolve this by requesting
``hdf5%clang+mpi^mpich`` explicitly, or we can configure Spack not to
use any other MPI implementation. Since we're focused on
configurations here and the former can get tedious, we'll need to
@@ -671,10 +746,17 @@ again.
buildable: False
intel-mpi:
buildable: False
+ intel-parallel-studio:
+ buildable: False
spectrum-mpi:
buildable: False
- intel-parallel-studio:
+ mpilander:
+ buildable: False
+ charm:
buildable: False
+ charmpp:
+ buildable: False
+
Now that we have configured Spack not to build any of the possible
providers for MPI we can try again.
@@ -686,17 +768,11 @@ providers for MPI we can try again.
--------------------------------
hdf5%clang
- Normalized
- --------------------------------
- hdf5%clang
- ^mpi
- ^zlib@1.1.2:
-
Concretized
--------------------------------
- hdf5@1.10.1%clang@3.8.0-2ubuntu4+cxx~debug~fortran~hl+mpi+pic~shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ hdf5@1.10.4%clang@3.8.0-2ubuntu4~cxx~debug~fortran~hl+mpi+pic~shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
^mpich@3.2%gcc@5.4.0 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
- ^zlib@1.2.8%gcc@5.4.0+pic+shared arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.8%gcc@5.4.0+optimize+pic~shared arch=linux-ubuntu16.04-x86_64
By configuring most of our package preferences in ``packages.yaml``,
@@ -706,6 +782,31 @@ preferences, we can specify version preferences as well. Anything
that you can specify on the command line can be specified in
``packages.yaml`` with the exact same spec syntax.
+^^^^^^^^^^^^^^^^^^^^^^^^
+Installation Permissions
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``packages.yaml`` file also controls the default permissions
+to use when installing a package. You'll notice that by default,
+the installation prefix will be world readable but only user writable.
+
+Let's say we need to install ``converge``, a licensed software package.
+Since a specific research group, ``fluid_dynamics``, pays for this
+license, we want to ensure that only members of this group can access
+the software. We can do this like so:
+
+.. code-block:: yaml
+
+ packages:
+ converge:
+ permissions:
+ read: group
+ group: fluid_dynamics
+
+
+Now, only members of the ``fluid_dynamics`` group can use any
+``converge`` installations.
+
.. warning::
Make sure to delete or move the ``packages.yaml`` you have been
@@ -736,8 +837,8 @@ As you can see, many of the directories Spack uses can be customized.
For example, you can tell Spack to install packages to a prefix
outside of the ``$SPACK_ROOT`` hierarchy. Module files can be
written to a central location if you are using multiple Spack
-instances. If you have a fast scratch filesystem, you can run builds
-from this filesystem with the following ``config.yaml``:
+instances. If you have a fast scratch file system, you can run builds
+from this file system with the following ``config.yaml``:
.. code-block:: yaml
@@ -762,39 +863,31 @@ into the build.
One last setting that may be of interest to many users is the ability
to customize the parallelism of Spack builds. By default, Spack
installs all packages in parallel with the number of jobs equal to the
-number of cores on the node. For example, on a node with 36 cores,
+number of cores on the node. For example, on a node with 16 cores,
this will look like:
.. code-block:: console
- $ spack install --verbose zlib
+ $ spack install --no-cache --verbose zlib
==> Installing zlib
- ==> Using cached archive: ~/spack/var/spack/cache/zlib/zlib-1.2.11.tar.gz
- ==> Staging archive: ~/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb/zlib-1.2.11.tar.gz
- ==> Created stage in ~/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
+ ==> Using cached archive: /home/user/spack/var/spack/cache/zlib/zlib-1.2.11.tar.gz
+ ==> Staging archive: /home/user/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb/zlib-1.2.11.tar.gz
+ ==> Created stage in /home/user/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> No patches needed for zlib
==> Building zlib [Package]
==> Executing phase: 'install'
- ==> './configure' '--prefix=~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb'
- Checking for shared library support...
- Building shared library libz.so.1.2.11 with ~/spack/lib/spack/env/gcc/gcc.
- Checking for size_t... Yes.
- Checking for off64_t... Yes.
- Checking for fseeko... Yes.
- Checking for strerror... Yes.
- Checking for unistd.h... Yes.
- Checking for stdarg.h... Yes.
- Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf().
- Checking for vsnprintf() in stdio.h... Yes.
- Checking for return value of vsnprintf()... Yes.
- Checking for attribute(visibility) support... Yes.
- ==> 'make' '-j36'
+ ==> './configure' '--prefix=/home/user/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb'
...
- ==> 'make' '-j36' 'install'
+ ==> 'make' '-j16'
...
+ ==> 'make' '-j16' 'install'
+ ...
+ ==> Successfully installed zlib
+ Fetch: 0.00s. Build: 1.03s. Total: 1.03s.
+ [+] /home/user/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
-As you can see, we are building with all 36 cores on the node. If you are
+As you can see, we are building with all 16 cores on the node. If you are
on a shared login node, this can slow down the system for other users. If
you have a strict ulimit or restriction on the number of available licenses,
you may not be able to build at all with this many cores. On nodes with 64+
@@ -811,33 +904,32 @@ If we uninstall and reinstall zlib, we see that it now uses only 4 cores:
.. code-block:: console
- $ spack install -v zlib
+ $ spack install --no-cache --verbose zlib
==> Installing zlib
- ==> Using cached archive: ~/spack/var/spack/cache/zlib/zlib-1.2.11.tar.gz
- ==> Staging archive: ~/spack/var/spack/stage/zlib-1.2.11-ezuwp4pa52e75v6iweawzwymmf4ahxxn/zlib-1.2.11.tar.gz
- ==> Created stage in ~/spack/var/spack/stage/zlib-1.2.11-ezuwp4pa52e75v6iweawzwymmf4ahxxn
+ ==> Using cached archive: /home/user/spack/var/spack/cache/zlib/zlib-1.2.11.tar.gz
+ ==> Staging archive: /home/user/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb/zlib-1.2.11.tar.gz
+ ==> Created stage in /home/user/spack/var/spack/stage/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
==> No patches needed for zlib
==> Building zlib [Package]
==> Executing phase: 'install'
- ==> './configure' '--prefix=~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/zlib-1.2.11-ezuwp4pa52e75v6iweawzwymmf4ahxxn'
- Checking for shared library support...
- Building shared library libz.so.1.2.11 with ~/spack/lib/spack/env/gcc/gcc.
- Checking for size_t... Yes.
- Checking for off64_t... Yes.
- Checking for fseeko... Yes.
- Checking for strerror... Yes.
- Checking for unistd.h... Yes.
- Checking for stdarg.h... Yes.
- Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf().
- Checking for vsnprintf() in stdio.h... Yes.
- Checking for return value of vsnprintf()... Yes.
- Checking for attribute(visibility) support... Yes.
+ ==> './configure' '--prefix=/home/user/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb'
+ ...
==> 'make' '-j4'
...
==> 'make' '-j4' 'install'
...
+ ==> Successfully installed zlib
+ Fetch: 0.00s. Build: 1.03s. Total: 1.03s.
+ [+] /home/user/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/zlib-1.2.11-5nus6knzumx4ik2yl44jxtgtsl7d54xb
Obviously, if you want to build everything in serial for whatever reason,
you would set ``build_jobs`` to 1.
+--------
+Examples
+--------
+
+For examples of how other sites configure Spack, see
+https://github.com/spack/spack-configs. If you use Spack at your site
+and want to share your config files, feel free to submit a pull request!
diff --git a/lib/spack/docs/tutorial_environments.rst b/lib/spack/docs/tutorial_environments.rst
new file mode 100644
index 0000000000..9ad2e9567c
--- /dev/null
+++ b/lib/spack/docs/tutorial_environments.rst
@@ -0,0 +1,815 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+.. _environments-tutorial:
+
+================================================
+Environments, ``spack.yaml``, and ``spack.lock``
+================================================
+
+We've shown you how to install and remove packages with Spack. You can
+use :ref:`cmd-spack-install` to install packages,
+:ref:`cmd-spack-uninstall` to remove them, and :ref:`cmd-spack-find` to
+look at and query what is installed. We've also shown you how to
+customize Spack's installation with configuration files like
+:ref:`packages.yaml <build-settings>`.
+
+If you build a lot of software, or if you work on multiple projects,
+managing everything in one place can be overwhelming. The default ``spack
+find`` output may contain many packages, but you may want to *just* focus
+on packages a particular project. Moreover, you may want to include
+special configuration with your package groups, e.g., to build all the
+packages in the same group the same way.
+
+Spack **environments** provide a way to handle these problems.
+
+-------------------
+Environment basics
+-------------------
+
+Let's look at the output of ``spack find`` at this point in the tutorial.
+
+.. code-block:: console
+
+ $ bin/spack find
+ ==> 70 installed packages
+ -- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 --------------
+ tcl@8.6.8 zlib@1.2.8 zlib@1.2.11
+
+ -- linux-ubuntu16.04-x86_64 / gcc@4.7 ---------------------------
+ zlib@1.2.11
+
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ adept-utils@1.0.1 hdf5@1.10.4 mpc@1.1.0 perl@5.26.2
+ autoconf@2.69 hdf5@1.10.4 mpfr@3.1.6 pkgconf@1.4.2
+ automake@1.16.1 hdf5@1.10.4 mpich@3.2.1 readline@7.0
+ boost@1.68.0 hwloc@1.11.9 mpileaks@1.0 suite-sparse@5.3.0
+ bzip2@1.0.6 hypre@2.15.1 mumps@5.1.1 tar@1.30
+ callpath@1.0.4 hypre@2.15.1 mumps@5.1.1 tcl@8.6.8
+ cmake@3.12.3 isl@0.18 ncurses@6.1 tcl@8.6.8
+ diffutils@3.6 libdwarf@20180129 netcdf@4.6.1 texinfo@6.5
+ dyninst@9.3.2 libiberty@2.31.1 netcdf@4.6.1 trilinos@12.12.1
+ elfutils@0.173 libpciaccess@0.13.5 netlib-scalapack@2.0.2 trilinos@12.12.1
+ findutils@4.6.0 libsigsegv@2.11 netlib-scalapack@2.0.2 util-macros@1.19.1
+ gcc@7.2.0 libtool@2.4.6 numactl@2.0.11 xz@5.2.4
+ gdbm@1.14.1 libxml2@2.9.8 openblas@0.3.3 zlib@1.2.8
+ gettext@0.19.8.1 m4@1.4.18 openmpi@3.1.3 zlib@1.2.8
+ glm@0.9.7.1 matio@1.5.9 openssl@1.0.2o zlib@1.2.11
+ gmp@6.1.2 matio@1.5.9 parmetis@4.0.3
+ hdf5@1.10.4 metis@5.1.0 parmetis@4.0.3
+
+
+This is a complete, but cluttered view. There are packages built with
+both ``openmpi`` and ``mpich``, as well as multiple variants of other
+packages, like ``zlib``. The query mechanism we learned about in ``spack
+find`` can help, but it would be nice if we could start from a clean
+slate without losing what we've already done.
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Creating and activating environments
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``spack env`` command can help. Let's create a new environment:
+
+.. code-block:: console
+
+ $ spack env create myproject
+ ==> Created environment 'myproject' in ~/spack/var/spack/environments/myproject
+
+An environment is a virtualized ``spack`` instance that you can use for a
+specific purpose. You can see the environments we've created so far like this:
+
+.. code-block:: console
+
+ $ spack env list
+ ==> 1 environments
+ myproject
+
+And you can **activate** an environment with ``spack env activate``:
+
+.. code-block:: console
+
+ $ spack env activate myproject
+
+Once you enter an environment, ``spack find`` shows only what is in the
+current environment. That's nothing, so far:
+
+.. code-block:: console
+
+ $ spack find
+ ==> In environment myproject
+ ==> No root specs
+
+ ==> 0 installed packages
+
+The ``spack find`` output is still *slightly* different. It tells you
+that you're in the ``myproject`` environment, so that you don't panic
+when you see that there is nothing installed. It also says that there
+are *no root specs*. We'll get back to what that means later.
+
+If you *only* want to check what environment you are in, you can use
+``spack env status``:
+
+.. code-block:: console
+
+ $ spack env status
+ ==> In environment myproject
+
+And, if you want to leave this environment and go back to normal Spack,
+you can use ``spack env deactivate``. We like to use the
+``despacktivate`` alias (which Spack sets up automatically) for short:
+
+.. code-block:: console
+
+ $ despacktivate # short alias for `spack env deactivate`
+ $ spack env status
+ ==> No active environment
+ $ spack find
+ netcdf@4.6.1 readline@7.0 zlib@1.2.11
+ diffutils@3.6 hdf5@1.10.4 m4@1.4.18 netcdf@4.6.1 suite-sparse@5.3.0
+ dyninst@10.0.0 hwloc@1.11.9 matio@1.5.9 netlib-scalapack@2.0.2 tar@1.30
+ elfutils@0.173 hypre@2.15.1 matio@1.5.9 netlib-scalapack@2.0.2 tcl@8.6.8
+ findutils@4.6.0 hypre@2.15.1 metis@5.1.0 numactl@2.0.11 tcl@8.6.8
+ gcc@7.2.0 intel-tbb@2019 mpc@1.1.0 openblas@0.3.3 texinfo@6.5~
+
+
+^^^^^^^^^^^^^^^^^^^
+Installing packages
+^^^^^^^^^^^^^^^^^^^
+
+Ok, now that we understand how creation and activation work, let's go
+back to ``myproject`` and *install* a few packages:
+
+.. code-block:: console
+
+ $ spack env activate myproject
+ $ spack install tcl
+ ==> tcl is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8-qhwyccywhx2i6s7ob2gvjrjtj3rnfuqt
+ $ spack install trilinos
+ ==> trilinos is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-rlsruavxqvwk2tgxzxboclbo6ykjf54r
+ $ spack find
+ ==> In environment myproject
+ ==> Root specs
+ tcl trilinos
+
+ ==> 22 installed packages
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ boost@1.68.0 hwloc@1.11.9 matio@1.5.9 netlib-scalapack@2.0.2 parmetis@4.0.3 xz@5.2.4
+ bzip2@1.0.6 hypre@2.15.1 metis@5.1.0 numactl@2.0.11 suite-sparse@5.3.0 zlib@1.2.11
+ glm@0.9.7.1 libpciaccess@0.13.5 mumps@5.1.1 openblas@0.3.3 tcl@8.6.8
+ hdf5@1.10.4 libxml2@2.9.8 netcdf@4.6.1 openmpi@3.1.3 trilinos@12.12.1
+
+We've installed ``tcl`` and ``trilinos`` in our environment, along with
+all of their dependencies. We call ``tcl`` and ``trilinos`` the
+**roots** because we asked for them explicitly. The other 20 packages
+listed under "installed packages" are present because they were needed as
+dependencies. So, these are the roots of the packages' dependency graph.
+
+The "<package> is already installed" messages above are generated because
+we already installed these packages in previous steps of the tutorial,
+and we don't have to rebuild them to put them in an environment.
+
+Now let's create *another* project. We'll call this one ``myproject2``:
+
+.. code-block:: console
+
+ $ spack env create myproject2
+ ==> Created environment 'myproject2' in ~/spack/var/spack/environments/myproject2
+ $ spack env activate myproject2
+ $ spack install hdf5
+ ==> hdf5 is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-ozyvmhzdew66byarohm4p36ep7wtcuiw
+ $ spack install trilinos
+ ==> trilinos is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-rlsruavxqvwk2tgxzxboclbo6ykjf54r
+ $ spack find
+ ==> In environment myproject2
+ ==> Root specs
+ hdf5 trilinos
+
+ ==> 22 installed packages
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ boost@1.68.0 hdf5@1.10.4 libxml2@2.9.8 netcdf@4.6.1 openmpi@3.1.3 xz@5.2.4
+ bzip2@1.0.6 hwloc@1.11.9 matio@1.5.9 netlib-scalapack@2.0.2 parmetis@4.0.3 zlib@1.2.11
+ glm@0.9.7.1 hypre@2.15.1 metis@5.1.0 numactl@2.0.11 suite-sparse@5.3.0
+ hdf5@1.10.4 libpciaccess@0.13.5 mumps@5.1.1 openblas@0.3.3 trilinos@12.12.1
+
+Now we have two environments: one with ``tcl`` and ``trilinos``, and
+another with ``hdf5`` and ``trilinos``.
+
+We can uninstall trilinos from ``myproject2`` as you would expect:
+
+.. code-block:: console
+
+ $ spack uninstall trilinos
+ ==> The following packages will be uninstalled:
+
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ rlsruav trilinos@12.12.1%gcc~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2
+ ==> Do you want to proceed? [y/N] y
+ $ spack find
+ ==> In environment myproject2
+ ==> Root specs
+ hdf5
+
+ ==> 8 installed packages
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ hdf5@1.10.4 libpciaccess@0.13.5 numactl@2.0.11 xz@5.2.4
+ hwloc@1.11.9 libxml2@2.9.8 openmpi@3.1.3 zlib@1.2.11
+
+Now there is only one root spec, ``hdf5``, which requires fewer
+additional dependencies.
+
+However, we still needed ``trilinos`` for the ``myproject`` environment!
+What happened to it? Let's switch back and see.
+
+.. code-block:: console
+
+ $ despacktivate
+ $ spack env activate myproject
+ $ spack find
+ ==> In environment myproject
+ ==> Root specs
+ tcl trilinos
+
+ ==> 22 installed packages
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ boost@1.68.0 hwloc@1.11.9 matio@1.5.9 netlib-scalapack@2.0.2 parmetis@4.0.3 xz@5.2.4
+ bzip2@1.0.6 hypre@2.15.1 metis@5.1.0 numactl@2.0.11 suite-sparse@5.3.0 zlib@1.2.11
+ glm@0.9.7.1 libpciaccess@0.13.5 mumps@5.1.1 openblas@0.3.3 tcl@8.6.8
+ hdf5@1.10.4 libxml2@2.9.8 netcdf@4.6.1 openmpi@3.1.3 trilinos@12.12.1
+
+
+Spack is smart enough to realize that ``trilinos`` is still present in
+the other environment. Trilinos won't *actually* be uninstalled unless
+it is no longer needed by any environments or packages. If it is still
+needed, it is only removed from the environment.
+
+-------------------------------
+Dealing with many specs at once
+-------------------------------
+
+In the above examples, we just used ``install`` and ``uninstall``. There
+are other ways to deal with groups of packages, as well.
+
+^^^^^^^^^^^^^
+Adding specs
+^^^^^^^^^^^^^
+
+Let's go back to our first ``myproject`` environment and *add* a few specs instead of installing them:
+
+.. code-block:: console
+
+ $ spack add hdf5
+ ==> Adding hdf5 to environment myproject
+ $ spack add gmp
+ ==> Adding mumps to environment myproject
+ $ spack find
+ ==> In environment myproject
+ ==> Root specs
+ gmp hdf5 tcl trilinos
+
+ ==> 22 installed packages
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ boost@1.68.0 hwloc@1.11.9 matio@1.5.9 netlib-scalapack@2.0.2 parmetis@4.0.3 xz@5.2.4
+ bzip2@1.0.6 hypre@2.15.1 metis@5.1.0 numactl@2.0.11 suite-sparse@5.3.0 zlib@1.2.11
+ glm@0.9.7.1 libpciaccess@0.13.5 mumps@5.1.1 openblas@0.3.3 tcl@8.6.8
+ hdf5@1.10.4 libxml2@2.9.8 netcdf@4.6.1 openmpi@3.1.3 trilinos@12.12.1
+
+Let's take a close look at what happened. The two packages we added,
+``hdf5`` and ``gmp``, are present, but they're not installed in the
+environment yet. ``spack add`` just adds *roots* to the environment, but
+it does not automatically install them.
+
+We can install *all* the as-yet uninstalled packages in an environment by
+simply running ``spack install`` with no arguments:
+
+.. code-block:: console
+
+ $ spack install
+ ==> Concretizing hdf5
+ [+] ozyvmhz hdf5@1.10.4%gcc@5.4.0~cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ [+] 3njc4q5 ^openmpi@3.1.3%gcc@5.4.0~cuda+cxx_exceptions fabrics= ~java~legacylaunchers~memchecker~pmi schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
+ [+] 43tkw5m ^hwloc@1.11.9%gcc@5.4.0~cairo~cuda+libxml2+pci+shared arch=linux-ubuntu16.04-x86_64
+ [+] 5urc6tc ^libpciaccess@0.13.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] milz7fm ^util-macros@1.19.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] wpexsph ^libxml2@2.9.8%gcc@5.4.0~python arch=linux-ubuntu16.04-x86_64
+ [+] teneqii ^xz@5.2.4%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ [+] ft463od ^numactl@2.0.11%gcc@5.4.0 patches=592f30f7f5f757dfc239ad0ffd39a9a048487ad803c26b419e0f96b8cda08c1a arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ==> Concretizing gmp
+ [+] qc4qcfz gmp@6.1.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ==> Installing environment myproject
+ ==> tcl is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/tcl-8.6.8-qhwyccywhx2i6s7ob2gvjrjtj3rnfuqt
+ ==> trilinos is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-rlsruavxqvwk2tgxzxboclbo6ykjf54r
+ ==> hdf5 is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/hdf5-1.10.4-ozyvmhzdew66byarohm4p36ep7wtcuiw
+ ==> gmp is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gmp-6.1.2-qc4qcfz4monpllc3nqupdo7vwinf73sw
+
+Spack will concretize the new roots, and install everything you added to
+the environment. Now we can see the installed roots in the output of
+``spack find``:
+
+.. code-block:: console
+
+ $ spack find
+ ==> In environment myproject
+ ==> Root specs
+ gmp hdf5 tcl trilinos
+
+ ==> 24 installed packages
+ -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
+ boost@1.68.0 hdf5@1.10.4 libpciaccess@0.13.5 mumps@5.1.1 openblas@0.3.3 tcl@8.6.8
+ bzip2@1.0.6 hdf5@1.10.4 libxml2@2.9.8 netcdf@4.6.1 openmpi@3.1.3 trilinos@12.12.1
+ glm@0.9.7.1 hwloc@1.11.9 matio@1.5.9 netlib-scalapack@2.0.2 parmetis@4.0.3 xz@5.2.4
+ gmp@6.1.2 hypre@2.15.1 metis@5.1.0 numactl@2.0.11 suite-sparse@5.3.0 zlib@1.2.11
+
+We can build whole environments this way, by adding specs and installing
+all at once, or we can install them with the usual ``install`` and
+``uninstall`` portions. The advantage to doing them all at once is that
+we don't have to write a script outside of Spack to automate this, and we
+can kick off a large build of many packages easily.
+
+^^^^^^^^^^^^^^^^^^^^^
+Configuration
+^^^^^^^^^^^^^^^^^^^^^
+
+So far, ``myproject`` does not have any special configuration associated
+with it. The specs concretize using Spack's defaults:
+
+.. code-block:: console
+
+ $ spack spec hypre
+ Input spec
+ --------------------------------
+ hypre
+
+ Concretized
+ --------------------------------
+ hypre@2.15.1%gcc@5.4.0~debug~int64+internal-superlu+mpi+shared arch=linux-ubuntu16.04-x86_64
+ ^openblas@0.3.3%gcc@5.4.0 cpu_target= ~ilp64 patches=47cfa7a952ac7b2e4632c73ae199d69fb54490627b66a62c681e21019c4ddc9d,714aea33692304a50bd0ccde42590c176c82ded4a8ac7f06e573dc8071929c33 +pic+shared threads=none ~virtual_machine arch=linux-ubuntu16.04-x86_64
+ ^openmpi@3.1.3%gcc@5.4.0~cuda+cxx_exceptions fabrics= ~java~legacylaunchers~memchecker~pmi schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
+ ^hwloc@1.11.9%gcc@5.4.0~cairo~cuda+libxml2+pci+shared arch=linux-ubuntu16.04-x86_64
+ ^libpciaccess@0.13.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^util-macros@1.19.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^libxml2@2.9.8%gcc@5.4.0~python arch=linux-ubuntu16.04-x86_64
+ ^xz@5.2.4%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ ^numactl@2.0.11%gcc@5.4.0 patches=592f30f7f5f757dfc239ad0ffd39a9a048487ad803c26b419e0f96b8cda08c1a arch=linux-ubuntu16.04-x86_64
+ ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+
+You may want to add extra configuration to your environment. You can see
+how your environment is configured using ``spack config get``:
+
+.. code-block:: console
+
+ $ spack config get
+ # This is a Spack Environment file.
+ #
+ # It describes a set of packages to be installed, along with
+ # configuration settings.
+ spack:
+ # add package specs to the `specs` list
+ specs: [tcl, trilinos, hdf5, gmp]
+
+It turns out that this is a special configuration format where Spack
+stores the state for the environment. Currently, the file is just a
+``spack:`` header and a list of ``specs``. These are the roots.
+
+You can edit this file to add your own custom configuration. Spack
+provides a shortcut to do that:
+
+.. code-block:: console
+
+ spack config edit
+
+You should now see the same file, and edit it to look like this:
+
+.. code-block:: yaml
+
+ # This is a Spack Environment file.
+ #
+ # It describes a set of packages to be installed, along with
+ # configuration settings.
+ spack:
+ packages:
+ all:
+ providers:
+ mpi: [mpich]
+
+ # add package specs to the `specs` list
+ specs: [tcl, trilinos, hdf5, gmp]
+
+Now if we run ``spack spec`` again in the environment, specs will concretize with ``mpich`` as the MPI implementation:
+
+.. code-block:: console
+
+ $ spack spec hypre
+ Input spec
+ --------------------------------
+ hypre
+
+ Concretized
+ --------------------------------
+ hypre@2.15.1%gcc@5.4.0~debug~int64+internal-superlu+mpi+shared arch=linux-ubuntu16.04-x86_64
+ ^mpich@3.2.1%gcc@5.4.0 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
+ ^findutils@4.6.0%gcc@5.4.0 patches=84b916c0bf8c51b7e7b28417692f0ad3e7030d1f3c248ba77c42ede5c1c5d11e,bd9e4e5cc280f9753ae14956c4e4aa17fe7a210f55dd6c84aa60b12d106d47a2 arch=linux-ubuntu16.04-x86_64
+ ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^texinfo@6.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ^openblas@0.3.3%gcc@5.4.0 cpu_target= ~ilp64 patches=47cfa7a952ac7b2e4632c73ae199d69fb54490627b66a62c681e21019c4ddc9d,714aea33692304a50bd0ccde42590c176c82ded4a8ac7f06e573dc8071929c33 +pic+shared threads=none ~virtual_machine arch=linux-ubuntu16.04-x86_64
+
+In addition to the ``specs`` section, an environment's configuration can
+contain any of the configuration options from Spack's various config
+sections. You can add custom repositories, a custom install location,
+custom compilers, or custom external packages, in addition to the ``package``
+preferences we show here.
+
+But now we have a problem. We already installed part of this environment
+with openmpi, but now we want to install it with ``mpich``.
+
+You can run ``spack concretize`` inside of an environment to concretize
+all of its specs. We can run it here:
+
+.. code-block:: console
+
+ $ spack concretize -f
+ ==> Concretizing tcl
+ [+] qhwyccy tcl@8.6.8%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ ==> Concretizing trilinos
+ [+] kqc52mo trilinos@12.12.1%gcc@5.4.0~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2 arch=linux-ubuntu16.04-x86_64
+ [+] zbgfxap ^boost@1.68.0%gcc@5.4.0+atomic+chrono~clanglibcpp cxxstd=default +date_time~debug+exception+filesystem+graph~icu+iostreams+locale+log+math~mpi+multithreaded~numpy patches=2ab6c72d03dec6a4ae20220a9dfd5c8c572c5294252155b85c6874d97c323199 +program_options~python+random+regex+serialization+shared+signals~singlethreaded+system~taggedlayout+test+thread+timer~versionedlayout+wave arch=linux-ubuntu16.04-x86_64
+ [+] ufczdvs ^bzip2@1.0.6%gcc@5.4.0+shared arch=linux-ubuntu16.04-x86_64
+ [+] 2rhuivg ^diffutils@3.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ [+] otafqzh ^cmake@3.12.3%gcc@5.4.0~doc+ncurses+openssl+ownlibs patches=dd3a40d4d92f6b2158b87d6fb354c277947c776424aa03f6dc8096cf3135f5d0 ~qt arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] b4y3w3b ^openssl@1.0.2o%gcc@5.4.0+systemcerts arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] jnw622j ^glm@0.9.7.1%gcc@5.4.0 build_type=RelWithDebInfo arch=linux-ubuntu16.04-x86_64
+ [+] xxd7syh ^hdf5@1.10.4%gcc@5.4.0~cxx~debug~fortran+hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ [+] p3f7p2r ^mpich@3.2.1%gcc@5.4.0 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
+ [+] d4iajxs ^findutils@4.6.0%gcc@5.4.0 patches=84b916c0bf8c51b7e7b28417692f0ad3e7030d1f3c248ba77c42ede5c1c5d11e,bd9e4e5cc280f9753ae14956c4e4aa17fe7a210f55dd6c84aa60b12d106d47a2 arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] zs7a2pc ^texinfo@6.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] obewuoz ^hypre@2.15.1%gcc@5.4.0~debug~int64~internal-superlu+mpi+shared arch=linux-ubuntu16.04-x86_64
+ [+] cyeg2yi ^openblas@0.3.3%gcc@5.4.0 cpu_target= ~ilp64 patches=47cfa7a952ac7b2e4632c73ae199d69fb54490627b66a62c681e21019c4ddc9d,714aea33692304a50bd0ccde42590c176c82ded4a8ac7f06e573dc8071929c33 +pic+shared threads=none ~virtual_machine arch=linux-ubuntu16.04-x86_64
+ [+] gvyqldh ^matio@1.5.9%gcc@5.4.0+hdf5+shared+zlib arch=linux-ubuntu16.04-x86_64
+ [+] 3wnvp4j ^metis@5.1.0%gcc@5.4.0 build_type=Release ~gdb~int64 patches=4991da938c1d3a1d3dea78e49bbebecba00273f98df2a656e38b83d55b281da1 ~real64+shared arch=linux-ubuntu16.04-x86_64
+ [+] cumcj5a ^mumps@5.1.1%gcc@5.4.0+complex+double+float~int64~metis+mpi~parmetis~ptscotch~scotch+shared arch=linux-ubuntu16.04-x86_64
+ [+] p7iln2p ^netlib-scalapack@2.0.2%gcc@5.4.0 build_type=RelWithDebInfo ~pic+shared arch=linux-ubuntu16.04-x86_64
+ [+] wmmx5sg ^netcdf@4.6.1%gcc@5.4.0~dap~hdf4 maxdims=1024 maxvars=8192 +mpi~parallel-netcdf+shared arch=linux-ubuntu16.04-x86_64
+ [+] jehtata ^parmetis@4.0.3%gcc@5.4.0 build_type=RelWithDebInfo ~gdb patches=4f892531eb0a807eb1b82e683a416d3e35154a455274cf9b162fb02054d11a5b,50ed2081bc939269689789942067c58b3e522c269269a430d5d34c00edbc5870,704b84f7c7444d4372cb59cca6e1209df4ef3b033bc4ee3cf50f369bce972a9d +shared arch=linux-ubuntu16.04-x86_64
+ [+] zaau4ki ^suite-sparse@5.3.0%gcc@5.4.0~cuda~openmp+pic~tbb arch=linux-ubuntu16.04-x86_64
+ ==> Concretizing hdf5
+ - zjgyn3w hdf5@1.10.4%gcc@5.4.0~cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ [+] p3f7p2r ^mpich@3.2.1%gcc@5.4.0 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu16.04-x86_64
+ [+] d4iajxs ^findutils@4.6.0%gcc@5.4.0 patches=84b916c0bf8c51b7e7b28417692f0ad3e7030d1f3c248ba77c42ede5c1c5d11e,bd9e4e5cc280f9753ae14956c4e4aa17fe7a210f55dd6c84aa60b12d106d47a2 arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] zs7a2pc ^texinfo@6.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ ==> Concretizing gmp
+ [+] qc4qcfz gmp@6.1.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+
+Now, all the specs in the environemnt are concrete and ready to be
+installed wiht ``mpich`` as the MPI immplementation.
+
+Normally, we could just run ``spack config edit``, edit the environment
+configuration, ``spack add`` some specs, and ``install``.
+
+But, when we already have installed packages in the environment, we have
+to force everything in the environment to be re-concretized using ``spack
+concretize -f``. *Then* we can re-run ``spack install``.
+
+
+-----------------------------------
+``spack.yaml`` and ``spack.lock``
+-----------------------------------
+
+So far we've shown you how to interact with environments from the command
+line, but they also have a file-based interface that can be used by
+developers and admins to manage workflows for projects.
+
+In this section we'll dive a little deeper to see how environments are
+implemented, and how you could use this in your day-to-day development.
+
+^^^^^^^^^^^^^^
+``spack.yaml``
+^^^^^^^^^^^^^^
+
+Earlier, we changed an environment's configuration using ``spack config
+edit``. We were actually editing a special file called ``spack.yaml``.
+Let's take a look.
+
+We can get directly to the current environment's location using ``spack cd``:
+
+.. code-block:: console
+
+ $ spack cd -e myproject
+ $ pwd
+ ~/spack/var/spack/environments/myproject
+ $ ls
+ spack.lock spack.yaml
+
+We notice two things here. First, the environment is just a directory
+inside of ``var/spack/environments`` within the Spack installation.
+Second, it contains two important files: ``spack.yaml`` and
+``spack.lock``.
+
+``spack.yaml`` is the configuration file for environments that we've
+already seen, but it does not *have* to live inside Spack. If you create
+an environment using ``spack env create``, it is *managed* by
+Spack in the ``var/spack/environments`` directory, and you can refer to
+it by name.
+
+You can actually put a ``spack.yaml`` file *anywhere*, and you can use it
+to bundle an environment, or a list of dependencies to install, with your
+project. Let's make a simple project:
+
+.. code-block:: console
+
+ $ cd
+ $ mkdir code
+ $ cd code
+ $ spack env create -d .
+ ==> Created environment in ~/code
+
+Here, we made a new directory called *code*, and we used the ``-d``
+option to create an environment in it.
+
+What really happened?
+
+.. code-block:: console
+
+ $ ls
+ spack.yaml
+ $ cat spack.yaml
+ # This is a Spack Environment file.
+ #
+ # It describes a set of packages to be installed, along with
+ # configuration settings.
+ spack:
+ # add package specs to the `specs` list
+ specs: []
+
+Spack just created a ``spack.yaml`` file in the code directory, with an
+empty list of root specs. Now we have a Spack environment, *in a
+directory*, that we can use to manage dependencies. Suppose your project
+depends on ``boost``, ``trilinos``, and ``openmpi``. You can add these
+to your spec list:
+
+.. code-block:: yaml
+
+ # This is a Spack Environment file.
+ #
+ # It describes a set of packages to be installed, along with
+ # configuration settings.
+ spack:
+ # add package specs to the `specs` list
+ specs:
+ - boost
+ - trilinos
+ - openmpi
+
+And now *anyone* who uses the *code* repository can use this format to
+install the project's dependencies. They need only clone the repository,
+``cd`` into it, and type ``spack install``:
+
+.. code-block:: console
+
+ $ spack install
+ ==> Concretizing boost
+ [+] zbgfxap boost@1.68.0%gcc@5.4.0+atomic+chrono~clanglibcpp cxxstd=default +date_time~debug+exception+filesystem+graph~icu+iostreams+locale+log+math~mpi+multithreaded~numpy patches=2ab6c72d03dec6a4ae20220a9dfd5c8c572c5294252155b85c6874d97c323199 +program_options~python+random+regex+serialization+shared+signals~singlethreaded+system~taggedlayout+test+thread+timer~versionedlayout+wave arch=linux-ubuntu16.04-x86_64
+ [+] ufczdvs ^bzip2@1.0.6%gcc@5.4.0+shared arch=linux-ubuntu16.04-x86_64
+ [+] 2rhuivg ^diffutils@3.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ ==> Concretizing trilinos
+ [+] rlsruav trilinos@12.12.1%gcc@5.4.0~alloptpkgs+amesos+amesos2+anasazi+aztec+belos+boost build_type=RelWithDebInfo ~cgns~complex~dtk+epetra+epetraext+exodus+explicit_template_instantiation~float+fortran~fortrilinos+gtest+hdf5+hypre+ifpack+ifpack2~intrepid~intrepid2~isorropia+kokkos+metis~minitensor+ml+muelu+mumps~nox~openmp~phalanx~piro~pnetcdf~python~rol~rythmos+sacado~shards+shared~stk+suite-sparse~superlu~superlu-dist~teko~tempus+teuchos+tpetra~x11~xsdkflags~zlib+zoltan+zoltan2 arch=linux-ubuntu16.04-x86_64
+ [+] zbgfxap ^boost@1.68.0%gcc@5.4.0+atomic+chrono~clanglibcpp cxxstd=default +date_time~debug+exception+filesystem+graph~icu+iostreams+locale+log+math~mpi+multithreaded~numpy patches=2ab6c72d03dec6a4ae20220a9dfd5c8c572c5294252155b85c6874d97c323199 +program_options~python+random+regex+serialization+shared+signals~singlethreaded+system~taggedlayout+test+thread+timer~versionedlayout+wave arch=linux-ubuntu16.04-x86_64
+ [+] ufczdvs ^bzip2@1.0.6%gcc@5.4.0+shared arch=linux-ubuntu16.04-x86_64
+ [+] 2rhuivg ^diffutils@3.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ [+] otafqzh ^cmake@3.12.3%gcc@5.4.0~doc+ncurses+openssl+ownlibs patches=dd3a40d4d92f6b2158b87d6fb354c277947c776424aa03f6dc8096cf3135f5d0 ~qt arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] b4y3w3b ^openssl@1.0.2o%gcc@5.4.0+systemcerts arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] jnw622j ^glm@0.9.7.1%gcc@5.4.0 build_type=RelWithDebInfo arch=linux-ubuntu16.04-x86_64
+ [+] oqwnui7 ^hdf5@1.10.4%gcc@5.4.0~cxx~debug~fortran+hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu16.04-x86_64
+ [+] 3njc4q5 ^openmpi@3.1.3%gcc@5.4.0~cuda+cxx_exceptions fabrics= ~java~legacylaunchers~memchecker~pmi schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
+ [+] 43tkw5m ^hwloc@1.11.9%gcc@5.4.0~cairo~cuda+libxml2+pci+shared arch=linux-ubuntu16.04-x86_64
+ [+] 5urc6tc ^libpciaccess@0.13.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] milz7fm ^util-macros@1.19.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] wpexsph ^libxml2@2.9.8%gcc@5.4.0~python arch=linux-ubuntu16.04-x86_64
+ [+] teneqii ^xz@5.2.4%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] ft463od ^numactl@2.0.11%gcc@5.4.0 patches=592f30f7f5f757dfc239ad0ffd39a9a048487ad803c26b419e0f96b8cda08c1a arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] fshksdp ^hypre@2.15.1%gcc@5.4.0~debug~int64~internal-superlu+mpi+shared arch=linux-ubuntu16.04-x86_64
+ [+] cyeg2yi ^openblas@0.3.3%gcc@5.4.0 cpu_target= ~ilp64 patches=47cfa7a952ac7b2e4632c73ae199d69fb54490627b66a62c681e21019c4ddc9d,714aea33692304a50bd0ccde42590c176c82ded4a8ac7f06e573dc8071929c33 +pic+shared threads=none ~virtual_machine arch=linux-ubuntu16.04-x86_64
+ [+] lmzdgss ^matio@1.5.9%gcc@5.4.0+hdf5+shared+zlib arch=linux-ubuntu16.04-x86_64
+ [+] 3wnvp4j ^metis@5.1.0%gcc@5.4.0 build_type=Release ~gdb~int64 patches=4991da938c1d3a1d3dea78e49bbebecba00273f98df2a656e38b83d55b281da1 ~real64+shared arch=linux-ubuntu16.04-x86_64
+ [+] acsg2dz ^mumps@5.1.1%gcc@5.4.0+complex+double+float~int64~metis+mpi~parmetis~ptscotch~scotch+shared arch=linux-ubuntu16.04-x86_64
+ [+] wotpfwf ^netlib-scalapack@2.0.2%gcc@5.4.0 build_type=RelWithDebInfo ~pic+shared arch=linux-ubuntu16.04-x86_64
+ [+] mhm4izp ^netcdf@4.6.1%gcc@5.4.0~dap~hdf4 maxdims=1024 maxvars=8192 +mpi~parallel-netcdf+shared arch=linux-ubuntu16.04-x86_64
+ [+] uv6h3sq ^parmetis@4.0.3%gcc@5.4.0 build_type=RelWithDebInfo ~gdb patches=4f892531eb0a807eb1b82e683a416d3e35154a455274cf9b162fb02054d11a5b,50ed2081bc939269689789942067c58b3e522c269269a430d5d34c00edbc5870,704b84f7c7444d4372cb59cca6e1209df4ef3b033bc4ee3cf50f369bce972a9d +shared arch=linux-ubuntu16.04-x86_64
+ [+] zaau4ki ^suite-sparse@5.3.0%gcc@5.4.0~cuda~openmp+pic~tbb arch=linux-ubuntu16.04-x86_64
+ ==> Concretizing openmpi
+ [+] 3njc4q5 openmpi@3.1.3%gcc@5.4.0~cuda+cxx_exceptions fabrics= ~java~legacylaunchers~memchecker~pmi schedulers= ~sqlite3~thread_multiple+vt arch=linux-ubuntu16.04-x86_64
+ [+] 43tkw5m ^hwloc@1.11.9%gcc@5.4.0~cairo~cuda+libxml2+pci+shared arch=linux-ubuntu16.04-x86_64
+ [+] 5urc6tc ^libpciaccess@0.13.5%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] o2pfwjf ^libtool@2.4.6%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] suf5jtc ^m4@1.4.18%gcc@5.4.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu16.04-x86_64
+ [+] fypapcp ^libsigsegv@2.11%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] fovrh7a ^pkgconf@1.4.2%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] milz7fm ^util-macros@1.19.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] wpexsph ^libxml2@2.9.8%gcc@5.4.0~python arch=linux-ubuntu16.04-x86_64
+ [+] teneqii ^xz@5.2.4%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 5nus6kn ^zlib@1.2.11%gcc@5.4.0+optimize+pic+shared arch=linux-ubuntu16.04-x86_64
+ [+] ft463od ^numactl@2.0.11%gcc@5.4.0 patches=592f30f7f5f757dfc239ad0ffd39a9a048487ad803c26b419e0f96b8cda08c1a arch=linux-ubuntu16.04-x86_64
+ [+] 3sx2gxe ^autoconf@2.69%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] ic2kyoa ^perl@5.26.2%gcc@5.4.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu16.04-x86_64
+ [+] q4fpyuo ^gdbm@1.14.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] nxhwrg7 ^readline@7.0%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ [+] 3o765ou ^ncurses@6.1%gcc@5.4.0~symlinks~termlib arch=linux-ubuntu16.04-x86_64
+ [+] rymw7im ^automake@1.16.1%gcc@5.4.0 arch=linux-ubuntu16.04-x86_64
+ ==> Installing environment ~/code
+ ==> boost is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/boost-1.68.0-zbgfxapchxa4awxdwpleubfuznblxzvt
+ ==> trilinos is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/trilinos-12.12.1-rlsruavxqvwk2tgxzxboclbo6ykjf54r
+ ==> openmpi is already installed in ~/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx
+
+
+Spack concretizes the specs in the ``spack.yaml`` file and installs them.
+
+What happened here? If you ``cd`` into a directory tha has a
+``spack.yaml`` file in it, Spack considers this directory's environment
+to be activated. The directory does not have to live within Spack; it
+can be anywhere.
+
+So, from ``~/code``, we can actually manipulate ``spack.yaml`` using
+``spack add`` and ``spack remove`` (just like managed environments):
+
+.. code-block:: console
+
+ $ spack add hdf5@5.5.1
+ ==> Adding hdf5 to environment ~/code
+ $ cat spack.yaml
+ # This is a Spack Environment file.
+ #
+ # It describes a set of packages to be installed, along with
+ # configuration settings.
+ spack:
+ # add package specs to the `specs` list
+ specs:
+ - boost
+ - trilinos
+ - openmpi
+ - hdf5@5.5.1
+
+ $ spack remove hdf5
+ ==> Removing hdf5 from environment ~/code
+ $ cat spack.yaml
+ # This is a Spack Environment file.
+ #
+ # It describes a set of packages to be installed, along with
+ # configuration settings.
+ spack:
+ # add package specs to the `specs` list
+ specs:
+ - boost
+ - trilinos
+ - openmpi
+
+
+^^^^^^^^^^^^^^
+``spack.lock``
+^^^^^^^^^^^^^^
+
+Ok, we've covered managed environments, environments in directories, and
+the last thing we'll cover is ``spack.lock``. You may remember that when
+we ran ``spack install``, Spack concretized all the specs in the
+``spack.yaml`` file and installed them.
+
+Whenever we concretize Specs in an environment, all concrete specs in the
+environment are written out to a ``spack.lock`` file *alongside*
+``spack.yaml``. The ``spack.lock`` file is not really human-readable
+like the ``spack.yaml`` file. It is a ``json`` format that contains all
+the information that we need to ``reproduce`` the build of an
+environment:
+
+.. code-block:: console
+
+ $ head spack.lock
+ {
+ "concrete_specs": {
+ "teneqii2xv5u6zl5r6qi3pwurc6pmypz": {
+ "xz": {
+ "version": "5.2.4",
+ "arch": {
+ "platform": "linux",
+ "platform_os": "ubuntu16.04",
+ "target": "x86_64"
+ },
+ ...
+
+``spack.yaml`` and ``spack.lock`` correspond to two fundamental concepts
+in Spack, but for environments:
+
+ * ``spack.yaml`` is the set of *abstract* specs and configuration that
+ you want to install.
+ * ``spack.lock`` is the set of all fully *concretized* specs generated
+ from concretizing ``spack.yaml``
+
+Using either of these, you can recreate an environment that someone else
+built. ``spack env create`` takes an extra optional argument, which can
+be either a ``spack.yaml`` or a ``spack.lock`` file:
+
+.. code-block:: console
+
+ $ spack env create my-project spack.yaml
+
+ $ spack env create my-project spack.lock
+
+Both of these create a new environment called ``my-project``, but which
+one you choose to use depends on your needs:
+
+ 1. copying the yaml file allows someone else to build your *requirements*,
+ potentially a different way.
+
+ 2. copying the lock file allows someone else to rebuild your
+ *installation* exactly as you built it.
+
+The first use case can *re-concretize* the same specs on new platforms in
+order to build, but it will preserve the abstract requirements. The
+second use case (currently) requires you to be on the same machine, but
+it retains all decisions made during concretization and is faithful to a
+prior install.
diff --git a/lib/spack/docs/tutorial_modules.rst b/lib/spack/docs/tutorial_modules.rst
index 21e1e5e886..31fb1cd749 100644
--- a/lib/spack/docs/tutorial_modules.rst
+++ b/lib/spack/docs/tutorial_modules.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _modules-tutorial:
============
@@ -144,77 +149,16 @@ how Spack can help with similar situations, as they will happen on real HPC clus
For instance, it's often preferable for Spack to use vendor-provided MPI
implementations than to build one itself.
-The best way to follow along is to use a Docker image, which comes
-with Spack and all the software used in the following parts already
-pre-installed. If you want to proceed this way, read :ref:`module_file_tutorial_use_docker`.
-
-If you don't have Docker installed or for any other reason you
-prefer to work locally, follow instead :ref:`module_file_tutorial_work_locally`
-to know how to clone Spack and install the software.
-Be aware that the set-up will take longer and that the details of the snippets
-below assume the Docker image and may need changes to work in your particular
-environment.
+To keep the set of software we're dealing with manageable, we're going
+to uninstall everything from earlier in the tutorial.
-.. _module_file_tutorial_use_docker:
-
-^^^^^^^^^^^^^^^^^^
-Use a Docker image
-^^^^^^^^^^^^^^^^^^
+.. code-block: console
-The fastest way to set-up your environment is to :ref:`use a Docker image <workflow_create_docker_image>`:
+ $ spack uninstall -ay
-.. code-block:: console
-
- $ docker pull alalazo/spack:module_tutorial
- $ docker run --rm -h module-file-tutorial -it alalazo/spack:module_tutorial
- root@module-file-tutorial:/#
-
-If you arrived at this point you should be ready to start, as all the software needed is
-pre-installed in the image:
-
-.. code-block:: console
-
- root@module-file-tutorial:/# which spack
- /usr/local/bin/spack
- root@module-file-tutorial:/# spack find
- ==> 46 installed packages.
- -- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- autoconf@2.69 gcc@7.2.0 git@2.9.4 isl@0.18 libtool@2.4.6 lua@5.3.4 lua-luaposix@33.4.0 mpc@1.0.3 ncurses@6.0 pkg-config@0.29.2 tcl@8.6.6
- automake@1.15.1 gdbm@1.13 gmp@6.1.2 libsigsegv@2.11 lmod@7.7 lua-luafilesystem@1_6_3 m4@1.4.18 mpfr@3.1.5 perl@5.24.1 readline@7.0 zlib@1.2.11
-
- -- linux-ubuntu16.04-x86_64 / gcc@7.2.0 -------------------------
- bzip2@1.0.6 ncurses@6.0 netlib-scalapack@2.0.2 openblas@0.2.20 pkg-config@0.29.2 py-packaging@16.8 py-setuptools@35.0.2 readline@7.0
- cmake@3.9.4 netlib-lapack@3.6.1 netlib-scalapack@2.0.2 openmpi@1.10.2 py-appdirs@1.4.3 py-pyparsing@2.2.0 py-six@1.10.0 sqlite@3.20.0
- mpich@3.2 netlib-scalapack@2.0.2 netlib-scalapack@2.0.2 openssl@1.0.2k py-numpy@1.13.1 py-scipy@0.19.1 python@2.7.14 zlib@1.2.11
-
-Go to :ref:`module_file_tutorial_non_hierarchical` to proceed with the tutorial.
-
-.. note::
- Dockerfile for this image
- Those of you that want to build a similar container themselves can find the
- ``Dockerfile`` and the other resources in Spack's ``share/spack/docs/docker``
- folder.
-
-.. _module_file_tutorial_work_locally:
-
-^^^^^^^^^^^^^^^^^^^^^^
-Work in a local folder
-^^^^^^^^^^^^^^^^^^^^^^
-
-If you don't feel like using a container, you can set-up your environment
-locally. Let's start by cloning the Spack repository and moving to the directory
-where it was checked out:
-
-.. code-block:: console
-
- $ git clone https://github.com/spack/spack.git
- $ cd spack
-
-From here we'll be building the required stack of software.
-
-"""""""""""""""""""
+^^^^^^^^^^^^^^^^^^^
Build a module tool
-"""""""""""""""""""
+^^^^^^^^^^^^^^^^^^^
The first thing that we need is the module tool. In this case we
choose ``lmod`` as it can work with both hierarchical and non-hierarchical
@@ -233,7 +177,8 @@ to remember, we'll employ the command ``spack location`` to retrieve the
$ . $(spack location -i lmod)/lmod/lmod/init/bash
-Now we can source the setup file and activate the :ref:`shell support <shell-support>`:
+Now we can re-source the setup file and Spack modules will be put in
+our module path.
.. code-block:: console
@@ -246,26 +191,15 @@ Now we can source the setup file and activate the :ref:`shell support <shell-sup
to the documentation :ref:`here <InstallEnvironmentModules>`.
-""""""""""""""""""
+^^^^^^^^^^^^^^^^^^
Add a new compiler
-""""""""""""""""""
+^^^^^^^^^^^^^^^^^^
The second step is to build a recent compiler. On first use, Spack
-scans the environment and automatically locates the
-compiler(s) already available on the system. This is what you'll see
-on Ubuntu 14.04:
-
-.. code-block:: console
-
- $ uname -a
- Linux nuvolari 4.4.0-45-generic #66~14.04.1-Ubuntu SMP Wed Oct 19 15:05:38 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
+scans the environment and automatically locates the compiler(s)
+already available on the system. For this tutorial, however, we want
+to use ``gcc@7.2.0``.
- $ spack compilers
- ==> Available compilers
- -- gcc ----------------------------------------------------------
- gcc@4.8
-
-Let's bootstrap a more recent compiler with the one that was automatically detected:
.. code-block:: console
@@ -294,7 +228,7 @@ You can use this command to double check:
$ module list
Currently Loaded Modules:
- 1) lmod-7.7-gcc-4.8-okcwjgw 2) gcc-7.2.0-gcc-4.8-twd5nqg
+ 1) gcc-7.2.0-gcc-5.4.0-b7smjjc
Note that the 7-digit hash at the end of the generated module may vary depending
on architecture or package version. Now that we have ``gcc@7.2.0`` in ``PATH`` we
@@ -303,38 +237,23 @@ can finally add it to the list of compilers known to Spack:
.. code-block:: console
$ spack compiler add
- ==> Added 1 new compiler to ~/.spack/linux/compilers.yaml
+ ==> Added 1 new compiler to /home/spack1/.spack/linux/compilers.yaml
gcc@7.2.0
+ ==> Compilers are defined in the following files:
+ /home/spack1/.spack/linux/compilers.yaml
- $ spack compilers
+ $ spack compiler list
==> Available compilers
- -- gcc ----------------------------------------------------------
- gcc@7.2.0 gcc@4.8
-
-
-""""""""""""""""""""""""""""""""""""""""""""""""""""
-Build the software that will be used in the tutorial
-""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-The last step is to install the software stack needed later on. To mimic
-an external installation of an MPI provider we'll install ``openmpi`` on
-the system we are working on. On Ubuntu 14.04 it boils down to:
-
-.. code-block:: console
+ -- clang ubuntu16.04-x86_64 -------------------------------------
+ clang@3.8.0-2ubuntu4 clang@3.7.1-2ubuntu2
- $ sudo apt-get install openmpi-bin openmpi-common libopenmpi-dev
- ...
-
-but the exact command varies according to your OS. Then we need to prepare
-a ``packages.yaml`` file that instructs Spack to use an externally provided MPI:
+ -- gcc ubuntu16.04-x86_64 ---------------------------------------
+ gcc@7.2.0 gcc@5.4.0 gcc@4.7
-.. code-block:: yaml
- packages:
- openmpi:
- buildable: False
- paths:
- openmpi@1.6: /usr
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Build the software that will be used in the tutorial
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Finally, we should use Spack to install the packages used in the examples:
@@ -357,19 +276,36 @@ If you arrived to this point you should have an environment that looks similar t
.. code-block:: console
- root@module-file-tutorial:/# module avail
+ $ module avail
+
+ ----------------------------------------------- /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------
+ autoconf-2.69-gcc-5.4.0-3sx2gxe libsigsegv-2.11-gcc-7.2.0-g67xpfd openssl-1.0.2o-gcc-5.4.0-b4y3w3b
+ autoconf-2.69-gcc-7.2.0-yb2makb libtool-2.4.6-gcc-5.4.0-o2pfwjf openssl-1.0.2o-gcc-7.2.0-cvldq3v
+ automake-1.16.1-gcc-5.4.0-rymw7im libtool-2.4.6-gcc-7.2.0-kt2udm6 pcre-8.42-gcc-5.4.0-gt5lgzi
+ automake-1.16.1-gcc-7.2.0-qoowd5q libxml2-2.9.8-gcc-5.4.0-wpexsph perl-5.26.2-gcc-5.4.0-ic2kyoa
+ bzip2-1.0.6-gcc-5.4.0-ufczdvs libxml2-2.9.8-gcc-7.2.0-47gf5kk perl-5.26.2-gcc-7.2.0-fdwz5yu
+ bzip2-1.0.6-gcc-7.2.0-mwamumj lmod-7.8-gcc-5.4.0-kmhks3p pkgconf-1.4.2-gcc-5.4.0-fovrh7a
+ cmake-3.12.3-gcc-7.2.0-obqgn2v lua-5.3.4-gcc-5.4.0-cpfeo2w pkgconf-1.4.2-gcc-7.2.0-yoxwmgb
+ curl-7.60.0-gcc-5.4.0-vzqreb2 lua-luafilesystem-1_6_3-gcc-5.4.0-alakjim py-numpy-1.15.2-gcc-7.2.0-wbwtcxf
+ diffutils-3.6-gcc-5.4.0-2rhuivg lua-luaposix-33.4.0-gcc-5.4.0-7wqhwoc py-scipy-1.1.0-gcc-7.2.0-d5n3cph
+ diffutils-3.6-gcc-7.2.0-eauxwi7 m4-1.4.18-gcc-5.4.0-suf5jtc py-setuptools-40.4.3-gcc-7.2.0-5dbwfwn
+ expat-2.2.5-gcc-5.4.0-emyv67q m4-1.4.18-gcc-7.2.0-wdzvagl python-2.7.15-gcc-7.2.0-ucmr2mn
+ findutils-4.6.0-gcc-7.2.0-ca4b7zq mpc-1.1.0-gcc-5.4.0-iuf3gc3 readline-7.0-gcc-5.4.0-nxhwrg7
+ gcc-7.2.0-gcc-5.4.0-b7smjjc (L) mpfr-3.1.6-gcc-5.4.0-jnt2nnp readline-7.0-gcc-7.2.0-ccruj2i
+ gdbm-1.14.1-gcc-5.4.0-q4fpyuo mpich-3.2.1-gcc-7.2.0-vt5xcat sqlite-3.23.1-gcc-7.2.0-5ltus3a
+ gdbm-1.14.1-gcc-7.2.0-zk5lhob ncurses-6.1-gcc-5.4.0-3o765ou tar-1.30-gcc-5.4.0-dk7lrpo
+ gettext-0.19.8.1-gcc-5.4.0-tawgous ncurses-6.1-gcc-7.2.0-xcgzqdv tcl-8.6.8-gcc-5.4.0-qhwyccy
+ git-2.19.1-gcc-5.4.0-p3gjnfa netlib-lapack-3.8.0-gcc-7.2.0-fj7nayd texinfo-6.5-gcc-7.2.0-cuqnfgf
+ gmp-6.1.2-gcc-5.4.0-qc4qcfz netlib-scalapack-2.0.2-gcc-7.2.0-67nmj7g unzip-6.0-gcc-5.4.0-ba23fbg
+ hwloc-1.11.9-gcc-7.2.0-gbyc65s netlib-scalapack-2.0.2-gcc-7.2.0-6jgjbyg util-macros-1.19.1-gcc-7.2.0-t62kozq
+ isl-0.18-gcc-5.4.0-vttqout netlib-scalapack-2.0.2-gcc-7.2.0-prgo67d xz-5.2.4-gcc-5.4.0-teneqii
+ libbsd-0.8.6-gcc-5.4.0-f4qkkwm netlib-scalapack-2.0.2-gcc-7.2.0-zxpt252 xz-5.2.4-gcc-7.2.0-rql5kog
+ libiconv-1.15-gcc-5.4.0-u2x3umv numactl-2.0.11-gcc-7.2.0-rifwktk zlib-1.2.11-gcc-5.4.0-5nus6kn
+ libpciaccess-0.13.5-gcc-7.2.0-riipwi2 openblas-0.3.3-gcc-7.2.0-xxoxfh4 zlib-1.2.11-gcc-7.2.0-ezuwp4p
+ libsigsegv-2.11-gcc-5.4.0-fypapcp openmpi-3.1.3-gcc-7.2.0-do5xfer
- ----------------------------------------------------------------------------- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------------------------------------
- autoconf-2.69-gcc-5.4.0-bvabhji libtool-2.4.6-gcc-5.4.0-o2pfwjf ncurses-6.0-gcc-7.2.0-oh6pqty pkg-config-0.29.2-gcc-5.4.0-ae2hwm7 readline-7.0-gcc-5.4.0-gizxpch
- automake-1.15.1-gcc-5.4.0-kaiefe4 lmod-7.7-gcc-5.4.0-okcwjgw netlib-lapack-3.6.1-gcc-7.2.0-5sywztc pkg-config-0.29.2-gcc-7.2.0-76z7ehw readline-7.0-gcc-7.2.0-eqos6rz
- bzip2-1.0.6-gcc-7.2.0-mwamumj lua-5.3.4-gcc-5.4.0-ytxw2gq netlib-scalapack-2.0.2-gcc-7.2.0-5lb2j5p py-appdirs-1.4.3-gcc-7.2.0-7ncu7zr sqlite-3.20.0-gcc-7.2.0-hfmjilk
- cmake-3.9.4-gcc-7.2.0-6bxdr6h lua-luafilesystem-1_6_3-gcc-5.4.0-5dzzlt4 netlib-scalapack-2.0.2-gcc-7.2.0-ax6aza6 py-numpy-1.13.1-gcc-7.2.0-22n5oub tcl-8.6.6-gcc-5.4.0-767ls4i
- gcc-7.2.0-gcc-5.4.0-go3z4hb lua-luaposix-33.4.0-gcc-5.4.0-w5jpnwm netlib-scalapack-2.0.2-gcc-7.2.0-c4v5l7j py-packaging-16.8-gcc-7.2.0-c37cjmq zlib-1.2.11-gcc-5.4.0-swly52a
- gdbm-1.13-gcc-5.4.0-vdhoris m4-1.4.18-gcc-5.4.0-r5envx3 netlib-scalapack-2.0.2-gcc-7.2.0-m7rzcmh py-pyparsing-2.2.0-gcc-7.2.0-ahdh5cx zlib-1.2.11-gcc-7.2.0-lv5fabl
- git-2.9.4-gcc-5.4.0-atwjs4i mpc-1.0.3-gcc-5.4.0-tumbpsh openblas-0.2.20-gcc-7.2.0-kvddide py-scipy-0.19.1-gcc-7.2.0-7hi7r5j
- gmp-6.1.2-gcc-5.4.0-qc4qcfz mpfr-3.1.5-gcc-5.4.0-mdi6irz openmpi-1.10.2-gcc-7.2.0-ufw7pdi py-setuptools-35.0.2-gcc-7.2.0-cvasi7i
- isl-0.18-gcc-5.4.0-vttqout mpich-3.2-gcc-7.2.0-7gxffhv openssl-1.0.2k-gcc-7.2.0-pxv3dh4 py-six-1.10.0-gcc-7.2.0-3xk5mod
- libsigsegv-2.11-gcc-5.4.0-fypapcp ncurses-6.0-gcc-5.4.0-ukq4tcc perl-5.24.1-gcc-5.4.0-mfzwy6y python-2.7.14-gcc-7.2.0-555u7ea
+ Where:
+ L: Module is loaded
Use "module spider" to find all possible modules.
Use "module keyword key1 key2 ..." to search for all possible modules matching any of the "keys".
@@ -380,19 +316,24 @@ Taking a look at the ``gcc`` module you'll see, for example:
.. code-block:: console
- root@module-file-tutorial:/# module show gcc-7.2.0-gcc-5.4.0-go3z4hb
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64/gcc-7.2.0-gcc-5.4.0-go3z4hb:
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ $ module show gcc-7.2.0-gcc-5.4.0-b7smjjc
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64/gcc-7.2.0-gcc-5.4.0-b7smjjc:
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
whatis("The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, and Go, as well as libraries for these languages. ")
- prepend_path("PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/bin")
- prepend_path("MANPATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/share/man")
- prepend_path("LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib")
- prepend_path("LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib64")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib64")
- prepend_path("CPATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/include")
- prepend_path("CMAKE_PREFIX_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/")
+ prepend_path("PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin")
+ prepend_path("MANPATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/share/man")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib")
+ prepend_path("LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib64")
+ prepend_path("LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib64")
+ prepend_path("CPATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/include")
+ prepend_path("CMAKE_PREFIX_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/")
+ setenv("CC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gcc")
+ setenv("CXX","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/g++")
+ setenv("FC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F77","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F90","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
help([[The GNU Compiler Collection includes front ends for C, C++, Objective-C,
Fortran, Ada, and Go, as well as libraries for these languages.
]])
@@ -422,19 +363,26 @@ Next you should regenerate all the module files:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type tcl
+ $ spack module tcl refresh
==> You are about to regenerate tcl module files for:
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- bvabhji autoconf@2.69 vdhoris gdbm@1.13 vttqout isl@0.18 okcwjgw lmod@7.7 w5jpnwm lua-luaposix@33.4.0 mdi6irz mpfr@3.1.5 ae2hwm7 pkg-config@0.29.2 swly52a zlib@1.2.11
- kaiefe4 automake@1.15.1 atwjs4i git@2.9.4 fypapcp libsigsegv@2.11 ytxw2gq lua@5.3.4 r5envx3 m4@1.4.18 ukq4tcc ncurses@6.0 gizxpch readline@7.0
- go3z4hb gcc@7.2.0 qc4qcfz gmp@6.1.2 o2pfwjf libtool@2.4.6 5dzzlt4 lua-luafilesystem@1_6_3 tumbpsh mpc@1.0.3 mfzwy6y perl@5.24.1 767ls4i tcl@8.6.6
+ 3sx2gxe autoconf@2.69 b7smjjc gcc@7.2.0 f4qkkwm libbsd@0.8.6 cpfeo2w lua@5.3.4 3o765ou ncurses@6.1 dk7lrpo tar@1.30
+ rymw7im automake@1.16.1 q4fpyuo gdbm@1.14.1 u2x3umv libiconv@1.15 alakjim lua-luafilesystem@1_6_3 b4y3w3b openssl@1.0.2o qhwyccy tcl@8.6.8
+ ufczdvs bzip2@1.0.6 tawgous gettext@0.19.8.1 fypapcp libsigsegv@2.11 7wqhwoc lua-luaposix@33.4.0 gt5lgzi pcre@8.42 ba23fbg unzip@6.0
+ vzqreb2 curl@7.60.0 p3gjnfa git@2.19.1 o2pfwjf libtool@2.4.6 suf5jtc m4@1.4.18 ic2kyoa perl@5.26.2 teneqii xz@5.2.4
+ 2rhuivg diffutils@3.6 qc4qcfz gmp@6.1.2 wpexsph libxml2@2.9.8 iuf3gc3 mpc@1.1.0 fovrh7a pkgconf@1.4.2 5nus6kn zlib@1.2.11
+ emyv67q expat@2.2.5 vttqout isl@0.18 kmhks3p lmod@7.8 jnt2nnp mpfr@3.1.6 nxhwrg7 readline@7.0
-- linux-ubuntu16.04-x86_64 / gcc@7.2.0 -------------------------
- mwamumj bzip2@1.0.6 5sywztc netlib-lapack@3.6.1 m7rzcmh netlib-scalapack@2.0.2 76z7ehw pkg-config@0.29.2 ahdh5cx py-pyparsing@2.2.0 555u7ea python@2.7.14
- 6bxdr6h cmake@3.9.4 ax6aza6 netlib-scalapack@2.0.2 kvddide openblas@0.2.20 7ncu7zr py-appdirs@1.4.3 7hi7r5j py-scipy@0.19.1 eqos6rz readline@7.0
- 7gxffhv mpich@3.2 c4v5l7j netlib-scalapack@2.0.2 ufw7pdi openmpi@1.10.2 22n5oub py-numpy@1.13.1 cvasi7i py-setuptools@35.0.2 hfmjilk sqlite@3.20.0
- oh6pqty ncurses@6.0 5lb2j5p netlib-scalapack@2.0.2 pxv3dh4 openssl@1.0.2k c37cjmq py-packaging@16.8 3xk5mod py-six@1.10.0 lv5fabl zlib@1.2.11
+ yb2makb autoconf@2.69 riipwi2 libpciaccess@0.13.5 6jgjbyg netlib-scalapack@2.0.2 fdwz5yu perl@5.26.2 cuqnfgf texinfo@6.5
+ qoowd5q automake@1.16.1 g67xpfd libsigsegv@2.11 zxpt252 netlib-scalapack@2.0.2 yoxwmgb pkgconf@1.4.2 t62kozq util-macros@1.19.1
+ mwamumj bzip2@1.0.6 kt2udm6 libtool@2.4.6 67nmj7g netlib-scalapack@2.0.2 wbwtcxf py-numpy@1.15.2 rql5kog xz@5.2.4
+ obqgn2v cmake@3.12.3 47gf5kk libxml2@2.9.8 prgo67d netlib-scalapack@2.0.2 d5n3cph py-scipy@1.1.0 ezuwp4p zlib@1.2.11
+ eauxwi7 diffutils@3.6 wdzvagl m4@1.4.18 rifwktk numactl@2.0.11 5dbwfwn py-setuptools@40.4.3
+ ca4b7zq findutils@4.6.0 vt5xcat mpich@3.2.1 xxoxfh4 openblas@0.3.3 ucmr2mn python@2.7.15
+ zk5lhob gdbm@1.14.1 xcgzqdv ncurses@6.1 do5xfer openmpi@3.1.3 ccruj2i readline@7.0
+ gbyc65s hwloc@1.11.9 fj7nayd netlib-lapack@3.8.0 cvldq3v openssl@1.0.2o 5ltus3a sqlite@3.23.1
==> Do you want to proceed? [y/n] y
==> Regenerating tcl module files
@@ -444,16 +392,21 @@ paths have disappeared:
.. code-block:: console
- root@module-file-tutorial:/# module show gcc-7.2.0-gcc-5.4.0-go3z4hb
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64/gcc-7.2.0-gcc-5.4.0-go3z4hb:
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ $ module show gcc-7.2.0-gcc-5.4.0-b7smjjc
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64/gcc-7.2.0-gcc-5.4.0-b7smjjc:
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
whatis("The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, and Go, as well as libraries for these languages. ")
- prepend_path("PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/bin")
- prepend_path("MANPATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/share/man")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib64")
- prepend_path("CMAKE_PREFIX_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/")
+ prepend_path("PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin")
+ prepend_path("MANPATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/share/man")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib64")
+ prepend_path("CMAKE_PREFIX_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/")
+ setenv("CC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gcc")
+ setenv("CXX","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/g++")
+ setenv("FC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F77","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F90","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
help([[The GNU Compiler Collection includes front ends for C, C++, Objective-C,
Fortran, Ada, and Go, as well as libraries for these languages.
]])
@@ -482,41 +435,55 @@ To do this you should add a ``blacklist`` keyword to ``~/.spack/modules.yaml``:
and regenerate the module files:
+This time it is convenient to pass the option ``--delete-tree`` to the command that
+regenerates the module files to instruct it to delete the existing tree and regenerate
+a new one instead of overwriting the files in the existing directory.
+
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type tcl --delete-tree
+ $ spack module tcl refresh --delete-tree
==> You are about to regenerate tcl module files for:
-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 -------------------------
- bvabhji autoconf@2.69 vdhoris gdbm@1.13 vttqout isl@0.18 okcwjgw lmod@7.7 w5jpnwm lua-luaposix@33.4.0 mdi6irz mpfr@3.1.5 ae2hwm7 pkg-config@0.29.2 swly52a zlib@1.2.11
- kaiefe4 automake@1.15.1 atwjs4i git@2.9.4 fypapcp libsigsegv@2.11 ytxw2gq lua@5.3.4 r5envx3 m4@1.4.18 ukq4tcc ncurses@6.0 gizxpch readline@7.0
- go3z4hb gcc@7.2.0 qc4qcfz gmp@6.1.2 o2pfwjf libtool@2.4.6 5dzzlt4 lua-luafilesystem@1_6_3 tumbpsh mpc@1.0.3 mfzwy6y perl@5.24.1 767ls4i tcl@8.6.6
+ 3sx2gxe autoconf@2.69 b7smjjc gcc@7.2.0 f4qkkwm libbsd@0.8.6 cpfeo2w lua@5.3.4 3o765ou ncurses@6.1 dk7lrpo tar@1.30
+ rymw7im automake@1.16.1 q4fpyuo gdbm@1.14.1 u2x3umv libiconv@1.15 alakjim lua-luafilesystem@1_6_3 b4y3w3b openssl@1.0.2o qhwyccy tcl@8.6.8
+ ufczdvs bzip2@1.0.6 tawgous gettext@0.19.8.1 fypapcp libsigsegv@2.11 7wqhwoc lua-luaposix@33.4.0 gt5lgzi pcre@8.42 ba23fbg unzip@6.0
+ vzqreb2 curl@7.60.0 p3gjnfa git@2.19.1 o2pfwjf libtool@2.4.6 suf5jtc m4@1.4.18 ic2kyoa perl@5.26.2 teneqii xz@5.2.4
+ 2rhuivg diffutils@3.6 qc4qcfz gmp@6.1.2 wpexsph libxml2@2.9.8 iuf3gc3 mpc@1.1.0 fovrh7a pkgconf@1.4.2 5nus6kn zlib@1.2.11
+ emyv67q expat@2.2.5 vttqout isl@0.18 kmhks3p lmod@7.8 jnt2nnp mpfr@3.1.6 nxhwrg7 readline@7.0
-- linux-ubuntu16.04-x86_64 / gcc@7.2.0 -------------------------
- mwamumj bzip2@1.0.6 5sywztc netlib-lapack@3.6.1 m7rzcmh netlib-scalapack@2.0.2 76z7ehw pkg-config@0.29.2 ahdh5cx py-pyparsing@2.2.0 555u7ea python@2.7.14
- 6bxdr6h cmake@3.9.4 ax6aza6 netlib-scalapack@2.0.2 kvddide openblas@0.2.20 7ncu7zr py-appdirs@1.4.3 7hi7r5j py-scipy@0.19.1 eqos6rz readline@7.0
- 7gxffhv mpich@3.2 c4v5l7j netlib-scalapack@2.0.2 ufw7pdi openmpi@1.10.2 22n5oub py-numpy@1.13.1 cvasi7i py-setuptools@35.0.2 hfmjilk sqlite@3.20.0
- oh6pqty ncurses@6.0 5lb2j5p netlib-scalapack@2.0.2 pxv3dh4 openssl@1.0.2k c37cjmq py-packaging@16.8 3xk5mod py-six@1.10.0 lv5fabl zlib@1.2.11
+ yb2makb autoconf@2.69 riipwi2 libpciaccess@0.13.5 6jgjbyg netlib-scalapack@2.0.2 fdwz5yu perl@5.26.2 cuqnfgf texinfo@6.5
+ qoowd5q automake@1.16.1 g67xpfd libsigsegv@2.11 zxpt252 netlib-scalapack@2.0.2 yoxwmgb pkgconf@1.4.2 t62kozq util-macros@1.19.1
+ mwamumj bzip2@1.0.6 kt2udm6 libtool@2.4.6 67nmj7g netlib-scalapack@2.0.2 wbwtcxf py-numpy@1.15.2 rql5kog xz@5.2.4
+ obqgn2v cmake@3.12.3 47gf5kk libxml2@2.9.8 prgo67d netlib-scalapack@2.0.2 d5n3cph py-scipy@1.1.0 ezuwp4p zlib@1.2.11
+ eauxwi7 diffutils@3.6 wdzvagl m4@1.4.18 rifwktk numactl@2.0.11 5dbwfwn py-setuptools@40.4.3
+ ca4b7zq findutils@4.6.0 vt5xcat mpich@3.2.1 xxoxfh4 openblas@0.3.3 ucmr2mn python@2.7.15
+ zk5lhob gdbm@1.14.1 xcgzqdv ncurses@6.1 do5xfer openmpi@3.1.3 ccruj2i readline@7.0
+ gbyc65s hwloc@1.11.9 fj7nayd netlib-lapack@3.8.0 cvldq3v openssl@1.0.2o 5ltus3a sqlite@3.23.1
==> Do you want to proceed? [y/n] y
==> Regenerating tcl module files
- root@module-file-tutorial:/# module avail
-
- ----------------------------------------------------------------------------- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------------------------------------
- bzip2-1.0.6-gcc-7.2.0-mwamumj netlib-scalapack-2.0.2-gcc-7.2.0-5lb2j5p openmpi-1.10.2-gcc-7.2.0-ufw7pdi py-packaging-16.8-gcc-7.2.0-c37cjmq python-2.7.14-gcc-7.2.0-555u7ea
- cmake-3.9.4-gcc-7.2.0-6bxdr6h netlib-scalapack-2.0.2-gcc-7.2.0-ax6aza6 openssl-1.0.2k-gcc-7.2.0-pxv3dh4 py-pyparsing-2.2.0-gcc-7.2.0-ahdh5cx readline-7.0-gcc-7.2.0-eqos6rz
- mpich-3.2-gcc-7.2.0-7gxffhv netlib-scalapack-2.0.2-gcc-7.2.0-c4v5l7j pkg-config-0.29.2-gcc-7.2.0-76z7ehw py-scipy-0.19.1-gcc-7.2.0-7hi7r5j sqlite-3.20.0-gcc-7.2.0-hfmjilk
- ncurses-6.0-gcc-7.2.0-oh6pqty netlib-scalapack-2.0.2-gcc-7.2.0-m7rzcmh py-appdirs-1.4.3-gcc-7.2.0-7ncu7zr py-setuptools-35.0.2-gcc-7.2.0-cvasi7i zlib-1.2.11-gcc-7.2.0-lv5fabl
- netlib-lapack-3.6.1-gcc-7.2.0-5sywztc openblas-0.2.20-gcc-7.2.0-kvddide py-numpy-1.13.1-gcc-7.2.0-22n5oub py-six-1.10.0-gcc-7.2.0-3xk5mod
+ $ module avail
+
+ ----------------------------------------------- /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------
+ autoconf-2.69-gcc-7.2.0-yb2makb m4-1.4.18-gcc-7.2.0-wdzvagl perl-5.26.2-gcc-7.2.0-fdwz5yu
+ automake-1.16.1-gcc-7.2.0-qoowd5q mpich-3.2.1-gcc-7.2.0-vt5xcat pkgconf-1.4.2-gcc-7.2.0-yoxwmgb
+ bzip2-1.0.6-gcc-7.2.0-mwamumj ncurses-6.1-gcc-7.2.0-xcgzqdv py-numpy-1.15.2-gcc-7.2.0-wbwtcxf
+ cmake-3.12.3-gcc-7.2.0-obqgn2v netlib-lapack-3.8.0-gcc-7.2.0-fj7nayd py-scipy-1.1.0-gcc-7.2.0-d5n3cph
+ diffutils-3.6-gcc-7.2.0-eauxwi7 netlib-scalapack-2.0.2-gcc-7.2.0-67nmj7g py-setuptools-40.4.3-gcc-7.2.0-5dbwfwn
+ findutils-4.6.0-gcc-7.2.0-ca4b7zq netlib-scalapack-2.0.2-gcc-7.2.0-6jgjbyg python-2.7.15-gcc-7.2.0-ucmr2mn
+ gdbm-1.14.1-gcc-7.2.0-zk5lhob netlib-scalapack-2.0.2-gcc-7.2.0-prgo67d readline-7.0-gcc-7.2.0-ccruj2i
+ hwloc-1.11.9-gcc-7.2.0-gbyc65s netlib-scalapack-2.0.2-gcc-7.2.0-zxpt252 sqlite-3.23.1-gcc-7.2.0-5ltus3a
+ libpciaccess-0.13.5-gcc-7.2.0-riipwi2 numactl-2.0.11-gcc-7.2.0-rifwktk texinfo-6.5-gcc-7.2.0-cuqnfgf
+ libsigsegv-2.11-gcc-7.2.0-g67xpfd openblas-0.3.3-gcc-7.2.0-xxoxfh4 util-macros-1.19.1-gcc-7.2.0-t62kozq
+ libtool-2.4.6-gcc-7.2.0-kt2udm6 openmpi-3.1.3-gcc-7.2.0-do5xfer xz-5.2.4-gcc-7.2.0-rql5kog
+ libxml2-2.9.8-gcc-7.2.0-47gf5kk openssl-1.0.2o-gcc-7.2.0-cvldq3v zlib-1.2.11-gcc-7.2.0-ezuwp4p
Use "module spider" to find all possible modules.
Use "module keyword key1 key2 ..." to search for all possible modules matching any of the "keys".
-This time it is convenient to pass the option ``--delete-tree`` to the command that
-regenerates the module files to instruct it to delete the existing tree and regenerate
-a new one instead of overwriting the files in the existing directory.
-
If you look closely you'll see though that we went too far in blacklisting modules:
the module for ``gcc@7.2.0`` disappeared as it was bootstrapped with ``gcc@5.4.0``. To specify
exceptions to the blacklist rules you can use ``whitelist``:
@@ -538,7 +505,7 @@ exceptions to the blacklist rules you can use ``whitelist``:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type tcl -y
+ $ spack module tcl refresh -y
==> Regenerating tcl module files
@@ -546,14 +513,33 @@ you'll see that now the module for ``gcc@7.2.0`` has reappeared:
.. code-block:: console
- root@module-file-tutorial:/# module avail gcc-7.2.0-gcc-5.4.0-go3z4hb
+ $ module avail gcc-7.2.0-gcc-5.4.0-b7smjjc
- ----------------------------------------------------------------------------- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------------------------------------
- gcc-7.2.0-gcc-5.4.0-go3z4hb
+ -------------------------------------------- /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64 ---------------------------------------------
+ gcc-7.2.0-gcc-5.4.0-b7smjjc
Use "module spider" to find all possible modules.
Use "module keyword key1 key2 ..." to search for all possible modules matching any of the "keys".
+An additional possibility that you can leverage to unclutter the environment
+is that of preventing the generation of module files for implicitly installed
+packages. In this case all one needs to do is to add the following line:
+
+.. code-block:: yaml
+ :emphasize-lines: 3
+
+ modules:
+ tcl:
+ blacklist_implicits: true
+ whitelist:
+ - gcc
+ blacklist:
+ - '%gcc@5.4.0'
+ all:
+ filter:
+ environment_blacklist: ['CPATH', 'LIBRARY_PATH']
+
+to ``modules.yaml`` and regenerate the module file tree as above.
^^^^^^^^^^^^^^^^^^^^^^^^^
Change module file naming
@@ -564,8 +550,6 @@ improve their naming scheme.
To reduce the length of the hash or remove it altogether you can
use the ``hash_length`` keyword in the configuration file:
-.. TODO: give reasons to remove hashes if they are not evident enough?
-
.. code-block:: yaml
:emphasize-lines: 3
@@ -584,10 +568,10 @@ If you try to regenerate the module files now you will get an error:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type tcl --delete-tree -y
+ $ spack module tcl refresh --delete-tree -y
==> Error: Name clashes detected in module files:
- file: /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64/netlib-scalapack-2.0.2-gcc-7.2.0
+ file: /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64/netlib-scalapack-2.0.2-gcc-7.2.0
spec: netlib-scalapack@2.0.2%gcc@7.2.0 build_type=RelWithDebInfo ~pic+shared arch=linux-ubuntu16.04-x86_64
spec: netlib-scalapack@2.0.2%gcc@7.2.0 build_type=RelWithDebInfo ~pic+shared arch=linux-ubuntu16.04-x86_64
spec: netlib-scalapack@2.0.2%gcc@7.2.0 build_type=RelWithDebInfo ~pic+shared arch=linux-ubuntu16.04-x86_64
@@ -631,17 +615,24 @@ Regenerating module files now we obtain:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type tcl --delete-tree -y
+ $ spack module tcl refresh --delete-tree -y
==> Regenerating tcl module files
-
- root@module-file-tutorial:/# module avail
-
- ----------------------------------------------------------------------------- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------------------------------------
- bzip2-1.0.6-gcc-7.2.0 netlib-lapack-3.6.1-gcc-7.2.0 openblas-0.2.20-gcc-7.2.0 py-numpy-1.13.1-gcc-7.2.0-openblas py-six-1.10.0-gcc-7.2.0
- cmake-3.9.4-gcc-7.2.0 netlib-scalapack-2.0.2-gcc-7.2.0-netlib-mpich openmpi-1.10.2-gcc-7.2.0 py-packaging-16.8-gcc-7.2.0 python-2.7.14-gcc-7.2.0
- gcc-7.2.0-gcc-5.4.0 netlib-scalapack-2.0.2-gcc-7.2.0-netlib-openmpi openssl-1.0.2k-gcc-7.2.0 py-pyparsing-2.2.0-gcc-7.2.0 readline-7.0-gcc-7.2.0
- mpich-3.2-gcc-7.2.0 netlib-scalapack-2.0.2-gcc-7.2.0-openblas-mpich pkg-config-0.29.2-gcc-7.2.0 py-scipy-0.19.1-gcc-7.2.0-openblas sqlite-3.20.0-gcc-7.2.0
- ncurses-6.0-gcc-7.2.0 netlib-scalapack-2.0.2-gcc-7.2.0-openblas-openmpi py-appdirs-1.4.3-gcc-7.2.0 py-setuptools-35.0.2-gcc-7.2.0 zlib-1.2.11-gcc-7.2.0
+ $ module avail
+
+ ----------------------------------------------- /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------
+ autoconf-2.69-gcc-7.2.0 m4-1.4.18-gcc-7.2.0 pkgconf-1.4.2-gcc-7.2.0
+ automake-1.16.1-gcc-7.2.0 mpich-3.2.1-gcc-7.2.0 py-numpy-1.15.2-gcc-7.2.0-openblas
+ bzip2-1.0.6-gcc-7.2.0 ncurses-6.1-gcc-7.2.0 py-scipy-1.1.0-gcc-7.2.0-openblas
+ cmake-3.12.3-gcc-7.2.0 netlib-lapack-3.8.0-gcc-7.2.0 py-setuptools-40.4.3-gcc-7.2.0
+ diffutils-3.6-gcc-7.2.0 netlib-scalapack-2.0.2-gcc-7.2.0-netlib-mpich python-2.7.15-gcc-7.2.0
+ findutils-4.6.0-gcc-7.2.0 netlib-scalapack-2.0.2-gcc-7.2.0-netlib-openmpi readline-7.0-gcc-7.2.0
+ gcc-7.2.0-gcc-5.4.0 netlib-scalapack-2.0.2-gcc-7.2.0-openblas-mpich sqlite-3.23.1-gcc-7.2.0
+ gdbm-1.14.1-gcc-7.2.0 netlib-scalapack-2.0.2-gcc-7.2.0-openblas-openmpi texinfo-6.5-gcc-7.2.0
+ hwloc-1.11.9-gcc-7.2.0 numactl-2.0.11-gcc-7.2.0 util-macros-1.19.1-gcc-7.2.0
+ libpciaccess-0.13.5-gcc-7.2.0 openblas-0.3.3-gcc-7.2.0 xz-5.2.4-gcc-7.2.0
+ libsigsegv-2.11-gcc-7.2.0 openmpi-3.1.3-gcc-7.2.0 zlib-1.2.11-gcc-7.2.0
+ libtool-2.4.6-gcc-7.2.0 openssl-1.0.2o-gcc-7.2.0
+ libxml2-2.9.8-gcc-7.2.0 perl-5.26.2-gcc-7.2.0
Use "module spider" to find all possible modules.
Use "module keyword key1 key2 ..." to search for all possible modules matching any of the "keys".
@@ -677,16 +668,24 @@ The final result should look like:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type tcl --delete-tree -y
+ $ spack module tcl refresh --delete-tree -y
==> Regenerating tcl module files
- root@module-file-tutorial:/# module avail
-
- ----------------------------------------------------------------------------- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------------------------------------
- bzip2/1.0.6-gcc-7.2.0 netlib-lapack/3.6.1-gcc-7.2.0 openblas/0.2.20-gcc-7.2.0 py-numpy/1.13.1-gcc-7.2.0-openblas py-six/1.10.0-gcc-7.2.0
- cmake/3.9.4-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-mpich openmpi/1.10.2-gcc-7.2.0 py-packaging/16.8-gcc-7.2.0 python/2.7.14-gcc-7.2.0
- gcc/7.2.0-gcc-5.4.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-openmpi openssl/1.0.2k-gcc-7.2.0 py-pyparsing/2.2.0-gcc-7.2.0 readline/7.0-gcc-7.2.0
- mpich/3.2-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-mpich pkg-config/0.29.2-gcc-7.2.0 py-scipy/0.19.1-gcc-7.2.0-openblas sqlite/3.20.0-gcc-7.2.0
- ncurses/6.0-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-openmpi (D) py-appdirs/1.4.3-gcc-7.2.0 py-setuptools/35.0.2-gcc-7.2.0 zlib/1.2.11-gcc-7.2.0
+ $ module avail
+
+ ----------------------------------------------- /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------
+ autoconf/2.69-gcc-7.2.0 m4/1.4.18-gcc-7.2.0 pkgconf/1.4.2-gcc-7.2.0
+ automake/1.16.1-gcc-7.2.0 mpich/3.2.1-gcc-7.2.0 py-numpy/1.15.2-gcc-7.2.0-openblas
+ bzip2/1.0.6-gcc-7.2.0 ncurses/6.1-gcc-7.2.0 py-scipy/1.1.0-gcc-7.2.0-openblas
+ cmake/3.12.3-gcc-7.2.0 netlib-lapack/3.8.0-gcc-7.2.0 py-setuptools/40.4.3-gcc-7.2.0
+ diffutils/3.6-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-mpich python/2.7.15-gcc-7.2.0
+ findutils/4.6.0-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-openmpi readline/7.0-gcc-7.2.0
+ gcc/7.2.0-gcc-5.4.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-mpich sqlite/3.23.1-gcc-7.2.0
+ gdbm/1.14.1-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-openmpi (D) texinfo/6.5-gcc-7.2.0
+ hwloc/1.11.9-gcc-7.2.0 numactl/2.0.11-gcc-7.2.0 util-macros/1.19.1-gcc-7.2.0
+ libpciaccess/0.13.5-gcc-7.2.0 openblas/0.3.3-gcc-7.2.0 xz/5.2.4-gcc-7.2.0
+ libsigsegv/2.11-gcc-7.2.0 openmpi/3.1.3-gcc-7.2.0 zlib/1.2.11-gcc-7.2.0
+ libtool/2.4.6-gcc-7.2.0 openssl/1.0.2o-gcc-7.2.0
+ libxml2/2.9.8-gcc-7.2.0 perl/5.26.2-gcc-7.2.0
Where:
D: Default Module
@@ -748,21 +747,26 @@ Regenerating the module files results in something like:
.. code-block:: console
:emphasize-lines: 15
- root@module-file-tutorial:/# spack module refresh -y --module-type tcl
+ $ spack module tcl refresh -y
==> Regenerating tcl module files
- root@module-file-tutorial:/# module show gcc
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64/gcc/7.2.0-gcc-5.4.0:
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ $ module show gcc
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64/gcc/7.2.0-gcc-5.4.0:
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
whatis("The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, and Go, as well as libraries for these languages. ")
conflict("gcc")
- prepend_path("PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/bin")
- prepend_path("MANPATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/share/man")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib64")
- prepend_path("CMAKE_PREFIX_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/")
- setenv("GCC_ROOT","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd")
+ prepend_path("PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin")
+ prepend_path("MANPATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/share/man")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib64")
+ prepend_path("CMAKE_PREFIX_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/")
+ setenv("CC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gcc")
+ setenv("CXX","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/g++")
+ setenv("FC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F77","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F90","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("GCC_ROOT","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs")
help([[The GNU Compiler Collection includes front ends for C, C++, Objective-C,
Fortran, Ada, and Go, as well as libraries for these languages.
]])
@@ -819,54 +823,60 @@ This time we will be more selective and regenerate only the ``gcc`` and
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh -y --module-type tcl gcc
+ $ spack module tcl refresh -y gcc
==> Regenerating tcl module files
- root@module-file-tutorial:/# spack module refresh -y --module-type tcl openmpi
+ $ spack module tcl refresh -y openmpi
==> Regenerating tcl module files
- root@module-file-tutorial:/# module show gcc
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64/gcc/7.2.0-gcc-5.4.0:
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ $ module show gcc
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64/gcc/7.2.0-gcc-5.4.0:
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
whatis("The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, and Go, as well as libraries for these languages. ")
conflict("gcc")
- prepend_path("PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/bin")
- prepend_path("MANPATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/share/man")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib")
- prepend_path("LD_LIBRARY_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/lib64")
- prepend_path("CMAKE_PREFIX_PATH","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd/")
- setenv("GCC_ROOT","/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-go3z4hbsa6wycoaedr3fforx5qnazdhd")
+ prepend_path("PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin")
+ prepend_path("MANPATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/share/man")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/lib64")
+ prepend_path("CMAKE_PREFIX_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/")
+ setenv("CC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gcc")
+ setenv("CXX","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/g++")
+ setenv("FC","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F77","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("F90","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs/bin/gfortran")
+ setenv("GCC_ROOT","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/gcc-7.2.0-b7smjjcsmwe5u5fcsvjmonlhlzzctnfs")
setenv("CC","gcc")
- setenv("CXX","g++")
+ setenv("CXX","g++'")
setenv("FC","gfortran")
- setenv("F90","gfortran")
setenv("F77","gfortran")
+ setenv("F90","gfortran")
help([[The GNU Compiler Collection includes front ends for C, C++, Objective-C,
Fortran, Ada, and Go, as well as libraries for these languages.
]])
- root@module-file-tutorial:/# module show openmpi
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64/openmpi/1.10.2-gcc-7.2.0:
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- whatis("The Open MPI Project is an open source Message Passing Interface implementation that is developed and maintained by a consortium of academic, research, and industry partners. Open MPI is therefore able t
- o combine the expertise, technologies, and resources from all across the High Performance Computing community in order to build the best MPI library available. Open MPI offers advantages for system and software
- vendors, application developers and computer science researchers. ")
+ $ module show openmpi
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64/openmpi/3.1.3-gcc-7.2.0:
+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ whatis("An open source Message Passing Interface implementation. ")
conflict("openmpi")
- prepend_path("MANPATH","/usr/share/man")
- prepend_path("ACLOCAL_PATH","/usr/share/aclocal")
- prepend_path("PKG_CONFIG_PATH","/usr/lib/pkgconfig")
- setenv("OPENMPI_ROOT","/usr")
+ prepend_path("PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4/bin")
+ prepend_path("MANPATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4/share/man")
+ prepend_path("LD_LIBRARY_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4/lib")
+ prepend_path("PKG_CONFIG_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4/lib/pkgconfig")
+ prepend_path("CMAKE_PREFIX_PATH","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4/")
+ setenv("OPENMPI_ROOT","/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/openmpi-3.1.3-do5xfer2whhk7gc26atgs3ozr3ljbvs4")
setenv("SLURM_MPI_TYPE","pmi2")
setenv("OMPI_MCA_btl_openib_warn_default_gid_prefix","0")
- help([[The Open MPI Project is an open source Message Passing Interface
- implementation that is developed and maintained by a consortium of
- academic, research, and industry partners. Open MPI is therefore able to
- combine the expertise, technologies, and resources from all across the
- High Performance Computing community in order to build the best MPI
- library available. Open MPI offers advantages for system and software
- vendors, application developers and computer science researchers.
+ help([[An open source Message Passing Interface implementation. The Open MPI
+ Project is an open source Message Passing Interface implementation that
+ is developed and maintained by a consortium of academic, research, and
+ industry partners. Open MPI is therefore able to combine the expertise,
+ technologies, and resources from all across the High Performance
+ Computing community in order to build the best MPI library available.
+ Open MPI offers advantages for system and software vendors, application
+ developers and computer science researchers.
]])
@@ -926,7 +936,7 @@ and regenerating the module files for every package that depends on ``python``:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh -y --module-type tcl ^python
+ root@module-file-tutorial:/# spack module tcl refresh -y ^python
==> Regenerating tcl module files
Now the ``py-scipy`` module will be:
@@ -934,47 +944,47 @@ Now the ``py-scipy`` module will be:
.. code-block:: tcl
#%Module1.0
- ## Module file created by spack (https://github.com/spack/spack) on 2017-10-07 15:02:14.974937
+ ## Module file created by spack (https://github.com/spack/spack) on 2018-11-11 22:10:48.834221
##
- ## py-scipy@0.19.1%gcc@7.2.0 arch=linux-ubuntu16.04-x86_64 /7hi7r5j
+ ## py-scipy@1.1.0%gcc@7.2.0 arch=linux-ubuntu16.04-x86_64 /d5n3cph
##
module-whatis "SciPy (pronounced 'Sigh Pie') is a Scientific Library for Python. It provides many user-friendly and efficient numerical routines such as routines for numerical integration and optimization."
proc ModulesHelp { } {
- puts stderr "SciPy (pronounced 'Sigh Pie') is a Scientific Library for Python. It"
+ puts stderr "SciPy (pronounced "Sigh Pie") is a Scientific Library for Python. It"
puts stderr "provides many user-friendly and efficient numerical routines such as"
puts stderr "routines for numerical integration and optimization."
}
- if ![ is-loaded python/2.7.14-gcc-7.2.0 ] {
- puts stderr "Autoloading python/2.7.14-gcc-7.2.0"
- module load python/2.7.14-gcc-7.2.0
+ if { [ module-info mode load ] && ![ is-loaded python/2.7.15-gcc-7.2.0 ] } {
+ puts stderr "Autoloading python/2.7.15-gcc-7.2.0"
+ module load python/2.7.15-gcc-7.2.0
}
- if ![ is-loaded openblas/0.2.20-gcc-7.2.0 ] {
- puts stderr "Autoloading openblas/0.2.20-gcc-7.2.0"
- module load openblas/0.2.20-gcc-7.2.0
+ if { [ module-info mode load ] && ![ is-loaded openblas/0.3.3-gcc-7.2.0 ] } {
+ puts stderr "Autoloading openblas/0.3.3-gcc-7.2.0"
+ module load openblas/0.3.3-gcc-7.2.0
}
- if ![ is-loaded py-numpy/1.13.1-gcc-7.2.0-openblas ] {
- puts stderr "Autoloading py-numpy/1.13.1-gcc-7.2.0-openblas"
- module load py-numpy/1.13.1-gcc-7.2.0-openblas
+ if { [ module-info mode load ] && ![ is-loaded py-numpy/1.15.2-gcc-7.2.0-openblas ] } {
+ puts stderr "Autoloading py-numpy/1.15.2-gcc-7.2.0-openblas"
+ module load py-numpy/1.15.2-gcc-7.2.0-openblas
}
conflict py-scipy
- prepend-path LD_LIBRARY_PATH "/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-0.19.1-7hi7r5jri7bmohh4oontvfxo7rgj4hef/lib"
- prepend-path CMAKE_PREFIX_PATH "/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-0.19.1-7hi7r5jri7bmohh4oontvfxo7rgj4hef/"
- prepend-path PYTHONPATH "/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-0.19.1-7hi7r5jri7bmohh4oontvfxo7rgj4hef/lib/python2.7/site-packages"
- setenv PY_SCIPY_ROOT "/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-0.19.1-7hi7r5jri7bmohh4oontvfxo7rgj4hef"
+ prepend-path LD_LIBRARY_PATH "/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-1.1.0-d5n3cphk2lx2v74ypwb6h7tna7vvgdyn/lib"
+ prepend-path CMAKE_PREFIX_PATH "/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-1.1.0-d5n3cphk2lx2v74ypwb6h7tna7vvgdyn/"
+ prepend-path PYTHONPATH "/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-1.1.0-d5n3cphk2lx2v74ypwb6h7tna7vvgdyn/lib/python2.7/site-packages"
+ setenv PY_SCIPY_ROOT "/home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/py-scipy-1.1.0-d5n3cphk2lx2v74ypwb6h7tna7vvgdyn"
and will contain code to autoload all the dependencies:
.. code-block:: console
- root@module-file-tutorial:/# module load py-scipy
- Autoloading python/2.7.14-gcc-7.2.0
- Autoloading openblas/0.2.20-gcc-7.2.0
- Autoloading py-numpy/1.13.1-gcc-7.2.0-openblas
+ $ module load py-scipy
+ Autoloading python/2.7.15-gcc-7.2.0
+ Autoloading openblas/0.3.3-gcc-7.2.0
+ Autoloading py-numpy/1.15.2-gcc-7.2.0-openblas
In case messages are unwanted during the autoload procedure, it will be
sufficient to omit the line setting ``verbose: True`` in the configuration file above.
@@ -990,16 +1000,25 @@ all the software is visible at the same time:
.. code-block:: console
- root@module-file-tutorial:/# module avail
-
- ----------------------------------------------------------------------------- /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------------------------------------
- bzip2/1.0.6-gcc-7.2.0 netlib-lapack/3.6.1-gcc-7.2.0 openblas/0.2.20-gcc-7.2.0 py-numpy/1.13.1-gcc-7.2.0-openblas py-six/1.10.0-gcc-7.2.0
- cmake/3.9.4-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-mpich openmpi/1.10.2-gcc-7.2.0 py-packaging/16.8-gcc-7.2.0 python/2.7.14-gcc-7.2.0
- gcc/7.2.0-gcc-5.4.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-openmpi openssl/1.0.2k-gcc-7.2.0 py-pyparsing/2.2.0-gcc-7.2.0 readline/7.0-gcc-7.2.0
- mpich/3.2-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-mpich pkg-config/0.29.2-gcc-7.2.0 py-scipy/0.19.1-gcc-7.2.0-openblas sqlite/3.20.0-gcc-7.2.0
- ncurses/6.0-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-openmpi (D) py-appdirs/1.4.3-gcc-7.2.0 py-setuptools/35.0.2-gcc-7.2.0 zlib/1.2.11-gcc-7.2.0
+ $ module avail
+
+ ----------------------------------------------- /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64 -----------------------------------------------
+ autoconf/2.69-gcc-7.2.0 m4/1.4.18-gcc-7.2.0 pkgconf/1.4.2-gcc-7.2.0
+ automake/1.16.1-gcc-7.2.0 mpich/3.2.1-gcc-7.2.0 py-numpy/1.15.2-gcc-7.2.0-openblas (L)
+ bzip2/1.0.6-gcc-7.2.0 ncurses/6.1-gcc-7.2.0 py-scipy/1.1.0-gcc-7.2.0-openblas (L)
+ cmake/3.12.3-gcc-7.2.0 netlib-lapack/3.8.0-gcc-7.2.0 py-setuptools/40.4.3-gcc-7.2.0
+ diffutils/3.6-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-mpich python/2.7.15-gcc-7.2.0 (L)
+ findutils/4.6.0-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-netlib-openmpi readline/7.0-gcc-7.2.0
+ gcc/7.2.0-gcc-5.4.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-mpich sqlite/3.23.1-gcc-7.2.0
+ gdbm/1.14.1-gcc-7.2.0 netlib-scalapack/2.0.2-gcc-7.2.0-openblas-openmpi (D) texinfo/6.5-gcc-7.2.0
+ hwloc/1.11.9-gcc-7.2.0 numactl/2.0.11-gcc-7.2.0 util-macros/1.19.1-gcc-7.2.0
+ libpciaccess/0.13.5-gcc-7.2.0 openblas/0.3.3-gcc-7.2.0 (L) xz/5.2.4-gcc-7.2.0
+ libsigsegv/2.11-gcc-7.2.0 openmpi/3.1.3-gcc-7.2.0 zlib/1.2.11-gcc-7.2.0
+ libtool/2.4.6-gcc-7.2.0 openssl/1.0.2o-gcc-7.2.0
+ libxml2/2.9.8-gcc-7.2.0 perl/5.26.2-gcc-7.2.0
Where:
+ L: Module is loaded
D: Default Module
Use "module spider" to find all possible modules.
@@ -1010,11 +1029,12 @@ that nothing prevents users from loading incompatible sets of modules:
.. code-block:: console
- root@module-file-tutorial:/# module load netlib-lapack/3.6.1-gcc-7.2.0 openblas/0.2.20-gcc-7.2.0
- root@module-file-tutorial:/# module list
+ $ module purge
+ $ module load netlib-lapack/3.8.0-gcc-7.2.0 openblas/0.3.3-gcc-7.2.0
+ $ module list
Currently Loaded Modules:
- 1) netlib-lapack/3.6.1-gcc-7.2.0 2) openblas/0.2.20-gcc-7.2.0
+ 1) netlib-lapack/3.8.0-gcc-7.2.0 2) openblas/0.3.3-gcc-7.2.0
Even if ``conflicts`` directives are carefully placed in module files, they:
@@ -1102,23 +1122,24 @@ If we now regenerate the module files:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh --module-type lmod --delete-tree -y
+ $ spack module lmod refresh --delete-tree -y
==> Regenerating lmod module files
and update ``MODULEPATH`` to point to the ``Core``:
.. code-block:: console
- root@module-file-tutorial:/# module unuse /usr/local/share/spack/modules/linux-ubuntu16.04-x86_64
- root@module-file-tutorial:/# module use /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/Core
+ $ module purge
+ $ module unuse /home/spack1/spack/share/spack/modules/linux-ubuntu16.04-x86_64
+ $ module use /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/Core
asking for the available modules will return:
.. code-block:: console
- root@module-file-tutorial:/# module avail
+ $ module avail
- ---------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/Core ----------------------------------------------------------------------------
+ ----------------------------------------------------------- share/spack/lmod/linux-ubuntu16.04-x86_64/Core ------------------------------------------------------------
gcc/7.2.0
Use "module spider" to find all possible modules.
@@ -1129,14 +1150,17 @@ the ``Compiler`` part of the hierarchy:
.. code-block:: console
- root@module-file-tutorial:/# module load gcc
- root@module-file-tutorial:/# module avail
+ $ module load gcc
+ $ module avail
- ------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------------------------------------
- bzip2/1.0.6 mpich/3.2 netlib-lapack/3.6.1 openmpi/1.10.2 pkg-config/0.29.2 py-numpy/1.13.1-openblas py-pyparsing/2.2.0 py-setuptools/35.0.2 python/2.7.14 sqlite/3.20.0
- cmake/3.9.4 ncurses/6.0 openblas/0.2.20 openssl/1.0.2k py-appdirs/1.4.3 py-packaging/16.8 py-scipy/0.19.1-openblas py-six/1.10.0 readline/7.0 zlib/1.2.11
+ ------------------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------
+ autoconf/2.69 findutils/4.6.0 libtool/2.4.6 netlib-lapack/3.8.0 perl/5.26.2 python/2.7.15 xz/5.2.4
+ automake/1.16.1 gdbm/1.14.1 libxml2/2.9.8 numactl/2.0.11 pkgconf/1.4.2 readline/7.0 zlib/1.2.11
+ bzip2/1.0.6 hwloc/1.11.9 m4/1.4.18 openblas/0.3.3 py-numpy/1.15.2-openblas sqlite/3.23.1
+ cmake/3.12.3 libpciaccess/0.13.5 mpich/3.2.1 openmpi/3.1.3 py-scipy/1.1.0-openblas texinfo/6.5
+ diffutils/3.6 libsigsegv/2.11 ncurses/6.1 openssl/1.0.2o py-setuptools/40.4.3 util-macros/1.19.1
- ---------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/Core ----------------------------------------------------------------------------
+ ----------------------------------------------------------- share/spack/lmod/linux-ubuntu16.04-x86_64/Core ------------------------------------------------------------
gcc/7.2.0 (L)
Where:
@@ -1150,17 +1174,20 @@ either ``mpich`` or ``openmpi``. Let's start by loading ``mpich``:
.. code-block:: console
- root@module-file-tutorial:/# module load mpich
- root@module-file-tutorial:/# module avail
+ $ module load mpich
+ $ module avail
- ---------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/mpich/3.2-7gxffhv/gcc/7.2.0 -----------------------------------------------------------------
+ --------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/mpich/3.2.1-vt5xcat/gcc/7.2.0 ----------------------------------
netlib-scalapack/2.0.2-netlib netlib-scalapack/2.0.2-openblas (D)
- ------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------------------------------------
- bzip2/1.0.6 mpich/3.2 (L) netlib-lapack/3.6.1 openmpi/1.10.2 pkg-config/0.29.2 py-numpy/1.13.1-openblas py-pyparsing/2.2.0 py-setuptools/35.0.2 python/2.7.14 sqlite/3.20.0
- cmake/3.9.4 ncurses/6.0 openblas/0.2.20 openssl/1.0.2k py-appdirs/1.4.3 py-packaging/16.8 py-scipy/0.19.1-openblas py-six/1.10.0 readline/7.0 zlib/1.2.11
+ ------------------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------
+ autoconf/2.69 findutils/4.6.0 libtool/2.4.6 netlib-lapack/3.8.0 perl/5.26.2 python/2.7.15 xz/5.2.4
+ automake/1.16.1 gdbm/1.14.1 libxml2/2.9.8 numactl/2.0.11 pkgconf/1.4.2 readline/7.0 zlib/1.2.11
+ bzip2/1.0.6 hwloc/1.11.9 m4/1.4.18 openblas/0.3.3 py-numpy/1.15.2-openblas sqlite/3.23.1
+ cmake/3.12.3 libpciaccess/0.13.5 mpich/3.2.1 (L) openmpi/3.1.3 py-scipy/1.1.0-openblas texinfo/6.5
+ diffutils/3.6 libsigsegv/2.11 ncurses/6.1 openssl/1.0.2o py-setuptools/40.4.3 util-macros/1.19.1
- ---------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/Core ----------------------------------------------------------------------------
+ ----------------------------------------------------------- share/spack/lmod/linux-ubuntu16.04-x86_64/Core ------------------------------------------------------------
gcc/7.2.0 (L)
Where:
@@ -1175,16 +1202,17 @@ either ``mpich`` or ``openmpi``. Let's start by loading ``mpich``:
root@module-file-tutorial:/# module list
Currently Loaded Modules:
- 1) gcc/7.2.0 2) mpich/3.2 3) openblas/0.2.20 4) netlib-scalapack/2.0.2-openblas
+ 1) gcc/7.2.0 2) mpich/3.2.1 3) openblas/0.3.3 4) netlib-scalapack/2.0.2-openblas
At this point we can showcase the improved consistency that a hierarchical layout provides
over a non-hierarchical one:
.. code-block:: console
- root@module-file-tutorial:/# module load openmpi
+ $ module load openmpi
+
+ Lmod is automatically replacing "mpich/3.2.1" with "openmpi/3.1.3".
- Lmod is automatically replacing "mpich/3.2" with "openmpi/1.10.2".
Due to MODULEPATH changes, the following have been reloaded:
1) netlib-scalapack/2.0.2-openblas
@@ -1213,10 +1241,9 @@ for ``LAPACK`` implementations:
root@module-file-tutorial:/# module list
Currently Loaded Modules:
- 1) gcc/7.2.0 2) openblas/0.2.20 3) openmpi/1.10.2 4) netlib-scalapack/2.0.2-openblas
+ 1) gcc/7.2.0 2) openblas/0.3.3 3) openmpi/3.1.3 4) netlib-scalapack/2.0.2-openblas
root@module-file-tutorial:/# module load netlib-scalapack/2.0.2-netlib
- Autoloading netlib-lapack/3.6.1
The following have been reloaded with a version change:
1) netlib-scalapack/2.0.2-openblas => netlib-scalapack/2.0.2-netlib
@@ -1224,7 +1251,7 @@ for ``LAPACK`` implementations:
root@module-file-tutorial:/# module list
Currently Loaded Modules:
- 1) gcc/7.2.0 2) openblas/0.2.20 3) openmpi/1.10.2 4) netlib-lapack/3.6.1 5) netlib-scalapack/2.0.2-netlib
+ 1) gcc/7.2.0 2) openblas/0.3.3 3) openmpi/3.1.3 4) netlib-scalapack/2.0.2-netlib
Hierarchies that are deeper than ``Core``/``Compiler``/``MPI`` are
probably still considered "unusual" or "impractical" at many sites, mainly because
@@ -1266,7 +1293,6 @@ Coming back to our example, let's add ``lapack`` to the hierarchy and remove any
- gcc
blacklist:
- '%gcc@5.4.0'
- - readline
all:
filter:
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
@@ -1293,25 +1319,28 @@ After module files have been regenerated as usual:
root@module-file-tutorial:/# module purge
- root@module-file-tutorial:/# spack module refresh --delete-tree -y -m lmod
+ root@module-file-tutorial:/# spack module lmod refresh --delete-tree -y
==> Regenerating lmod module files
we can see that now we have additional components in the hierarchy:
.. code-block:: console
- root@module-file-tutorial:/# module load gcc
- root@module-file-tutorial:/# module load openblas
- root@module-file-tutorial:/# module avail
+ $ module load gcc
+ $ module load openblas
+ $ module avail
- ------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/openblas/0.2.20-kvddide/gcc/7.2.0 --------------------------------------------------------------
- py-numpy/1.13.1 py-scipy/0.19.1
+ -------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/openblas/0.3.3-xxoxfh4/gcc/7.2.0 --------------------------------
+ py-numpy/1.15.2 py-scipy/1.1.0
- ------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------------------------------------
- bzip2/1.0.6 mpich/3.2 netlib-lapack/3.6.1 openmpi/1.10.2 pkg-config/0.29.2 py-packaging/16.8 py-setuptools/35.0.2 python/2.7.14 sqlite/3.20.0
- cmake/3.9.4 ncurses/6.0 openblas/0.2.20 (L) openssl/1.0.2k py-appdirs/1.4.3 py-pyparsing/2.2.0 py-six/1.10.0 readline/7.0 zlib/1.2.11
+ ------------------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------
+ autoconf/2.69 findutils/4.6.0 libtool/2.4.6 netlib-lapack/3.8.0 perl/5.26.2 sqlite/3.23.1
+ automake/1.16.1 gdbm/1.14.1 libxml2/2.9.8 numactl/2.0.11 pkgconf/1.4.2 texinfo/6.5
+ bzip2/1.0.6 hwloc/1.11.9 m4/1.4.18 openblas/0.3.3 (L) py-setuptools/40.4.3 util-macros/1.19.1
+ cmake/3.12.3 libpciaccess/0.13.5 mpich/3.2.1 openmpi/3.1.3 python/2.7.15 xz/5.2.4
+ diffutils/3.6 libsigsegv/2.11 ncurses/6.1 openssl/1.0.2o readline/7.0 zlib/1.2.11
- ---------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/Core ----------------------------------------------------------------------------
+ ----------------------------------------------------------- share/spack/lmod/linux-ubuntu16.04-x86_64/Core ------------------------------------------------------------
gcc/7.2.0 (L)
Where:
@@ -1321,20 +1350,23 @@ we can see that now we have additional components in the hierarchy:
Use "module keyword key1 key2 ..." to search for all possible modules matching any of the "keys".
- root@module-file-tutorial:/# module load openmpi
- root@module-file-tutorial:/# module avail
+ $ module load openmpi
+ $ module avail
- -------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/openmpi/1.10.2-ufw7pdi/openblas/0.2.20-kvddide/gcc/7.2.0 --------------------------------------------------
+ --------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/openmpi/3.1.3-do5xfer/openblas/0.3.3-xxoxfh4/gcc/7.2.0 ---------------------
netlib-scalapack/2.0.2
- ------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/openblas/0.2.20-kvddide/gcc/7.2.0 --------------------------------------------------------------
- py-numpy/1.13.1 py-scipy/0.19.1
+ -------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/openblas/0.3.3-xxoxfh4/gcc/7.2.0 --------------------------------
+ py-numpy/1.15.2 py-scipy/1.1.0
- ------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------------------------------------
- bzip2/1.0.6 mpich/3.2 netlib-lapack/3.6.1 openmpi/1.10.2 (L) pkg-config/0.29.2 py-packaging/16.8 py-setuptools/35.0.2 python/2.7.14 sqlite/3.20.0
- cmake/3.9.4 ncurses/6.0 openblas/0.2.20 (L) openssl/1.0.2k py-appdirs/1.4.3 py-pyparsing/2.2.0 py-six/1.10.0 readline/7.0 zlib/1.2.11
+ ------------------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/gcc/7.2.0 --------------------------------------------
+ autoconf/2.69 findutils/4.6.0 libtool/2.4.6 netlib-lapack/3.8.0 perl/5.26.2 sqlite/3.23.1
+ automake/1.16.1 gdbm/1.14.1 libxml2/2.9.8 numactl/2.0.11 pkgconf/1.4.2 texinfo/6.5
+ bzip2/1.0.6 hwloc/1.11.9 m4/1.4.18 openblas/0.3.3 (L) py-setuptools/40.4.3 util-macros/1.19.1
+ cmake/3.12.3 libpciaccess/0.13.5 mpich/3.2.1 openmpi/3.1.3 (L) python/2.7.15 xz/5.2.4
+ diffutils/3.6 libsigsegv/2.11 ncurses/6.1 openssl/1.0.2o readline/7.0 zlib/1.2.11
- ---------------------------------------------------------------------------- /usr/local/share/spack/lmod/linux-ubuntu16.04-x86_64/Core ----------------------------------------------------------------------------
+ ---------------------------------------------- /home/spack1/spack/share/spack/lmod/linux-ubuntu16.04-x86_64/Core ----------------------------------------------
gcc/7.2.0 (L)
Where:
@@ -1347,18 +1379,18 @@ Both ``MPI`` and ``LAPACK`` providers will now benefit from the same safety feat
.. code-block:: console
- root@module-file-tutorial:/# module load py-numpy netlib-scalapack
- root@module-file-tutorial:/# module load mpich
+ $ module load py-numpy netlib-scalapack
+ $ module load mpich
- Lmod is automatically replacing "openmpi/1.10.2" with "mpich/3.2".
+ Lmod is automatically replacing "openmpi/3.1.3" with "mpich/3.2.1".
Due to MODULEPATH changes, the following have been reloaded:
1) netlib-scalapack/2.0.2
- root@module-file-tutorial:/# module load netlib-lapack
+ $ module load netlib-lapack
- Lmod is automatically replacing "openblas/0.2.20" with "netlib-lapack/3.6.1".
+ Lmod is automatically replacing "openblas/0.3.3" with "netlib-lapack/3.8.0".
Inactive Modules:
@@ -1385,11 +1417,12 @@ Module file templates
^^^^^^^^^^^^^^^^^^^^^
The templates that Spack uses to generate module files are stored in the
-``templates/module`` directory, and they all share the same common structure.
-Usually, they start with a header that identifies the type of
-module being generated. In the case of hierarchical module files it's:
+``share/spack/templates/module`` directory within the Spack prefix, and
+they all share the same common structure. Usually, they start with a
+header that identifies the type of module being generated. In the case of
+hierarchical module files it's:
-.. literalinclude:: ../../../templates/modules/modulefile.lua
+.. literalinclude:: ../../../share/spack/templates/modules/modulefile.lua
:language: jinja
:lines: 1-6
@@ -1403,7 +1436,7 @@ that can be overridden or extended by users, if need be.
, delimited by ``{% ... %}``,
are also permitted in the template language:
-.. literalinclude:: ../../../templates/modules/modulefile.lua
+.. literalinclude:: ../../../share/spack/templates/modules/modulefile.lua
:language: jinja
:lines: 73-88
@@ -1522,7 +1555,7 @@ If we regenerate the module files one last time:
.. code-block:: console
- root@module-file-tutorial:/# spack module refresh -y -m lmod netlib-scalapack
+ root@module-file-tutorial:/# spack module lmod refresh -y netlib-scalapack
==> Regenerating lmod module files
we'll find the following at the end of each ``netlib-scalapack`` module file:
@@ -1530,7 +1563,7 @@ we'll find the following at the end of each ``netlib-scalapack`` module file:
.. code-block:: lua
-- Access is granted only to specific groups
- if not isDir("/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/netlib-scalapack-2.0.2-ax6aza6vyepceyr3fihewp7rbr2vp7ym") then
+ if not isDir("/usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-7.2.0/netlib-scalapack-2.0.2-d3lertflood3twaor44eam2kcr4l72ag") then
LmodError (
"You don't have the necessary rights to run \"netlib-scalapack\".\n\n",
"\tPlease write an e-mail to 1234@foo.com if you need further information on how to get access to it.\n"
diff --git a/lib/spack/docs/tutorial_packaging.rst b/lib/spack/docs/tutorial_packaging.rst
index e85be7c637..328c36b61f 100644
--- a/lib/spack/docs/tutorial_packaging.rst
+++ b/lib/spack/docs/tutorial_packaging.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
.. _packaging-tutorial:
=========================
@@ -43,6 +48,16 @@ A few things before we get started:
Creating the Package File
-------------------------
+We will use a separate package repository for the tutorial. Package
+repositories allow you to separate sets of packages that take
+precedence over one another. We will use the tutorial repo that ships
+with Spack to avoid breaking the builtin Spack packages.
+
+.. code-block:: console
+
+ $ spack repo add $SPACK_ROOT/var/spack/repos/tutorial/
+ ==> Added repo with namespace 'tutorial'.
+
Spack comes with a handy command to create a new package: ``spack create``.
This command is given the location of a package's source code, downloads
@@ -55,9 +70,9 @@ we run ``spack create`` on it:
$ spack create -t generic -f https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
==> This looks like a URL for mpileaks
==> Found 1 version of mpileaks:
-
+
1.0 https://github.com/LLNL/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
-
+
==> How many would you like to checksum? (default is 1, q to abort) 1
==> Downloading...
==> Fetching https://github.com/LLNL/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
@@ -65,7 +80,7 @@ we run ``spack create`` on it:
==> Checksummed 1 version of mpileaks
==> Using specified package template: 'generic'
==> Created template for mpileaks package
- ==> Created package file: $SPACK_ROOT/var/spack/repos/builtin/packages/mpileaks/package.py
+ ==> Created package file: /home/spack1/spack/var/spack/repos/builtin/packages/mpileaks/package.py
And Spack should spawn a text editor with this file:
@@ -73,7 +88,7 @@ And Spack should spawn a text editor with this file:
:language: python
Spack has created this file in
-``$SPACK_ROOT/var/spack/repos/builtin/packages/mpileaks/package.py``. Take a
+``/home/spack1/spack/var/spack/repos/builtin/packages/mpileaks/package.py``. Take a
moment to look over the file. There's a few placeholders that Spack has
created, which we'll fill in as part of this tutorial:
@@ -88,26 +103,27 @@ to build this package:
.. code-block:: console
$ spack install mpileaks
- ==> Installing mpileaks
- ==> Using cached archive: /usr/workspace/wsa/legendre/spack/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
- ==> Staging archive: /usr/workspace/wsa/legendre/spack/var/spack/stage/mpileaks-1.0-hufwhwpq5benv3sslie6ryflk5s6nm35/mpileaks-1.0.tar.gz
- ==> Created stage in /usr/workspace/wsa/legendre/spack/var/spack/stage/mpileaks-1.0-hufwhwpq5benv3sslie6ryflk5s6nm35
- ==> Ran patch() for mpileaks
- ==> Building mpileaks [AutotoolsPackage]
- ==> Executing phase : 'autoreconf'
- ==> Executing phase : 'configure'
- ==> Error: ProcessError: Command exited with status 1:
- './configure' '--prefix=/usr/workspace/wsa/legendre/spack/opt/spack/linux-rhel7-x86_64/gcc-4.9.3/mpileaks-1.0-hufwhwpq5benv3sslie6ryflk5s6nm35'
- /usr/workspace/wsa/legendre/spack/lib/spack/spack/build_systems/autotools.py:150, in configure:
- 145 def configure(self, spec, prefix):
- 146 """Runs configure with the arguments specified in `configure_args`
- 147 and an appropriately set prefix
- 148 """
- 149 options = ['--prefix={0}'.format(prefix)] + self.configure_args()
- >> 150 inspect.getmodule(self).configure(*options)
+ ==> No binary for mpileaks found: installing from source
+ ==> Fetching file:///mirror/mpileaks/mpileaks-1.0.tar.gz
+ curl: (37) Couldn't open file /mirror/mpileaks/mpileaks-1.0.tar.gz
+ ==> Fetching from file:///mirror/mpileaks/mpileaks-1.0.tar.gz failed.
+ ==> Fetching https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
+ ######################################################################## 100.0%
+ ==> Staging archive: /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-sv75n3u5ev6mljwcezisz3slooozbbxu/mpileaks-1.0.tar.gz
+ ==> Created stage in /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-sv75n3u5ev6mljwcezisz3slooozbbxu
+ ==> No patches needed for mpileaks
+ ==> Building mpileaks [Package]
+ ==> Executing phase: 'install'
+ ==> Error: ProcessError: Command exited with status 2:
+ 'make' '-j16'
+
+ 1 error found in build log:
+ 1 ==> Executing phase: 'install'
+ 2 ==> 'make' '-j16'
+ >> 3 make: *** No targets specified and no makefile found. Stop.
See build log for details:
- /tmp/legendre/spack-stage/spack-stage-8HVzqu/mpileaks-1.0/spack-build.out
+ /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-sv75n3u5ev6mljwcezisz3slooozbbxu/mpileaks-1.0/spack-build.out
This obviously didn't work; we need to fill in the package-specific
information. Specifically, Spack didn't try to build any of mpileaks'
@@ -133,7 +149,7 @@ found in ``$SPACK_ROOT/lib/spack/docs/tutorial/examples/1.package.py``
and are below. Make these changes to your ``package.py``:
.. literalinclude:: tutorial/examples/1.package.py
- :lines: 25-
+ :lines: 6-
:language: python
We've filled in the comment that describes what this package does and
@@ -143,8 +159,19 @@ allow Spack to provide some documentation on this package to other users:
.. code-block:: console
$ spack info mpileaks
- AutotoolsPackage: mpileaks
- Homepage: https://github.com/hpc/mpileaks
+ Package: mpileaks
+
+ Description:
+ Tool to detect and report MPI objects like MPI_Requests and
+ MPI_Datatypes.
+
+ Homepage: https://github.com/hpc/mpileaks
+
+ Tags:
+ None
+
+ Preferred version:
+ 1.0 https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
Safe versions:
1.0 https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
@@ -153,7 +180,7 @@ allow Spack to provide some documentation on this package to other users:
None
Installation Phases:
- autoreconf configure build install
+ install
Build Dependencies:
None
@@ -167,10 +194,6 @@ allow Spack to provide some documentation on this package to other users:
Virtual Packages:
None
- Description:
- Tool to detect and report MPI objects like MPI_Requests and
- MPI_Datatypes
-
As we fill in more information about this package the ``spack info`` command
will become more informative. Now let's start making this package build.
@@ -184,7 +207,7 @@ The mpileaks packages depends on three other package: ``MPI``,
``$SPACK_ROOT/lib/spack/docs/tutorial/examples/2.package.py``):
.. literalinclude:: tutorial/examples/2.package.py
- :lines: 25-
+ :lines: 6-
:language: python
Now when we go to build mpileaks, Spack will fetch and build these
@@ -201,26 +224,40 @@ Now when we try to install this package a lot more happens:
$ spack install mpileaks
...
- ==> libdwarf is already installed in SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libdwarf-20160507-er4jrjynul6uba7wiu5tasuj35roxw6m
- ==> dyninst is already installed in SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/dyninst-9.3.2-t7mau34jv3e76mpspdzhf2p2a6k7qubg
- ==> callpath is already installed in SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/callpath-1.0.4-ikbbkvfmsfmqzo624nvvrbooovf7egoc
+ ==> Successfully installed libdwarf from binary cache
+ [+] /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libdwarf-20180129-p4jeflorwlnkoq2vpuyocwrbcht2ayak
+ ==> Installing callpath
+ ==> Searching for binary cache of callpath
+ ==> Installing callpath from binary cache
+ ==> Fetching file:///mirror/build_cache/linux-ubuntu16.04-x86_64/gcc-5.4.0/callpath-1.0.4/linux-ubuntu16.04-x86_64-gcc-5.4.0-callpath-1.0.4-empvyxdkc4j4pwg7gznwhbiumruey66x.spack
+ ######################################################################## 100.0%
+ gpg: Signature made Sat 10 Nov 2018 05:30:21 AM UTC using RSA key ID 3B7C69B2
+ gpg: Good signature from "sc-tutorial (GPG created for Spack) <becker33@llnl.gov>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 95C7 1787 7AC0 0FFD AA8F D6E9 9CFA 4A45 3B7C 69B2
+ ==> Successfully installed callpath from binary cache
+ [+] /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/callpath-1.0.4-empvyxdkc4j4pwg7gznwhbiumruey66x
==> Installing mpileaks
- ==> Using cached archive: SPACK_ROOT/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
- ==> Already staged mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7 in SPACK_ROOT/var/spack/stage/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7
+ ==> Searching for binary cache of mpileaks
+ ==> No binary for mpileaks found: installing from source
+ ==> Using cached archive: /home/ubuntu/packaging/spack/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
+ ==> Staging archive: /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb/mpileaks-1.0.tar.gz
+ ==> Created stage in /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb
==> No patches needed for mpileaks
==> Building mpileaks [Package]
==> Executing phase: 'install'
==> Error: ProcessError: Command exited with status 2:
- 'make' '-j36'
-
+ 'make' '-j16'
+
1 error found in build log:
- 1 ==> Executing phase: 'install'
- 2 ==> 'make' '-j36'
- >> 3 make: *** No targets specified and no makefile found. Stop.
-
+ 1 ==> Executing phase: 'install'
+ 2 ==> 'make' '-j16'
+ >> 3 make: *** No targets specified and no makefile found. Stop.
+
See build log for details:
- SPACK_ROOT/var/spack/stage/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7/mpileaks-1.0/spack-build.out
-
+ /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb/mpileaks-1.0/spack-build.out
+
Note that this command may take a while to run and produce more output if
you don't have an MPI already installed or configured in Spack.
@@ -239,35 +276,51 @@ call to ``configure()`` to the top of the install routine. The resulting
package.py is in ``$SPACK_ROOT/lib/spack/docs/tutorial/examples/3.package.py``:
.. literalinclude:: tutorial/examples/3.package.py
- :lines: 25-
+ :lines: 6-
:language: python
If we re-run we still get errors:
.. code-block:: console
+ $ spack install mpileask
+ ...
==> Installing mpileaks
- ==> Using cached archive: SPACK_ROOT/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
- ==> Already staged mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7 in SPACK_ROOT/var/spack/stage/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7
+ ==> Searching for binary cache of mpileaks
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> No binary for mpileaks found: installing from source
+ ==> Using cached archive: /home/ubuntu/packaging/spack/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
+ ==> Staging archive: /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb/mpileaks-1.0.tar.gz
+ ==> Created stage in /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb
==> No patches needed for mpileaks
==> Building mpileaks [Package]
==> Executing phase: 'install'
==> Error: ProcessError: Command exited with status 1:
'./configure'
-
+
1 error found in build log:
- [ ... ]
- 21 checking whether SPACK_ROOT/lib/spack/env/gcc/gcc and cc understand -c and -o together... yes
- 22 checking whether we are using the GNU C++ compiler... yes
- 23 checking whether SPACK_ROOT/lib/spack/env/gcc/g++ accepts -g... yes
- 24 checking dependency style of SPACK_ROOT/lib/spack/env/gcc/g++... gcc3
- 25 checking for SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc... SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc
- 26 Checking whether SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc responds to '-showme:compile'... yes
- >> 27 configure: error: unable to locate adept-utils installation
-
+ 25 checking for /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-
+ 5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx/bin/mpicc... /home/ubuntu/pa
+ ckaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.1.3-3njc4q5p
+ qdpptq6jvqjrezkffwokv2sx/bin/mpicc
+ 26 Checking whether /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/
+ gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx/bin/mpicc responds to '-
+ showme:compile'... no
+ 27 Checking whether /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/
+ gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx/bin/mpicc responds to '-
+ showme'... no
+ 28 Checking whether /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/
+ gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx/bin/mpicc responds to '-
+ compile-info'... no
+ 29 Checking whether /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/
+ gcc-5.4.0/openmpi-3.1.3-3njc4q5pqdpptq6jvqjrezkffwokv2sx/bin/mpicc responds to '-
+ show'... no
+ 30 ./configure: line 4809: Echo: command not found
+ >> 31 configure: error: unable to locate adept-utils installation
+
See build log for details:
- SPACK_ROOT/var/spack/stage/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7/mpileaks-1.0/spack-build.out
-
+ /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb/mpileaks-1.0/spack-build.out
+
Again, the problem may be obvious. But let's pretend we're not
all intelligent developers and use this opportunity spend some
time debugging. We have a few options that can tell us about
@@ -276,7 +329,7 @@ what's going wrong:
As per the error message, Spack has given us a ``spack-build.out`` debug log:
.. code-block:: console
-
+
==> Executing phase: 'install'
==> './configure'
checking metadata... no
@@ -286,23 +339,23 @@ As per the error message, Spack has given us a ``spack-build.out`` debug log:
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
- checking for gcc... SPACK_ROOT/lib/spack/env/gcc/gcc
+ checking for gcc... /home/spack1/spack/lib/spack/env/gcc/gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
- checking for suffix of executables...
+ checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
- checking whether SPACK_ROOT/lib/spack/env/gcc/gcc accepts -g... yes
- checking for SPACK_ROOT/lib/spack/env/gcc/gcc option to accept ISO C89... none needed
+ checking whether /home/spack1/spack/lib/spack/env/gcc/gcc accepts -g... yes
+ checking for /home/spack1/spack/lib/spack/env/gcc/gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
- checking dependency style of SPACK_ROOT/lib/spack/env/gcc/gcc... gcc3
- checking whether SPACK_ROOT/lib/spack/env/gcc/gcc and cc understand -c and -o together... yes
+ checking dependency style of /home/spack1/spack/lib/spack/env/gcc/gcc... gcc3
+ checking whether /home/spack1/spack/lib/spack/env/gcc/gcc and cc understand -c and -o together... yes
checking whether we are using the GNU C++ compiler... yes
- checking whether SPACK_ROOT/lib/spack/env/gcc/g++ accepts -g... yes
- checking dependency style of SPACK_ROOT/lib/spack/env/gcc/g++... gcc3
- checking for SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc... SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc
- Checking whether SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc responds to '-showme:compile'... yes
+ checking whether /home/spack1/spack/lib/spack/env/gcc/g++ accepts -g... yes
+ checking dependency style of /home/spack1/spack/lib/spack/env/gcc/g++... gcc3
+ checking for /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc... /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc
+ Checking whether /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc responds to '-showme:compile'... yes
configure: error: unable to locate adept-utils installation
This gives us the output from the build, and mpileaks isn't
@@ -317,7 +370,7 @@ We can also enter the build area and try to manually run the build:
.. code-block:: console
- $ spack env mpileaks bash
+ $ spack build-env mpileaks bash
$ spack cd mpileaks
The ``spack env`` command spawned a new shell that contains the same
@@ -336,23 +389,23 @@ From here we can manually re-run the build:
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
- checking for gcc... SPACK_ROOT/lib/spack/env/gcc/gcc
+ checking for gcc... /home/spack1/spack/lib/spack/env/gcc/gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
- checking for suffix of executables...
+ checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
- checking whether SPACK_ROOT/lib/spack/env/gcc/gcc accepts -g... yes
- checking for SPACK_ROOT/lib/spack/env/gcc/gcc option to accept ISO C89... none needed
+ checking whether /home/spack1/spack/lib/spack/env/gcc/gcc accepts -g... yes
+ checking for /home/spack1/spack/lib/spack/env/gcc/gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
- checking dependency style of SPACK_ROOT/lib/spack/env/gcc/gcc... gcc3
- checking whether SPACK_ROOT/lib/spack/env/gcc/gcc and cc understand -c and -o together... yes
+ checking dependency style of /home/spack1/spack/lib/spack/env/gcc/gcc... gcc3
+ checking whether /home/spack1/spack/lib/spack/env/gcc/gcc and cc understand -c and -o together... yes
checking whether we are using the GNU C++ compiler... yes
- checking whether SPACK_ROOT/lib/spack/env/gcc/g++ accepts -g... yes
- checking dependency style of SPACK_ROOT/lib/spack/env/gcc/g++... gcc3
- checking for SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc... SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc
- Checking whether SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc responds to '-showme:compile'... yes
+ checking whether /home/spack1/spack/lib/spack/env/gcc/g++ accepts -g... yes
+ checking dependency style of /home/spack1/spack/lib/spack/env/gcc/g++... gcc3
+ checking for /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc... /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc
+ Checking whether /home/spack1/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f/bin/mpicc responds to '-showme:compile'... yes
configure: error: unable to locate adept-utils installation
We're seeing the same error, but now we're in a shell where we can run
@@ -372,7 +425,7 @@ version can be found in
``$SPACK_ROOT/lib/spack/docs/tutorial/examples/4.package.py``:
.. literalinclude:: tutorial/examples/4.package.py
- :lines: 25-
+ :lines: 6-
:language: python
This is all we need for working mpileaks! If we install now we'll see:
@@ -382,16 +435,18 @@ This is all we need for working mpileaks! If we install now we'll see:
$ spack install mpileaks
...
==> Installing mpileaks
- ==> Using cached archive: SPACK_ROOT/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
- ==> Staging archive: SPACK_ROOT/var/spack/stage/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7/mpileaks-1.0.tar.gz
- ==> Created stage in SPACK_ROOT/var/spack/stage/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7
+ ==> Searching for binary cache of mpileaks
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> No binary for mpileaks found: installing from source
+ ==> Using cached archive: /home/ubuntu/packaging/spack/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
+ ==> Staging archive: /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb/mpileaks-1.0.tar.gz
+ ==> Created stage in /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb
==> No patches needed for mpileaks
==> Building mpileaks [Package]
==> Executing phase: 'install'
==> Successfully installed mpileaks
- Fetch: 0.00s. Build: 9.01s. Total: 9.01s.
- [+] SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpileaks-1.0-lfgf53rns5mswq25rxckzgvmjc6ywam7
-
+ Fetch: 0.00s. Build: 9.41s. Total: 9.41s.
+ [+] /home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpileaks-1.0-csoikctsalli4cdkkdk377gprkc472rb
There are some special circumstances in package that are worth highlighting.
Normally spack would have automatically detected that mpileaks was an
@@ -408,7 +463,7 @@ a full install routine we would have just written:
Similarly, if this had been a CMake-based package we
would have been filling in a ``cmake_args`` function instead of
``configure_args``. There are similar default package types for
-many build environments.
+many build environments that will be discussed later in the tutorial.
--------
Variants
@@ -423,7 +478,7 @@ To do this, we'll add a variant to our package, as per the following (see
``$SPACK_ROOT/lib/spack/docs/tutorial/examples/5.package.py``):
.. literalinclude:: tutorial/examples/5.package.py
- :lines: 25-
+ :lines: 6-
:language: python
We've added the variant ``stackstart``, and given it a default value of
@@ -435,13 +490,16 @@ configure line (output truncated for length):
$ spack install --verbose mpileaks stackstart=4
...
==> Installing mpileaks
- ==> Using cached archive: SPACK_ROOT/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
- ==> Staging archive: SPACK_ROOT/var/spack/stage/mpileaks-1.0-gxxi4fp57b4j6xalra5t65hyx5rj25t7/mpileaks-1.0.tar.gz
- ==> Created stage in SPACK_ROOT/var/spack/stage/mpileaks-1.0-gxxi4fp57b4j6xalra5t65hyx5rj25t7
+ ==> Searching for binary cache of mpileaks
+ ==> Finding buildcaches in /mirror/build_cache
+ ==> No binary for mpileaks found: installing from source
+ ==> Using cached archive: /home/ubuntu/packaging/spack/var/spack/cache/mpileaks/mpileaks-1.0.tar.gz
+ ==> Staging archive: /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-meufjojkxve3l7rci2mbud3faidgplto/mpileaks-1.0.tar.gz
+ ==> Created stage in /home/ubuntu/packaging/spack/var/spack/stage/mpileaks-1.0-meufjojkxve3l7rci2mbud3faidgplto
==> No patches needed for mpileaks
==> Building mpileaks [Package]
==> Executing phase: 'install'
- ==> './configure' '--with-adept-utils=SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/adept-utils-1.0.1-pm3gffhrnwsdtqthtvsfvs2tny4r65wb' '--with-callpath=SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/callpath-1.0.4-ikbbkvfmsfmqzo624nvvrbooovf7egoc' '--prefix=SPACK_ROOT/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpileaks-1.0-gxxi4fp57b4j6xalra5t65hyx5rj25t7' '--with-stack-start-c=4' '--with-stack-start-fortran=4'
+ ==> './configure' '--with-adept-utils=/home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/adept-utils-1.0.1-7tippnvo5g76wpijk7x5kwfpr3iqiaen' '--with-callpath=/home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/callpath-1.0.4-empvyxdkc4j4pwg7gznwhbiumruey66x' '--prefix=/home/ubuntu/packaging/spack/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/mpileaks-1.0-meufjojkxve3l7rci2mbud3faidgplto' '--with-stack-start-c=4' '--with-stack-start-fortran=4'
---------------
The Spec Object
diff --git a/lib/spack/docs/workflows.rst b/lib/spack/docs/workflows.rst
index 4c674f92e4..b55c8bfd49 100644
--- a/lib/spack/docs/workflows.rst
+++ b/lib/spack/docs/workflows.rst
@@ -1,3 +1,8 @@
+.. Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+ Spack Project Developers. See the top-level COPYRIGHT file for details.
+
+ SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
=========
Workflows
=========
@@ -276,11 +281,11 @@ have some drawbacks:
2. The ``spack spec`` and ``spack install`` commands use a
sophisticated concretization algorithm that chooses the "best"
among several options, taking into account ``packages.yaml`` file.
- The ``spack load`` and ``spack module loads`` commands, on the
+ The ``spack load`` and ``spack module tcl loads`` commands, on the
other hand, are not very smart: if the user-supplied spec matches
- more than one installed package, then ``spack module loads`` will
+ more than one installed package, then ``spack module tcl loads`` will
fail. This may change in the future. For now, the workaround is to
- be more specific on any ``spack module loads`` lines that fail.
+ be more specific on any ``spack module tcl loads`` lines that fail.
""""""""""""""""""""""
@@ -290,7 +295,7 @@ Generated Load Scripts
Another problem with using `spack load` is, it is slow; a typical user
environment could take several seconds to load, and would not be
appropriate to put into ``.bashrc`` directly. It is preferable to use
-a series of ``spack module loads`` commands to pre-compute which
+a series of ``spack module tcl loads`` commands to pre-compute which
modules to load. These can be put in a script that is run whenever
installed Spack packages change. For example:
@@ -301,7 +306,7 @@ installed Spack packages change. For example:
# Generate module load commands in ~/env/spackenv
cat <<EOF | /bin/sh >$HOME/env/spackenv
- FIND='spack module loads --prefix linux-SuSE11-x86_64/'
+ FIND='spack module tcl loads --prefix linux-SuSE11-x86_64/'
\$FIND modele-utils
\$FIND emacs
@@ -346,14 +351,14 @@ Users may now put ``source ~/env/spackenv`` into ``.bashrc``.
Some module systems put a prefix on the names of modules created
by Spack. For example, that prefix is ``linux-SuSE11-x86_64/`` in
the above case. If a prefix is not needed, you may omit the
- ``--prefix`` flag from ``spack module loads``.
+ ``--prefix`` flag from ``spack module tcl loads``.
"""""""""""""""""""""""
Transitive Dependencies
"""""""""""""""""""""""
-In the script above, each ``spack module loads`` command generates a
+In the script above, each ``spack module tcl loads`` command generates a
*single* ``module load`` line. Transitive dependencies do not usually
need to be loaded, only modules the user needs in ``$PATH``. This is
because Spack builds binaries with RPATH. Spack's RPATH policy has
@@ -394,38 +399,13 @@ Unfortunately, Spack's RPATH support does not work in all case. For example:
In cases where RPATH support doesn't make things "just work," it can
be necessary to load a module's dependencies as well as the module
itself. This is done by adding the ``--dependencies`` flag to the
-``spack module loads`` command. For example, the following line,
+``spack module tcl loads`` command. For example, the following line,
added to the script above, would be used to load SciPy, along with
Numpy, core Python, BLAS/LAPACK and anything else needed:
.. code-block:: sh
- spack module loads --dependencies py-scipy
-
-^^^^^^^^^^^^^^^^^^
-Extension Packages
-^^^^^^^^^^^^^^^^^^
-
-:ref:`packaging_extensions` may be used as an alternative to loading
-Python (and similar systems) packages directly. If extensions are
-activated, then ``spack load python`` will also load all the
-extensions activated for the given ``python``. This reduces the need
-for users to load a large number of modules.
-
-However, Spack extensions have two potential drawbacks:
-
-#. Activated packages that involve compiled C extensions may still
- need their dependencies to be loaded manually. For example,
- ``spack load openblas`` might be required to make ``py-numpy``
- work.
-
-#. Extensions "break" a core feature of Spack, which is that multiple
- versions of a package can co-exist side-by-side. For example,
- suppose you wish to run a Python package in two different
- environments but the same basic Python --- one with
- ``py-numpy@1.7`` and one with ``py-numpy@1.8``. Spack extensions
- will not support this potential debugging use case.
-
+ spack module tcl loads --dependencies py-scipy
^^^^^^^^^^^^^^
Dummy Packages
@@ -447,6 +427,8 @@ it. A disadvantage is the set of packages will be consistent; this
means you cannot load up two applications this way if they are not
consistent with each other.
+.. _filesystem-views:
+
^^^^^^^^^^^^^^^^
Filesystem Views
^^^^^^^^^^^^^^^^
@@ -537,7 +519,7 @@ dependencies, but not ``appsy`` itself:
.. code-block:: console
- $ spack view symlink --dependencies yes --exclude appsy appsy
+ $ spack view --dependencies yes --exclude appsy symlink /path/to/MYVIEW/ appsy
Alternately, you wish to create a view whose purpose is to provide
binary executables to end users. You only need to include
@@ -546,7 +528,7 @@ dependencies. In this case, you might use:
.. code-block:: console
- $ spack view symlink --dependencies no cmake
+ $ spack view --dependencies no symlink /path/to/MYVIEW/ cmake
"""""""""""""""""""""""
@@ -587,6 +569,29 @@ symlinks. At any time one can delete ``/path/to/MYVIEW`` or use
``spack view`` to manage it surgically. None of this will affect the
real Spack install area.
+^^^^^^^^^^^^^^^^^^
+Global Activations
+^^^^^^^^^^^^^^^^^^
+
+:ref:`cmd-spack-activate` may be used as an alternative to loading
+Python (and similar systems) packages directly or creating a view.
+If extensions are globally activated, then ``spack load python`` will
+also load all the extensions activated for the given ``python``.
+This reduces the need for users to load a large number of modules.
+
+However, Spack global activations have two potential drawbacks:
+
+#. Activated packages that involve compiled C extensions may still
+ need their dependencies to be loaded manually. For example,
+ ``spack load openblas`` might be required to make ``py-numpy``
+ work.
+
+#. Global activations "break" a core feature of Spack, which is that
+ multiple versions of a package can co-exist side-by-side. For example,
+ suppose you wish to run a Python package in two different
+ environments but the same basic Python --- one with
+ ``py-numpy@1.7`` and one with ``py-numpy@1.8``. Spack extensions
+ will not support this potential debugging use case.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Discussion: Running Binaries
@@ -630,7 +635,7 @@ environments:
and extension packages.
* Views and activated extensions maintain state that is semantically
- equivalent to the information in a ``spack module loads`` script.
+ equivalent to the information in a ``spack module tcl loads`` script.
Administrators might find things easier to maintain without the
added "heavyweight" state of a view.
@@ -787,7 +792,7 @@ for the ``mylib`` package (ellipses for brevity):
depends_on('cmake', type='build')
depends_on('doxygen', type='build')
- def configure_args(self):
+ def cmake_args(self):
spec = self.spec
return [
'-DUSE_EVERYTRACE=%s' % ('YES' if '+everytrace' in spec else 'NO'),
@@ -1254,6 +1259,28 @@ Just use the `docker bootstraping mechanism <http://singularity.lbl.gov/quicksta
%runscript
exec /bin/bash -l
+""""""""""""""""""""""
+Docker for Development
+""""""""""""""""""""""
+
+For examples of how we use docker in development, see
+:ref:`docker_for_developers`.
+
+"""""""""""""""""""""""""
+Docker on Windows and OSX
+"""""""""""""""""""""""""
+
+On Mac OS and Windows, docker runs on a hypervisor that is not allocated much
+memory by default, and some spack packages may fail to build due to lack of
+memory. To work around this issue, consider configuring your docker installation
+to use more of your host memory. In some cases, you can also ease the memory
+pressure on parallel builds by limiting the parallelism in your config.yaml.
+
+.. code-block:: yaml
+
+ config:
+ build_jobs: 2
+
------------------
Upstream Bug Fixes
------------------
diff --git a/lib/spack/env/cc b/lib/spack/env/cc
index b06c6fd6fc..3b83291cc2 100755
--- a/lib/spack/env/cc
+++ b/lib/spack/env/cc
@@ -1,28 +1,10 @@
#!/bin/bash
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
#
# Spack compiler wrapper script.
#
@@ -52,6 +34,7 @@ parameters=(
SPACK_F77_RPATH_ARG
SPACK_FC_RPATH_ARG
SPACK_SHORT_SPEC
+ SPACK_SYSTEM_DIRS
)
# The compiler input variables are checked for sanity later:
@@ -73,7 +56,31 @@ function die {
exit 1
}
-for param in ${parameters[@]}; do
+# read input parameters into proper bash arrays.
+# SYSTEM_DIRS is delimited by :
+IFS=':' read -ra SPACK_SYSTEM_DIRS <<< "${SPACK_SYSTEM_DIRS}"
+
+# SPACK_<LANG>FLAGS and SPACK_LDLIBS are split by ' '
+IFS=' ' read -ra SPACK_FFLAGS <<< "$SPACK_FFLAGS"
+IFS=' ' read -ra SPACK_CPPFLAGS <<< "$SPACK_CPPFLAGS"
+IFS=' ' read -ra SPACK_CFLAGS <<< "$SPACK_CFLAGS"
+IFS=' ' read -ra SPACK_CXXFLAGS <<< "$SPACK_CXXFLAGS"
+IFS=' ' read -ra SPACK_LDFLAGS <<< "$SPACK_LDFLAGS"
+IFS=' ' read -ra SPACK_LDLIBS <<< "$SPACK_LDLIBS"
+
+# test whether a path is a system directory
+function system_dir {
+ path="$1"
+ for sd in "${SPACK_SYSTEM_DIRS[@]}"; do
+ if [ "${path}" == "${sd}" ] || [ "${path}" == "${sd}/" ]; then
+ # success if path starts with a system prefix
+ return 0
+ fi
+ done
+ return 1 # fail if path starts no system prefix
+}
+
+for param in "${parameters[@]}"; do
if [[ -z ${!param} ]]; then
die "Spack compiler must be run from Spack! Input '$param' is missing."
fi
@@ -117,7 +124,7 @@ case "$command" in
comp="FC"
lang_flags=F
;;
- f77|gfortran|flang|ifort|pgfortran|xlf|xlf_r|nagfor|ftn)
+ f77|xlf|xlf_r|pgf77)
command="$SPACK_F77"
language="Fortran 77"
comp="F77"
@@ -136,10 +143,12 @@ esac
# libraries.
if [[ -z $mode ]] || [[ $mode == ld ]]; then
for arg in "$@"; do
- if [[ $arg == -v || $arg == -V || $arg == --version || $arg == -dumpversion ]]; then
- mode=vcheck
- break
- fi
+ case $arg in
+ -v|-V|--version|-dumpversion)
+ mode=vcheck
+ break
+ ;;
+ esac
done
fi
@@ -163,7 +172,7 @@ fi
# Set up rpath variable according to language.
eval rpath=\$SPACK_${comp}_RPATH_ARG
-# Dump the version and exit if we're in testing mode.
+# Dump the mode and exit if the command is dump-mode.
if [[ $SPACK_TEST_COMMAND == dump-mode ]]; then
echo "$mode"
exit
@@ -176,50 +185,40 @@ if [[ -z $command ]]; then
fi
#
-# Set paths as defined in the 'environment' section of the compiler config
-# names are stored in SPACK_ENV_TO_SET
-# values are stored in SPACK_ENV_SET_<varname>
-#
-IFS=':' read -ra env_set_varnames <<< "$SPACK_ENV_TO_SET"
-for varname in "${env_set_varnames[@]}"; do
- spack_varname="SPACK_ENV_SET_$varname"
- export $varname=${!spack_varname}
- unset $spack_varname
-done
-
-#
# Filter '.' and Spack environment directories out of PATH so that
# this script doesn't just call itself
#
IFS=':' read -ra env_path <<< "$PATH"
IFS=':' read -ra spack_env_dirs <<< "$SPACK_ENV_PATH"
spack_env_dirs+=("" ".")
-PATH=""
+export PATH=""
for dir in "${env_path[@]}"; do
addpath=true
for env_dir in "${spack_env_dirs[@]}"; do
- if [[ $dir == $env_dir ]]; then
+ if [[ "$dir" == "$env_dir" ]]; then
addpath=false
break
fi
done
if $addpath; then
- PATH="${PATH:+$PATH:}$dir"
+ export PATH="${PATH:+$PATH:}$dir"
fi
done
-export PATH
if [[ $mode == vcheck ]]; then
- exec ${command} "$@"
+ exec "${command}" "$@"
fi
# Darwin's linker has a -r argument that merges object files together.
# It doesn't work with -rpath.
# This variable controls whether they are added.
add_rpaths=true
-if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]]; then
+if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]];
+then
for arg in "$@"; do
- if [[ ($arg == -r && $mode == ld) || ($arg == -r && $mode == ccld) || ($arg == -Wl,-r && $mode == ccld) ]]; then
+ if [[ ($arg == -r && $mode == ld) ||
+ ($arg == -r && $mode == ccld) ||
+ ($arg == -Wl,-r && $mode == ccld) ]]; then
add_rpaths=false
break
fi
@@ -227,126 +226,285 @@ if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]]; then
fi
# Save original command for debug logging
-input_command="$@"
-args=("$@")
+input_command="$*"
+
+#
+# Parse the command line arguments.
+#
+# We extract -L, -I, and -Wl,-rpath arguments from the command line and
+# recombine them with Spack arguments later. We parse these out so that
+# we can make sure that system paths come last, that package arguments
+# come first, and that Spack arguments are injected properly.
+#
+# All other arguments, including -l arguments, are treated as
+# 'other_args' and left in their original order. This ensures that
+# --start-group, --end-group, and other order-sensitive flags continue to
+# work as the caller expects.
+#
+# The libs variable is initialized here for completeness, and it is also
+# used later to inject flags supplied via `ldlibs` on the command
+# line. These come into the wrappers via SPACK_LDLIBS.
+#
+includes=()
+libdirs=()
+rpaths=()
+system_includes=()
+system_libdirs=()
+system_rpaths=()
+libs=()
+other_args=()
-# Prepend cppflags, cflags, cxxflags, fcflags, fflags, and ldflags
+while [ -n "$1" ]; do
+ # an RPATH to be added after the case statement.
+ rp=""
-# Add ldflags
+ case "$1" in
+ -I*)
+ arg="${1#-I}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if system_dir "$arg"; then
+ system_includes+=("$arg")
+ else
+ includes+=("$arg")
+ fi
+ ;;
+ -L*)
+ arg="${1#-L}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if system_dir "$arg"; then
+ system_libdirs+=("$arg")
+ else
+ libdirs+=("$arg")
+ fi
+ ;;
+ -l*)
+ arg="${1#-l}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ other_args+=("-l$arg")
+ ;;
+ -Wl,*)
+ arg="${1#-Wl,}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if [[ "$arg" = -rpath=* ]]; then
+ rp="${arg#-rpath=}"
+ elif [[ "$arg" = -rpath,* ]]; then
+ rp="${arg#-rpath,}"
+ elif [[ "$arg" = -rpath ]]; then
+ shift; arg="$1"
+ if [[ "$arg" != -Wl,* ]]; then
+ die "-Wl,-rpath was not followed by -Wl,*"
+ fi
+ rp="${arg#-Wl,}"
+ else
+ other_args+=("-Wl,$arg")
+ fi
+ ;;
+ -Xlinker,*)
+ arg="${1#-Xlinker,}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if [[ "$arg" = -rpath=* ]]; then
+ rp="${arg#-rpath=}"
+ elif [[ "$arg" = -rpath ]]; then
+ shift; arg="$1"
+ if [[ "$arg" != -Xlinker,* ]]; then
+ die "-Xlinker,-rpath was not followed by -Xlinker,*"
+ fi
+ rp="${arg#-Xlinker,}"
+ else
+ other_args+=("-Xlinker,$arg")
+ fi
+ ;;
+ -Xlinker)
+ if [[ "$2" == "-rpath" ]]; then
+ if [[ "$3" != "-Xlinker" ]]; then
+ die "-Xlinker,-rpath was not followed by -Xlinker,*"
+ fi
+ shift 3;
+ rp="$1"
+ else
+ other_args+=("$1")
+ fi
+ ;;
+ *)
+ other_args+=("$1")
+ ;;
+ esac
+
+ # test rpaths against system directories in one place.
+ if [ -n "$rp" ]; then
+ if system_dir "$rp"; then
+ system_rpaths+=("$rp")
+ else
+ rpaths+=("$rp")
+ fi
+ fi
+ shift
+done
+
+#
+# Add flags from Spack's cppflags, cflags, cxxflags, fcflags, fflags, and
+# ldflags. We stick to the order that gmake puts the flags in by default.
+#
+# See the gmake manual on implicit rules for details:
+# https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
+#
+flags=()
+
+# Fortran flags come before CPPFLAGS
case "$mode" in
- ld|ccld)
- args=(${SPACK_LDFLAGS[@]} "${args[@]}") ;;
+ cc|ccld)
+ case $lang_flags in
+ F)
+ flags=("${flags[@]}" "${SPACK_FFLAGS[@]}") ;;
+ esac
+ ;;
+esac
+
+# C preprocessor flags come before any C/CXX flags
+case "$mode" in
+ cpp|as|cc|ccld)
+ flags=("${flags[@]}" "${SPACK_CPPFLAGS[@]}") ;;
esac
-# Add compiler flags.
+
+# Add C and C++ flags
case "$mode" in
cc|ccld)
- # Add c, cxx, fc, and f flags
case $lang_flags in
C)
- args=(${SPACK_CFLAGS[@]} "${args[@]}") ;;
+ flags=("${flags[@]}" "${SPACK_CFLAGS[@]}") ;;
CXX)
- args=(${SPACK_CXXFLAGS[@]} "${args[@]}") ;;
+ flags=("${flags[@]}" "${SPACK_CXXFLAGS[@]}") ;;
esac
;;
esac
-# Add cppflags
+# Linker flags
case "$mode" in
- cpp|as|cc|ccld)
- args=(${SPACK_CPPFLAGS[@]} "${args[@]}") ;;
+ ld|ccld)
+ flags=("${flags[@]}" "${SPACK_LDFLAGS[@]}") ;;
esac
-case "$mode" in cc|ccld)
- # Add fortran flags
- case $lang_flags in
- F)
- args=(${SPACK_FFLAGS[@]} "${args[@]}") ;;
- esac
+
+# Include the package's prefix/lib[64] dirs in rpath. We don't know until
+# *after* installation which one's correct, so we include both lib and
+# lib64, assuming that only one will be present.
+case "$mode" in
+ ld|ccld)
+ $add_rpaths && rpaths+=("$SPACK_PREFIX/lib")
+ $add_rpaths && rpaths+=("$SPACK_PREFIX/lib64")
;;
esac
-# Read spack dependencies from the path environment variable
+# Read spack dependencies from the environment. This is a list of prefixes.
IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES"
for dep in "${deps[@]}"; do
- # Prepend include directories
- if [[ -d $dep/include ]]; then
- if [[ $mode == cpp || $mode == cc || $mode == as || $mode == ccld ]]; then
- args=("-I$dep/include" "${args[@]}")
- fi
- fi
-
- # Prepend lib and RPATH directories
- if [[ -d $dep/lib ]]; then
- if [[ $mode == ccld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("$rpath$dep/lib" "${args[@]}")
- fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib" "${args[@]}")
- fi
- elif [[ $mode == ld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("-rpath" "$dep/lib" "${args[@]}")
+ # Append include directories in any compilation mode
+ case "$mode" in
+ cpp|cc|as|ccld)
+ if [[ -d $dep/include ]]; then
+ includes=("${includes[@]}" "$dep/include")
fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib" "${args[@]}")
- fi
- fi
- fi
+ ;;
+ esac
- # Prepend lib64 and RPATH directories
- if [[ -d $dep/lib64 ]]; then
- if [[ $mode == ccld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("$rpath$dep/lib64" "${args[@]}")
+ # Append lib/lib64 and RPATH directories, but only if we're linking
+ case "$mode" in
+ ld|ccld)
+ if [[ -d $dep/lib ]]; then
+ if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
+ $add_rpaths && rpaths=("${rpaths[@]}" "$dep/lib")
+ fi
+ if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
+ libdirs=("${libdirs[@]}" "$dep/lib")
+ fi
fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib64" "${args[@]}")
- fi
- elif [[ $mode == ld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("-rpath" "$dep/lib64" "${args[@]}")
- fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib64" "${args[@]}")
+
+ if [[ -d $dep/lib64 ]]; then
+ if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
+ $add_rpaths && rpaths+=("$dep/lib64")
+ fi
+ if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
+ libdirs+=("$dep/lib64")
+ fi
fi
- fi
- fi
+ ;;
+ esac
done
-# Include all -L's and prefix/whatever dirs in rpath
-if [[ $mode == ccld ]]; then
- $add_rpaths && args=("$rpath$SPACK_PREFIX/lib64" "${args[@]}")
- $add_rpaths && args=("$rpath$SPACK_PREFIX/lib" "${args[@]}")
-elif [[ $mode == ld ]]; then
- $add_rpaths && args=("-rpath" "$SPACK_PREFIX/lib64" "${args[@]}")
- $add_rpaths && args=("-rpath" "$SPACK_PREFIX/lib" "${args[@]}")
-fi
+# add RPATHs if we're in in any linking mode
+case "$mode" in
+ ld|ccld)
+ # Set extra RPATHs
+ IFS=':' read -ra extra_rpaths <<< "$SPACK_COMPILER_EXTRA_RPATHS"
+ for extra_rpath in "${extra_rpaths[@]}"; do
+ $add_rpaths && rpaths+=("$extra_rpath")
+ libdirs+=("$extra_rpath")
+ done
-# Set extra RPATHs
-IFS=':' read -ra extra_rpaths <<< "$SPACK_COMPILER_EXTRA_RPATHS"
-for extra_rpath in "${extra_rpaths[@]}"; do
- if [[ $mode == ccld ]]; then
- $add_rpaths && args=("$rpath$extra_rpath" "${args[@]}")
- args=("-L$extra_rpath" "${args[@]}")
- elif [[ $mode == ld ]]; then
- $add_rpaths && args=("-rpath" "$extra_rpath" "${args[@]}")
- args=("-L$extra_rpath" "${args[@]}")
- fi
-done
+ # Add SPACK_LDLIBS to args
+ for lib in "${SPACK_LDLIBS[@]}"; do
+ libs+=("${lib#-l}")
+ done
+ ;;
+esac
+
+#
+# Finally, reassemble the command line.
+#
+
+# Includes and system includes first
+args=()
+
+# flags assembled earlier
+args+=("${flags[@]}")
-# Add SPACK_LDLIBS to args
+# include directory search paths
+for dir in "${includes[@]}"; do args+=("-I$dir"); done
+for dir in "${system_includes[@]}"; do args+=("-I$dir"); done
+
+# Library search paths
+for dir in "${libdirs[@]}"; do args+=("-L$dir"); done
+for dir in "${system_libdirs[@]}"; do args+=("-L$dir"); done
+
+# RPATHs arguments
case "$mode" in
- ld|ccld)
- args=("${args[@]}" ${SPACK_LDLIBS[@]}) ;;
+ ccld)
+ for dir in "${rpaths[@]}"; do args+=("$rpath$dir"); done
+ for dir in "${system_rpaths[@]}"; do args+=("$rpath$dir"); done
+ ;;
+ ld)
+ for dir in "${rpaths[@]}"; do args+=("-rpath" "$dir"); done
+ for dir in "${system_rpaths[@]}"; do args+=("-rpath" "$dir"); done
+ ;;
esac
+# Other arguments from the input command
+args+=("${other_args[@]}")
+
+# Inject SPACK_LDLIBS, if supplied
+for lib in "${libs[@]}"; do
+ args+=("-l$lib");
+done
+
full_command=("$command" "${args[@]}")
-# In test command mode, write out full command for Spack tests.
+# prepend the ccache binary if we're using ccache
+if [ -n "$SPACK_CCACHE_BINARY" ]; then
+ case "$lang_flags" in
+ C|CXX) # ccache only supports C languages
+ full_command=("${SPACK_CCACHE_BINARY}" "${full_command[@]}")
+ # workaround for stage being a temp folder
+ # see #3761#issuecomment-294352232
+ export CCACHE_NOHASHDIR=yes
+ ;;
+ esac
+fi
+
+# dump the full command if the caller supplies SPACK_TEST_COMMAND=dump-args
if [[ $SPACK_TEST_COMMAND == dump-args ]]; then
- echo "${full_command[@]}"
+ IFS="
+" && echo "${full_command[*]}"
exit
elif [[ -n $SPACK_TEST_COMMAND ]]; then
die "ERROR: Unknown test command"
@@ -359,7 +517,7 @@ if [[ $SPACK_DEBUG == TRUE ]]; then
input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_DEBUG_LOG_ID.in.log"
output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_DEBUG_LOG_ID.out.log"
echo "[$mode] $command $input_command" >> "$input_log"
- echo "[$mode] ${full_command[@]}" >> "$output_log"
+ echo "[$mode] ${full_command[*]}" >> "$output_log"
fi
exec "${full_command[@]}"
diff --git a/lib/spack/external/__init__.py b/lib/spack/external/__init__.py
index 1dfdf7f72d..320d3a6341 100644
--- a/lib/spack/external/__init__.py
+++ b/lib/spack/external/__init__.py
@@ -1,51 +1,120 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-"""
-This module contains external, potentially separately licensed,
-packages that are included in spack.
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""This module contains the following external, potentially separately
+licensed, packages that are included in Spack:
+
+argparse
+--------
+
+* Homepage: https://pypi.python.org/pypi/argparse
+* Usage: We include our own version to be Python 2.6 compatible.
+* Version: 1.4.0
+* Note: This package has been slightly modified to improve
+ error message formatting. See the following commit if the
+ vendored copy ever needs to be updated again:
+ https://github.com/spack/spack/pull/6786/commits/dfcef577b77249106ea4e4c69a6cd9e64fa6c418
+
+ctest_log_parser
+----------------
+
+* Homepage: https://github.com/Kitware/CMake/blob/master/Source/CTest/cmCTestBuildHandler.cxx
+* Usage: Functions to parse build logs and extract error messages.
+* Version: Unversioned
+* Note: This is a homemade port of Kitware's CTest build handler.
+
+distro
+------
+
+* Homepage: https://pypi.python.org/pypi/distro
+* Usage: Provides a more stable linux distribution detection.
+* Version: 1.0.4 (last version supporting Python 2.6)
+
+functools
+---------
+
+* Homepage: https://github.com/python/cpython/blob/2.7/Lib/functools.py
+* Usage: Used for implementation of total_ordering.
+* Version: Unversioned
+* Note: This is the functools.total_ordering implementation
+ from Python 2.7 backported so we can run on Python 2.6.
+
+jinja2
+------
+
+* Homepage: https://pypi.python.org/pypi/Jinja2
+* Usage: A modern and designer-friendly templating language for Python.
+* Version: 2.10
+
+jsonschema
+----------
+
+* Homepage: https://pypi.python.org/pypi/jsonschema
+* Usage: An implementation of JSON Schema for Python.
+* Version: 2.4.0 (last version before functools32 dependency was added)
+* Note: functools32 doesn't support Python 2.6 or 3.0, so jsonschema
+ cannot be upgraded any further
+
+markupsafe
+----------
+
+* Homepage: https://pypi.python.org/pypi/MarkupSafe
+* Usage: Implements a XML/HTML/XHTML Markup safe string for Python.
+* Version: 1.0
+
+orderddict
+----------
+
+* Homepage: https://pypi.org/project/ordereddict/
+* Usage: A drop-in substitute for Py2.7's new collections.OrderedDict
+ that works in Python 2.4-2.6.
+* Version: 1.1
-So far:
- argparse: We include our own version to be Python 2.6 compatible.
+py
+--
- distro: Provides a more stable linux distribution detection.
+* Homepage: https://pypi.python.org/pypi/py
+* Usage: Needed by pytest. Library with cross-python path,
+ ini-parsing, io, code, and log facilities.
+* Version: 1.4.34 (last version supporting Python 2.6)
- functools: Used for implementation of total_ordering.
+pyqver
+------
- jinja2: A modern and designer-friendly templating language for Python
+* Homepage: https://github.com/ghewgill/pyqver
+* Usage: External script to query required python version of
+ python source code. Used for ensuring 2.6 compatibility.
+* Version: Unversioned
- jsonschema: An implementation of JSON Schema for Python.
+pytest
+------
- ordereddict: We include our own version to be Python 2.6 compatible.
+* Homepage: https://pypi.python.org/pypi/pytest
+* Usage: Testing framework used by Spack.
+* Version: 3.2.5 (last version supporting Python 2.6)
+* Note: This package has been slightly modified to improve
+ Python 2.6 compatibility. See the following commit if the
+ vendored copy ever needs to be updated again:
+ https://github.com/spack/spack/pull/6801/commits/ff513c39f2c67ff615de5cbc581dd69a8ec96526
- py: Needed by pytest. Library with cross-python path,
- ini-parsing, io, code, and log facilities.
+ruamel.yaml
+------
- pyqver2: External script to query required python version of
- python source code. Used for ensuring 2.6 compatibility.
+* Homepage: https://yaml.readthedocs.io/
+* Usage: Used for config files. Ruamel is based on PyYAML but is more
+ actively maintained and has more features, including round-tripping
+ comments read from config files.
+* Version: 0.11.15 (last version supporting Python 2.6)
+* Note: This package has been slightly modified to improve Python 2.6
+ compatibility -- some ``{}`` format strings were replaced, and the
+ import for ``OrderedDict`` was tweaked.
- pytest: Testing framework used by Spack.
+six
+---
- yaml: Used for config files.
+* Homepage: https://pypi.python.org/pypi/six
+* Usage: Python 2 and 3 compatibility utilities.
+* Version: 1.11.0
"""
diff --git a/lib/spack/external/_pytest/AUTHORS b/lib/spack/external/_pytest/AUTHORS
deleted file mode 100644
index 8c7cb19cee..0000000000
--- a/lib/spack/external/_pytest/AUTHORS
+++ /dev/null
@@ -1,141 +0,0 @@
-Holger Krekel, holger at merlinux eu
-merlinux GmbH, Germany, office at merlinux eu
-
-Contributors include::
-
-Abdeali JK
-Abhijeet Kasurde
-Ahn Ki-Wook
-Alexei Kozlenok
-Anatoly Bubenkoff
-Andreas Zeidler
-Andrzej Ostrowski
-Andy Freeland
-Anthon van der Neut
-Antony Lee
-Armin Rigo
-Aron Curzon
-Aviv Palivoda
-Ben Webb
-Benjamin Peterson
-Bernard Pratz
-Bob Ippolito
-Brian Dorsey
-Brian Okken
-Brianna Laugher
-Bruno Oliveira
-Cal Leeming
-Carl Friedrich Bolz
-Charles Cloud
-Charnjit SiNGH (CCSJ)
-Chris Lamb
-Christian Boelsen
-Christian Theunert
-Christian Tismer
-Christopher Gilling
-Daniel Grana
-Daniel Hahler
-Daniel Nuri
-Daniel Wandschneider
-Danielle Jenkins
-Dave Hunt
-David Díaz-Barquero
-David Mohr
-David Vierra
-Diego Russo
-Dmitry Dygalo
-Duncan Betts
-Edison Gustavo Muenz
-Edoardo Batini
-Eduardo Schettino
-Elizaveta Shashkova
-Endre Galaczi
-Eric Hunsberger
-Eric Siegerman
-Erik M. Bray
-Feng Ma
-Florian Bruhin
-Floris Bruynooghe
-Gabriel Reis
-Georgy Dyuldin
-Graham Horler
-Greg Price
-Grig Gheorghiu
-Grigorii Eremeev (budulianin)
-Guido Wesdorp
-Harald Armin Massa
-Ian Bicking
-Jaap Broekhuizen
-Jan Balster
-Janne Vanhala
-Jason R. Coombs
-Javier Domingo Cansino
-Javier Romero
-John Towler
-Jon Sonesen
-Jordan Guymon
-Joshua Bronson
-Jurko Gospodnetić
-Justyna Janczyszyn
-Kale Kundert
-Katarzyna Jachim
-Kevin Cox
-Lee Kamentsky
-Lev Maximov
-Lukas Bednar
-Luke Murphy
-Maciek Fijalkowski
-Maho
-Marc Schlaich
-Marcin Bachry
-Mark Abramowitz
-Markus Unterwaditzer
-Martijn Faassen
-Martin K. Scherer
-Martin Prusse
-Mathieu Clabaut
-Matt Bachmann
-Matt Williams
-Matthias Hafner
-mbyt
-Michael Aquilina
-Michael Birtwell
-Michael Droettboom
-Michael Seifert
-Mike Lundy
-Ned Batchelder
-Neven Mundar
-Nicolas Delaby
-Oleg Pidsadnyi
-Oliver Bestwalter
-Omar Kohl
-Pieter Mulder
-Piotr Banaszkiewicz
-Punyashloka Biswal
-Quentin Pradet
-Ralf Schmitt
-Raphael Pierzina
-Raquel Alegre
-Roberto Polli
-Romain Dorgueil
-Roman Bolshakov
-Ronny Pfannschmidt
-Ross Lawley
-Russel Winder
-Ryan Wooden
-Samuele Pedroni
-Simon Gomizelj
-Stefan Farmbauer
-Stefan Zimmermann
-Stefano Taschini
-Steffen Allner
-Stephan Obermann
-Tareq Alayan
-Ted Xiao
-Thomas Grainger
-Tom Viner
-Trevor Bekolay
-Tyler Goodlet
-Vasily Kuznetsov
-Wouter van Ackooy
-Xuecong Liao
diff --git a/lib/spack/external/_pytest/LICENSE b/lib/spack/external/_pytest/LICENSE
index 9e27bd7841..629df45ac4 100644
--- a/lib/spack/external/_pytest/LICENSE
+++ b/lib/spack/external/_pytest/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2004-2016 Holger Krekel and others
+Copyright (c) 2004-2017 Holger Krekel and others
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
diff --git a/lib/spack/external/_pytest/README.rst b/lib/spack/external/_pytest/README.rst
deleted file mode 100644
index d5650af655..0000000000
--- a/lib/spack/external/_pytest/README.rst
+++ /dev/null
@@ -1,102 +0,0 @@
-.. image:: http://docs.pytest.org/en/latest/_static/pytest1.png
- :target: http://docs.pytest.org
- :align: center
- :alt: pytest
-
-------
-
-.. image:: https://img.shields.io/pypi/v/pytest.svg
- :target: https://pypi.python.org/pypi/pytest
-.. image:: https://img.shields.io/pypi/pyversions/pytest.svg
- :target: https://pypi.python.org/pypi/pytest
-.. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg
- :target: https://coveralls.io/r/pytest-dev/pytest
-.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
- :target: https://travis-ci.org/pytest-dev/pytest
-.. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true
- :target: https://ci.appveyor.com/project/pytestbot/pytest
-
-The ``pytest`` framework makes it easy to write small tests, yet
-scales to support complex functional testing for applications and libraries.
-
-An example of a simple test:
-
-.. code-block:: python
-
- # content of test_sample.py
- def inc(x):
- return x + 1
-
- def test_answer():
- assert inc(3) == 5
-
-
-To execute it::
-
- $ pytest
- ============================= test session starts =============================
- collected 1 items
-
- test_sample.py F
-
- ================================== FAILURES ===================================
- _________________________________ test_answer _________________________________
-
- def test_answer():
- > assert inc(3) == 5
- E assert 4 == 5
- E + where 4 = inc(3)
-
- test_sample.py:5: AssertionError
- ========================== 1 failed in 0.04 seconds ===========================
-
-
-Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <http://docs.pytest.org/en/latest/getting-started.html#our-first-test-run>`_ for more examples.
-
-
-Features
---------
-
-- Detailed info on failing `assert statements <http://docs.pytest.org/en/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
-
-- `Auto-discovery
- <http://docs.pytest.org/en/latest/goodpractices.html#python-test-discovery>`_
- of test modules and functions;
-
-- `Modular fixtures <http://docs.pytest.org/en/latest/fixture.html>`_ for
- managing small or parametrized long-lived test resources;
-
-- Can run `unittest <http://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
- `nose <http://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
-
-- Python2.6+, Python3.3+, PyPy-2.3, Jython-2.5 (untested);
-
-- Rich plugin architecture, with over 150+ `external plugins <http://docs.pytest.org/en/latest/plugins.html#installing-external-plugins-searching>`_ and thriving community;
-
-
-Documentation
--------------
-
-For full documentation, including installation, tutorials and PDF documents, please see http://docs.pytest.org.
-
-
-Bugs/Requests
--------------
-
-Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issues>`_ to submit bugs or request features.
-
-
-Changelog
----------
-
-Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`__ page for fixes and enhancements of each version.
-
-
-License
--------
-
-Copyright Holger Krekel and others, 2004-2016.
-
-Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
-
-.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
diff --git a/lib/spack/external/_pytest/__init__.py b/lib/spack/external/_pytest/__init__.py
index be20d3d41c..6e41f0504e 100644
--- a/lib/spack/external/_pytest/__init__.py
+++ b/lib/spack/external/_pytest/__init__.py
@@ -1,2 +1,8 @@
-#
-__version__ = '3.0.5'
+__all__ = ['__version__']
+
+try:
+ from ._version import version as __version__
+except ImportError:
+ # broken installation, we don't even try
+ # unknown only works because we do poor mans version compare
+ __version__ = 'unknown'
diff --git a/lib/spack/external/_pytest/_argcomplete.py b/lib/spack/external/_pytest/_argcomplete.py
index 3ab679d8be..965ec79513 100644
--- a/lib/spack/external/_pytest/_argcomplete.py
+++ b/lib/spack/external/_pytest/_argcomplete.py
@@ -57,26 +57,29 @@ If things do not work right away:
which should throw a KeyError: 'COMPLINE' (which is properly set by the
global argcomplete script).
"""
-
+from __future__ import absolute_import, division, print_function
import sys
import os
from glob import glob
+
class FastFilesCompleter:
'Fast file completer class'
+
def __init__(self, directories=True):
self.directories = directories
def __call__(self, prefix, **kwargs):
"""only called on non option completions"""
- if os.path.sep in prefix[1:]: #
+ if os.path.sep in prefix[1:]:
prefix_dir = len(os.path.dirname(prefix) + os.path.sep)
else:
prefix_dir = 0
completion = []
globbed = []
if '*' not in prefix and '?' not in prefix:
- if prefix[-1] == os.path.sep: # we are on unix, otherwise no bash
+ # we are on unix, otherwise no bash
+ if not prefix or prefix[-1] == os.path.sep:
globbed.extend(glob(prefix + '.*'))
prefix += '*'
globbed.extend(glob(prefix))
@@ -96,7 +99,8 @@ if os.environ.get('_ARGCOMPLETE'):
filescompleter = FastFilesCompleter()
def try_argcomplete(parser):
- argcomplete.autocomplete(parser)
+ argcomplete.autocomplete(parser, always_complete_options=False)
else:
- def try_argcomplete(parser): pass
+ def try_argcomplete(parser):
+ pass
filescompleter = None
diff --git a/lib/spack/external/_pytest/_code/__init__.py b/lib/spack/external/_pytest/_code/__init__.py
index 3463c11eac..815c13b42c 100644
--- a/lib/spack/external/_pytest/_code/__init__.py
+++ b/lib/spack/external/_pytest/_code/__init__.py
@@ -1,4 +1,5 @@
""" python inspection/code generation API """
+from __future__ import absolute_import, division, print_function
from .code import Code # noqa
from .code import ExceptionInfo # noqa
from .code import Frame # noqa
diff --git a/lib/spack/external/_pytest/_code/_py2traceback.py b/lib/spack/external/_pytest/_code/_py2traceback.py
index a830d9899a..5aacf0a428 100644
--- a/lib/spack/external/_pytest/_code/_py2traceback.py
+++ b/lib/spack/external/_pytest/_code/_py2traceback.py
@@ -2,8 +2,10 @@
# CHANGES:
# - some_str is replaced, trying to create unicode strings
#
+from __future__ import absolute_import, division, print_function
import types
+
def format_exception_only(etype, value):
"""Format the exception part of a traceback.
@@ -29,7 +31,7 @@ def format_exception_only(etype, value):
# would throw another exception and mask the original problem.
if (isinstance(etype, BaseException) or
isinstance(etype, types.InstanceType) or
- etype is None or type(etype) is str):
+ etype is None or type(etype) is str):
return [_format_final_exc_line(etype, value)]
stype = etype.__name__
@@ -61,6 +63,7 @@ def format_exception_only(etype, value):
lines.append(_format_final_exc_line(stype, value))
return lines
+
def _format_final_exc_line(etype, value):
"""Return a list of a single line -- normal case for format_exception_only"""
valuestr = _some_str(value)
@@ -70,6 +73,7 @@ def _format_final_exc_line(etype, value):
line = "%s: %s\n" % (etype, valuestr)
return line
+
def _some_str(value):
try:
return unicode(value)
diff --git a/lib/spack/external/_pytest/_code/code.py b/lib/spack/external/_pytest/_code/code.py
index 616d5c4313..f3b7eedfce 100644
--- a/lib/spack/external/_pytest/_code/code.py
+++ b/lib/spack/external/_pytest/_code/code.py
@@ -1,14 +1,16 @@
+from __future__ import absolute_import, division, print_function
import sys
from inspect import CO_VARARGS, CO_VARKEYWORDS
import re
from weakref import ref
+from _pytest.compat import _PY2, _PY3, PY35, safe_str
import py
builtin_repr = repr
reprlib = py.builtin._tryimport('repr', 'reprlib')
-if sys.version_info[0] >= 3:
+if _PY3:
from traceback import format_exception_only
else:
from ._py2traceback import format_exception_only
@@ -16,6 +18,7 @@ else:
class Code(object):
""" wrapper around Python code objects """
+
def __init__(self, rawcode):
if not hasattr(rawcode, "co_filename"):
rawcode = getrawcode(rawcode)
@@ -24,7 +27,7 @@ class Code(object):
self.firstlineno = rawcode.co_firstlineno - 1
self.name = rawcode.co_name
except AttributeError:
- raise TypeError("not a code object: %r" %(rawcode,))
+ raise TypeError("not a code object: %r" % (rawcode,))
self.raw = rawcode
def __eq__(self, other):
@@ -80,6 +83,7 @@ class Code(object):
argcount += raw.co_flags & CO_VARKEYWORDS
return raw.co_varnames[:argcount]
+
class Frame(object):
"""Wrapper around a Python frame holding f_locals and f_globals
in which expressions can be evaluated."""
@@ -117,7 +121,7 @@ class Frame(object):
"""
f_locals = self.f_locals.copy()
f_locals.update(vars)
- py.builtin.exec_(code, self.f_globals, f_locals )
+ py.builtin.exec_(code, self.f_globals, f_locals)
def repr(self, object):
""" return a 'safe' (non-recursive, one-line) string repr for 'object'
@@ -141,6 +145,7 @@ class Frame(object):
pass # this can occur when using Psyco
return retval
+
class TracebackEntry(object):
""" a single entry in a traceback """
@@ -166,7 +171,7 @@ class TracebackEntry(object):
return self.lineno - self.frame.code.firstlineno
def __repr__(self):
- return "<TracebackEntry %s:%d>" %(self.frame.code.path, self.lineno+1)
+ return "<TracebackEntry %s:%d>" % (self.frame.code.path, self.lineno + 1)
@property
def statement(self):
@@ -245,19 +250,21 @@ class TracebackEntry(object):
line = str(self.statement).lstrip()
except KeyboardInterrupt:
raise
- except:
+ except: # noqa
line = "???"
- return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line)
+ return " File %r:%d in %s\n %s\n" % (fn, self.lineno + 1, name, line)
def name(self):
return self.frame.code.raw.co_name
name = property(name, None, None, "co_name of underlaying code")
+
class Traceback(list):
""" Traceback objects encapsulate and offer higher level
access to Traceback entries.
"""
Entry = TracebackEntry
+
def __init__(self, tb, excinfo=None):
""" initialize from given python traceback object and ExceptionInfo """
self._excinfo = excinfo
@@ -287,7 +294,7 @@ class Traceback(list):
(excludepath is None or not hasattr(codepath, 'relto') or
not codepath.relto(excludepath)) and
(lineno is None or x.lineno == lineno) and
- (firstlineno is None or x.frame.code.firstlineno == firstlineno)):
+ (firstlineno is None or x.frame.code.firstlineno == firstlineno)):
return Traceback(x._rawentry, self._excinfo)
return self
@@ -313,7 +320,7 @@ class Traceback(list):
""" return last non-hidden traceback entry that lead
to the exception of a traceback.
"""
- for i in range(-1, -len(self)-1, -1):
+ for i in range(-1, -len(self) - 1, -1):
entry = self[i]
if not entry.ishidden():
return entry
@@ -328,30 +335,33 @@ class Traceback(list):
# id for the code.raw is needed to work around
# the strange metaprogramming in the decorator lib from pypi
# which generates code objects that have hash/value equality
- #XXX needs a test
+ # XXX needs a test
key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
- #print "checking for recursion at", key
- l = cache.setdefault(key, [])
- if l:
+ # print "checking for recursion at", key
+ values = cache.setdefault(key, [])
+ if values:
f = entry.frame
loc = f.f_locals
- for otherloc in l:
+ for otherloc in values:
if f.is_true(f.eval(co_equal,
- __recursioncache_locals_1=loc,
- __recursioncache_locals_2=otherloc)):
+ __recursioncache_locals_1=loc,
+ __recursioncache_locals_2=otherloc)):
return i
- l.append(entry.frame.f_locals)
+ values.append(entry.frame.f_locals)
return None
co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2',
'?', 'eval')
+
class ExceptionInfo(object):
""" wraps sys.exc_info() objects and offers
help for navigating the traceback.
"""
_striptext = ''
+ _assert_start_repr = "AssertionError(u\'assert " if _PY2 else "AssertionError(\'assert "
+
def __init__(self, tup=None, exprinfo=None):
import _pytest._code
if tup is None:
@@ -359,8 +369,8 @@ class ExceptionInfo(object):
if exprinfo is None and isinstance(tup[1], AssertionError):
exprinfo = getattr(tup[1], 'msg', None)
if exprinfo is None:
- exprinfo = py._builtin._totext(tup[1])
- if exprinfo and exprinfo.startswith('assert '):
+ exprinfo = py.io.saferepr(tup[1])
+ if exprinfo and exprinfo.startswith(self._assert_start_repr):
self._striptext = 'AssertionError: '
self._excinfo = tup
#: the exception class
@@ -401,10 +411,10 @@ class ExceptionInfo(object):
exconly = self.exconly(tryshort=True)
entry = self.traceback.getcrashentry()
path, lineno = entry.frame.code.raw.co_filename, entry.lineno
- return ReprFileLocation(path, lineno+1, exconly)
+ return ReprFileLocation(path, lineno + 1, exconly)
def getrepr(self, showlocals=False, style="long",
- abspath=False, tbfilter=True, funcargs=False):
+ abspath=False, tbfilter=True, funcargs=False):
""" return str()able representation of this exception info.
showlocals: show locals per traceback entry
style: long|short|no|native traceback style
@@ -421,7 +431,7 @@ class ExceptionInfo(object):
)), self._getreprcrash())
fmt = FormattedExcinfo(showlocals=showlocals, style=style,
- abspath=abspath, tbfilter=tbfilter, funcargs=funcargs)
+ abspath=abspath, tbfilter=tbfilter, funcargs=funcargs)
return fmt.repr_excinfo(self)
def __str__(self):
@@ -465,15 +475,15 @@ class FormattedExcinfo(object):
def _getindent(self, source):
# figure out indent for given source
try:
- s = str(source.getstatement(len(source)-1))
+ s = str(source.getstatement(len(source) - 1))
except KeyboardInterrupt:
raise
- except:
+ except: # noqa
try:
s = str(source[-1])
except KeyboardInterrupt:
raise
- except:
+ except: # noqa
return 0
return 4 + (len(s) - len(s.lstrip()))
@@ -509,7 +519,7 @@ class FormattedExcinfo(object):
for line in source.lines[:line_index]:
lines.append(space_prefix + line)
lines.append(self.flow_marker + " " + source.lines[line_index])
- for line in source.lines[line_index+1:]:
+ for line in source.lines[line_index + 1:]:
lines.append(space_prefix + line)
if excinfo is not None:
indent = 4 if short else self._getindent(source)
@@ -542,10 +552,10 @@ class FormattedExcinfo(object):
# _repr() function, which is only reprlib.Repr in
# disguise, so is very configurable.
str_repr = self._saferepr(value)
- #if len(str_repr) < 70 or not isinstance(value,
+ # if len(str_repr) < 70 or not isinstance(value,
# (list, tuple, dict)):
- lines.append("%-10s = %s" %(name, str_repr))
- #else:
+ lines.append("%-10s = %s" % (name, str_repr))
+ # else:
# self._line("%-10s =\\" % (name,))
# # XXX
# py.std.pprint.pprint(value, stream=self.excinfowriter)
@@ -571,14 +581,14 @@ class FormattedExcinfo(object):
s = self.get_source(source, line_index, excinfo, short=short)
lines.extend(s)
if short:
- message = "in %s" %(entry.name)
+ message = "in %s" % (entry.name)
else:
message = excinfo and excinfo.typename or ""
path = self._makepath(entry.path)
- filelocrepr = ReprFileLocation(path, entry.lineno+1, message)
+ filelocrepr = ReprFileLocation(path, entry.lineno + 1, message)
localsrepr = None
if not short:
- localsrepr = self.repr_locals(entry.locals)
+ localsrepr = self.repr_locals(entry.locals)
return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style)
if excinfo:
lines.extend(self.get_exconly(excinfo, indent=4))
@@ -598,24 +608,54 @@ class FormattedExcinfo(object):
traceback = excinfo.traceback
if self.tbfilter:
traceback = traceback.filter()
- recursionindex = None
+
if is_recursion_error(excinfo):
- recursionindex = traceback.recursionindex()
+ traceback, extraline = self._truncate_recursive_traceback(traceback)
+ else:
+ extraline = None
+
last = traceback[-1]
entries = []
- extraline = None
for index, entry in enumerate(traceback):
einfo = (last == entry) and excinfo or None
reprentry = self.repr_traceback_entry(entry, einfo)
entries.append(reprentry)
- if index == recursionindex:
- extraline = "!!! Recursion detected (same locals & position)"
- break
return ReprTraceback(entries, extraline, style=self.style)
+ def _truncate_recursive_traceback(self, traceback):
+ """
+ Truncate the given recursive traceback trying to find the starting point
+ of the recursion.
+
+ The detection is done by going through each traceback entry and finding the
+ point in which the locals of the frame are equal to the locals of a previous frame (see ``recursionindex()``.
+
+ Handle the situation where the recursion process might raise an exception (for example
+ comparing numpy arrays using equality raises a TypeError), in which case we do our best to
+ warn the user of the error and show a limited traceback.
+ """
+ try:
+ recursionindex = traceback.recursionindex()
+ except Exception as e:
+ max_frames = 10
+ extraline = (
+ '!!! Recursion error detected, but an error occurred locating the origin of recursion.\n'
+ ' The following exception happened when comparing locals in the stack frame:\n'
+ ' {exc_type}: {exc_msg}\n'
+ ' Displaying first and last {max_frames} stack frames out of {total}.'
+ ).format(exc_type=type(e).__name__, exc_msg=safe_str(e), max_frames=max_frames, total=len(traceback))
+ traceback = traceback[:max_frames] + traceback[-max_frames:]
+ else:
+ if recursionindex is not None:
+ extraline = "!!! Recursion detected (same locals & position)"
+ traceback = traceback[:recursionindex + 1]
+ else:
+ extraline = None
+
+ return traceback, extraline
def repr_excinfo(self, excinfo):
- if sys.version_info[0] < 3:
+ if _PY2:
reprtraceback = self.repr_traceback(excinfo)
reprcrash = excinfo._getreprcrash()
@@ -639,7 +679,7 @@ class FormattedExcinfo(object):
e = e.__cause__
excinfo = ExceptionInfo((type(e), e, e.__traceback__)) if e.__traceback__ else None
descr = 'The above exception was the direct cause of the following exception:'
- elif e.__context__ is not None:
+ elif (e.__context__ is not None and not e.__suppress_context__):
e = e.__context__
excinfo = ExceptionInfo((type(e), e, e.__traceback__)) if e.__traceback__ else None
descr = 'During handling of the above exception, another exception occurred:'
@@ -652,7 +692,7 @@ class FormattedExcinfo(object):
class TerminalRepr(object):
def __str__(self):
s = self.__unicode__()
- if sys.version_info[0] < 3:
+ if _PY2:
s = s.encode('utf-8')
return s
@@ -665,7 +705,7 @@ class TerminalRepr(object):
return io.getvalue().strip()
def __repr__(self):
- return "<%s instance at %0x>" %(self.__class__, id(self))
+ return "<%s instance at %0x>" % (self.__class__, id(self))
class ExceptionRepr(TerminalRepr):
@@ -709,6 +749,7 @@ class ReprExceptionInfo(ExceptionRepr):
self.reprtraceback.toterminal(tw)
super(ReprExceptionInfo, self).toterminal(tw)
+
class ReprTraceback(TerminalRepr):
entrysep = "_ "
@@ -724,7 +765,7 @@ class ReprTraceback(TerminalRepr):
tw.line("")
entry.toterminal(tw)
if i < len(self.reprentries) - 1:
- next_entry = self.reprentries[i+1]
+ next_entry = self.reprentries[i + 1]
if entry.style == "long" or \
entry.style == "short" and next_entry.style == "long":
tw.sep(self.entrysep)
@@ -732,12 +773,14 @@ class ReprTraceback(TerminalRepr):
if self.extraline:
tw.line(self.extraline)
+
class ReprTracebackNative(ReprTraceback):
def __init__(self, tblines):
self.style = "native"
self.reprentries = [ReprEntryNative(tblines)]
self.extraline = None
+
class ReprEntryNative(TerminalRepr):
style = "native"
@@ -747,6 +790,7 @@ class ReprEntryNative(TerminalRepr):
def toterminal(self, tw):
tw.write("".join(self.lines))
+
class ReprEntry(TerminalRepr):
localssep = "_ "
@@ -763,7 +807,7 @@ class ReprEntry(TerminalRepr):
for line in self.lines:
red = line.startswith("E ")
tw.line(line, bold=True, red=red)
- #tw.line("")
+ # tw.line("")
return
if self.reprfuncargs:
self.reprfuncargs.toterminal(tw)
@@ -771,7 +815,7 @@ class ReprEntry(TerminalRepr):
red = line.startswith("E ")
tw.line(line, bold=True, red=red)
if self.reprlocals:
- #tw.sep(self.localssep, "Locals")
+ # tw.sep(self.localssep, "Locals")
tw.line("")
self.reprlocals.toterminal(tw)
if self.reprfileloc:
@@ -784,6 +828,7 @@ class ReprEntry(TerminalRepr):
self.reprlocals,
self.reprfileloc)
+
class ReprFileLocation(TerminalRepr):
def __init__(self, path, lineno, message):
self.path = str(path)
@@ -800,6 +845,7 @@ class ReprFileLocation(TerminalRepr):
tw.write(self.path, bold=True, red=True)
tw.line(":%s: %s" % (self.lineno, msg))
+
class ReprLocals(TerminalRepr):
def __init__(self, lines):
self.lines = lines
@@ -808,6 +854,7 @@ class ReprLocals(TerminalRepr):
for line in self.lines:
tw.line(line)
+
class ReprFuncArgs(TerminalRepr):
def __init__(self, args):
self.args = args
@@ -816,11 +863,11 @@ class ReprFuncArgs(TerminalRepr):
if self.args:
linesofar = ""
for name, value in self.args:
- ns = "%s = %s" %(name, value)
+ ns = "%s = %s" % (safe_str(name), safe_str(value))
if len(ns) + len(linesofar) + 2 > tw.fullwidth:
if linesofar:
tw.line(linesofar)
- linesofar = ns
+ linesofar = ns
else:
if linesofar:
linesofar += ", " + ns
@@ -848,7 +895,7 @@ def getrawcode(obj, trycall=True):
return obj
-if sys.version_info[:2] >= (3, 5): # RecursionError introduced in 3.5
+if PY35: # RecursionError introduced in 3.5
def is_recursion_error(excinfo):
return excinfo.errisinstance(RecursionError) # noqa
else:
diff --git a/lib/spack/external/_pytest/_code/source.py b/lib/spack/external/_pytest/_code/source.py
index fcec0f5ca7..fc41712649 100644
--- a/lib/spack/external/_pytest/_code/source.py
+++ b/lib/spack/external/_pytest/_code/source.py
@@ -1,8 +1,9 @@
-from __future__ import generators
+from __future__ import absolute_import, division, generators, print_function
from bisect import bisect_right
import sys
-import inspect, tokenize
+import inspect
+import tokenize
import py
cpy_compile = compile
@@ -19,6 +20,7 @@ class Source(object):
possibly deindenting it.
"""
_compilecounter = 0
+
def __init__(self, *parts, **kwargs):
self.lines = lines = []
de = kwargs.get('deindent', True)
@@ -73,7 +75,7 @@ class Source(object):
start, end = 0, len(self)
while start < end and not self.lines[start].strip():
start += 1
- while end > start and not self.lines[end-1].strip():
+ while end > start and not self.lines[end - 1].strip():
end -= 1
source = Source()
source.lines[:] = self.lines[start:end]
@@ -86,8 +88,8 @@ class Source(object):
before = Source(before)
after = Source(after)
newsource = Source()
- lines = [ (indent + line) for line in self.lines]
- newsource.lines = before.lines + lines + after.lines
+ lines = [(indent + line) for line in self.lines]
+ newsource.lines = before.lines + lines + after.lines
return newsource
def indent(self, indent=' ' * 4):
@@ -95,7 +97,7 @@ class Source(object):
all lines indented by the given indent-string.
"""
newsource = Source()
- newsource.lines = [(indent+line) for line in self.lines]
+ newsource.lines = [(indent + line) for line in self.lines]
return newsource
def getstatement(self, lineno, assertion=False):
@@ -134,7 +136,8 @@ class Source(object):
try:
import parser
except ImportError:
- syntax_checker = lambda x: compile(x, 'asd', 'exec')
+ def syntax_checker(x):
+ return compile(x, 'asd', 'exec')
else:
syntax_checker = parser.suite
@@ -143,8 +146,8 @@ class Source(object):
else:
source = str(self)
try:
- #compile(source+'\n', "x", "exec")
- syntax_checker(source+'\n')
+ # compile(source+'\n', "x", "exec")
+ syntax_checker(source + '\n')
except KeyboardInterrupt:
raise
except Exception:
@@ -164,8 +167,8 @@ class Source(object):
"""
if not filename or py.path.local(filename).check(file=0):
if _genframe is None:
- _genframe = sys._getframe(1) # the caller
- fn,lineno = _genframe.f_code.co_filename, _genframe.f_lineno
+ _genframe = sys._getframe(1) # the caller
+ fn, lineno = _genframe.f_code.co_filename, _genframe.f_lineno
base = "<%d-codegen " % self._compilecounter
self.__class__._compilecounter += 1
if not filename:
@@ -180,7 +183,7 @@ class Source(object):
# re-represent syntax errors from parsing python strings
msglines = self.lines[:ex.lineno]
if ex.offset:
- msglines.append(" "*ex.offset + '^')
+ msglines.append(" " * ex.offset + '^')
msglines.append("(code was compiled probably from here: %s)" % filename)
newex = SyntaxError('\n'.join(msglines))
newex.offset = ex.offset
@@ -198,8 +201,8 @@ class Source(object):
# public API shortcut functions
#
-def compile_(source, filename=None, mode='exec', flags=
- generators.compiler_flag, dont_inherit=0):
+
+def compile_(source, filename=None, mode='exec', flags=generators.compiler_flag, dont_inherit=0):
""" compile the given source to a raw code object,
and maintain an internal cache which allows later
retrieval of the source code for the code object
@@ -208,7 +211,7 @@ def compile_(source, filename=None, mode='exec', flags=
if _ast is not None and isinstance(source, _ast.AST):
# XXX should Source support having AST?
return cpy_compile(source, filename, mode, flags, dont_inherit)
- _genframe = sys._getframe(1) # the caller
+ _genframe = sys._getframe(1) # the caller
s = Source(source)
co = s.compile(filename, mode, flags, _genframe=_genframe)
return co
@@ -245,12 +248,13 @@ def getfslineno(obj):
# helper functions
#
+
def findsource(obj):
try:
sourcelines, lineno = py.std.inspect.findsource(obj)
except py.builtin._sysex:
raise
- except:
+ except: # noqa
return None, -1
source = Source()
source.lines = [line.rstrip() for line in sourcelines]
@@ -274,7 +278,7 @@ def deindent(lines, offset=None):
line = line.expandtabs()
s = line.lstrip()
if s:
- offset = len(line)-len(s)
+ offset = len(line) - len(s)
break
else:
offset = 0
@@ -293,11 +297,11 @@ def deindent(lines, offset=None):
try:
for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(lambda: next(it)):
if sline > len(lines):
- break # End of input reached
+ break # End of input reached
if sline > len(newlines):
line = lines[sline - 1].expandtabs()
if line.lstrip() and line[:offset].isspace():
- line = line[offset:] # Deindent
+ line = line[offset:] # Deindent
newlines.append(line)
for i in range(sline, eline):
@@ -315,29 +319,29 @@ def get_statement_startend2(lineno, node):
import ast
# flatten all statements and except handlers into one lineno-list
# AST's line numbers start indexing at 1
- l = []
+ values = []
for x in ast.walk(node):
if isinstance(x, _ast.stmt) or isinstance(x, _ast.ExceptHandler):
- l.append(x.lineno - 1)
+ values.append(x.lineno - 1)
for name in "finalbody", "orelse":
val = getattr(x, name, None)
if val:
# treat the finally/orelse part as its own statement
- l.append(val[0].lineno - 1 - 1)
- l.sort()
- insert_index = bisect_right(l, lineno)
- start = l[insert_index - 1]
- if insert_index >= len(l):
+ values.append(val[0].lineno - 1 - 1)
+ values.sort()
+ insert_index = bisect_right(values, lineno)
+ start = values[insert_index - 1]
+ if insert_index >= len(values):
end = None
else:
- end = l[insert_index]
+ end = values[insert_index]
return start, end
def getstatementrange_ast(lineno, source, assertion=False, astnode=None):
if astnode is None:
content = str(source)
- if sys.version_info < (2,7):
+ if sys.version_info < (2, 7):
content += "\n"
try:
astnode = compile(content, "source", "exec", 1024) # 1024 for AST
@@ -393,7 +397,7 @@ def getstatementrange_old(lineno, source, assertion=False):
raise IndexError("likely a subclass")
if "assert" not in line and "raise" not in line:
continue
- trylines = source.lines[start:lineno+1]
+ trylines = source.lines[start:lineno + 1]
# quick hack to prepare parsing an indented line with
# compile_command() (which errors on "return" outside defs)
trylines.insert(0, 'def xxx():')
@@ -405,10 +409,8 @@ def getstatementrange_old(lineno, source, assertion=False):
continue
# 2. find the end of the statement
- for end in range(lineno+1, len(source)+1):
+ for end in range(lineno + 1, len(source) + 1):
trysource = source[start:end]
if trysource.isparseable():
return start, end
raise SyntaxError("no valid source range around line %d " % (lineno,))
-
-
diff --git a/lib/spack/external/_pytest/_pluggy.py b/lib/spack/external/_pytest/_pluggy.py
index 87d32cf8dd..6cc1d3d54a 100644
--- a/lib/spack/external/_pytest/_pluggy.py
+++ b/lib/spack/external/_pytest/_pluggy.py
@@ -2,7 +2,7 @@
imports symbols from vendored "pluggy" if available, otherwise
falls back to importing "pluggy" from the default namespace.
"""
-
+from __future__ import absolute_import, division, print_function
try:
from _pytest.vendored_packages.pluggy import * # noqa
from _pytest.vendored_packages.pluggy import __version__ # noqa
diff --git a/lib/spack/external/_pytest/_version.py b/lib/spack/external/_pytest/_version.py
new file mode 100644
index 0000000000..3edb7da9ad
--- /dev/null
+++ b/lib/spack/external/_pytest/_version.py
@@ -0,0 +1,4 @@
+# coding: utf-8
+# file generated by setuptools_scm
+# don't change, don't track in version control
+version = '3.2.5'
diff --git a/lib/spack/external/_pytest/assertion/__init__.py b/lib/spack/external/_pytest/assertion/__init__.py
index 3f14a7ae76..b0ef667d56 100644
--- a/lib/spack/external/_pytest/assertion/__init__.py
+++ b/lib/spack/external/_pytest/assertion/__init__.py
@@ -1,12 +1,13 @@
"""
support for presenting detailed information in failing assertions.
"""
+from __future__ import absolute_import, division, print_function
import py
-import os
import sys
from _pytest.assertion import util
from _pytest.assertion import rewrite
+from _pytest.assertion import truncate
def pytest_addoption(parser):
@@ -24,10 +25,6 @@ def pytest_addoption(parser):
expression information.""")
-def pytest_namespace():
- return {'register_assert_rewrite': register_assert_rewrite}
-
-
def register_assert_rewrite(*names):
"""Register one or more module names to be rewritten on import.
@@ -100,12 +97,6 @@ def pytest_collection(session):
assertstate.hook.set_session(session)
-def _running_on_ci():
- """Check if we're currently running on a CI system."""
- env_vars = ['CI', 'BUILD_NUMBER']
- return any(var in os.environ for var in env_vars)
-
-
def pytest_runtest_setup(item):
"""Setup the pytest_assertrepr_compare hook
@@ -119,8 +110,8 @@ def pytest_runtest_setup(item):
This uses the first result from the hook and then ensures the
following:
- * Overly verbose explanations are dropped unless -vv was used or
- running on a CI.
+ * Overly verbose explanations are truncated unless configured otherwise
+ (eg. if running in verbose mode).
* Embedded newlines are escaped to help util.format_explanation()
later.
* If the rewrite mode is used embedded %-characters are replaced
@@ -133,14 +124,7 @@ def pytest_runtest_setup(item):
config=item.config, op=op, left=left, right=right)
for new_expl in hook_result:
if new_expl:
- if (sum(len(p) for p in new_expl[1:]) > 80*8 and
- item.config.option.verbose < 2 and
- not _running_on_ci()):
- show_max = 10
- truncated_lines = len(new_expl) - show_max
- new_expl[show_max:] = [py.builtin._totext(
- 'Detailed information truncated (%d more lines)'
- ', use "-vv" to show' % truncated_lines)]
+ new_expl = truncate.truncate_if_required(new_expl, item)
new_expl = [line.replace("\n", "\\n") for line in new_expl]
res = py.builtin._totext("\n~").join(new_expl)
if item.config.getvalue("assertmode") == "rewrite":
diff --git a/lib/spack/external/_pytest/assertion/rewrite.py b/lib/spack/external/_pytest/assertion/rewrite.py
index abf5b491fe..d48b6648fb 100644
--- a/lib/spack/external/_pytest/assertion/rewrite.py
+++ b/lib/spack/external/_pytest/assertion/rewrite.py
@@ -1,5 +1,5 @@
"""Rewrite assertion AST to produce nice error messages"""
-
+from __future__ import absolute_import, division, print_function
import ast
import _ast
import errno
@@ -11,7 +11,6 @@ import re
import struct
import sys
import types
-from fnmatch import fnmatch
import py
from _pytest.assertion import util
@@ -37,10 +36,11 @@ PYC_TAIL = "." + PYTEST_TAG + PYC_EXT
REWRITE_NEWLINES = sys.version_info[:2] != (2, 7) and sys.version_info < (3, 2)
ASCII_IS_DEFAULT_ENCODING = sys.version_info[0] < 3
-if sys.version_info >= (3,5):
+if sys.version_info >= (3, 5):
ast_Call = ast.Call
else:
- ast_Call = lambda a,b,c: ast.Call(a, b, c, None, None)
+ def ast_Call(a, b, c):
+ return ast.Call(a, b, c, None, None)
class AssertionRewritingHook(object):
@@ -163,11 +163,7 @@ class AssertionRewritingHook(object):
# modules not passed explicitly on the command line are only
# rewritten if they match the naming convention for test files
for pat in self.fnpats:
- # use fnmatch instead of fn_pypath.fnmatch because the
- # latter might trigger an import to fnmatch.fnmatch
- # internally, which would cause this method to be
- # called recursively
- if fnmatch(fn_pypath.basename, pat):
+ if fn_pypath.fnmatch(pat):
state.trace("matched test file %r" % (fn,))
return True
@@ -214,13 +210,12 @@ class AssertionRewritingHook(object):
mod.__cached__ = pyc
mod.__loader__ = self
py.builtin.exec_(co, mod.__dict__)
- except:
- del sys.modules[name]
+ except: # noqa
+ if name in sys.modules:
+ del sys.modules[name]
raise
return sys.modules[name]
-
-
def is_package(self, name):
try:
fd, fn, desc = imp.find_module(name)
@@ -265,7 +260,7 @@ def _write_pyc(state, co, source_stat, pyc):
fp = open(pyc, "wb")
except IOError:
err = sys.exc_info()[1].errno
- state.trace("error writing pyc file at %s: errno=%s" %(pyc, err))
+ state.trace("error writing pyc file at %s: errno=%s" % (pyc, err))
# we ignore any failure to write the cache file
# there are many reasons, permission-denied, __pycache__ being a
# file etc.
@@ -287,6 +282,7 @@ N = "\n".encode("utf-8")
cookie_re = re.compile(r"^[ \t\f]*#.*coding[:=][ \t]*[-\w.]+")
BOM_UTF8 = '\xef\xbb\xbf'
+
def _rewrite_test(config, fn):
"""Try to read and rewrite *fn* and return the code object."""
state = config._assertstate
@@ -311,7 +307,7 @@ def _rewrite_test(config, fn):
end2 = source.find("\n", end1 + 1)
if (not source.startswith(BOM_UTF8) and
cookie_re.match(source[0:end1]) is None and
- cookie_re.match(source[end1 + 1:end2]) is None):
+ cookie_re.match(source[end1 + 1:end2]) is None):
if hasattr(state, "_indecode"):
# encodings imported us again, so don't rewrite.
return None, None
@@ -336,7 +332,7 @@ def _rewrite_test(config, fn):
return None, None
rewrite_asserts(tree, fn, config)
try:
- co = compile(tree, fn.strpath, "exec")
+ co = compile(tree, fn.strpath, "exec", dont_inherit=True)
except SyntaxError:
# It's possible that this error is from some bug in the
# assertion rewriting, but I don't know of a fast way to tell.
@@ -344,6 +340,7 @@ def _rewrite_test(config, fn):
return None, None
return stat, co
+
def _make_rewritten_pyc(state, source_stat, pyc, co):
"""Try to dump rewritten code to *pyc*."""
if sys.platform.startswith("win"):
@@ -357,6 +354,7 @@ def _make_rewritten_pyc(state, source_stat, pyc, co):
if _write_pyc(state, co, source_stat, proc_pyc):
os.rename(proc_pyc, pyc)
+
def _read_pyc(source, pyc, trace=lambda x: None):
"""Possibly read a pytest pyc containing rewritten code.
@@ -414,7 +412,8 @@ def _saferepr(obj):
return repr.replace(t("\n"), t("\\n"))
-from _pytest.assertion.util import format_explanation as _format_explanation # noqa
+from _pytest.assertion.util import format_explanation as _format_explanation # noqa
+
def _format_assertmsg(obj):
"""Format the custom assertion message given.
@@ -443,9 +442,11 @@ def _format_assertmsg(obj):
s = s.replace(t("\\n"), t("\n~"))
return s
+
def _should_repr_global_name(obj):
return not hasattr(obj, "__name__") and not py.builtin.callable(obj)
+
def _format_boolop(explanations, is_or):
explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")"
if py.builtin._istext(explanation):
@@ -454,6 +455,7 @@ def _format_boolop(explanations, is_or):
t = py.builtin.bytes
return explanation.replace(t('%'), t('%%'))
+
def _call_reprcompare(ops, results, expls, each_obj):
for i, res, expl in zip(range(len(ops)), results, expls):
try:
@@ -487,7 +489,7 @@ binop_map = {
ast.Mult: "*",
ast.Div: "/",
ast.FloorDiv: "//",
- ast.Mod: "%%", # escaped for string formatting
+ ast.Mod: "%%", # escaped for string formatting
ast.Eq: "==",
ast.NotEq: "!=",
ast.Lt: "<",
@@ -593,23 +595,26 @@ class AssertionRewriter(ast.NodeVisitor):
# docstrings and __future__ imports.
aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"),
ast.alias("_pytest.assertion.rewrite", "@pytest_ar")]
- expect_docstring = True
+ doc = getattr(mod, "docstring", None)
+ expect_docstring = doc is None
+ if doc is not None and self.is_rewrite_disabled(doc):
+ return
pos = 0
- lineno = 0
+ lineno = 1
for item in mod.body:
if (expect_docstring and isinstance(item, ast.Expr) and
isinstance(item.value, ast.Str)):
doc = item.value.s
- if "PYTEST_DONT_REWRITE" in doc:
- # The module has disabled assertion rewriting.
+ if self.is_rewrite_disabled(doc):
return
- lineno += len(doc) - 1
expect_docstring = False
elif (not isinstance(item, ast.ImportFrom) or item.level > 0 or
item.module != "__future__"):
lineno = item.lineno
break
pos += 1
+ else:
+ lineno = item.lineno
imports = [ast.Import([alias], lineno=lineno, col_offset=0)
for alias in aliases]
mod.body[pos:pos] = imports
@@ -635,6 +640,9 @@ class AssertionRewriter(ast.NodeVisitor):
not isinstance(field, ast.expr)):
nodes.append(field)
+ def is_rewrite_disabled(self, docstring):
+ return "PYTEST_DONT_REWRITE" in docstring
+
def variable(self):
"""Get a new variable."""
# Use a character invalid in python identifiers to avoid clashing.
@@ -727,7 +735,7 @@ class AssertionRewriter(ast.NodeVisitor):
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn('R1', 'assertion is always true, perhaps '
- 'remove parentheses?', fslocation=fslocation)
+ 'remove parentheses?', fslocation=fslocation)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
@@ -791,7 +799,7 @@ class AssertionRewriter(ast.NodeVisitor):
if i:
fail_inner = []
# cond is set in a prior loop iteration below
- self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa
+ self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa
self.on_failure = fail_inner
self.push_format_context()
res, expl = self.visit(v)
@@ -843,7 +851,7 @@ class AssertionRewriter(ast.NodeVisitor):
new_kwargs.append(ast.keyword(keyword.arg, res))
if keyword.arg:
arg_expls.append(keyword.arg + "=" + expl)
- else: ## **args have `arg` keywords with an .arg of None
+ else: # **args have `arg` keywords with an .arg of None
arg_expls.append("**" + expl)
expl = "%s(%s)" % (func_expl, ', '.join(arg_expls))
@@ -897,7 +905,6 @@ class AssertionRewriter(ast.NodeVisitor):
else:
visit_Call = visit_Call_legacy
-
def visit_Attribute(self, attr):
if not isinstance(attr.ctx, ast.Load):
return self.generic_visit(attr)
diff --git a/lib/spack/external/_pytest/assertion/truncate.py b/lib/spack/external/_pytest/assertion/truncate.py
new file mode 100644
index 0000000000..1e13063569
--- /dev/null
+++ b/lib/spack/external/_pytest/assertion/truncate.py
@@ -0,0 +1,102 @@
+"""
+Utilities for truncating assertion output.
+
+Current default behaviour is to truncate assertion explanations at
+~8 terminal lines, unless running in "-vv" mode or running on CI.
+"""
+from __future__ import absolute_import, division, print_function
+import os
+
+import py
+
+
+DEFAULT_MAX_LINES = 8
+DEFAULT_MAX_CHARS = 8 * 80
+USAGE_MSG = "use '-vv' to show"
+
+
+def truncate_if_required(explanation, item, max_length=None):
+ """
+ Truncate this assertion explanation if the given test item is eligible.
+ """
+ if _should_truncate_item(item):
+ return _truncate_explanation(explanation)
+ return explanation
+
+
+def _should_truncate_item(item):
+ """
+ Whether or not this test item is eligible for truncation.
+ """
+ verbose = item.config.option.verbose
+ return verbose < 2 and not _running_on_ci()
+
+
+def _running_on_ci():
+ """Check if we're currently running on a CI system."""
+ env_vars = ['CI', 'BUILD_NUMBER']
+ return any(var in os.environ for var in env_vars)
+
+
+def _truncate_explanation(input_lines, max_lines=None, max_chars=None):
+ """
+ Truncate given list of strings that makes up the assertion explanation.
+
+ Truncates to either 8 lines, or 640 characters - whichever the input reaches
+ first. The remaining lines will be replaced by a usage message.
+ """
+
+ if max_lines is None:
+ max_lines = DEFAULT_MAX_LINES
+ if max_chars is None:
+ max_chars = DEFAULT_MAX_CHARS
+
+ # Check if truncation required
+ input_char_count = len("".join(input_lines))
+ if len(input_lines) <= max_lines and input_char_count <= max_chars:
+ return input_lines
+
+ # Truncate first to max_lines, and then truncate to max_chars if max_chars
+ # is exceeded.
+ truncated_explanation = input_lines[:max_lines]
+ truncated_explanation = _truncate_by_char_count(truncated_explanation, max_chars)
+
+ # Add ellipsis to final line
+ truncated_explanation[-1] = truncated_explanation[-1] + "..."
+
+ # Append useful message to explanation
+ truncated_line_count = len(input_lines) - len(truncated_explanation)
+ truncated_line_count += 1 # Account for the part-truncated final line
+ msg = '...Full output truncated'
+ if truncated_line_count == 1:
+ msg += ' ({0} line hidden)'.format(truncated_line_count)
+ else:
+ msg += ' ({0} lines hidden)'.format(truncated_line_count)
+ msg += ", {0}" .format(USAGE_MSG)
+ truncated_explanation.extend([
+ py.builtin._totext(""),
+ py.builtin._totext(msg),
+ ])
+ return truncated_explanation
+
+
+def _truncate_by_char_count(input_lines, max_chars):
+ # Check if truncation required
+ if len("".join(input_lines)) <= max_chars:
+ return input_lines
+
+ # Find point at which input length exceeds total allowed length
+ iterated_char_count = 0
+ for iterated_index, input_line in enumerate(input_lines):
+ if iterated_char_count + len(input_line) > max_chars:
+ break
+ iterated_char_count += len(input_line)
+
+ # Create truncated explanation with modified final line
+ truncated_result = input_lines[:iterated_index]
+ final_line = input_lines[iterated_index]
+ if final_line:
+ final_line_truncate_point = max_chars - iterated_char_count
+ final_line = final_line[:final_line_truncate_point]
+ truncated_result.append(final_line)
+ return truncated_result
diff --git a/lib/spack/external/_pytest/assertion/util.py b/lib/spack/external/_pytest/assertion/util.py
index 4a0a4e4310..9f00929073 100644
--- a/lib/spack/external/_pytest/assertion/util.py
+++ b/lib/spack/external/_pytest/assertion/util.py
@@ -1,4 +1,5 @@
"""Utilities for assertion debugging"""
+from __future__ import absolute_import, division, print_function
import pprint
import _pytest._code
@@ -8,7 +9,7 @@ try:
except ImportError:
Sequence = list
-BuiltinAssertionError = py.builtin.builtins.AssertionError
+
u = py.builtin._totext
# The _reprcompare attribute on the util module is used by the new assertion
@@ -52,11 +53,11 @@ def _split_explanation(explanation):
"""
raw_lines = (explanation or u('')).split('\n')
lines = [raw_lines[0]]
- for l in raw_lines[1:]:
- if l and l[0] in ['{', '}', '~', '>']:
- lines.append(l)
+ for values in raw_lines[1:]:
+ if values and values[0] in ['{', '}', '~', '>']:
+ lines.append(values)
else:
- lines[-1] += '\\n' + l
+ lines[-1] += '\\n' + values
return lines
@@ -81,7 +82,7 @@ def _format_lines(lines):
stack.append(len(result))
stackcnt[-1] += 1
stackcnt.append(0)
- result.append(u(' +') + u(' ')*(len(stack)-1) + s + line[1:])
+ result.append(u(' +') + u(' ') * (len(stack) - 1) + s + line[1:])
elif line.startswith('}'):
stack.pop()
stackcnt.pop()
@@ -90,7 +91,7 @@ def _format_lines(lines):
assert line[0] in ['~', '>']
stack[-1] += 1
indent = len(stack) if line.startswith('~') else len(stack) - 1
- result.append(u(' ')*indent + line[1:])
+ result.append(u(' ') * indent + line[1:])
assert len(stack) == 1
return result
@@ -105,16 +106,22 @@ except NameError:
def assertrepr_compare(config, op, left, right):
"""Return specialised explanations for some operators/operands"""
width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op
- left_repr = py.io.saferepr(left, maxsize=int(width//2))
- right_repr = py.io.saferepr(right, maxsize=width-len(left_repr))
+ left_repr = py.io.saferepr(left, maxsize=int(width // 2))
+ right_repr = py.io.saferepr(right, maxsize=width - len(left_repr))
summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr))
- issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) and
- not isinstance(x, basestring))
- istext = lambda x: isinstance(x, basestring)
- isdict = lambda x: isinstance(x, dict)
- isset = lambda x: isinstance(x, (set, frozenset))
+ def issequence(x):
+ return (isinstance(x, (list, tuple, Sequence)) and not isinstance(x, basestring))
+
+ def istext(x):
+ return isinstance(x, basestring)
+
+ def isdict(x):
+ return isinstance(x, dict)
+
+ def isset(x):
+ return isinstance(x, (set, frozenset))
def isiterable(obj):
try:
@@ -256,8 +263,8 @@ def _compare_eq_dict(left, right, verbose=False):
explanation = []
common = set(left).intersection(set(right))
same = dict((k, left[k]) for k in common if left[k] == right[k])
- if same and not verbose:
- explanation += [u('Omitting %s identical items, use -v to show') %
+ if same and verbose < 2:
+ explanation += [u('Omitting %s identical items, use -vv to show') %
len(same)]
elif same:
explanation += [u('Common items:')]
@@ -284,7 +291,7 @@ def _compare_eq_dict(left, right, verbose=False):
def _notin_text(term, text, verbose=False):
index = text.find(term)
head = text[:index]
- tail = text[index+len(term):]
+ tail = text[index + len(term):]
correct_text = head + tail
diff = _diff_text(correct_text, text, verbose)
newdiff = [u('%s is contained here:') % py.io.saferepr(term, maxsize=42)]
diff --git a/lib/spack/external/_pytest/cacheprovider.py b/lib/spack/external/_pytest/cacheprovider.py
index 0657001f2d..c537c14472 100644..100755
--- a/lib/spack/external/_pytest/cacheprovider.py
+++ b/lib/spack/external/_pytest/cacheprovider.py
@@ -1,20 +1,21 @@
"""
merged implementation of the cache provider
-the name cache was not choosen to ensure pluggy automatically
+the name cache was not chosen to ensure pluggy automatically
ignores the external pytest-cache
"""
-
+from __future__ import absolute_import, division, print_function
import py
import pytest
import json
+import os
from os.path import sep as _sep, altsep as _altsep
class Cache(object):
def __init__(self, config):
self.config = config
- self._cachedir = config.rootdir.join(".cache")
+ self._cachedir = Cache.cache_dir_from_config(config)
self.trace = config.trace.root.get("cache")
if config.getvalue("cacheclear"):
self.trace("clearing cachedir")
@@ -22,6 +23,16 @@ class Cache(object):
self._cachedir.remove()
self._cachedir.mkdir()
+ @staticmethod
+ def cache_dir_from_config(config):
+ cache_dir = config.getini("cache_dir")
+ cache_dir = os.path.expanduser(cache_dir)
+ cache_dir = os.path.expandvars(cache_dir)
+ if os.path.isabs(cache_dir):
+ return py.path.local(cache_dir)
+ else:
+ return config.rootdir.join(cache_dir)
+
def makedir(self, name):
""" return a directory path object with the given name. If the
directory does not yet exist, it will be created. You can use it
@@ -89,31 +100,31 @@ class Cache(object):
class LFPlugin:
""" Plugin which implements the --lf (run last-failing) option """
+
def __init__(self, config):
self.config = config
active_keys = 'lf', 'failedfirst'
self.active = any(config.getvalue(key) for key in active_keys)
- if self.active:
- self.lastfailed = config.cache.get("cache/lastfailed", {})
- else:
- self.lastfailed = {}
+ self.lastfailed = config.cache.get("cache/lastfailed", {})
+ self._previously_failed_count = None
- def pytest_report_header(self):
+ def pytest_report_collectionfinish(self):
if self.active:
- if not self.lastfailed:
+ if not self._previously_failed_count:
mode = "run all (no recorded failures)"
else:
- mode = "rerun last %d failures%s" % (
- len(self.lastfailed),
- " first" if self.config.getvalue("failedfirst") else "")
+ noun = 'failure' if self._previously_failed_count == 1 else 'failures'
+ suffix = " first" if self.config.getvalue("failedfirst") else ""
+ mode = "rerun previous {count} {noun}{suffix}".format(
+ count=self._previously_failed_count, suffix=suffix, noun=noun
+ )
return "run-last-failure: %s" % mode
def pytest_runtest_logreport(self, report):
- if report.failed and "xfail" not in report.keywords:
+ if (report.when == 'call' and report.passed) or report.skipped:
+ self.lastfailed.pop(report.nodeid, None)
+ elif report.failed:
self.lastfailed[report.nodeid] = True
- elif not report.failed:
- if report.when == "call":
- self.lastfailed.pop(report.nodeid, None)
def pytest_collectreport(self, report):
passed = report.outcome in ('passed', 'skipped')
@@ -135,22 +146,24 @@ class LFPlugin:
previously_failed.append(item)
else:
previously_passed.append(item)
- if not previously_failed and previously_passed:
+ self._previously_failed_count = len(previously_failed)
+ if not previously_failed:
# running a subset of all tests with recorded failures outside
# of the set of tests currently executing
- pass
- elif self.config.getvalue("failedfirst"):
- items[:] = previously_failed + previously_passed
- else:
+ return
+ if self.config.getvalue("lf"):
items[:] = previously_failed
config.hook.pytest_deselected(items=previously_passed)
+ else:
+ items[:] = previously_failed + previously_passed
def pytest_sessionfinish(self, session):
config = self.config
if config.getvalue("cacheshow") or hasattr(config, "slaveinput"):
return
- prev_failed = config.cache.get("cache/lastfailed", None) is not None
- if (session.testscollected and prev_failed) or self.lastfailed:
+
+ saved_lastfailed = config.cache.get("cache/lastfailed", {})
+ if saved_lastfailed != self.lastfailed:
config.cache.set("cache/lastfailed", self.lastfailed)
@@ -171,6 +184,9 @@ def pytest_addoption(parser):
group.addoption(
'--cache-clear', action='store_true', dest="cacheclear",
help="remove all cache contents at start of test run.")
+ parser.addini(
+ "cache_dir", default='.cache',
+ help="cache directory path.")
def pytest_cmdline_main(config):
@@ -179,7 +195,6 @@ def pytest_cmdline_main(config):
return wrap_session(config, cacheshow)
-
@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
config.cache = Cache(config)
@@ -219,12 +234,12 @@ def cacheshow(config, session):
basedir = config.cache._cachedir
vdir = basedir.join("v")
tw.sep("-", "cache values")
- for valpath in vdir.visit(lambda x: x.isfile()):
+ for valpath in sorted(vdir.visit(lambda x: x.isfile())):
key = valpath.relto(vdir).replace(valpath.sep, "/")
val = config.cache.get(key, dummy)
if val is dummy:
tw.line("%s contains unreadable content, "
- "will be ignored" % key)
+ "will be ignored" % key)
else:
tw.line("%s contains:" % key)
stream = py.io.TextIO()
@@ -235,8 +250,8 @@ def cacheshow(config, session):
ddir = basedir.join("d")
if ddir.isdir() and ddir.listdir():
tw.sep("-", "cache directories")
- for p in basedir.join("d").visit():
- #if p.check(dir=1):
+ for p in sorted(basedir.join("d").visit()):
+ # if p.check(dir=1):
# print("%s/" % p.relto(basedir))
if p.isfile():
key = p.relto(basedir)
diff --git a/lib/spack/external/_pytest/capture.py b/lib/spack/external/_pytest/capture.py
index eea81ca187..cb5af6fcb3 100644
--- a/lib/spack/external/_pytest/capture.py
+++ b/lib/spack/external/_pytest/capture.py
@@ -2,17 +2,19 @@
per-test stdout/stderr capturing mechanism.
"""
-from __future__ import with_statement
+from __future__ import absolute_import, division, print_function
import contextlib
import sys
import os
+import io
+from io import UnsupportedOperation
from tempfile import TemporaryFile
import py
import pytest
+from _pytest.compat import CaptureIO
-from py.io import TextIO
unicode = py.builtin.text
patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
@@ -32,8 +34,11 @@ def pytest_addoption(parser):
@pytest.hookimpl(hookwrapper=True)
def pytest_load_initial_conftests(early_config, parser, args):
- _readline_workaround()
ns = early_config.known_args_namespace
+ if ns.capture == "fd":
+ _py36_windowsconsoleio_workaround(sys.stdout)
+ _colorama_workaround()
+ _readline_workaround()
pluginmanager = early_config.pluginmanager
capman = CaptureManager(ns.capture)
pluginmanager.register(capman, "capturemanager")
@@ -130,7 +135,7 @@ class CaptureManager:
self.resumecapture()
self.activate_funcargs(item)
yield
- #self.deactivate_funcargs() called from suspendcapture()
+ # self.deactivate_funcargs() called from suspendcapture()
self.suspendcapture_item(item, "call")
@pytest.hookimpl(hookwrapper=True)
@@ -167,6 +172,7 @@ def capsys(request):
request.node._capfuncarg = c = CaptureFixture(SysCapture, request)
return c
+
@pytest.fixture
def capfd(request):
"""Enable capturing of writes to file descriptors 1 and 2 and make
@@ -234,6 +240,7 @@ def safe_text_dupfile(f, mode, default_encoding="UTF8"):
class EncodedFile(object):
errors = "strict" # possibly needed by py3 code (issue555)
+
def __init__(self, buffer, encoding):
self.buffer = buffer
self.encoding = encoding
@@ -247,6 +254,11 @@ class EncodedFile(object):
data = ''.join(linelist)
self.write(data)
+ @property
+ def name(self):
+ """Ensure that file.name is a string."""
+ return repr(self.buffer)
+
def __getattr__(self, name):
return getattr(object.__getattribute__(self, "buffer"), name)
@@ -314,9 +326,11 @@ class MultiCapture(object):
return (self.out.snap() if self.out is not None else "",
self.err.snap() if self.err is not None else "")
+
class NoCapture:
__init__ = start = done = suspend = resume = lambda *args: None
+
class FDCapture:
""" Capture IO to/from a given os-level filedescriptor. """
@@ -389,7 +403,7 @@ class FDCapture:
def writeorg(self, data):
""" write to original file descriptor. """
if py.builtin._istext(data):
- data = data.encode("utf8") # XXX use encoding of original stream
+ data = data.encode("utf8") # XXX use encoding of original stream
os.write(self.targetfd_save, data)
@@ -402,7 +416,7 @@ class SysCapture:
if name == "stdin":
tmpfile = DontReadFromInput()
else:
- tmpfile = TextIO()
+ tmpfile = CaptureIO()
self.tmpfile = tmpfile
def start(self):
@@ -448,7 +462,8 @@ class DontReadFromInput:
__iter__ = read
def fileno(self):
- raise ValueError("redirected Stdin is pseudofile, has no fileno()")
+ raise UnsupportedOperation("redirected stdin is pseudofile, "
+ "has no fileno()")
def isatty(self):
return False
@@ -458,12 +473,30 @@ class DontReadFromInput:
@property
def buffer(self):
- if sys.version_info >= (3,0):
+ if sys.version_info >= (3, 0):
return self
else:
raise AttributeError('redirected stdin has no attribute buffer')
+def _colorama_workaround():
+ """
+ Ensure colorama is imported so that it attaches to the correct stdio
+ handles on Windows.
+
+ colorama uses the terminal on import time. So if something does the
+ first import of colorama while I/O capture is active, colorama will
+ fail in various ways.
+ """
+
+ if not sys.platform.startswith('win32'):
+ return
+ try:
+ import colorama # noqa
+ except ImportError:
+ pass
+
+
def _readline_workaround():
"""
Ensure readline is imported so that it attaches to the correct stdio
@@ -489,3 +522,56 @@ def _readline_workaround():
import readline # noqa
except ImportError:
pass
+
+
+def _py36_windowsconsoleio_workaround(stream):
+ """
+ Python 3.6 implemented unicode console handling for Windows. This works
+ by reading/writing to the raw console handle using
+ ``{Read,Write}ConsoleW``.
+
+ The problem is that we are going to ``dup2`` over the stdio file
+ descriptors when doing ``FDCapture`` and this will ``CloseHandle`` the
+ handles used by Python to write to the console. Though there is still some
+ weirdness and the console handle seems to only be closed randomly and not
+ on the first call to ``CloseHandle``, or maybe it gets reopened with the
+ same handle value when we suspend capturing.
+
+ The workaround in this case will reopen stdio with a different fd which
+ also means a different handle by replicating the logic in
+ "Py_lifecycle.c:initstdio/create_stdio".
+
+ :param stream: in practice ``sys.stdout`` or ``sys.stderr``, but given
+ here as parameter for unittesting purposes.
+
+ See https://github.com/pytest-dev/py/issues/103
+ """
+ if not sys.platform.startswith('win32') or sys.version_info[:2] < (3, 6):
+ return
+
+ # bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666)
+ if not hasattr(stream, 'buffer'):
+ return
+
+ buffered = hasattr(stream.buffer, 'raw')
+ raw_stdout = stream.buffer.raw if buffered else stream.buffer
+
+ if not isinstance(raw_stdout, io._WindowsConsoleIO):
+ return
+
+ def _reopen_stdio(f, mode):
+ if not buffered and mode[0] == 'w':
+ buffering = 0
+ else:
+ buffering = -1
+
+ return io.TextIOWrapper(
+ open(os.dup(f.fileno()), mode, buffering),
+ f.encoding,
+ f.errors,
+ f.newlines,
+ f.line_buffering)
+
+ sys.__stdin__ = sys.stdin = _reopen_stdio(sys.stdin, 'rb')
+ sys.__stdout__ = sys.stdout = _reopen_stdio(sys.stdout, 'wb')
+ sys.__stderr__ = sys.stderr = _reopen_stdio(sys.stderr, 'wb')
diff --git a/lib/spack/external/_pytest/compat.py b/lib/spack/external/_pytest/compat.py
index 51fc3bc5c1..255f69ce0d 100644
--- a/lib/spack/external/_pytest/compat.py
+++ b/lib/spack/external/_pytest/compat.py
@@ -1,6 +1,7 @@
"""
python version compatibility code
"""
+from __future__ import absolute_import, division, print_function
import sys
import inspect
import types
@@ -9,8 +10,8 @@ import functools
import py
-import _pytest
-
+import _pytest
+from _pytest.outcomes import TEST_OUTCOME
try:
@@ -19,6 +20,7 @@ except ImportError: # pragma: no cover
# Only available in Python 3.4+ or as a backport
enum = None
+
_PY3 = sys.version_info > (3, 0)
_PY2 = not _PY3
@@ -26,6 +28,10 @@ _PY2 = not _PY3
NoneType = type(None)
NOTSET = object()
+PY35 = sys.version_info[:2] >= (3, 5)
+PY36 = sys.version_info[:2] >= (3, 6)
+MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError'
+
if hasattr(inspect, 'signature'):
def _format_args(func):
return str(inspect.signature(func))
@@ -42,11 +48,18 @@ REGEX_TYPE = type(re.compile(''))
def is_generator(func):
- try:
- return _pytest._code.getrawcode(func).co_flags & 32 # generator function
- except AttributeError: # builtin functions have no bytecode
- # assume them to not be generators
- return False
+ genfunc = inspect.isgeneratorfunction(func)
+ return genfunc and not iscoroutinefunction(func)
+
+
+def iscoroutinefunction(func):
+ """Return True if func is a decorated coroutine function.
+
+ Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly,
+ which in turns also initializes the "logging" module as side-effect (see issue #8).
+ """
+ return (getattr(func, '_is_coroutine', False) or
+ (hasattr(inspect, 'iscoroutinefunction') and inspect.iscoroutinefunction(func)))
def getlocation(function, curdir):
@@ -55,7 +68,7 @@ def getlocation(function, curdir):
lineno = py.builtin._getcode(function).co_firstlineno
if fn.relto(curdir):
fn = fn.relto(curdir)
- return "%s:%d" %(fn, lineno+1)
+ return "%s:%d" % (fn, lineno + 1)
def num_mock_patch_args(function):
@@ -66,13 +79,21 @@ def num_mock_patch_args(function):
mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None))
if mock is not None:
return len([p for p in patchings
- if not p.attribute_name and p.new is mock.DEFAULT])
+ if not p.attribute_name and p.new is mock.DEFAULT])
return len(patchings)
-def getfuncargnames(function, startindex=None):
+def getfuncargnames(function, startindex=None, cls=None):
+ """
+ @RonnyPfannschmidt: This function should be refactored when we revisit fixtures. The
+ fixture mechanism should ask the node for the fixture names, and not try to obtain
+ directly from the function object well after collection has occurred.
+ """
+ if startindex is None and cls is not None:
+ is_staticmethod = isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
+ startindex = 0 if is_staticmethod else 1
# XXX merge with main.py's varnames
- #assert not isclass(function)
+ # assert not isclass(function)
realfunction = function
while hasattr(realfunction, "__wrapped__"):
realfunction = realfunction.__wrapped__
@@ -98,8 +119,7 @@ def getfuncargnames(function, startindex=None):
return tuple(argnames[startindex:])
-
-if sys.version_info[:2] == (2, 6):
+if sys.version_info[:2] == (2, 6):
def isclass(object):
""" Return true if the object is a class. Overrides inspect.isclass for
python 2.6 because it will return True for objects which always return
@@ -111,10 +131,12 @@ if sys.version_info[:2] == (2, 6):
if _PY3:
import codecs
-
+ imap = map
+ izip = zip
STRING_TYPES = bytes, str
+ UNICODE_TYPES = str,
- def _escape_strings(val):
+ def _ascii_escaped(val):
"""If val is pure ascii, returns it as a str(). Otherwise, escapes
bytes objects into a sequence of escaped bytes:
@@ -144,8 +166,11 @@ if _PY3:
return val.encode('unicode_escape').decode('ascii')
else:
STRING_TYPES = bytes, str, unicode
+ UNICODE_TYPES = unicode,
- def _escape_strings(val):
+ from itertools import imap, izip # NOQA
+
+ def _ascii_escaped(val):
"""In py2 bytes and str are the same type, so return if it's a bytes
object, return it unchanged if it is a full ascii string,
otherwise escape it into its binary form.
@@ -167,8 +192,18 @@ def get_real_func(obj):
""" gets the real function object of the (possibly) wrapped object by
functools.wraps or functools.partial.
"""
- while hasattr(obj, "__wrapped__"):
- obj = obj.__wrapped__
+ start_obj = obj
+ for i in range(100):
+ new_obj = getattr(obj, '__wrapped__', None)
+ if new_obj is None:
+ break
+ obj = new_obj
+ else:
+ raise ValueError(
+ ("could not find real function of {start}"
+ "\nstopped at {current}").format(
+ start=py.io.saferepr(start_obj),
+ current=py.io.saferepr(obj)))
if isinstance(obj, functools.partial):
obj = obj.func
return obj
@@ -195,14 +230,16 @@ def getimfunc(func):
def safe_getattr(object, name, default):
- """ Like getattr but return default upon any Exception.
+ """ Like getattr but return default upon any Exception or any OutcomeException.
Attribute access can potentially fail for 'evil' Python objects.
- See issue214
+ See issue #214.
+ It catches OutcomeException because of #2490 (issue #580), new outcomes are derived from BaseException
+ instead of Exception (for more details check #2707)
"""
try:
return getattr(object, name, default)
- except Exception:
+ except TEST_OUTCOME:
return default
@@ -226,5 +263,64 @@ else:
try:
return str(v)
except UnicodeError:
+ if not isinstance(v, unicode):
+ v = unicode(v)
errors = 'replace'
- return v.encode('ascii', errors)
+ return v.encode('utf-8', errors)
+
+
+COLLECT_FAKEMODULE_ATTRIBUTES = (
+ 'Collector',
+ 'Module',
+ 'Generator',
+ 'Function',
+ 'Instance',
+ 'Session',
+ 'Item',
+ 'Class',
+ 'File',
+ '_fillfuncargs',
+)
+
+
+def _setup_collect_fakemodule():
+ from types import ModuleType
+ import pytest
+ pytest.collect = ModuleType('pytest.collect')
+ pytest.collect.__all__ = [] # used for setns
+ for attr in COLLECT_FAKEMODULE_ATTRIBUTES:
+ setattr(pytest.collect, attr, getattr(pytest, attr))
+
+
+if _PY2:
+ # Without this the test_dupfile_on_textio will fail, otherwise CaptureIO could directly inherit from StringIO.
+ from py.io import TextIO
+
+ class CaptureIO(TextIO):
+
+ @property
+ def encoding(self):
+ return getattr(self, '_encoding', 'UTF-8')
+
+else:
+ import io
+
+ class CaptureIO(io.TextIOWrapper):
+ def __init__(self):
+ super(CaptureIO, self).__init__(
+ io.BytesIO(),
+ encoding='UTF-8', newline='', write_through=True,
+ )
+
+ def getvalue(self):
+ return self.buffer.getvalue().decode('UTF-8')
+
+
+class FuncargnamesCompatAttr(object):
+ """ helper class so that Metafunc, Function and FixtureRequest
+ don't need to each define the "funcargnames" compatibility attribute.
+ """
+ @property
+ def funcargnames(self):
+ """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
+ return self.fixturenames
diff --git a/lib/spack/external/_pytest/config.py b/lib/spack/external/_pytest/config.py
index fe386ed0b1..19835d2c39 100644
--- a/lib/spack/external/_pytest/config.py
+++ b/lib/spack/external/_pytest/config.py
@@ -1,4 +1,5 @@
""" command line options, ini-file and conftest.py processing. """
+from __future__ import absolute_import, division, print_function
import argparse
import shlex
import traceback
@@ -7,7 +8,8 @@ import warnings
import py
# DON't import pytest here because it causes import cycle troubles
-import sys, os
+import sys
+import os
import _pytest._code
import _pytest.hookspec # the extension point definitions
import _pytest.assertion
@@ -53,15 +55,15 @@ def main(args=None, plugins=None):
return 4
else:
try:
- config.pluginmanager.check_pending()
return config.hook.pytest_cmdline_main(config=config)
finally:
config._ensure_unconfigure()
except UsageError as e:
for msg in e.args:
- sys.stderr.write("ERROR: %s\n" %(msg,))
+ sys.stderr.write("ERROR: %s\n" % (msg,))
return 4
+
class cmdline: # compatibility namespace
main = staticmethod(main)
@@ -70,6 +72,12 @@ class UsageError(Exception):
""" error in pytest usage or invocation"""
+class PrintHelp(Exception):
+ """Raised when pytest should print it's help to skip the rest of the
+ argument parsing and validation."""
+ pass
+
+
def filename_arg(path, optname):
""" Argparse type validator for filename arguments.
@@ -95,10 +103,11 @@ def directory_arg(path, optname):
_preinit = []
default_plugins = (
- "mark main terminal runner python fixtures debugging unittest capture skipping "
- "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion "
- "junitxml resultlog doctest cacheprovider freeze_support "
- "setuponly setupplan").split()
+ "mark main terminal runner python fixtures debugging unittest capture skipping "
+ "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion "
+ "junitxml resultlog doctest cacheprovider freeze_support "
+ "setuponly setupplan warnings").split()
+
builtin_plugins = set(default_plugins)
builtin_plugins.add("pytester")
@@ -108,6 +117,7 @@ def _preloadplugins():
assert not _preinit
_preinit.append(get_config())
+
def get_config():
if _preinit:
return _preinit.pop(0)
@@ -118,6 +128,7 @@ def get_config():
pluginmanager.import_plugin(spec)
return config
+
def get_plugin_manager():
"""
Obtain a new instance of the
@@ -129,6 +140,7 @@ def get_plugin_manager():
"""
return get_config().pluginmanager
+
def _prepareconfig(args=None, plugins=None):
warning = None
if args is None:
@@ -153,7 +165,7 @@ def _prepareconfig(args=None, plugins=None):
if warning:
config.warn('C1', warning)
return pluginmanager.hook.pytest_cmdline_parse(
- pluginmanager=pluginmanager, args=args)
+ pluginmanager=pluginmanager, args=args)
except BaseException:
config._ensure_unconfigure()
raise
@@ -161,13 +173,14 @@ def _prepareconfig(args=None, plugins=None):
class PytestPluginManager(PluginManager):
"""
- Overwrites :py:class:`pluggy.PluginManager` to add pytest-specific
+ Overwrites :py:class:`pluggy.PluginManager <_pytest.vendored_packages.pluggy.PluginManager>` to add pytest-specific
functionality:
* loading plugins from the command line, ``PYTEST_PLUGIN`` env variable and
``pytest_plugins`` global variables found in plugins being loaded;
* ``conftest.py`` loading during start-up;
"""
+
def __init__(self):
super(PytestPluginManager, self).__init__("pytest", implprefix="pytest_")
self._conftest_plugins = set()
@@ -198,7 +211,8 @@ class PytestPluginManager(PluginManager):
"""
.. deprecated:: 2.8
- Use :py:meth:`pluggy.PluginManager.add_hookspecs` instead.
+ Use :py:meth:`pluggy.PluginManager.add_hookspecs <_pytest.vendored_packages.pluggy.PluginManager.add_hookspecs>`
+ instead.
"""
warning = dict(code="I2",
fslocation=_pytest._code.getfslineno(sys._getframe(1)),
@@ -227,7 +241,7 @@ class PytestPluginManager(PluginManager):
def parse_hookspec_opts(self, module_or_class, name):
opts = super(PytestPluginManager, self).parse_hookspec_opts(
- module_or_class, name)
+ module_or_class, name)
if opts is None:
method = getattr(module_or_class, name)
if name.startswith("pytest_"):
@@ -250,7 +264,10 @@ class PytestPluginManager(PluginManager):
ret = super(PytestPluginManager, self).register(plugin, name)
if ret:
self.hook.pytest_plugin_registered.call_historic(
- kwargs=dict(plugin=plugin, manager=self))
+ kwargs=dict(plugin=plugin, manager=self))
+
+ if isinstance(plugin, types.ModuleType):
+ self.consider_module(plugin)
return ret
def getplugin(self, name):
@@ -265,11 +282,11 @@ class PytestPluginManager(PluginManager):
# XXX now that the pluginmanager exposes hookimpl(tryfirst...)
# we should remove tryfirst/trylast as markers
config.addinivalue_line("markers",
- "tryfirst: mark a hook implementation function such that the "
- "plugin machinery will try to call it first/as early as possible.")
+ "tryfirst: mark a hook implementation function such that the "
+ "plugin machinery will try to call it first/as early as possible.")
config.addinivalue_line("markers",
- "trylast: mark a hook implementation function such that the "
- "plugin machinery will try to call it last/as late as possible.")
+ "trylast: mark a hook implementation function such that the "
+ "plugin machinery will try to call it last/as late as possible.")
def _warn(self, message):
kwargs = message if isinstance(message, dict) else {
@@ -293,7 +310,7 @@ class PytestPluginManager(PluginManager):
"""
current = py.path.local()
self._confcutdir = current.join(namespace.confcutdir, abs=True) \
- if namespace.confcutdir else None
+ if namespace.confcutdir else None
self._noconftest = namespace.noconftest
testpaths = namespace.file_or_dir
foundanchor = False
@@ -304,7 +321,7 @@ class PytestPluginManager(PluginManager):
if i != -1:
path = path[:i]
anchor = current.join(path, abs=1)
- if exists(anchor): # we found some file object
+ if exists(anchor): # we found some file object
self._try_load_conftest(anchor)
foundanchor = True
if not foundanchor:
@@ -371,7 +388,7 @@ class PytestPluginManager(PluginManager):
if path and path.relto(dirpath) or path == dirpath:
assert mod not in mods
mods.append(mod)
- self.trace("loaded conftestmodule %r" %(mod))
+ self.trace("loaded conftestmodule %r" % (mod))
self.consider_conftest(mod)
return mod
@@ -381,7 +398,7 @@ class PytestPluginManager(PluginManager):
#
def consider_preparse(self, args):
- for opt1,opt2 in zip(args, args[1:]):
+ for opt1, opt2 in zip(args, args[1:]):
if opt1 == "-p":
self.consider_pluginarg(opt2)
@@ -395,38 +412,33 @@ class PytestPluginManager(PluginManager):
self.import_plugin(arg)
def consider_conftest(self, conftestmodule):
- if self.register(conftestmodule, name=conftestmodule.__file__):
- self.consider_module(conftestmodule)
+ self.register(conftestmodule, name=conftestmodule.__file__)
def consider_env(self):
self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS"))
def consider_module(self, mod):
- plugins = getattr(mod, 'pytest_plugins', [])
- if isinstance(plugins, str):
- plugins = [plugins]
- self.rewrite_hook.mark_rewrite(*plugins)
- self._import_plugin_specs(plugins)
+ self._import_plugin_specs(getattr(mod, 'pytest_plugins', []))
def _import_plugin_specs(self, spec):
- if spec:
- if isinstance(spec, str):
- spec = spec.split(",")
- for import_spec in spec:
- self.import_plugin(import_spec)
+ plugins = _get_plugin_specs_as_list(spec)
+ for import_spec in plugins:
+ self.import_plugin(import_spec)
def import_plugin(self, modname):
# most often modname refers to builtin modules, e.g. "pytester",
# "terminal" or "capture". Those plugins are registered under their
# basename for historic purposes but must be imported with the
# _pytest prefix.
- assert isinstance(modname, str)
+ assert isinstance(modname, (py.builtin.text, str)), "module name as text required, got %r" % modname
+ modname = str(modname)
if self.get_plugin(modname) is not None:
return
if modname in builtin_plugins:
importspec = "_pytest." + modname
else:
importspec = modname
+ self.rewrite_hook.mark_rewrite(importspec)
try:
__import__(importspec)
except ImportError as e:
@@ -440,11 +452,28 @@ class PytestPluginManager(PluginManager):
import pytest
if not hasattr(pytest, 'skip') or not isinstance(e, pytest.skip.Exception):
raise
- self._warn("skipped plugin %r: %s" %((modname, e.msg)))
+ self._warn("skipped plugin %r: %s" % ((modname, e.msg)))
else:
mod = sys.modules[importspec]
self.register(mod, modname)
- self.consider_module(mod)
+
+
+def _get_plugin_specs_as_list(specs):
+ """
+ Parses a list of "plugin specs" and returns a list of plugin names.
+
+ Plugin specs can be given as a list of strings separated by "," or already as a list/tuple in
+ which case it is returned as a list. Specs can also be `None` in which case an
+ empty list is returned.
+ """
+ if specs is not None:
+ if isinstance(specs, str):
+ specs = specs.split(',') if specs else []
+ if not isinstance(specs, (list, tuple)):
+ raise UsageError("Plugin specs must be a ','-separated string or a "
+ "list/tuple of strings for plugin names. Given: %r" % specs)
+ return list(specs)
+ return []
class Parser:
@@ -488,7 +517,7 @@ class Parser:
for i, grp in enumerate(self._groups):
if grp.name == after:
break
- self._groups.insert(i+1, group)
+ self._groups.insert(i + 1, group)
return group
def addoption(self, *opts, **attrs):
@@ -526,7 +555,7 @@ class Parser:
a = option.attrs()
arggroup.add_argument(*n, **a)
# bash like autocompletion for dirs (appending '/')
- optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter
+ optparser.add_argument(FILE_OR_DIR, nargs='*').completer = filescompleter
return optparser
def parse_setoption(self, args, option, namespace=None):
@@ -670,7 +699,7 @@ class Argument:
if self._attrs.get('help'):
a = self._attrs['help']
a = a.replace('%default', '%(default)s')
- #a = a.replace('%prog', '%(prog)s')
+ # a = a.replace('%prog', '%(prog)s')
self._attrs['help'] = a
return self._attrs
@@ -754,7 +783,7 @@ class MyOptionParser(argparse.ArgumentParser):
extra_info = {}
self._parser = parser
argparse.ArgumentParser.__init__(self, usage=parser._usage,
- add_help=False, formatter_class=DropShorterLongHelpFormatter)
+ add_help=False, formatter_class=DropShorterLongHelpFormatter)
# extra_info is a dict of (param -> value) to display if there's
# an usage error to provide more contextual information to the user
self.extra_info = extra_info
@@ -782,9 +811,10 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter):
- shortcut if there are only two options and one of them is a short one
- cache result on action object as this is called at least 2 times
"""
+
def _format_action_invocation(self, action):
orgstr = argparse.HelpFormatter._format_action_invocation(self, action)
- if orgstr and orgstr[0] != '-': # only optional arguments
+ if orgstr and orgstr[0] != '-': # only optional arguments
return orgstr
res = getattr(action, '_formatted_action_invocation', None)
if res:
@@ -795,7 +825,7 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter):
action._formatted_action_invocation = orgstr
return orgstr
return_list = []
- option_map = getattr(action, 'map_long_option', {})
+ option_map = getattr(action, 'map_long_option', {})
if option_map is None:
option_map = {}
short_long = {}
@@ -813,7 +843,7 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter):
short_long[shortened] = xxoption
# now short_long has been filled out to the longest with dashes
# **and** we keep the right option ordering from add_argument
- for option in options: #
+ for option in options:
if len(option) == 2 or option[2] == ' ':
return_list.append(option)
if option[2:] == short_long.get(option.replace('-', '')):
@@ -822,22 +852,26 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter):
return action._formatted_action_invocation
-
def _ensure_removed_sysmodule(modname):
try:
del sys.modules[modname]
except KeyError:
pass
+
class CmdOptions(object):
""" holds cmdline options as attributes."""
+
def __init__(self, values=()):
self.__dict__.update(values)
+
def __repr__(self):
- return "<CmdOptions %r>" %(self.__dict__,)
+ return "<CmdOptions %r>" % (self.__dict__,)
+
def copy(self):
return CmdOptions(self.__dict__)
+
class Notset:
def __repr__(self):
return "<NOTSET>"
@@ -847,6 +881,18 @@ notset = Notset()
FILE_OR_DIR = 'file_or_dir'
+def _iter_rewritable_modules(package_files):
+ for fn in package_files:
+ is_simple_module = '/' not in fn and fn.endswith('.py')
+ is_package = fn.count('/') == 1 and fn.endswith('__init__.py')
+ if is_simple_module:
+ module_name, _ = os.path.splitext(fn)
+ yield module_name
+ elif is_package:
+ package_name = os.path.dirname(fn)
+ yield package_name
+
+
class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """
@@ -864,6 +910,7 @@ class Config(object):
self.trace = self.pluginmanager.trace.root.get("config")
self.hook = self.pluginmanager.hook
self._inicache = {}
+ self._override_ini = ()
self._opt2dest = {}
self._cleanup = []
self._warn = self.pluginmanager._warn
@@ -896,11 +943,11 @@ class Config(object):
fin = self._cleanup.pop()
fin()
- def warn(self, code, message, fslocation=None):
+ def warn(self, code, message, fslocation=None, nodeid=None):
""" generate a warning for this test session. """
self.hook.pytest_logwarning.call_historic(kwargs=dict(
code=code, message=message,
- fslocation=fslocation, nodeid=None))
+ fslocation=fslocation, nodeid=nodeid))
def get_terminal_writer(self):
return self.pluginmanager.get_plugin("terminalreporter")._tw
@@ -916,14 +963,14 @@ class Config(object):
else:
style = "native"
excrepr = excinfo.getrepr(funcargs=True,
- showlocals=getattr(option, 'showlocals', False),
- style=style,
- )
+ showlocals=getattr(option, 'showlocals', False),
+ style=style,
+ )
res = self.hook.pytest_internalerror(excrepr=excrepr,
excinfo=excinfo)
if not py.builtin.any(res):
for line in str(excrepr).split("\n"):
- sys.stderr.write("INTERNALERROR> %s\n" %line)
+ sys.stderr.write("INTERNALERROR> %s\n" % line)
sys.stderr.flush()
def cwd_relative_nodeid(self, nodeid):
@@ -964,8 +1011,9 @@ class Config(object):
self.invocation_dir = py.path.local()
self._parser.addini('addopts', 'extra command line options', 'args')
self._parser.addini('minversion', 'minimally required pytest version')
+ self._override_ini = ns.override_ini or ()
- def _consider_importhook(self, args, entrypoint_name):
+ def _consider_importhook(self, args):
"""Install the PEP 302 import hook if using assertion re-writing.
Needs to parse the --assert=<mode> option from the commandline
@@ -980,26 +1028,34 @@ class Config(object):
except SystemError:
mode = 'plain'
else:
- import pkg_resources
- self.pluginmanager.rewrite_hook = hook
- for entrypoint in pkg_resources.iter_entry_points('pytest11'):
- # 'RECORD' available for plugins installed normally (pip install)
- # 'SOURCES.txt' available for plugins installed in dev mode (pip install -e)
- # for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa
- # so it shouldn't be an issue
- for metadata in ('RECORD', 'SOURCES.txt'):
- for entry in entrypoint.dist._get_metadata(metadata):
- fn = entry.split(',')[0]
- is_simple_module = os.sep not in fn and fn.endswith('.py')
- is_package = fn.count(os.sep) == 1 and fn.endswith('__init__.py')
- if is_simple_module:
- module_name, ext = os.path.splitext(fn)
- hook.mark_rewrite(module_name)
- elif is_package:
- package_name = os.path.dirname(fn)
- hook.mark_rewrite(package_name)
+ self._mark_plugins_for_rewrite(hook)
self._warn_about_missing_assertion(mode)
+ def _mark_plugins_for_rewrite(self, hook):
+ """
+ Given an importhook, mark for rewrite any top-level
+ modules or packages in the distribution package for
+ all pytest plugins.
+ """
+ import pkg_resources
+ self.pluginmanager.rewrite_hook = hook
+
+ # 'RECORD' available for plugins installed normally (pip install)
+ # 'SOURCES.txt' available for plugins installed in dev mode (pip install -e)
+ # for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa
+ # so it shouldn't be an issue
+ metadata_files = 'RECORD', 'SOURCES.txt'
+
+ package_files = (
+ entry.split(',')[0]
+ for entrypoint in pkg_resources.iter_entry_points('pytest11')
+ for metadata in metadata_files
+ for entry in entrypoint.dist._get_metadata(metadata)
+ )
+
+ for name in _iter_rewritable_modules(package_files):
+ hook.mark_rewrite(name)
+
def _warn_about_missing_assertion(self, mode):
try:
assert False
@@ -1023,19 +1079,17 @@ class Config(object):
args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args
args[:] = self.getini("addopts") + args
self._checkversion()
- entrypoint_name = 'pytest11'
- self._consider_importhook(args, entrypoint_name)
+ self._consider_importhook(args)
self.pluginmanager.consider_preparse(args)
- self.pluginmanager.load_setuptools_entrypoints(entrypoint_name)
+ self.pluginmanager.load_setuptools_entrypoints('pytest11')
self.pluginmanager.consider_env()
self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy())
- confcutdir = self.known_args_namespace.confcutdir
if self.known_args_namespace.confcutdir is None and self.inifile:
confcutdir = py.path.local(self.inifile).dirname
self.known_args_namespace.confcutdir = confcutdir
try:
self.hook.pytest_load_initial_conftests(early_config=self,
- args=args, parser=self._parser)
+ args=args, parser=self._parser)
except ConftestImportFailure:
e = sys.exc_info()[1]
if ns.help or ns.version:
@@ -1053,28 +1107,32 @@ class Config(object):
myver = pytest.__version__.split(".")
if myver < ver:
raise pytest.UsageError(
- "%s:%d: requires pytest-%s, actual pytest-%s'" %(
- self.inicfg.config.path, self.inicfg.lineof('minversion'),
- minver, pytest.__version__))
+ "%s:%d: requires pytest-%s, actual pytest-%s'" % (
+ self.inicfg.config.path, self.inicfg.lineof('minversion'),
+ minver, pytest.__version__))
def parse(self, args, addopts=True):
# parse given cmdline arguments into this config object.
assert not hasattr(self, 'args'), (
- "can only parse cmdline args at most once per Config object")
+ "can only parse cmdline args at most once per Config object")
self._origargs = args
self.hook.pytest_addhooks.call_historic(
- kwargs=dict(pluginmanager=self.pluginmanager))
+ kwargs=dict(pluginmanager=self.pluginmanager))
self._preparse(args, addopts=addopts)
# XXX deprecated hook:
self.hook.pytest_cmdline_preparse(config=self, args=args)
- args = self._parser.parse_setoption(args, self.option, namespace=self.option)
- if not args:
- cwd = os.getcwd()
- if cwd == self.rootdir:
- args = self.getini('testpaths')
+ self._parser.after_preparse = True
+ try:
+ args = self._parser.parse_setoption(args, self.option, namespace=self.option)
if not args:
- args = [cwd]
- self.args = args
+ cwd = os.getcwd()
+ if cwd == self.rootdir:
+ args = self.getini('testpaths')
+ if not args:
+ args = [cwd]
+ self.args = args
+ except PrintHelp:
+ pass
def addinivalue_line(self, name, line):
""" add a line to an ini-file option. The option must have been
@@ -1082,12 +1140,12 @@ class Config(object):
the first line in its value. """
x = self.getini(name)
assert isinstance(x, list)
- x.append(line) # modifies the cached list inline
+ x.append(line) # modifies the cached list inline
def getini(self, name):
""" return configuration value from an :ref:`ini file <inifiles>`. If the
specified name hasn't been registered through a prior
- :py:func:`parser.addini <pytest.config.Parser.addini>`
+ :py:func:`parser.addini <_pytest.config.Parser.addini>`
call (usually from a plugin), a ValueError is raised. """
try:
return self._inicache[name]
@@ -1099,7 +1157,7 @@ class Config(object):
try:
description, type, default = self._parser._inidict[name]
except KeyError:
- raise ValueError("unknown configuration value: %r" %(name,))
+ raise ValueError("unknown configuration value: %r" % (name,))
value = self._get_override_ini_value(name)
if value is None:
try:
@@ -1112,10 +1170,10 @@ class Config(object):
return []
if type == "pathlist":
dp = py.path.local(self.inicfg.config.path).dirpath()
- l = []
+ values = []
for relpath in shlex.split(value):
- l.append(dp.join(relpath, abs=True))
- return l
+ values.append(dp.join(relpath, abs=True))
+ return values
elif type == "args":
return shlex.split(value)
elif type == "linelist":
@@ -1132,13 +1190,13 @@ class Config(object):
except KeyError:
return None
modpath = py.path.local(mod.__file__).dirpath()
- l = []
+ values = []
for relroot in relroots:
if not isinstance(relroot, py.path.local):
relroot = relroot.replace("/", py.path.local.sep)
relroot = modpath.join(relroot, abs=True)
- l.append(relroot)
- return l
+ values.append(relroot)
+ return values
def _get_override_ini_value(self, name):
value = None
@@ -1146,15 +1204,14 @@ class Config(object):
# and -o foo1=bar1 -o foo2=bar2 options
# always use the last item if multiple value set for same ini-name,
# e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2
- if self.getoption("override_ini", None):
- for ini_config_list in self.option.override_ini:
- for ini_config in ini_config_list:
- try:
- (key, user_ini_value) = ini_config.split("=", 1)
- except ValueError:
- raise UsageError("-o/--override-ini expects option=value style.")
- if key == name:
- value = user_ini_value
+ for ini_config_list in self._override_ini:
+ for ini_config in ini_config_list:
+ try:
+ (key, user_ini_value) = ini_config.split("=", 1)
+ except ValueError:
+ raise UsageError("-o/--override-ini expects option=value style.")
+ if key == name:
+ value = user_ini_value
return value
def getoption(self, name, default=notset, skip=False):
@@ -1177,7 +1234,7 @@ class Config(object):
return default
if skip:
import pytest
- pytest.skip("no %r option found" %(name,))
+ pytest.skip("no %r option found" % (name,))
raise ValueError("no option named %r" % (name,))
def getvalue(self, name, path=None):
@@ -1188,12 +1245,14 @@ class Config(object):
""" (deprecated, use getoption(skip=True)) """
return self.getoption(name, skip=True)
+
def exists(path, ignore=EnvironmentError):
try:
return path.check()
except ignore:
return False
+
def getcfg(args, warnfunc=None):
"""
Search the list of arguments for a valid ini-file for pytest,
@@ -1228,25 +1287,20 @@ def getcfg(args, warnfunc=None):
return None, None, None
-def get_common_ancestor(args):
- # args are what we get after early command line parsing (usually
- # strings, but can be py.path.local objects as well)
+def get_common_ancestor(paths):
common_ancestor = None
- for arg in args:
- if str(arg)[0] == "-":
- continue
- p = py.path.local(arg)
- if not p.exists():
+ for path in paths:
+ if not path.exists():
continue
if common_ancestor is None:
- common_ancestor = p
+ common_ancestor = path
else:
- if p.relto(common_ancestor) or p == common_ancestor:
+ if path.relto(common_ancestor) or path == common_ancestor:
continue
- elif common_ancestor.relto(p):
- common_ancestor = p
+ elif common_ancestor.relto(path):
+ common_ancestor = path
else:
- shared = p.common(common_ancestor)
+ shared = path.common(common_ancestor)
if shared is not None:
common_ancestor = shared
if common_ancestor is None:
@@ -1257,9 +1311,29 @@ def get_common_ancestor(args):
def get_dirs_from_args(args):
- return [d for d in (py.path.local(x) for x in args
- if not str(x).startswith("-"))
- if d.exists()]
+ def is_option(x):
+ return str(x).startswith('-')
+
+ def get_file_part_from_node_id(x):
+ return str(x).split('::')[0]
+
+ def get_dir_from_path(path):
+ if path.isdir():
+ return path
+ return py.path.local(path.dirname)
+
+ # These look like paths but may not exist
+ possible_paths = (
+ py.path.local(get_file_part_from_node_id(arg))
+ for arg in args
+ if not is_option(arg)
+ )
+
+ return [
+ get_dir_from_path(path)
+ for path in possible_paths
+ if path.exists()
+ ]
def determine_setup(inifile, args, warnfunc=None):
@@ -1282,7 +1356,7 @@ def determine_setup(inifile, args, warnfunc=None):
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
if rootdir is None:
rootdir = get_common_ancestor([py.path.local(), ancestor])
- is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep
+ is_fs_root = os.path.splitdrive(str(rootdir))[1] == '/'
if is_fs_root:
rootdir = ancestor
return rootdir, inifile, inicfg or {}
@@ -1304,7 +1378,7 @@ def setns(obj, dic):
else:
setattr(obj, name, value)
obj.__all__.append(name)
- #if obj != pytest:
+ # if obj != pytest:
# pytest.__all__.append(name)
setattr(pytest, name, value)
diff --git a/lib/spack/external/_pytest/debugging.py b/lib/spack/external/_pytest/debugging.py
index d96170bd8b..aa9c9a3863 100644
--- a/lib/spack/external/_pytest/debugging.py
+++ b/lib/spack/external/_pytest/debugging.py
@@ -1,10 +1,8 @@
""" interactive debugging with PDB, the Python Debugger. """
-from __future__ import absolute_import
+from __future__ import absolute_import, division, print_function
import pdb
import sys
-import pytest
-
def pytest_addoption(parser):
group = parser.getgroup("general")
@@ -16,19 +14,17 @@ def pytest_addoption(parser):
help="start a custom interactive Python debugger on errors. "
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb")
-def pytest_namespace():
- return {'set_trace': pytestPDB().set_trace}
def pytest_configure(config):
- if config.getvalue("usepdb") or config.getvalue("usepdb_cls"):
+ if config.getvalue("usepdb_cls"):
+ modname, classname = config.getvalue("usepdb_cls").split(":")
+ __import__(modname)
+ pdb_cls = getattr(sys.modules[modname], classname)
+ else:
+ pdb_cls = pdb.Pdb
+
+ if config.getvalue("usepdb"):
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke')
- if config.getvalue("usepdb_cls"):
- modname, classname = config.getvalue("usepdb_cls").split(":")
- __import__(modname)
- pdb_cls = getattr(sys.modules[modname], classname)
- else:
- pdb_cls = pdb.Pdb
- pytestPDB._pdb_cls = pdb_cls
old = (pdb.set_trace, pytestPDB._pluginmanager)
@@ -37,30 +33,33 @@ def pytest_configure(config):
pytestPDB._config = None
pytestPDB._pdb_cls = pdb.Pdb
- pdb.set_trace = pytest.set_trace
+ pdb.set_trace = pytestPDB.set_trace
pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config
+ pytestPDB._pdb_cls = pdb_cls
config._cleanup.append(fin)
+
class pytestPDB:
""" Pseudo PDB that defers to the real pdb. """
_pluginmanager = None
_config = None
_pdb_cls = pdb.Pdb
- def set_trace(self):
+ @classmethod
+ def set_trace(cls):
""" invoke PDB set_trace debugging, dropping any IO capturing. """
import _pytest.config
frame = sys._getframe().f_back
- if self._pluginmanager is not None:
- capman = self._pluginmanager.getplugin("capturemanager")
+ if cls._pluginmanager is not None:
+ capman = cls._pluginmanager.getplugin("capturemanager")
if capman:
capman.suspendcapture(in_=True)
- tw = _pytest.config.create_terminal_writer(self._config)
+ tw = _pytest.config.create_terminal_writer(cls._config)
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
- self._pluginmanager.hook.pytest_enter_pdb(config=self._config)
- self._pdb_cls().set_trace(frame)
+ cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config)
+ cls._pdb_cls().set_trace(frame)
class PdbInvoke:
@@ -74,7 +73,7 @@ class PdbInvoke:
def pytest_internalerror(self, excrepr, excinfo):
for line in str(excrepr).split("\n"):
- sys.stderr.write("INTERNALERROR> %s\n" %line)
+ sys.stderr.write("INTERNALERROR> %s\n" % line)
sys.stderr.flush()
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
diff --git a/lib/spack/external/_pytest/deprecated.py b/lib/spack/external/_pytest/deprecated.py
index 6edc475f6e..38e9496778 100644
--- a/lib/spack/external/_pytest/deprecated.py
+++ b/lib/spack/external/_pytest/deprecated.py
@@ -5,10 +5,15 @@ that is planned to be removed in the next pytest release.
Keeping it in a central location makes it easy to track what is deprecated and should
be removed when the time comes.
"""
+from __future__ import absolute_import, division, print_function
+
+
+class RemovedInPytest4Warning(DeprecationWarning):
+ """warning class for features removed in pytest 4.0"""
MAIN_STR_ARGS = 'passing a string to pytest.main() is deprecated, ' \
- 'pass a list of arguments instead.'
+ 'pass a list of arguments instead.'
YIELD_TESTS = 'yield tests are deprecated, and scheduled to be removed in pytest 4.0'
@@ -21,4 +26,17 @@ SETUP_CFG_PYTEST = '[pytest] section in setup.cfg files is deprecated, use [tool
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"
-RESULT_LOG = '--result-log is deprecated and scheduled for removal in pytest 4.0'
+RESULT_LOG = (
+ '--result-log is deprecated and scheduled for removal in pytest 4.0.\n'
+ 'See https://docs.pytest.org/en/latest/usage.html#creating-resultlog-format-files for more information.'
+)
+
+MARK_INFO_ATTRIBUTE = RemovedInPytest4Warning(
+ "MarkInfo objects are deprecated as they contain the merged marks"
+)
+
+MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning(
+ "Applying marks directly to parameters is deprecated,"
+ " please use pytest.param(..., marks=...) instead.\n"
+ "For more details, see: https://docs.pytest.org/en/latest/parametrize.html"
+)
diff --git a/lib/spack/external/_pytest/doctest.py b/lib/spack/external/_pytest/doctest.py
index f4782dded5..4c05acddf7 100644
--- a/lib/spack/external/_pytest/doctest.py
+++ b/lib/spack/external/_pytest/doctest.py
@@ -1,5 +1,5 @@
""" discover and run doctests in modules and test files."""
-from __future__ import absolute_import
+from __future__ import absolute_import, division, print_function
import traceback
@@ -22,27 +22,29 @@ DOCTEST_REPORT_CHOICES = (
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE,
)
+
def pytest_addoption(parser):
parser.addini('doctest_optionflags', 'option flags for doctests',
- type="args", default=["ELLIPSIS"])
+ type="args", default=["ELLIPSIS"])
+ parser.addini("doctest_encoding", 'encoding used for doctest files', default="utf-8")
group = parser.getgroup("collect")
group.addoption("--doctest-modules",
- action="store_true", default=False,
- help="run doctests in all .py modules",
- dest="doctestmodules")
+ action="store_true", default=False,
+ help="run doctests in all .py modules",
+ dest="doctestmodules")
group.addoption("--doctest-report",
- type=str.lower, default="udiff",
- help="choose another output format for diffs on doctest failure",
- choices=DOCTEST_REPORT_CHOICES,
- dest="doctestreport")
+ type=str.lower, default="udiff",
+ help="choose another output format for diffs on doctest failure",
+ choices=DOCTEST_REPORT_CHOICES,
+ dest="doctestreport")
group.addoption("--doctest-glob",
- action="append", default=[], metavar="pat",
- help="doctests file matching pattern, default: test*.txt",
- dest="doctestglob")
+ action="append", default=[], metavar="pat",
+ help="doctests file matching pattern, default: test*.txt",
+ dest="doctestglob")
group.addoption("--doctest-ignore-import-errors",
- action="store_true", default=False,
- help="ignore doctest ImportErrors",
- dest="doctest_ignore_import_errors")
+ action="store_true", default=False,
+ help="ignore doctest ImportErrors",
+ dest="doctest_ignore_import_errors")
def pytest_collect_file(path, parent):
@@ -118,7 +120,7 @@ class DoctestItem(pytest.Item):
lines = ["%03d %s" % (i + test.lineno + 1, x)
for (i, x) in enumerate(lines)]
# trim docstring error lines to 10
- lines = lines[example.lineno - 9:example.lineno + 1]
+ lines = lines[max(example.lineno - 9, 0):example.lineno + 1]
else:
lines = ['EXAMPLE LOCATION UNKNOWN, not showing all tests of that example']
indent = '>>>'
@@ -127,18 +129,18 @@ class DoctestItem(pytest.Item):
indent = '...'
if excinfo.errisinstance(doctest.DocTestFailure):
lines += checker.output_difference(example,
- doctestfailure.got, report_choice).split("\n")
+ doctestfailure.got, report_choice).split("\n")
else:
inner_excinfo = ExceptionInfo(excinfo.value.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" %
- repr(inner_excinfo.value)]
+ repr(inner_excinfo.value)]
lines += traceback.format_exception(*excinfo.value.exc_info)
return ReprFailDoctest(reprlocation, lines)
else:
return super(DoctestItem, self).repr_failure(excinfo)
def reportinfo(self):
- return self.fspath, None, "[doctest] %s" % self.name
+ return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name
def _get_flag_lookup():
@@ -171,15 +173,16 @@ class DoctestTextfile(pytest.Module):
# inspired by doctest.testfile; ideally we would use it directly,
# but it doesn't support passing a custom checker
- text = self.fspath.read()
+ encoding = self.config.getini("doctest_encoding")
+ text = self.fspath.read_text(encoding)
filename = str(self.fspath)
name = self.fspath.basename
globs = {'__name__': '__main__'}
-
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_checker())
+ _fix_spoof_python2(runner, encoding)
parser = doctest.DocTestParser()
test = parser.get_doctest(text, globs, name, filename, 0)
@@ -215,6 +218,7 @@ class DoctestModule(pytest.Module):
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_checker())
+
for test in finder.find(module, module.__name__):
if test.examples: # skip empty doctests
yield DoctestItem(test.name, self, runner, test)
@@ -323,6 +327,33 @@ def _get_report_choice(key):
DOCTEST_REPORT_CHOICE_NONE: 0,
}[key]
+
+def _fix_spoof_python2(runner, encoding):
+ """
+ Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. This
+ should patch only doctests for text files because they don't have a way to declare their
+ encoding. Doctests in docstrings from Python modules don't have the same problem given that
+ Python already decoded the strings.
+
+ This fixes the problem related in issue #2434.
+ """
+ from _pytest.compat import _PY2
+ if not _PY2:
+ return
+
+ from doctest import _SpoofOut
+
+ class UnicodeSpoof(_SpoofOut):
+
+ def getvalue(self):
+ result = _SpoofOut.getvalue(self)
+ if encoding:
+ result = result.decode(encoding)
+ return result
+
+ runner._fakeout = UnicodeSpoof()
+
+
@pytest.fixture(scope='session')
def doctest_namespace():
"""
diff --git a/lib/spack/external/_pytest/fixtures.py b/lib/spack/external/_pytest/fixtures.py
index 28bcd4d8d7..98317a4889 100644
--- a/lib/spack/external/_pytest/fixtures.py
+++ b/lib/spack/external/_pytest/fixtures.py
@@ -1,22 +1,36 @@
-import sys
+from __future__ import absolute_import, division, print_function
-from py._code.code import FormattedExcinfo
+import inspect
+import sys
+import warnings
import py
-import pytest
-import warnings
+from py._code.code import FormattedExcinfo
-import inspect
import _pytest
+from _pytest import nodes
from _pytest._code.code import TerminalRepr
from _pytest.compat import (
NOTSET, exc_clear, _format_args,
getfslineno, get_real_func,
is_generator, isclass, getimfunc,
getlocation, getfuncargnames,
+ safe_getattr,
+ FuncargnamesCompatAttr,
)
+from _pytest.outcomes import fail, TEST_OUTCOME
+
+
+from ordereddict_backport import OrderedDict
+
def pytest_sessionstart(session):
+ import _pytest.python
+ scopename2class.update({
+ 'class': _pytest.python.Class,
+ 'module': _pytest.python.Module,
+ 'function': _pytest.main.Item,
+ })
session._fixturemanager = FixtureManager(session)
@@ -29,6 +43,7 @@ scope2props["class"] = scope2props["module"] + ("cls",)
scope2props["instance"] = scope2props["class"] + ("instance", )
scope2props["function"] = scope2props["instance"] + ("function", "keywords")
+
def scopeproperty(name=None, doc=None):
def decoratescope(func):
scopename = name or func.__name__
@@ -43,19 +58,6 @@ def scopeproperty(name=None, doc=None):
return decoratescope
-def pytest_namespace():
- scopename2class.update({
- 'class': pytest.Class,
- 'module': pytest.Module,
- 'function': pytest.Item,
- })
- return {
- 'fixture': fixture,
- 'yield_fixture': yield_fixture,
- 'collect': {'_fillfuncargs': fillfixtures}
- }
-
-
def get_scope_node(node, scope):
cls = scopename2class.get(scope)
if cls is None:
@@ -73,7 +75,7 @@ def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
# XXX we can probably avoid this algorithm if we modify CallSpec2
# to directly care for creating the fixturedefs within its methods.
if not metafunc._calls[0].funcargs:
- return # this function call does not have direct parametrization
+ return # this function call does not have direct parametrization
# collect funcargs of all callspecs into a list of values
arg2params = {}
arg2scope = {}
@@ -103,36 +105,32 @@ def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
if scope != "function":
node = get_scope_node(collector, scope)
if node is None:
- assert scope == "class" and isinstance(collector, pytest.Module)
+ assert scope == "class" and isinstance(collector, _pytest.python.Module)
# use module-level collector for class-scope (for now)
node = collector
if node and argname in node._name2pseudofixturedef:
arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
else:
- fixturedef = FixtureDef(fixturemanager, '', argname,
- get_direct_param_fixture_func,
- arg2scope[argname],
- valuelist, False, False)
+ fixturedef = FixtureDef(fixturemanager, '', argname,
+ get_direct_param_fixture_func,
+ arg2scope[argname],
+ valuelist, False, False)
arg2fixturedefs[argname] = [fixturedef]
if node is not None:
node._name2pseudofixturedef[argname] = fixturedef
-
def getfixturemarker(obj):
""" return fixturemarker or None if it doesn't exist or raised
exceptions."""
try:
return getattr(obj, "_pytestfixturefunction", None)
- except KeyboardInterrupt:
- raise
- except Exception:
+ except TEST_OUTCOME:
# some objects raise errors like request (from flask import request)
# we don't expect them to be fixture functions
return None
-
def get_parametrized_fixture_keys(item, scopenum):
""" return list of keys for all parametrized arguments which match
the specified scope. """
@@ -142,10 +140,10 @@ def get_parametrized_fixture_keys(item, scopenum):
except AttributeError:
pass
else:
- # cs.indictes.items() is random order of argnames but
- # then again different functions (items) can change order of
- # arguments so it doesn't matter much probably
- for argname, param_index in cs.indices.items():
+ # cs.indices.items() is random order of argnames. Need to
+ # sort this so that different calls to
+ # get_parametrized_fixture_keys will be deterministic.
+ for argname, param_index in sorted(cs.indices.items()):
if cs._arg2scopenum[argname] != scopenum:
continue
if scopenum == 0: # session
@@ -167,20 +165,21 @@ def reorder_items(items):
for scopenum in range(0, scopenum_function):
argkeys_cache[scopenum] = d = {}
for item in items:
- keys = set(get_parametrized_fixture_keys(item, scopenum))
+ keys = OrderedDict.fromkeys(get_parametrized_fixture_keys(item, scopenum))
if keys:
d[item] = keys
return reorder_items_atscope(items, set(), argkeys_cache, 0)
+
def reorder_items_atscope(items, ignore, argkeys_cache, scopenum):
if scopenum >= scopenum_function or len(items) < 3:
return items
items_done = []
while 1:
items_before, items_same, items_other, newignore = \
- slice_items(items, ignore, argkeys_cache[scopenum])
+ slice_items(items, ignore, argkeys_cache[scopenum])
items_before = reorder_items_atscope(
- items_before, ignore, argkeys_cache,scopenum+1)
+ items_before, ignore, argkeys_cache, scopenum + 1)
if items_same is None:
# nothing to reorder in this scope
assert items_other is None
@@ -201,9 +200,9 @@ def slice_items(items, ignore, scoped_argkeys_cache):
for i, item in enumerate(it):
argkeys = scoped_argkeys_cache.get(item)
if argkeys is not None:
- argkeys = argkeys.difference(ignore)
- if argkeys: # found a slicing key
- slicing_argkey = argkeys.pop()
+ newargkeys = OrderedDict.fromkeys(k for k in argkeys if k not in ignore)
+ if newargkeys: # found a slicing key
+ slicing_argkey, _ = newargkeys.popitem()
items_before = items[:i]
items_same = [item]
items_other = []
@@ -211,7 +210,7 @@ def slice_items(items, ignore, scoped_argkeys_cache):
for item in it:
argkeys = scoped_argkeys_cache.get(item)
if argkeys and slicing_argkey in argkeys and \
- slicing_argkey not in ignore:
+ slicing_argkey not in ignore:
items_same.append(item)
else:
items_other.append(item)
@@ -221,17 +220,6 @@ def slice_items(items, ignore, scoped_argkeys_cache):
return items, None, None, None
-
-class FuncargnamesCompatAttr:
- """ helper class so that Metafunc, Function and FixtureRequest
- don't need to each define the "funcargnames" compatibility attribute.
- """
- @property
- def funcargnames(self):
- """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
- return self.fixturenames
-
-
def fillfixtures(function):
""" fill missing funcargs for a test function. """
try:
@@ -254,10 +242,10 @@ def fillfixtures(function):
request._fillfixtures()
-
def get_direct_param_fixture_func(request):
return request.param
+
class FuncFixtureInfo:
def __init__(self, argnames, names_closure, name2fixturedefs):
self.argnames = argnames
@@ -296,7 +284,6 @@ class FixtureRequest(FuncargnamesCompatAttr):
""" underlying collection node (depends on current request scope)"""
return self._getscopeitem(self.scope)
-
def _getnextfixturedef(self, argname):
fixturedefs = self._arg2fixturedefs.get(argname, None)
if fixturedefs is None:
@@ -318,7 +305,6 @@ class FixtureRequest(FuncargnamesCompatAttr):
""" the pytest config object associated with this request. """
return self._pyfuncitem.config
-
@scopeproperty()
def function(self):
""" test function object if the request has a per-function scope. """
@@ -327,7 +313,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
@scopeproperty("class")
def cls(self):
""" class (can be None) where the test function was collected. """
- clscol = self._pyfuncitem.getparent(pytest.Class)
+ clscol = self._pyfuncitem.getparent(_pytest.python.Class)
if clscol:
return clscol.obj
@@ -345,7 +331,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
@scopeproperty()
def module(self):
""" python module object where the test function was collected. """
- return self._pyfuncitem.getparent(pytest.Module).obj
+ return self._pyfuncitem.getparent(_pytest.python.Module).obj
@scopeproperty()
def fspath(self):
@@ -414,7 +400,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
:arg extrakey: added to internal caching key of (funcargname, scope).
"""
if not hasattr(self.config, '_setupcache'):
- self.config._setupcache = {} # XXX weakref?
+ self.config._setupcache = {} # XXX weakref?
cachekey = (self.fixturename, self._getscopeitem(scope), extrakey)
cache = self.config._setupcache
try:
@@ -445,7 +431,8 @@ class FixtureRequest(FuncargnamesCompatAttr):
from _pytest import deprecated
warnings.warn(
deprecated.GETFUNCARGVALUE,
- DeprecationWarning)
+ DeprecationWarning,
+ stacklevel=2)
return self.getfixturevalue(argname)
def _get_active_fixturedef(self, argname):
@@ -470,13 +457,13 @@ class FixtureRequest(FuncargnamesCompatAttr):
def _get_fixturestack(self):
current = self
- l = []
+ values = []
while 1:
fixturedef = getattr(current, "_fixturedef", None)
if fixturedef is None:
- l.reverse()
- return l
- l.append(fixturedef)
+ values.reverse()
+ return values
+ values.append(fixturedef)
current = current._parent_request
def _getfixturevalue(self, fixturedef):
@@ -508,7 +495,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
source_lineno,
)
)
- pytest.fail(msg)
+ fail(msg)
else:
# indices might not be set if old-style metafunc.addcall() was used
param_index = funcitem.callspec.indices.get(argname, 0)
@@ -541,11 +528,11 @@ class FixtureRequest(FuncargnamesCompatAttr):
if scopemismatch(invoking_scope, requested_scope):
# try to report something helpful
lines = self._factorytraceback()
- pytest.fail("ScopeMismatch: You tried to access the %r scoped "
- "fixture %r with a %r scoped request object, "
- "involved factories\n%s" %(
- (requested_scope, argname, invoking_scope, "\n".join(lines))),
- pytrace=False)
+ fail("ScopeMismatch: You tried to access the %r scoped "
+ "fixture %r with a %r scoped request object, "
+ "involved factories\n%s" % (
+ (requested_scope, argname, invoking_scope, "\n".join(lines))),
+ pytrace=False)
def _factorytraceback(self):
lines = []
@@ -554,7 +541,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
fs, lineno = getfslineno(factory)
p = self._pyfuncitem.session.fspath.bestrelpath(fs)
args = _format_args(factory)
- lines.append("%s:%d: def %s%s" %(
+ lines.append("%s:%d: def %s%s" % (
p, lineno, factory.__name__, args))
return lines
@@ -570,12 +557,13 @@ class FixtureRequest(FuncargnamesCompatAttr):
return node
def __repr__(self):
- return "<FixtureRequest for %r>" %(self.node)
+ return "<FixtureRequest for %r>" % (self.node)
class SubRequest(FixtureRequest):
""" a sub request for handling getting a fixture from a
test function/fixture. """
+
def __init__(self, request, scope, param, param_index, fixturedef):
self._parent_request = request
self.fixturename = fixturedef.argname
@@ -584,9 +572,8 @@ class SubRequest(FixtureRequest):
self.param_index = param_index
self.scope = scope
self._fixturedef = fixturedef
- self.addfinalizer = fixturedef.addfinalizer
self._pyfuncitem = request._pyfuncitem
- self._fixture_values = request._fixture_values
+ self._fixture_values = request._fixture_values
self._fixture_defs = request._fixture_defs
self._arg2fixturedefs = request._arg2fixturedefs
self._arg2index = request._arg2index
@@ -595,6 +582,9 @@ class SubRequest(FixtureRequest):
def __repr__(self):
return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
+ def addfinalizer(self, finalizer):
+ self._fixturedef.addfinalizer(finalizer)
+
class ScopeMismatchError(Exception):
""" A fixture function tries to use a different fixture function which
@@ -626,6 +616,7 @@ def scope2index(scope, descr, where=None):
class FixtureLookupError(LookupError):
""" could not return a requested Fixture (missing or invalid). """
+
def __init__(self, argname, request, msg=None):
self.argname = argname
self.request = request
@@ -648,9 +639,9 @@ class FixtureLookupError(LookupError):
lines, _ = inspect.getsourcelines(get_real_func(function))
except (IOError, IndexError, TypeError):
error_msg = "file %s, line %s: source code not available"
- addline(error_msg % (fspath, lineno+1))
+ addline(error_msg % (fspath, lineno + 1))
else:
- addline("file %s, line %s" % (fspath, lineno+1))
+ addline("file %s, line %s" % (fspath, lineno + 1))
for i, line in enumerate(lines):
line = line.rstrip()
addline(" " + line)
@@ -666,7 +657,7 @@ class FixtureLookupError(LookupError):
if faclist and name not in available:
available.append(name)
msg = "fixture %r not found" % (self.argname,)
- msg += "\n available fixtures: %s" %(", ".join(sorted(available)),)
+ msg += "\n available fixtures: %s" % (", ".join(sorted(available)),)
msg += "\n use 'pytest --fixtures [testpath]' for help on them."
return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
@@ -692,15 +683,16 @@ class FixtureLookupErrorRepr(TerminalRepr):
tw.line('{0} {1}'.format(FormattedExcinfo.flow_marker,
line.strip()), red=True)
tw.line()
- tw.line("%s:%d" % (self.filename, self.firstlineno+1))
+ tw.line("%s:%d" % (self.filename, self.firstlineno + 1))
def fail_fixturefunc(fixturefunc, msg):
fs, lineno = getfslineno(fixturefunc)
- location = "%s:%s" % (fs, lineno+1)
+ location = "%s:%s" % (fs, lineno + 1)
source = _pytest._code.Source(fixturefunc)
- pytest.fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
- pytrace=False)
+ fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
+ pytrace=False)
+
def call_fixture_func(fixturefunc, request, kwargs):
yieldctx = is_generator(fixturefunc)
@@ -715,7 +707,7 @@ def call_fixture_func(fixturefunc, request, kwargs):
pass
else:
fail_fixturefunc(fixturefunc,
- "yield_fixture function has more than one 'yield'")
+ "yield_fixture function has more than one 'yield'")
request.addfinalizer(teardown)
else:
@@ -725,6 +717,7 @@ def call_fixture_func(fixturefunc, request, kwargs):
class FixtureDef:
""" A container for a factory definition. """
+
def __init__(self, fixturemanager, baseid, argname, func, scope, params,
unittest=False, ids=None):
self._fixturemanager = fixturemanager
@@ -749,10 +742,19 @@ class FixtureDef:
self._finalizer.append(finalizer)
def finish(self):
+ exceptions = []
try:
while self._finalizer:
- func = self._finalizer.pop()
- func()
+ try:
+ func = self._finalizer.pop()
+ func()
+ except: # noqa
+ exceptions.append(sys.exc_info())
+ if exceptions:
+ e = exceptions[0]
+ del exceptions # ensure we don't keep all frames alive because of the traceback
+ py.builtin._reraise(*e)
+
finally:
ihook = self._fixturemanager.session.ihook
ihook.pytest_fixture_post_finalizer(fixturedef=self)
@@ -790,6 +792,7 @@ class FixtureDef:
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
(self.argname, self.scope, self.baseid))
+
def pytest_fixture_setup(fixturedef, request):
""" Execution of fixture setup. """
kwargs = {}
@@ -815,7 +818,7 @@ def pytest_fixture_setup(fixturedef, request):
my_cache_key = request.param_index
try:
result = call_fixture_func(fixturefunc, request, kwargs)
- except Exception:
+ except TEST_OUTCOME:
fixturedef.cached_result = (None, my_cache_key, sys.exc_info())
raise
fixturedef.cached_result = (result, my_cache_key, None)
@@ -833,17 +836,16 @@ class FixtureFunctionMarker:
def __call__(self, function):
if isclass(function):
raise ValueError(
- "class fixtures not supported (may be in the future)")
+ "class fixtures not supported (may be in the future)")
function._pytestfixturefunction = self
return function
-
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
""" (return a) decorator to mark a fixture factory function.
- This decorator can be used (with or or without parameters) to define
- a fixture function. The name of the fixture function can later be
+ This decorator can be used (with or without parameters) to define a
+ fixture function. The name of the fixture function can later be
referenced to cause its invocation ahead of running tests: test
modules or classes can use the pytest.mark.usefixtures(fixturename)
marker. Test functions can directly use fixture names as input
@@ -862,25 +864,25 @@ def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
reference is needed to activate the fixture.
:arg ids: list of string ids each corresponding to the params
- so that they are part of the test id. If no ids are provided
- they will be generated automatically from the params.
+ so that they are part of the test id. If no ids are provided
+ they will be generated automatically from the params.
:arg name: the name of the fixture. This defaults to the name of the
- decorated function. If a fixture is used in the same module in
- which it is defined, the function name of the fixture will be
- shadowed by the function arg that requests the fixture; one way
- to resolve this is to name the decorated function
- ``fixture_<fixturename>`` and then use
- ``@pytest.fixture(name='<fixturename>')``.
+ decorated function. If a fixture is used in the same module in
+ which it is defined, the function name of the fixture will be
+ shadowed by the function arg that requests the fixture; one way
+ to resolve this is to name the decorated function
+ ``fixture_<fixturename>`` and then use
+ ``@pytest.fixture(name='<fixturename>')``.
Fixtures can optionally provide their values to test functions using a ``yield`` statement,
instead of ``return``. In this case, the code block after the ``yield`` statement is executed
as teardown code regardless of the test outcome. A fixture function must yield exactly once.
"""
- if callable(scope) and params is None and autouse == False:
+ if callable(scope) and params is None and autouse is False:
# direct decoration
return FixtureFunctionMarker(
- "function", params, autouse, name=name)(scope)
+ "function", params, autouse, name=name)(scope)
if params is not None and not isinstance(params, (list, tuple)):
params = list(params)
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
@@ -895,7 +897,7 @@ def yield_fixture(scope="function", params=None, autouse=False, ids=None, name=N
if callable(scope) and params is None and not autouse:
# direct decoration
return FixtureFunctionMarker(
- "function", params, autouse, ids=ids, name=name)(scope)
+ "function", params, autouse, ids=ids, name=name)(scope)
else:
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
@@ -954,14 +956,9 @@ class FixtureManager:
self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))]
session.config.pluginmanager.register(self, "funcmanage")
-
def getfixtureinfo(self, node, func, cls, funcargs=True):
if funcargs and not hasattr(node, "nofuncargs"):
- if cls is not None:
- startindex = 1
- else:
- startindex = None
- argnames = getfuncargnames(func, startindex)
+ argnames = getfuncargnames(func, cls=cls)
else:
argnames = ()
usefixtures = getattr(func, "usefixtures", None)
@@ -985,8 +982,8 @@ class FixtureManager:
# by their test id)
if p.basename.startswith("conftest.py"):
nodeid = p.dirpath().relto(self.config.rootdir)
- if p.sep != "/":
- nodeid = nodeid.replace(p.sep, "/")
+ if p.sep != nodes.SEP:
+ nodeid = nodeid.replace(p.sep, nodes.SEP)
self.parsefactories(plugin, nodeid)
def _getautousenames(self, nodeid):
@@ -996,7 +993,7 @@ class FixtureManager:
if nodeid.startswith(baseid):
if baseid:
i = len(baseid)
- nextchar = nodeid[i:i+1]
+ nextchar = nodeid[i:i + 1]
if nextchar and nextchar not in ":/":
continue
autousenames.extend(basenames)
@@ -1041,9 +1038,14 @@ class FixtureManager:
if faclist:
fixturedef = faclist[-1]
if fixturedef.params is not None:
- func_params = getattr(getattr(metafunc.function, 'parametrize', None), 'args', [[None]])
+ parametrize_func = getattr(metafunc.function, 'parametrize', None)
+ func_params = getattr(parametrize_func, 'args', [[None]])
+ func_kwargs = getattr(parametrize_func, 'kwargs', {})
# skip directly parametrized arguments
- argnames = func_params[0]
+ if "argnames" in func_kwargs:
+ argnames = parametrize_func.kwargs["argnames"]
+ else:
+ argnames = func_params[0]
if not isinstance(argnames, (tuple, list)):
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
if argname not in func_params and argname not in argnames:
@@ -1068,7 +1070,9 @@ class FixtureManager:
self._holderobjseen.add(holderobj)
autousenames = []
for name in dir(holderobj):
- obj = getattr(holderobj, name, None)
+ # The attribute can be an arbitrary descriptor, so the attribute
+ # access below can raise. safe_getatt() ignores such exceptions.
+ obj = safe_getattr(holderobj, name, None)
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
# or are "@pytest.fixture" marked
marker = getfixturemarker(obj)
@@ -1079,7 +1083,7 @@ class FixtureManager:
continue
marker = defaultfuncargprefixmarker
from _pytest import deprecated
- self.config.warn('C1', deprecated.FUNCARG_PREFIX.format(name=name))
+ self.config.warn('C1', deprecated.FUNCARG_PREFIX.format(name=name), nodeid=nodeid)
name = name[len(self._argprefix):]
elif not isinstance(marker, FixtureFunctionMarker):
# magic globals with __getattr__ might have got us a wrong
@@ -1129,6 +1133,5 @@ class FixtureManager:
def _matchfactories(self, fixturedefs, nodeid):
for fixturedef in fixturedefs:
- if nodeid.startswith(fixturedef.baseid):
+ if nodes.ischildnode(fixturedef.baseid, nodeid):
yield fixturedef
-
diff --git a/lib/spack/external/_pytest/freeze_support.py b/lib/spack/external/_pytest/freeze_support.py
index b27f59d74a..97147a8825 100644
--- a/lib/spack/external/_pytest/freeze_support.py
+++ b/lib/spack/external/_pytest/freeze_support.py
@@ -2,9 +2,7 @@
Provides a function to report all internal modules for using freezing tools
pytest
"""
-
-def pytest_namespace():
- return {'freeze_includes': freeze_includes}
+from __future__ import absolute_import, division, print_function
def freeze_includes():
diff --git a/lib/spack/external/_pytest/helpconfig.py b/lib/spack/external/_pytest/helpconfig.py
index 6e66b11c48..e744637f86 100644
--- a/lib/spack/external/_pytest/helpconfig.py
+++ b/lib/spack/external/_pytest/helpconfig.py
@@ -1,25 +1,61 @@
""" version info, help messages, tracing configuration. """
+from __future__ import absolute_import, division, print_function
+
import py
import pytest
-import os, sys
+from _pytest.config import PrintHelp
+import os
+import sys
+from argparse import Action
+
+
+class HelpAction(Action):
+ """This is an argparse Action that will raise an exception in
+ order to skip the rest of the argument parsing when --help is passed.
+ This prevents argparse from quitting due to missing required arguments
+ when any are defined, for example by ``pytest_addoption``.
+ This is similar to the way that the builtin argparse --help option is
+ implemented by raising SystemExit.
+ """
+
+ def __init__(self,
+ option_strings,
+ dest=None,
+ default=False,
+ help=None):
+ super(HelpAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ const=True,
+ default=default,
+ nargs=0,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, self.const)
+
+ # We should only skip the rest of the parsing after preparse is done
+ if getattr(parser._parser, 'after_preparse', False):
+ raise PrintHelp
+
def pytest_addoption(parser):
group = parser.getgroup('debugconfig')
group.addoption('--version', action="store_true",
- help="display pytest lib version and import information.")
- group._addoption("-h", "--help", action="store_true", dest="help",
- help="show help message and configuration info")
- group._addoption('-p', action="append", dest="plugins", default = [],
- metavar="name",
- help="early-load given plugin (multi-allowed). "
- "To avoid loading of plugins, use the `no:` prefix, e.g. "
- "`no:doctest`.")
+ help="display pytest lib version and import information.")
+ group._addoption("-h", "--help", action=HelpAction, dest="help",
+ help="show help message and configuration info")
+ group._addoption('-p', action="append", dest="plugins", default=[],
+ metavar="name",
+ help="early-load given plugin (multi-allowed). "
+ "To avoid loading of plugins, use the `no:` prefix, e.g. "
+ "`no:doctest`.")
group.addoption('--traceconfig', '--trace-config',
- action="store_true", default=False,
- help="trace considerations of conftest.py files."),
+ action="store_true", default=False,
+ help="trace considerations of conftest.py files."),
group.addoption('--debug',
- action="store_true", dest="debug", default=False,
- help="store internal tracing debug information in 'pytestdebug.log'.")
+ action="store_true", dest="debug", default=False,
+ help="store internal tracing debug information in 'pytestdebug.log'.")
group._addoption(
'-o', '--override-ini', nargs='*', dest="override_ini",
action="append",
@@ -34,10 +70,10 @@ def pytest_cmdline_parse():
path = os.path.abspath("pytestdebug.log")
debugfile = open(path, 'w')
debugfile.write("versions pytest-%s, py-%s, "
- "python-%s\ncwd=%s\nargs=%s\n\n" %(
- pytest.__version__, py.__version__,
- ".".join(map(str, sys.version_info)),
- os.getcwd(), config._origargs))
+ "python-%s\ncwd=%s\nargs=%s\n\n" % (
+ pytest.__version__, py.__version__,
+ ".".join(map(str, sys.version_info)),
+ os.getcwd(), config._origargs))
config.trace.root.setwriter(debugfile.write)
undo_tracing = config.pluginmanager.enable_tracing()
sys.stderr.write("writing pytestdebug information to %s\n" % path)
@@ -51,11 +87,12 @@ def pytest_cmdline_parse():
config.add_cleanup(unset_tracing)
+
def pytest_cmdline_main(config):
if config.option.version:
p = py.path.local(pytest.__file__)
sys.stderr.write("This is pytest version %s, imported from %s\n" %
- (pytest.__version__, p))
+ (pytest.__version__, p))
plugininfo = getpluginversioninfo(config)
if plugininfo:
for line in plugininfo:
@@ -67,6 +104,7 @@ def pytest_cmdline_main(config):
config._ensure_unconfigure()
return 0
+
def showhelp(config):
reporter = config.pluginmanager.get_plugin('terminalreporter')
tw = reporter._tw
@@ -82,7 +120,7 @@ def showhelp(config):
if type is None:
type = "string"
spec = "%s (%s)" % (name, type)
- line = " %-24s %s" %(spec, help)
+ line = " %-24s %s" % (spec, help)
tw.line(line[:tw.fullwidth])
tw.line()
@@ -111,6 +149,7 @@ conftest_options = [
('pytest_plugins', 'list of plugin names to load'),
]
+
def getpluginversioninfo(config):
lines = []
plugininfo = config.pluginmanager.list_plugin_distinfo()
@@ -122,11 +161,12 @@ def getpluginversioninfo(config):
lines.append(" " + content)
return lines
+
def pytest_report_header(config):
lines = []
if config.option.debug or config.option.traceconfig:
lines.append("using: pytest-%s pylib-%s" %
- (pytest.__version__,py.__version__))
+ (pytest.__version__, py.__version__))
verinfo = getpluginversioninfo(config)
if verinfo:
@@ -140,5 +180,5 @@ def pytest_report_header(config):
r = plugin.__file__
else:
r = repr(plugin)
- lines.append(" %-20s: %s" %(name, r))
+ lines.append(" %-20s: %s" % (name, r))
return lines
diff --git a/lib/spack/external/_pytest/hookspec.py b/lib/spack/external/_pytest/hookspec.py
index b5f51eccf5..e5c966e58b 100644
--- a/lib/spack/external/_pytest/hookspec.py
+++ b/lib/spack/external/_pytest/hookspec.py
@@ -8,6 +8,7 @@ hookspec = HookspecMarker("pytest")
# Initialization hooks called for every plugin
# -------------------------------------------------------------------------
+
@hookspec(historic=True)
def pytest_addhooks(pluginmanager):
"""called at plugin registration time to allow adding new hooks via a call to
@@ -16,11 +17,14 @@ def pytest_addhooks(pluginmanager):
@hookspec(historic=True)
def pytest_namespace():
- """return dict of name->object to be made globally available in
+ """
+ DEPRECATED: this hook causes direct monkeypatching on pytest, its use is strongly discouraged
+ return dict of name->object to be made globally available in
the pytest namespace. This hook is called at plugin registration
time.
"""
+
@hookspec(historic=True)
def pytest_plugin_registered(plugin, manager):
""" a new pytest plugin got registered. """
@@ -56,11 +60,20 @@ def pytest_addoption(parser):
via (deprecated) ``pytest.config``.
"""
+
@hookspec(historic=True)
def pytest_configure(config):
- """ called after command line options have been parsed
- and all plugins and initial conftest files been loaded.
- This hook is called for every plugin.
+ """
+ Allows plugins and conftest files to perform initial configuration.
+
+ This hook is called for every plugin and initial conftest file
+ after command line options have been parsed.
+
+ After that, the hook is called for other conftest files as they are
+ imported.
+
+ :arg config: pytest config object
+ :type config: _pytest.config.Config
"""
# -------------------------------------------------------------------------
@@ -69,17 +82,25 @@ def pytest_configure(config):
# discoverable conftest.py local plugins.
# -------------------------------------------------------------------------
+
@hookspec(firstresult=True)
def pytest_cmdline_parse(pluginmanager, args):
- """return initialized config object, parsing the specified args. """
+ """return initialized config object, parsing the specified args.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_cmdline_preparse(config, args):
"""(deprecated) modify command line arguments before option parsing. """
+
@hookspec(firstresult=True)
def pytest_cmdline_main(config):
""" called for performing the main command line action. The default
- implementation will invoke the configure hooks and runtest_mainloop. """
+ implementation will invoke the configure hooks and runtest_mainloop.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_load_initial_conftests(early_config, parser, args):
""" implements the loading of initial conftest files ahead
@@ -92,88 +113,124 @@ def pytest_load_initial_conftests(early_config, parser, args):
@hookspec(firstresult=True)
def pytest_collection(session):
- """ perform the collection protocol for the given session. """
+ """ perform the collection protocol for the given session.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_collection_modifyitems(session, config, items):
""" called after collection has been performed, may filter or re-order
the items in-place."""
+
def pytest_collection_finish(session):
""" called after collection has been performed and modified. """
+
@hookspec(firstresult=True)
def pytest_ignore_collect(path, config):
""" return True to prevent considering this path for collection.
This hook is consulted for all files and directories prior to calling
more specific hooks.
+
+ Stops at first non-None result, see :ref:`firstresult`
"""
+
@hookspec(firstresult=True)
def pytest_collect_directory(path, parent):
- """ called before traversing a directory for collection files. """
+ """ called before traversing a directory for collection files.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_collect_file(path, parent):
""" return collection Node or None for the given path. Any new node
needs to have the specified ``parent`` as a parent."""
# logging hooks for collection
+
+
def pytest_collectstart(collector):
""" collector starts collecting. """
+
def pytest_itemcollected(item):
""" we just collected a test item. """
+
def pytest_collectreport(report):
""" collector finished collecting. """
+
def pytest_deselected(items):
""" called for test items deselected by keyword. """
+
@hookspec(firstresult=True)
def pytest_make_collect_report(collector):
- """ perform ``collector.collect()`` and return a CollectReport. """
+ """ perform ``collector.collect()`` and return a CollectReport.
+
+ Stops at first non-None result, see :ref:`firstresult` """
# -------------------------------------------------------------------------
# Python test function related hooks
# -------------------------------------------------------------------------
+
@hookspec(firstresult=True)
def pytest_pycollect_makemodule(path, parent):
""" return a Module collector or None for the given path.
This hook will be called for each matching test module path.
The pytest_collect_file hook needs to be used if you want to
create test modules for files that do not match as a test module.
- """
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
@hookspec(firstresult=True)
def pytest_pycollect_makeitem(collector, name, obj):
- """ return custom item/collector for a python object in a module, or None. """
+ """ return custom item/collector for a python object in a module, or None.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
@hookspec(firstresult=True)
def pytest_pyfunc_call(pyfuncitem):
- """ call underlying test function. """
+ """ call underlying test function.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_generate_tests(metafunc):
""" generate (multiple) parametrized calls to a test function."""
+
@hookspec(firstresult=True)
-def pytest_make_parametrize_id(config, val):
+def pytest_make_parametrize_id(config, val, argname):
"""Return a user-friendly string representation of the given ``val`` that will be used
by @pytest.mark.parametrize calls. Return None if the hook doesn't know about ``val``.
- """
+ The parameter name is available as ``argname``, if required.
+
+ Stops at first non-None result, see :ref:`firstresult` """
# -------------------------------------------------------------------------
# generic runtest related hooks
# -------------------------------------------------------------------------
+
@hookspec(firstresult=True)
def pytest_runtestloop(session):
""" called for performing the main runtest loop
- (after collection finished). """
+ (after collection finished).
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_itemstart(item, node):
""" (deprecated, use pytest_runtest_logstart). """
+
@hookspec(firstresult=True)
def pytest_runtest_protocol(item, nextitem):
""" implements the runtest_setup/call/teardown protocol for
@@ -187,17 +244,23 @@ def pytest_runtest_protocol(item, nextitem):
:py:func:`pytest_runtest_teardown`.
:return boolean: True if no further hook implementations should be invoked.
- """
+
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_runtest_logstart(nodeid, location):
""" signal the start of running a single test item. """
+
def pytest_runtest_setup(item):
""" called before ``pytest_runtest_call(item)``. """
+
def pytest_runtest_call(item):
""" called to execute the test ``item``. """
+
def pytest_runtest_teardown(item, nextitem):
""" called after ``pytest_runtest_call``.
@@ -207,12 +270,15 @@ def pytest_runtest_teardown(item, nextitem):
so that nextitem only needs to call setup-functions.
"""
+
@hookspec(firstresult=True)
def pytest_runtest_makereport(item, call):
""" return a :py:class:`_pytest.runner.TestReport` object
- for the given :py:class:`pytest.Item` and
+ for the given :py:class:`pytest.Item <_pytest.main.Item>` and
:py:class:`_pytest.runner.CallInfo`.
- """
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_runtest_logreport(report):
""" process a test setup/call/teardown report relating to
@@ -222,9 +288,13 @@ def pytest_runtest_logreport(report):
# Fixture related hooks
# -------------------------------------------------------------------------
+
@hookspec(firstresult=True)
def pytest_fixture_setup(fixturedef, request):
- """ performs fixture setup execution. """
+ """ performs fixture setup execution.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_fixture_post_finalizer(fixturedef):
""" called after fixture teardown, but before the cache is cleared so
@@ -235,18 +305,21 @@ def pytest_fixture_post_finalizer(fixturedef):
# test session related hooks
# -------------------------------------------------------------------------
+
def pytest_sessionstart(session):
""" before session.main() is called. """
+
def pytest_sessionfinish(session, exitstatus):
""" whole test run finishes. """
+
def pytest_unconfigure(config):
""" called before test process is exited. """
# -------------------------------------------------------------------------
-# hooks for customising the assert methods
+# hooks for customizing the assert methods
# -------------------------------------------------------------------------
def pytest_assertrepr_compare(config, op, left, right):
@@ -255,19 +328,48 @@ def pytest_assertrepr_compare(config, op, left, right):
Return None for no custom explanation, otherwise return a list
of strings. The strings will be joined by newlines but any newlines
*in* a string will be escaped. Note that all but the first line will
- be indented sligthly, the intention is for the first line to be a summary.
+ be indented slightly, the intention is for the first line to be a summary.
"""
# -------------------------------------------------------------------------
# hooks for influencing reporting (invoked from _pytest_terminal)
# -------------------------------------------------------------------------
+
def pytest_report_header(config, startdir):
- """ return a string to be displayed as header info for terminal reporting."""
+ """ return a string or list of strings to be displayed as header info for terminal reporting.
+
+ :param config: the pytest config object.
+ :param startdir: py.path object with the starting dir
+
+ .. note::
+
+ This function should be implemented only in plugins or ``conftest.py``
+ files situated at the tests root directory due to how pytest
+ :ref:`discovers plugins during startup <pluginorder>`.
+ """
+
+
+def pytest_report_collectionfinish(config, startdir, items):
+ """
+ .. versionadded:: 3.2
+
+ return a string or list of strings to be displayed after collection has finished successfully.
+
+ This strings will be displayed after the standard "collected X items" message.
+
+ :param config: the pytest config object.
+ :param startdir: py.path object with the starting dir
+ :param items: list of pytest items that are going to be executed; this list should not be modified.
+ """
+
@hookspec(firstresult=True)
def pytest_report_teststatus(report):
- """ return result-category, shortletter and verbose word for reporting."""
+ """ return result-category, shortletter and verbose word for reporting.
+
+ Stops at first non-None result, see :ref:`firstresult` """
+
def pytest_terminal_summary(terminalreporter, exitstatus):
""" add additional section in terminal summary reporting. """
@@ -283,20 +385,26 @@ def pytest_logwarning(message, code, nodeid, fslocation):
# doctest hooks
# -------------------------------------------------------------------------
+
@hookspec(firstresult=True)
def pytest_doctest_prepare_content(content):
- """ return processed content for a given doctest"""
+ """ return processed content for a given doctest
+
+ Stops at first non-None result, see :ref:`firstresult` """
# -------------------------------------------------------------------------
# error handling and internal debugging hooks
# -------------------------------------------------------------------------
+
def pytest_internalerror(excrepr, excinfo):
""" called for internal errors. """
+
def pytest_keyboard_interrupt(excinfo):
""" called for keyboard interrupt. """
+
def pytest_exception_interact(node, call, report):
"""called when an exception was raised which can potentially be
interactively handled.
@@ -305,6 +413,7 @@ def pytest_exception_interact(node, call, report):
that is not an internal exception like ``skip.Exception``.
"""
+
def pytest_enter_pdb(config):
""" called upon pdb.set_trace(), can be used by plugins to take special
action just before the python debugger enters in interactive mode.
diff --git a/lib/spack/external/_pytest/junitxml.py b/lib/spack/external/_pytest/junitxml.py
index 317382e637..7fb40dc354 100644
--- a/lib/spack/external/_pytest/junitxml.py
+++ b/lib/spack/external/_pytest/junitxml.py
@@ -4,9 +4,11 @@
Based on initial code from Ross Lawley.
+
+Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/
+src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
"""
-# Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/
-# src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
+from __future__ import absolute_import, division, print_function
import functools
import py
@@ -15,6 +17,7 @@ import re
import sys
import time
import pytest
+from _pytest import nodes
from _pytest.config import filename_arg
# Python 2.X and 3.X compatibility
@@ -105,6 +108,8 @@ class _NodeReporter(object):
}
if testreport.location[1] is not None:
attrs["line"] = testreport.location[1]
+ if hasattr(testreport, "url"):
+ attrs["url"] = testreport.url
self.attrs = attrs
def to_xml(self):
@@ -119,7 +124,7 @@ class _NodeReporter(object):
node = kind(data, message=message)
self.append(node)
- def _write_captured_output(self, report):
+ def write_captured_output(self, report):
for capname in ('out', 'err'):
content = getattr(report, 'capstd' + capname)
if content:
@@ -128,7 +133,6 @@ class _NodeReporter(object):
def append_pass(self, report):
self.add_stats('passed')
- self._write_captured_output(report)
def append_failure(self, report):
# msg = str(report.longrepr.reprtraceback.extraline)
@@ -147,7 +151,6 @@ class _NodeReporter(object):
fail = Junit.failure(message=message)
fail.append(bin_xml_escape(report.longrepr))
self.append(fail)
- self._write_captured_output(report)
def append_collect_error(self, report):
# msg = str(report.longrepr.reprtraceback.extraline)
@@ -165,7 +168,6 @@ class _NodeReporter(object):
msg = "test setup failure"
self._add_simple(
Junit.error, msg, report.longrepr)
- self._write_captured_output(report)
def append_skipped(self, report):
if hasattr(report, "wasxfail"):
@@ -180,7 +182,7 @@ class _NodeReporter(object):
Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason),
type="pytest.skip",
message=skipreason))
- self._write_captured_output(report)
+ self.write_captured_output(report)
def finalize(self):
data = self.to_xml().unicode(indent=0)
@@ -225,13 +227,14 @@ def pytest_addoption(parser):
metavar="str",
default=None,
help="prepend prefix to classnames in junit-xml output")
+ parser.addini("junit_suite_name", "Test suite name for JUnit report", default="pytest")
def pytest_configure(config):
xmlpath = config.option.xmlpath
# prevent opening xmllog on slave nodes (xdist)
if xmlpath and not hasattr(config, 'slaveinput'):
- config._xml = LogXML(xmlpath, config.option.junitprefix)
+ config._xml = LogXML(xmlpath, config.option.junitprefix, config.getini("junit_suite_name"))
config.pluginmanager.register(config._xml)
@@ -250,7 +253,7 @@ def mangle_test_address(address):
except ValueError:
pass
# convert file path to dotted path
- names[0] = names[0].replace("/", '.')
+ names[0] = names[0].replace(nodes.SEP, '.')
names[0] = _py_ext_re.sub("", names[0])
# put any params back
names[-1] += possible_open_bracket + params
@@ -258,10 +261,11 @@ def mangle_test_address(address):
class LogXML(object):
- def __init__(self, logfile, prefix):
+ def __init__(self, logfile, prefix, suite_name="pytest"):
logfile = os.path.expanduser(os.path.expandvars(logfile))
self.logfile = os.path.normpath(os.path.abspath(logfile))
self.prefix = prefix
+ self.suite_name = suite_name
self.stats = dict.fromkeys([
'error',
'passed',
@@ -271,6 +275,9 @@ class LogXML(object):
self.node_reporters = {} # nodeid -> _NodeReporter
self.node_reporters_ordered = []
self.global_properties = []
+ # List of reports that failed on call but teardown is pending.
+ self.open_reports = []
+ self.cnt_double_fail_tests = 0
def finalize(self, report):
nodeid = getattr(report, 'nodeid', report)
@@ -330,14 +337,33 @@ class LogXML(object):
-> teardown node2
-> teardown node1
"""
+ close_report = None
if report.passed:
if report.when == "call": # ignore setup/teardown
reporter = self._opentestcase(report)
reporter.append_pass(report)
elif report.failed:
+ if report.when == "teardown":
+ # The following vars are needed when xdist plugin is used
+ report_wid = getattr(report, "worker_id", None)
+ report_ii = getattr(report, "item_index", None)
+ close_report = next(
+ (rep for rep in self.open_reports
+ if (rep.nodeid == report.nodeid and
+ getattr(rep, "item_index", None) == report_ii and
+ getattr(rep, "worker_id", None) == report_wid
+ )
+ ), None)
+ if close_report:
+ # We need to open new testcase in case we have failure in
+ # call and error in teardown in order to follow junit
+ # schema
+ self.finalize(close_report)
+ self.cnt_double_fail_tests += 1
reporter = self._opentestcase(report)
if report.when == "call":
reporter.append_failure(report)
+ self.open_reports.append(report)
else:
reporter.append_error(report)
elif report.skipped:
@@ -345,7 +371,20 @@ class LogXML(object):
reporter.append_skipped(report)
self.update_testcase_duration(report)
if report.when == "teardown":
+ reporter = self._opentestcase(report)
+ reporter.write_captured_output(report)
self.finalize(report)
+ report_wid = getattr(report, "worker_id", None)
+ report_ii = getattr(report, "item_index", None)
+ close_report = next(
+ (rep for rep in self.open_reports
+ if (rep.nodeid == report.nodeid and
+ getattr(rep, "item_index", None) == report_ii and
+ getattr(rep, "worker_id", None) == report_wid
+ )
+ ), None)
+ if close_report:
+ self.open_reports.remove(close_report)
def update_testcase_duration(self, report):
"""accumulates total duration for nodeid from given report and updates
@@ -378,14 +417,15 @@ class LogXML(object):
suite_stop_time = time.time()
suite_time_delta = suite_stop_time - self.suite_start_time
- numtests = self.stats['passed'] + self.stats['failure'] + self.stats['skipped'] + self.stats['error']
-
+ numtests = (self.stats['passed'] + self.stats['failure'] +
+ self.stats['skipped'] + self.stats['error'] -
+ self.cnt_double_fail_tests)
logfile.write('<?xml version="1.0" encoding="utf-8"?>')
logfile.write(Junit.testsuite(
self._get_global_properties_node(),
[x.to_xml() for x in self.node_reporters_ordered],
- name="pytest",
+ name=self.suite_name,
errors=self.stats['error'],
failures=self.stats['failure'],
skips=self.stats['skipped'],
@@ -405,9 +445,9 @@ class LogXML(object):
"""
if self.global_properties:
return Junit.properties(
- [
- Junit.property(name=name, value=value)
- for name, value in self.global_properties
- ]
+ [
+ Junit.property(name=name, value=value)
+ for name, value in self.global_properties
+ ]
)
return ''
diff --git a/lib/spack/external/_pytest/main.py b/lib/spack/external/_pytest/main.py
index 52876c12a4..eacae8dab1 100644
--- a/lib/spack/external/_pytest/main.py
+++ b/lib/spack/external/_pytest/main.py
@@ -1,18 +1,21 @@
""" core implementation of testing process: init, session, runtest loop. """
+from __future__ import absolute_import, division, print_function
+
import functools
import os
import sys
import _pytest
+from _pytest import nodes
import _pytest._code
import py
-import pytest
try:
from collections import MutableMapping as MappingMixin
except ImportError:
from UserDict import DictMixin as MappingMixin
-from _pytest.config import directory_arg
+from _pytest.config import directory_arg, UsageError, hookimpl
+from _pytest.outcomes import exit
from _pytest.runner import collect_one_node
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
@@ -25,63 +28,73 @@ EXIT_INTERNALERROR = 3
EXIT_USAGEERROR = 4
EXIT_NOTESTSCOLLECTED = 5
+
def pytest_addoption(parser):
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
- type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg'])
- parser.addini("testpaths", "directories to search for tests when no files or directories are given in the command line.",
- type="args", default=[])
- #parser.addini("dirpatterns",
+ type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv'])
+ parser.addini("testpaths", "directories to search for tests when no files or directories are given in the "
+ "command line.",
+ type="args", default=[])
+ # parser.addini("dirpatterns",
# "patterns specifying possible locations of test files",
# type="linelist", default=["**/test_*.txt",
# "**/test_*.py", "**/*_test.py"]
- #)
+ # )
group = parser.getgroup("general", "running and selection options")
group._addoption('-x', '--exitfirst', action="store_const",
- dest="maxfail", const=1,
- help="exit instantly on first error or failed test."),
+ dest="maxfail", const=1,
+ help="exit instantly on first error or failed test."),
group._addoption('--maxfail', metavar="num",
- action="store", type=int, dest="maxfail", default=0,
- help="exit after first num failures or errors.")
+ action="store", type=int, dest="maxfail", default=0,
+ help="exit after first num failures or errors.")
group._addoption('--strict', action="store_true",
- help="run pytest in strict mode, warnings become errors.")
+ help="marks not registered in configuration file raise errors.")
group._addoption("-c", metavar="file", type=str, dest="inifilename",
- help="load configuration from `file` instead of trying to locate one of the implicit configuration files.")
+ help="load configuration from `file` instead of trying to locate one of the implicit "
+ "configuration files.")
group._addoption("--continue-on-collection-errors", action="store_true",
- default=False, dest="continue_on_collection_errors",
- help="Force test execution even if collection errors occur.")
+ default=False, dest="continue_on_collection_errors",
+ help="Force test execution even if collection errors occur.")
group = parser.getgroup("collect", "collection")
group.addoption('--collectonly', '--collect-only', action="store_true",
- help="only collect tests, don't execute them."),
+ help="only collect tests, don't execute them."),
group.addoption('--pyargs', action="store_true",
- help="try to interpret all arguments as python packages.")
+ help="try to interpret all arguments as python packages.")
group.addoption("--ignore", action="append", metavar="path",
- help="ignore path during collection (multi-allowed).")
+ help="ignore path during collection (multi-allowed).")
# when changing this to --conf-cut-dir, config.py Conftest.setinitial
# needs upgrading as well
group.addoption('--confcutdir', dest="confcutdir", default=None,
- metavar="dir", type=functools.partial(directory_arg, optname="--confcutdir"),
- help="only load conftest.py's relative to specified dir.")
+ metavar="dir", type=functools.partial(directory_arg, optname="--confcutdir"),
+ help="only load conftest.py's relative to specified dir.")
group.addoption('--noconftest', action="store_true",
- dest="noconftest", default=False,
- help="Don't load any conftest.py files.")
+ dest="noconftest", default=False,
+ help="Don't load any conftest.py files.")
group.addoption('--keepduplicates', '--keep-duplicates', action="store_true",
- dest="keepduplicates", default=False,
- help="Keep duplicate tests.")
+ dest="keepduplicates", default=False,
+ help="Keep duplicate tests.")
+ group.addoption('--collect-in-virtualenv', action='store_true',
+ dest='collect_in_virtualenv', default=False,
+ help="Don't ignore tests in a local virtualenv directory")
group = parser.getgroup("debugconfig",
- "test session debugging and configuration")
+ "test session debugging and configuration")
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
- help="base temporary directory for this test run.")
+ help="base temporary directory for this test run.")
def pytest_namespace():
- collect = dict(Item=Item, Collector=Collector, File=File, Session=Session)
- return dict(collect=collect)
+ """keeping this one works around a deeper startup issue in pytest
+
+ i tried to find it for a while but the amount of time turned unsustainable,
+ so i put a hack in to revisit later
+ """
+ return {}
def pytest_configure(config):
- pytest.config = config # compatibiltiy
+ __import__('pytest').config = config # compatibiltiy
def wrap_session(config, doit):
@@ -96,17 +109,16 @@ def wrap_session(config, doit):
config.hook.pytest_sessionstart(session=session)
initstate = 2
session.exitstatus = doit(config, session) or 0
- except pytest.UsageError:
+ except UsageError:
raise
except KeyboardInterrupt:
excinfo = _pytest._code.ExceptionInfo()
- if initstate < 2 and isinstance(
- excinfo.value, pytest.exit.Exception):
+ if initstate < 2 and isinstance(excinfo.value, exit.Exception):
sys.stderr.write('{0}: {1}\n'.format(
excinfo.typename, excinfo.value.msg))
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
session.exitstatus = EXIT_INTERRUPTED
- except:
+ except: # noqa
excinfo = _pytest._code.ExceptionInfo()
config.notify_exception(excinfo, config.option)
session.exitstatus = EXIT_INTERNALERROR
@@ -123,9 +135,11 @@ def wrap_session(config, doit):
config._ensure_unconfigure()
return session.exitstatus
+
def pytest_cmdline_main(config):
return wrap_session(config, _main)
+
def _main(config, session):
""" default command line protocol for initialization, session,
running tests and reporting. """
@@ -137,9 +151,11 @@ def _main(config, session):
elif session.testscollected == 0:
return EXIT_NOTESTSCOLLECTED
+
def pytest_collection(session):
return session.perform_collect()
+
def pytest_runtestloop(session):
if (session.testsfailed and
not session.config.option.continue_on_collection_errors):
@@ -150,21 +166,36 @@ def pytest_runtestloop(session):
return True
for i, item in enumerate(session.items):
- nextitem = session.items[i+1] if i+1 < len(session.items) else None
+ nextitem = session.items[i + 1] if i + 1 < len(session.items) else None
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
if session.shouldstop:
raise session.Interrupted(session.shouldstop)
return True
+
+def _in_venv(path):
+ """Attempts to detect if ``path`` is the root of a Virtual Environment by
+ checking for the existence of the appropriate activate script"""
+ bindir = path.join('Scripts' if sys.platform.startswith('win') else 'bin')
+ if not bindir.exists():
+ return False
+ activates = ('activate', 'activate.csh', 'activate.fish',
+ 'Activate', 'Activate.bat', 'Activate.ps1')
+ return any([fname.basename in activates for fname in bindir.listdir()])
+
+
def pytest_ignore_collect(path, config):
- p = path.dirpath()
- ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
+ ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath())
ignore_paths = ignore_paths or []
excludeopt = config.getoption("ignore")
if excludeopt:
ignore_paths.extend([py.path.local(x) for x in excludeopt])
- if path in ignore_paths:
+ if py.path.local(path) in ignore_paths:
+ return True
+
+ allow_in_venv = config.getoption("collect_in_virtualenv")
+ if _in_venv(path) and not allow_in_venv:
return True
# Skip duplicate paths.
@@ -190,14 +221,22 @@ class FSHookProxy:
self.__dict__[name] = x
return x
-def compatproperty(name):
- def fget(self):
- import warnings
- warnings.warn("This usage is deprecated, please use pytest.{0} instead".format(name),
- PendingDeprecationWarning, stacklevel=2)
- return getattr(pytest, name)
- return property(fget)
+class _CompatProperty(object):
+ def __init__(self, name):
+ self.name = name
+
+ def __get__(self, obj, owner):
+ if obj is None:
+ return self
+
+ # TODO: reenable in the features branch
+ # warnings.warn(
+ # "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format(
+ # name=self.name, owner=type(owner).__name__),
+ # PendingDeprecationWarning, stacklevel=2)
+ return getattr(__import__('pytest'), self.name)
+
class NodeKeywords(MappingMixin):
def __init__(self, node):
@@ -269,24 +308,28 @@ class Node(object):
""" fspath sensitive hook proxy used to call pytest hooks"""
return self.session.gethookproxy(self.fspath)
- Module = compatproperty("Module")
- Class = compatproperty("Class")
- Instance = compatproperty("Instance")
- Function = compatproperty("Function")
- File = compatproperty("File")
- Item = compatproperty("Item")
+ Module = _CompatProperty("Module")
+ Class = _CompatProperty("Class")
+ Instance = _CompatProperty("Instance")
+ Function = _CompatProperty("Function")
+ File = _CompatProperty("File")
+ Item = _CompatProperty("Item")
def _getcustomclass(self, name):
- cls = getattr(self, name)
- if cls != getattr(pytest, name):
- py.log._apiwarn("2.0", "use of node.%s is deprecated, "
- "use pytest_pycollect_makeitem(...) to create custom "
- "collection nodes" % name)
+ maybe_compatprop = getattr(type(self), name)
+ if isinstance(maybe_compatprop, _CompatProperty):
+ return getattr(__import__('pytest'), name)
+ else:
+ cls = getattr(self, name)
+ # TODO: reenable in the features branch
+ # warnings.warn("use of node.%s is deprecated, "
+ # "use pytest_pycollect_makeitem(...) to create custom "
+ # "collection nodes" % name, category=DeprecationWarning)
return cls
def __repr__(self):
- return "<%s %r>" %(self.__class__.__name__,
- getattr(self, 'name', None))
+ return "<%s %r>" % (self.__class__.__name__,
+ getattr(self, 'name', None))
def warn(self, code, message):
""" generate a warning with the given code and message for this
@@ -295,9 +338,6 @@ class Node(object):
fslocation = getattr(self, "location", None)
if fslocation is None:
fslocation = getattr(self, "fspath", None)
- else:
- fslocation = "%s:%s" % (fslocation[0], fslocation[1] + 1)
-
self.ihook.pytest_logwarning.call_historic(kwargs=dict(
code=code, message=message,
nodeid=self.nodeid, fslocation=fslocation))
@@ -335,7 +375,7 @@ class Node(object):
res = function()
except py.builtin._sysex:
raise
- except:
+ except: # noqa
failure = sys.exc_info()
setattr(self, exattrname, failure)
raise
@@ -358,9 +398,9 @@ class Node(object):
``marker`` can be a string or pytest.mark.* instance.
"""
- from _pytest.mark import MarkDecorator
+ from _pytest.mark import MarkDecorator, MARK_GEN
if isinstance(marker, py.builtin._basestring):
- marker = MarkDecorator(marker)
+ marker = getattr(MARK_GEN, marker)
elif not isinstance(marker, MarkDecorator):
raise ValueError("is not a string or pytest.mark.* Marker")
self.keywords[marker.name] = marker
@@ -410,7 +450,7 @@ class Node(object):
return excinfo.value.formatrepr()
tbfilter = True
if self.config.option.fulltrace:
- style="long"
+ style = "long"
else:
tb = _pytest._code.Traceback([excinfo.traceback[-1]])
self._prunetraceback(excinfo)
@@ -438,6 +478,7 @@ class Node(object):
repr_failure = _repr_failure_py
+
class Collector(Node):
""" Collector instances create children through collect()
and thus iteratively build a tree.
@@ -459,10 +500,6 @@ class Collector(Node):
return str(exc.args[0])
return self._repr_failure_py(excinfo, style="short")
- def _memocollect(self):
- """ internal helper method to cache results of calling collect(). """
- return self._memoizedcall('_collected', lambda: list(self.collect()))
-
def _prunetraceback(self, excinfo):
if hasattr(self, 'fspath'):
traceback = excinfo.traceback
@@ -471,27 +508,38 @@ class Collector(Node):
ntraceback = ntraceback.cut(excludepath=tracebackcutdir)
excinfo.traceback = ntraceback.filter()
+
class FSCollector(Collector):
def __init__(self, fspath, parent=None, config=None, session=None):
- fspath = py.path.local(fspath) # xxx only for test_resultlog.py?
+ fspath = py.path.local(fspath) # xxx only for test_resultlog.py?
name = fspath.basename
if parent is not None:
rel = fspath.relto(parent.fspath)
if rel:
name = rel
- name = name.replace(os.sep, "/")
+ name = name.replace(os.sep, nodes.SEP)
super(FSCollector, self).__init__(name, parent, config, session)
self.fspath = fspath
+ def _check_initialpaths_for_relpath(self):
+ for initialpath in self.session._initialpaths:
+ if self.fspath.common(initialpath) == initialpath:
+ return self.fspath.relto(initialpath.dirname)
+
def _makeid(self):
relpath = self.fspath.relto(self.config.rootdir)
- if os.sep != "/":
- relpath = relpath.replace(os.sep, "/")
+
+ if not relpath:
+ relpath = self._check_initialpaths_for_relpath()
+ if os.sep != nodes.SEP:
+ relpath = relpath.replace(os.sep, nodes.SEP)
return relpath
+
class File(FSCollector):
""" base class for collecting tests from a file. """
+
class Item(Node):
""" a basic test invocation item. Note that for a single function
there might be multiple test invocation items.
@@ -503,6 +551,21 @@ class Item(Node):
self._report_sections = []
def add_report_section(self, when, key, content):
+ """
+ Adds a new report section, similar to what's done internally to add stdout and
+ stderr captured output::
+
+ item.add_report_section("call", "stdout", "report section contents")
+
+ :param str when:
+ One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``.
+ :param str key:
+ Name of the section, can be customized at will. Pytest uses ``"stdout"`` and
+ ``"stderr"`` internally.
+
+ :param str content:
+ The full contents as a string.
+ """
if content:
self._report_sections.append((when, key, content))
@@ -526,12 +589,15 @@ class Item(Node):
self._location = location
return location
+
class NoMatch(Exception):
""" raised if matching cannot locate a matching names. """
+
class Interrupted(KeyboardInterrupt):
""" signals an interrupted test run. """
- __module__ = 'builtins' # for py3
+ __module__ = 'builtins' # for py3
+
class Session(FSCollector):
Interrupted = Interrupted
@@ -550,12 +616,12 @@ class Session(FSCollector):
def _makeid(self):
return ""
- @pytest.hookimpl(tryfirst=True)
+ @hookimpl(tryfirst=True)
def pytest_collectstart(self):
if self.shouldstop:
raise self.Interrupted(self.shouldstop)
- @pytest.hookimpl(tryfirst=True)
+ @hookimpl(tryfirst=True)
def pytest_runtest_logreport(self, report):
if report.failed and not hasattr(report, 'wasxfail'):
self.testsfailed += 1
@@ -586,8 +652,9 @@ class Session(FSCollector):
hook = self.config.hook
try:
items = self._perform_collect(args, genitems)
+ self.config.pluginmanager.check_pending()
hook.pytest_collection_modifyitems(session=self,
- config=self.config, items=items)
+ config=self.config, items=items)
finally:
hook.pytest_collection_finish(session=self)
self.testscollected = len(items)
@@ -614,8 +681,8 @@ class Session(FSCollector):
for arg, exc in self._notfound:
line = "(no name %r in any of %r)" % (arg, exc.args[0])
errors.append("not found: %s\n%s" % (arg, line))
- #XXX: test this
- raise pytest.UsageError(*errors)
+ # XXX: test this
+ raise UsageError(*errors)
if not genitems:
return rep.result
else:
@@ -643,7 +710,7 @@ class Session(FSCollector):
names = self._parsearg(arg)
path = names.pop(0)
if path.check(dir=1):
- assert not names, "invalid arg %r" %(arg,)
+ assert not names, "invalid arg %r" % (arg,)
for path in path.visit(fil=lambda x: x.check(file=1),
rec=self._recurse, bf=True, sort=True):
for x in self._collectfile(path):
@@ -702,9 +769,11 @@ class Session(FSCollector):
path = self.config.invocation_dir.join(relpath, abs=True)
if not path.check():
if self.config.option.pyargs:
- raise pytest.UsageError("file or package not found: " + arg + " (missing __init__.py?)")
+ raise UsageError(
+ "file or package not found: " + arg +
+ " (missing __init__.py?)")
else:
- raise pytest.UsageError("file not found: " + arg)
+ raise UsageError("file not found: " + arg)
parts[0] = path
return parts
@@ -727,11 +796,11 @@ class Session(FSCollector):
nextnames = names[1:]
resultnodes = []
for node in matching:
- if isinstance(node, pytest.Item):
+ if isinstance(node, Item):
if not names:
resultnodes.append(node)
continue
- assert isinstance(node, pytest.Collector)
+ assert isinstance(node, Collector)
rep = collect_one_node(node)
if rep.passed:
has_matched = False
@@ -744,16 +813,20 @@ class Session(FSCollector):
if not has_matched and len(rep.result) == 1 and x.name == "()":
nextnames.insert(0, name)
resultnodes.extend(self.matchnodes([x], nextnames))
- node.ihook.pytest_collectreport(report=rep)
+ else:
+ # report collection failures here to avoid failing to run some test
+ # specified in the command line because the module could not be
+ # imported (#134)
+ node.ihook.pytest_collectreport(report=rep)
return resultnodes
def genitems(self, node):
self.trace("genitems", node)
- if isinstance(node, pytest.Item):
+ if isinstance(node, Item):
node.ihook.pytest_itemcollected(item=node)
yield node
else:
- assert isinstance(node, pytest.Collector)
+ assert isinstance(node, Collector)
rep = collect_one_node(node)
if rep.passed:
for subnode in rep.result:
diff --git a/lib/spack/external/_pytest/mark.py b/lib/spack/external/_pytest/mark.py
index 357a60492e..454722ca2c 100644
--- a/lib/spack/external/_pytest/mark.py
+++ b/lib/spack/external/_pytest/mark.py
@@ -1,5 +1,75 @@
""" generic mechanism for marking and selecting python functions. """
+from __future__ import absolute_import, division, print_function
+
import inspect
+import warnings
+from collections import namedtuple
+from operator import attrgetter
+from .compat import imap
+from .deprecated import MARK_PARAMETERSET_UNPACKING
+
+
+def alias(name, warning=None):
+ getter = attrgetter(name)
+
+ def warned(self):
+ warnings.warn(warning, stacklevel=2)
+ return getter(self)
+
+ return property(getter if warning is None else warned, doc='alias for ' + name)
+
+
+class ParameterSet(namedtuple('ParameterSet', 'values, marks, id')):
+ @classmethod
+ def param(cls, *values, **kw):
+ marks = kw.pop('marks', ())
+ if isinstance(marks, MarkDecorator):
+ marks = marks,
+ else:
+ assert isinstance(marks, (tuple, list, set))
+
+ def param_extract_id(id=None):
+ return id
+
+ id = param_extract_id(**kw)
+ return cls(values, marks, id)
+
+ @classmethod
+ def extract_from(cls, parameterset, legacy_force_tuple=False):
+ """
+ :param parameterset:
+ a legacy style parameterset that may or may not be a tuple,
+ and may or may not be wrapped into a mess of mark objects
+
+ :param legacy_force_tuple:
+ enforce tuple wrapping so single argument tuple values
+ don't get decomposed and break tests
+
+ """
+
+ if isinstance(parameterset, cls):
+ return parameterset
+ if not isinstance(parameterset, MarkDecorator) and legacy_force_tuple:
+ return cls.param(parameterset)
+
+ newmarks = []
+ argval = parameterset
+ while isinstance(argval, MarkDecorator):
+ newmarks.append(MarkDecorator(Mark(
+ argval.markname, argval.args[:-1], argval.kwargs)))
+ argval = argval.args[-1]
+ assert not isinstance(argval, ParameterSet)
+ if legacy_force_tuple:
+ argval = argval,
+
+ if newmarks:
+ warnings.warn(MARK_PARAMETERSET_UNPACKING)
+
+ return cls(argval, marks=newmarks, id=None)
+
+ @property
+ def deprecated_arg_dict(self):
+ return dict((mark.name, mark) for mark in self.marks)
class MarkerError(Exception):
@@ -7,8 +77,8 @@ class MarkerError(Exception):
"""Error in use of a pytest marker/attribute."""
-def pytest_namespace():
- return {'mark': MarkGenerator()}
+def param(*values, **kw):
+ return ParameterSet.param(*values, **kw)
def pytest_addoption(parser):
@@ -21,7 +91,8 @@ def pytest_addoption(parser):
"where all names are substring-matched against test names "
"and their parent classes. Example: -k 'test_method or test_"
"other' matches all test functions and classes whose name "
- "contains 'test_method' or 'test_other'. "
+ "contains 'test_method' or 'test_other', while -k 'not test_method' "
+ "matches those that don't contain 'test_method' in their names. "
"Additionally keywords are matched to classes and functions "
"containing extra names in their 'extra_keyword_matches' set, "
"as well as functions which have names assigned directly to them."
@@ -66,7 +137,7 @@ def pytest_collection_modifyitems(items, config):
return
# pytest used to allow "-" for negating
# but today we just allow "-" at the beginning, use "not" instead
- # we probably remove "-" alltogether soon
+ # we probably remove "-" altogether soon
if keywordexpr.startswith("-"):
keywordexpr = "not " + keywordexpr[1:]
selectuntil = False
@@ -96,6 +167,7 @@ def pytest_collection_modifyitems(items, config):
class MarkMapping:
"""Provides a local mapping for markers where item access
resolves to True if the marker is present. """
+
def __init__(self, keywords):
mymarks = set()
for key, value in keywords.items():
@@ -111,6 +183,7 @@ class KeywordMapping:
"""Provides a local mapping for keywords.
Given a list of names, map any substring of one of these names to True.
"""
+
def __init__(self, names):
self._names = names
@@ -162,9 +235,13 @@ def matchkeyword(colitem, keywordexpr):
def pytest_configure(config):
- import pytest
+ config._old_mark_config = MARK_GEN._config
if config.option.strict:
- pytest.mark._config = config
+ MARK_GEN._config = config
+
+
+def pytest_unconfigure(config):
+ MARK_GEN._config = getattr(config, '_old_mark_config', None)
class MarkGenerator:
@@ -178,13 +255,14 @@ class MarkGenerator:
will set a 'slowtest' :class:`MarkInfo` object
on the ``test_function`` object. """
+ _config = None
def __getattr__(self, name):
if name[0] == "_":
raise AttributeError("Marker name must NOT start with underscore")
- if hasattr(self, '_config'):
+ if self._config is not None:
self._check(name)
- return MarkDecorator(name)
+ return MarkDecorator(Mark(name, (), {}))
def _check(self, name):
try:
@@ -192,18 +270,21 @@ class MarkGenerator:
return
except AttributeError:
pass
- self._markers = l = set()
+ self._markers = values = set()
for line in self._config.getini("markers"):
- beginning = line.split(":", 1)
- x = beginning[0].split("(", 1)[0]
- l.add(x)
+ marker, _ = line.split(":", 1)
+ marker = marker.rstrip()
+ x = marker.split("(", 1)[0]
+ values.add(x)
if name not in self._markers:
raise AttributeError("%r not a registered marker" % (name,))
+
def istestfunc(func):
return hasattr(func, "__call__") and \
getattr(func, "__name__", "<lambda>") != "<lambda>"
+
class MarkDecorator:
""" A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be
@@ -237,19 +318,35 @@ class MarkDecorator:
additional keyword or positional arguments.
"""
- def __init__(self, name, args=None, kwargs=None):
- self.name = name
- self.args = args or ()
- self.kwargs = kwargs or {}
+
+ def __init__(self, mark):
+ assert isinstance(mark, Mark), repr(mark)
+ self.mark = mark
+
+ name = alias('mark.name')
+ args = alias('mark.args')
+ kwargs = alias('mark.kwargs')
@property
def markname(self):
- return self.name # for backward-compat (2.4.1 had this attr)
+ return self.name # for backward-compat (2.4.1 had this attr)
+
+ def __eq__(self, other):
+ return self.mark == other.mark if isinstance(other, MarkDecorator) else False
def __repr__(self):
- d = self.__dict__.copy()
- name = d.pop('name')
- return "<MarkDecorator %r %r>" % (name, d)
+ return "<MarkDecorator %r>" % (self.mark,)
+
+ def with_args(self, *args, **kwargs):
+ """ return a MarkDecorator with extra arguments added
+
+ unlike call this can be used even if the sole argument is a callable/class
+
+ :return: MarkDecorator
+ """
+
+ mark = Mark(self.name, args, kwargs)
+ return self.__class__(self.mark.combined_with(mark))
def __call__(self, *args, **kwargs):
""" if passed a single callable argument: decorate it with mark info.
@@ -259,70 +356,110 @@ class MarkDecorator:
is_class = inspect.isclass(func)
if len(args) == 1 and (istestfunc(func) or is_class):
if is_class:
- if hasattr(func, 'pytestmark'):
- mark_list = func.pytestmark
- if not isinstance(mark_list, list):
- mark_list = [mark_list]
- # always work on a copy to avoid updating pytestmark
- # from a superclass by accident
- mark_list = mark_list + [self]
- func.pytestmark = mark_list
- else:
- func.pytestmark = [self]
+ store_mark(func, self.mark)
else:
- holder = getattr(func, self.name, None)
- if holder is None:
- holder = MarkInfo(
- self.name, self.args, self.kwargs
- )
- setattr(func, self.name, holder)
- else:
- holder.add(self.args, self.kwargs)
+ store_legacy_markinfo(func, self.mark)
+ store_mark(func, self.mark)
return func
- kw = self.kwargs.copy()
- kw.update(kwargs)
- args = self.args + args
- return self.__class__(self.name, args=args, kwargs=kw)
-
-
-def extract_argvalue(maybe_marked_args):
- # TODO: incorrect mark data, the old code wanst able to collect lists
- # individual parametrized argument sets can be wrapped in a series
- # of markers in which case we unwrap the values and apply the mark
- # at Function init
- newmarks = {}
- argval = maybe_marked_args
- while isinstance(argval, MarkDecorator):
- newmark = MarkDecorator(argval.markname,
- argval.args[:-1], argval.kwargs)
- newmarks[newmark.markname] = newmark
- argval = argval.args[-1]
- return argval, newmarks
-
-
-class MarkInfo:
+ return self.with_args(*args, **kwargs)
+
+
+def get_unpacked_marks(obj):
+ """
+ obtain the unpacked marks that are stored on a object
+ """
+ mark_list = getattr(obj, 'pytestmark', [])
+
+ if not isinstance(mark_list, list):
+ mark_list = [mark_list]
+ return [
+ getattr(mark, 'mark', mark) # unpack MarkDecorator
+ for mark in mark_list
+ ]
+
+
+def store_mark(obj, mark):
+ """store a Mark on a object
+ this is used to implement the Mark declarations/decorators correctly
+ """
+ assert isinstance(mark, Mark), mark
+ # always reassign name to avoid updating pytestmark
+ # in a reference that was only borrowed
+ obj.pytestmark = get_unpacked_marks(obj) + [mark]
+
+
+def store_legacy_markinfo(func, mark):
+ """create the legacy MarkInfo objects and put them onto the function
+ """
+ if not isinstance(mark, Mark):
+ raise TypeError("got {mark!r} instead of a Mark".format(mark=mark))
+ holder = getattr(func, mark.name, None)
+ if holder is None:
+ holder = MarkInfo(mark)
+ setattr(func, mark.name, holder)
+ else:
+ holder.add_mark(mark)
+
+
+class Mark(namedtuple('Mark', 'name, args, kwargs')):
+
+ def combined_with(self, other):
+ assert self.name == other.name
+ return Mark(
+ self.name, self.args + other.args,
+ dict(self.kwargs, **other.kwargs))
+
+
+class MarkInfo(object):
""" Marking object created by :class:`MarkDecorator` instances. """
- def __init__(self, name, args, kwargs):
- #: name of attribute
- self.name = name
- #: positional argument list, empty if none specified
- self.args = args
- #: keyword argument dictionary, empty if nothing specified
- self.kwargs = kwargs.copy()
- self._arglist = [(args, kwargs.copy())]
+
+ def __init__(self, mark):
+ assert isinstance(mark, Mark), repr(mark)
+ self.combined = mark
+ self._marks = [mark]
+
+ name = alias('combined.name')
+ args = alias('combined.args')
+ kwargs = alias('combined.kwargs')
def __repr__(self):
- return "<MarkInfo %r args=%r kwargs=%r>" % (
- self.name, self.args, self.kwargs
- )
+ return "<MarkInfo {0!r}>".format(self.combined)
- def add(self, args, kwargs):
+ def add_mark(self, mark):
""" add a MarkInfo with the given args and kwargs. """
- self._arglist.append((args, kwargs))
- self.args += args
- self.kwargs.update(kwargs)
+ self._marks.append(mark)
+ self.combined = self.combined.combined_with(mark)
def __iter__(self):
""" yield MarkInfo objects each relating to a marking-call. """
- for args, kwargs in self._arglist:
- yield MarkInfo(self.name, args, kwargs)
+ return imap(MarkInfo, self._marks)
+
+
+MARK_GEN = MarkGenerator()
+
+
+def _marked(func, mark):
+ """ Returns True if :func: is already marked with :mark:, False otherwise.
+ This can happen if marker is applied to class and the test file is
+ invoked more than once.
+ """
+ try:
+ func_mark = getattr(func, mark.name)
+ except AttributeError:
+ return False
+ return mark.args == func_mark.args and mark.kwargs == func_mark.kwargs
+
+
+def transfer_markers(funcobj, cls, mod):
+ """
+ this function transfers class level markers and module level markers
+ into function level markinfo objects
+
+ this is the main reason why marks are so broken
+ the resolution will involve phasing out function level MarkInfo objects
+
+ """
+ for obj in (cls, mod):
+ for mark in get_unpacked_marks(obj):
+ if not _marked(funcobj, mark):
+ store_legacy_markinfo(funcobj, mark)
diff --git a/lib/spack/external/_pytest/monkeypatch.py b/lib/spack/external/_pytest/monkeypatch.py
index 852e72beda..39ac770135 100644
--- a/lib/spack/external/_pytest/monkeypatch.py
+++ b/lib/spack/external/_pytest/monkeypatch.py
@@ -1,17 +1,18 @@
""" monkeypatching and mocking functionality. """
+from __future__ import absolute_import, division, print_function
-import os, sys
+import os
+import sys
import re
from py.builtin import _basestring
-
-import pytest
+from _pytest.fixtures import fixture
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
-@pytest.fixture
-def monkeypatch(request):
+@fixture
+def monkeypatch():
"""The returned ``monkeypatch`` fixture provides these
helper methods to modify objects, dictionaries or os.environ::
@@ -30,8 +31,8 @@ def monkeypatch(request):
will be raised if the set/deletion operation has no target.
"""
mpatch = MonkeyPatch()
- request.addfinalizer(mpatch.undo)
- return mpatch
+ yield mpatch
+ mpatch.undo()
def resolve(name):
@@ -70,9 +71,9 @@ def annotated_getattr(obj, name, ann):
obj = getattr(obj, name)
except AttributeError:
raise AttributeError(
- '%r object at %s has no attribute %r' % (
- type(obj).__name__, ann, name
- )
+ '%r object at %s has no attribute %r' % (
+ type(obj).__name__, ann, name
+ )
)
return obj
diff --git a/lib/spack/external/_pytest/nodes.py b/lib/spack/external/_pytest/nodes.py
new file mode 100644
index 0000000000..ad3af2ce67
--- /dev/null
+++ b/lib/spack/external/_pytest/nodes.py
@@ -0,0 +1,37 @@
+SEP = "/"
+
+
+def _splitnode(nodeid):
+ """Split a nodeid into constituent 'parts'.
+
+ Node IDs are strings, and can be things like:
+ ''
+ 'testing/code'
+ 'testing/code/test_excinfo.py'
+ 'testing/code/test_excinfo.py::TestFormattedExcinfo::()'
+
+ Return values are lists e.g.
+ []
+ ['testing', 'code']
+ ['testing', 'code', 'test_excinfo.py']
+ ['testing', 'code', 'test_excinfo.py', 'TestFormattedExcinfo', '()']
+ """
+ if nodeid == '':
+ # If there is no root node at all, return an empty list so the caller's logic can remain sane
+ return []
+ parts = nodeid.split(SEP)
+ # Replace single last element 'test_foo.py::Bar::()' with multiple elements 'test_foo.py', 'Bar', '()'
+ parts[-1:] = parts[-1].split("::")
+ return parts
+
+
+def ischildnode(baseid, nodeid):
+ """Return True if the nodeid is a child node of the baseid.
+
+ E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp'
+ """
+ base_parts = _splitnode(baseid)
+ node_parts = _splitnode(nodeid)
+ if len(node_parts) < len(base_parts):
+ return False
+ return node_parts[:len(base_parts)] == base_parts
diff --git a/lib/spack/external/_pytest/nose.py b/lib/spack/external/_pytest/nose.py
index 0387468686..d246c5603d 100644
--- a/lib/spack/external/_pytest/nose.py
+++ b/lib/spack/external/_pytest/nose.py
@@ -1,10 +1,11 @@
""" run test suites written for nose. """
+from __future__ import absolute_import, division, print_function
import sys
import py
-import pytest
-from _pytest import unittest
+from _pytest import unittest, runner, python
+from _pytest.config import hookimpl
def get_skip_exceptions():
@@ -19,45 +20,46 @@ def get_skip_exceptions():
def pytest_runtest_makereport(item, call):
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
# let's substitute the excinfo with a pytest.skip one
- call2 = call.__class__(lambda:
- pytest.skip(str(call.excinfo.value)), call.when)
+ call2 = call.__class__(
+ lambda: runner.skip(str(call.excinfo.value)), call.when)
call.excinfo = call2.excinfo
-@pytest.hookimpl(trylast=True)
+@hookimpl(trylast=True)
def pytest_runtest_setup(item):
if is_potential_nosetest(item):
- if isinstance(item.parent, pytest.Generator):
+ if isinstance(item.parent, python.Generator):
gen = item.parent
if not hasattr(gen, '_nosegensetup'):
call_optional(gen.obj, 'setup')
- if isinstance(gen.parent, pytest.Instance):
+ if isinstance(gen.parent, python.Instance):
call_optional(gen.parent.obj, 'setup')
gen._nosegensetup = True
if not call_optional(item.obj, 'setup'):
# call module level setup if there is no object level one
call_optional(item.parent.obj, 'setup')
- #XXX this implies we only call teardown when setup worked
+ # XXX this implies we only call teardown when setup worked
item.session._setupstate.addfinalizer((lambda: teardown_nose(item)), item)
+
def teardown_nose(item):
if is_potential_nosetest(item):
if not call_optional(item.obj, 'teardown'):
call_optional(item.parent.obj, 'teardown')
- #if hasattr(item.parent, '_nosegensetup'):
+ # if hasattr(item.parent, '_nosegensetup'):
# #call_optional(item._nosegensetup, 'teardown')
# del item.parent._nosegensetup
def pytest_make_collect_report(collector):
- if isinstance(collector, pytest.Generator):
+ if isinstance(collector, python.Generator):
call_optional(collector.obj, 'setup')
def is_potential_nosetest(item):
# extra check needed since we do not do nose style setup/teardown
# on direct unittest style classes
- return isinstance(item, pytest.Function) and \
+ return isinstance(item, python.Function) and \
not isinstance(item, unittest.TestCaseFunction)
diff --git a/lib/spack/external/_pytest/outcomes.py b/lib/spack/external/_pytest/outcomes.py
new file mode 100644
index 0000000000..ff5ef756d9
--- /dev/null
+++ b/lib/spack/external/_pytest/outcomes.py
@@ -0,0 +1,140 @@
+"""
+exception classes and constants handling test outcomes
+as well as functions creating them
+"""
+from __future__ import absolute_import, division, print_function
+import py
+import sys
+
+
+class OutcomeException(BaseException):
+ """ OutcomeException and its subclass instances indicate and
+ contain info about test and collection outcomes.
+ """
+ def __init__(self, msg=None, pytrace=True):
+ BaseException.__init__(self, msg)
+ self.msg = msg
+ self.pytrace = pytrace
+
+ def __repr__(self):
+ if self.msg:
+ val = self.msg
+ if isinstance(val, bytes):
+ val = py._builtin._totext(val, errors='replace')
+ return val
+ return "<%s instance>" % (self.__class__.__name__,)
+ __str__ = __repr__
+
+
+TEST_OUTCOME = (OutcomeException, Exception)
+
+
+class Skipped(OutcomeException):
+ # XXX hackish: on 3k we fake to live in the builtins
+ # in order to have Skipped exception printing shorter/nicer
+ __module__ = 'builtins'
+
+ def __init__(self, msg=None, pytrace=True, allow_module_level=False):
+ OutcomeException.__init__(self, msg=msg, pytrace=pytrace)
+ self.allow_module_level = allow_module_level
+
+
+class Failed(OutcomeException):
+ """ raised from an explicit call to pytest.fail() """
+ __module__ = 'builtins'
+
+
+class Exit(KeyboardInterrupt):
+ """ raised for immediate program exits (no tracebacks/summaries)"""
+ def __init__(self, msg="unknown reason"):
+ self.msg = msg
+ KeyboardInterrupt.__init__(self, msg)
+
+# exposed helper methods
+
+
+def exit(msg):
+ """ exit testing process as if KeyboardInterrupt was triggered. """
+ __tracebackhide__ = True
+ raise Exit(msg)
+
+
+exit.Exception = Exit
+
+
+def skip(msg=""):
+ """ skip an executing test with the given message. Note: it's usually
+ better to use the pytest.mark.skipif marker to declare a test to be
+ skipped under certain conditions like mismatching platforms or
+ dependencies. See the pytest_skipping plugin for details.
+ """
+ __tracebackhide__ = True
+ raise Skipped(msg=msg)
+
+
+skip.Exception = Skipped
+
+
+def fail(msg="", pytrace=True):
+ """ explicitly fail an currently-executing test with the given Message.
+
+ :arg pytrace: if false the msg represents the full failure information
+ and no python traceback will be reported.
+ """
+ __tracebackhide__ = True
+ raise Failed(msg=msg, pytrace=pytrace)
+
+
+fail.Exception = Failed
+
+
+class XFailed(fail.Exception):
+ """ raised from an explicit call to pytest.xfail() """
+
+
+def xfail(reason=""):
+ """ xfail an executing test or setup functions with the given reason."""
+ __tracebackhide__ = True
+ raise XFailed(reason)
+
+
+xfail.Exception = XFailed
+
+
+def importorskip(modname, minversion=None):
+ """ return imported module if it has at least "minversion" as its
+ __version__ attribute. If no minversion is specified the a skip
+ is only triggered if the module can not be imported.
+ """
+ import warnings
+ __tracebackhide__ = True
+ compile(modname, '', 'eval') # to catch syntaxerrors
+ should_skip = False
+
+ with warnings.catch_warnings():
+ # make sure to ignore ImportWarnings that might happen because
+ # of existing directories with the same name we're trying to
+ # import but without a __init__.py file
+ warnings.simplefilter('ignore')
+ try:
+ __import__(modname)
+ except ImportError:
+ # Do not raise chained exception here(#1485)
+ should_skip = True
+ if should_skip:
+ raise Skipped("could not import %r" % (modname,), allow_module_level=True)
+ mod = sys.modules[modname]
+ if minversion is None:
+ return mod
+ verattr = getattr(mod, '__version__', None)
+ if minversion is not None:
+ try:
+ from pkg_resources import parse_version as pv
+ except ImportError:
+ raise Skipped("we have a required version for %r but can not import "
+ "pkg_resources to parse version strings." % (modname,),
+ allow_module_level=True)
+ if verattr is None or pv(verattr) < pv(minversion):
+ raise Skipped("module %r has __version__ %r, required is: %r" % (
+ modname, verattr, minversion), allow_module_level=True)
+ return mod
diff --git a/lib/spack/external/_pytest/pastebin.py b/lib/spack/external/_pytest/pastebin.py
index 9f1cf90637..9d689819f0 100644
--- a/lib/spack/external/_pytest/pastebin.py
+++ b/lib/spack/external/_pytest/pastebin.py
@@ -1,4 +1,6 @@
""" submit failure or test session information to a pastebin service. """
+from __future__ import absolute_import, division, print_function
+
import pytest
import sys
import tempfile
@@ -7,9 +9,9 @@ import tempfile
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")
group._addoption('--pastebin', metavar="mode",
- action='store', dest="pastebin", default=None,
- choices=['failed', 'all'],
- help="send failed|all info to bpaste.net pastebin service.")
+ action='store', dest="pastebin", default=None,
+ choices=['failed', 'all'],
+ help="send failed|all info to bpaste.net pastebin service.")
@pytest.hookimpl(trylast=True)
@@ -95,4 +97,4 @@ def pytest_terminal_summary(terminalreporter):
s = tw.stringio.getvalue()
assert len(s)
pastebinurl = create_new_paste(s)
- tr.write_line("%s --> %s" %(msg, pastebinurl))
+ tr.write_line("%s --> %s" % (msg, pastebinurl))
diff --git a/lib/spack/external/_pytest/pytester.py b/lib/spack/external/_pytest/pytester.py
index d87c0a762a..2db85dff22 100644
--- a/lib/spack/external/_pytest/pytester.py
+++ b/lib/spack/external/_pytest/pytester.py
@@ -1,4 +1,6 @@
""" (disabled by default) support for testing pytest and pytest plugins. """
+from __future__ import absolute_import, division, print_function
+
import codecs
import gc
import os
@@ -10,8 +12,9 @@ import time
import traceback
from fnmatch import fnmatch
-from py.builtin import print_
+from weakref import WeakKeyDictionary
+from _pytest.capture import MultiCapture, SysCapture
from _pytest._code import Source
import py
import pytest
@@ -22,13 +25,13 @@ from _pytest.assertion.rewrite import AssertionRewritingHook
def pytest_addoption(parser):
# group = parser.getgroup("pytester", "pytester (self-tests) options")
parser.addoption('--lsof',
- action="store_true", dest="lsof", default=False,
- help=("run FD checks if lsof is available"))
+ action="store_true", dest="lsof", default=False,
+ help=("run FD checks if lsof is available"))
parser.addoption('--runpytest', default="inprocess", dest="runpytest",
- choices=("inprocess", "subprocess", ),
- help=("run pytest sub runs in tests using an 'inprocess' "
- "or 'subprocess' (python -m main) method"))
+ choices=("inprocess", "subprocess", ),
+ help=("run pytest sub runs in tests using an 'inprocess' "
+ "or 'subprocess' (python -m main) method"))
def pytest_configure(config):
@@ -59,7 +62,7 @@ class LsofFdLeakChecker(object):
def _parse_lsof_output(self, out):
def isopen(line):
return line.startswith('f') and ("deleted" not in line and
- 'mem' not in line and "txt" not in line and 'cwd' not in line)
+ 'mem' not in line and "txt" not in line and 'cwd' not in line)
open_files = []
@@ -85,7 +88,7 @@ class LsofFdLeakChecker(object):
return True
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
- def pytest_runtest_item(self, item):
+ def pytest_runtest_protocol(self, item):
lines1 = self.get_open_files()
yield
if hasattr(sys, "pypy_version_info"):
@@ -104,7 +107,8 @@ class LsofFdLeakChecker(object):
error.extend([str(f) for f in lines2])
error.append(error[0])
error.append("*** function %s:%s: %s " % item.location)
- pytest.fail("\n".join(error), pytrace=False)
+ error.append("See issue #2366")
+ item.warn('', "\n".join(error))
# XXX copied from execnet's conftest.py - needs to be merged
@@ -118,6 +122,7 @@ winpymap = {
'python3.5': r'C:\Python35\python.exe',
}
+
def getexecutable(name, cache={}):
try:
return cache[name]
@@ -126,19 +131,20 @@ def getexecutable(name, cache={}):
if executable:
import subprocess
popen = subprocess.Popen([str(executable), "--version"],
- universal_newlines=True, stderr=subprocess.PIPE)
+ universal_newlines=True, stderr=subprocess.PIPE)
out, err = popen.communicate()
if name == "jython":
if not err or "2.5" not in err:
executable = None
if "2.5.2" in err:
- executable = None # http://bugs.jython.org/issue1790
+ executable = None # http://bugs.jython.org/issue1790
elif popen.returncode != 0:
# Handle pyenv's 127.
executable = None
cache[name] = executable
return executable
+
@pytest.fixture(params=['python2.6', 'python2.7', 'python3.3', "python3.4",
'pypy', 'pypy3'])
def anypython(request):
@@ -155,6 +161,8 @@ def anypython(request):
return executable
# used at least by pytest-xdist plugin
+
+
@pytest.fixture
def _pytest(request):
""" Return a helper which offers a gethookrecorder(hook)
@@ -163,6 +171,7 @@ def _pytest(request):
"""
return PytestArg(request)
+
class PytestArg:
def __init__(self, request):
self.request = request
@@ -173,9 +182,9 @@ class PytestArg:
return hookrecorder
-def get_public_names(l):
- """Only return names from iterator l without a leading underscore."""
- return [x for x in l if x[0] != "_"]
+def get_public_names(values):
+ """Only return names from iterator values without a leading underscore."""
+ return [x for x in values if x[0] != "_"]
class ParsedCall:
@@ -186,7 +195,7 @@ class ParsedCall:
def __repr__(self):
d = self.__dict__.copy()
del d['_name']
- return "<ParsedCall %r(**%r)>" %(self._name, d)
+ return "<ParsedCall %r(**%r)>" % (self._name, d)
class HookRecorder:
@@ -226,15 +235,15 @@ class HookRecorder:
name, check = entries.pop(0)
for ind, call in enumerate(self.calls[i:]):
if call._name == name:
- print_("NAMEMATCH", name, call)
+ print("NAMEMATCH", name, call)
if eval(check, backlocals, call.__dict__):
- print_("CHECKERMATCH", repr(check), "->", call)
+ print("CHECKERMATCH", repr(check), "->", call)
else:
- print_("NOCHECKERMATCH", repr(check), "-", call)
+ print("NOCHECKERMATCH", repr(check), "-", call)
continue
i += ind + 1
break
- print_("NONAMEMATCH", name, "with", call)
+ print("NONAMEMATCH", name, "with", call)
else:
pytest.fail("could not find %r check %r" % (name, check))
@@ -249,9 +258,9 @@ class HookRecorder:
pytest.fail("\n".join(lines))
def getcall(self, name):
- l = self.getcalls(name)
- assert len(l) == 1, (name, l)
- return l[0]
+ values = self.getcalls(name)
+ assert len(values) == 1, (name, values)
+ return values[0]
# functionality for test reports
@@ -260,9 +269,9 @@ class HookRecorder:
return [x.report for x in self.getcalls(names)]
def matchreport(self, inamepart="",
- names="pytest_runtest_logreport pytest_collectreport", when=None):
+ names="pytest_runtest_logreport pytest_collectreport", when=None):
""" return a testreport whose dotted import path matches """
- l = []
+ values = []
for rep in self.getreports(names=names):
try:
if not when and rep.when != "call" and rep.passed:
@@ -273,14 +282,14 @@ class HookRecorder:
if when and getattr(rep, 'when', None) != when:
continue
if not inamepart or inamepart in rep.nodeid.split("::"):
- l.append(rep)
- if not l:
+ values.append(rep)
+ if not values:
raise ValueError("could not find test report matching %r: "
"no test reports at all!" % (inamepart,))
- if len(l) > 1:
+ if len(values) > 1:
raise ValueError(
- "found 2 or more testreports matching %r: %s" %(inamepart, l))
- return l[0]
+ "found 2 or more testreports matching %r: %s" % (inamepart, values))
+ return values[0]
def getfailures(self,
names='pytest_runtest_logreport pytest_collectreport'):
@@ -294,7 +303,7 @@ class HookRecorder:
skipped = []
failed = []
for rep in self.getreports(
- "pytest_collectreport pytest_runtest_logreport"):
+ "pytest_collectreport pytest_runtest_logreport"):
if rep.passed:
if getattr(rep, "when", None) == "call":
passed.append(rep)
@@ -332,7 +341,9 @@ def testdir(request, tmpdir_factory):
return Testdir(request, tmpdir_factory)
-rex_outcome = re.compile("(\d+) ([\w-]+)")
+rex_outcome = re.compile(r"(\d+) ([\w-]+)")
+
+
class RunResult:
"""The result of running a command.
@@ -348,6 +359,7 @@ class RunResult:
:duration: Duration in seconds.
"""
+
def __init__(self, ret, outlines, errlines, duration):
self.ret = ret
self.outlines = outlines
@@ -367,15 +379,19 @@ class RunResult:
for num, cat in outcomes:
d[cat] = int(num)
return d
+ raise ValueError("Pytest terminal report not found")
- def assert_outcomes(self, passed=0, skipped=0, failed=0):
+ def assert_outcomes(self, passed=0, skipped=0, failed=0, error=0):
""" assert that the specified outcomes appear with the respective
numbers (0 means it didn't occur) in the text output from a test run."""
d = self.parseoutcomes()
- assert passed == d.get("passed", 0)
- assert skipped == d.get("skipped", 0)
- assert failed == d.get("failed", 0)
-
+ obtained = {
+ 'passed': d.get('passed', 0),
+ 'skipped': d.get('skipped', 0),
+ 'failed': d.get('failed', 0),
+ 'error': d.get('error', 0),
+ }
+ assert obtained == dict(passed=passed, skipped=skipped, failed=failed, error=error)
class Testdir:
@@ -401,6 +417,7 @@ class Testdir:
def __init__(self, request, tmpdir_factory):
self.request = request
+ self._mod_collections = WeakKeyDictionary()
# XXX remove duplication with tmpdir plugin
basetmp = tmpdir_factory.ensuretemp("testdir")
name = request.function.__name__
@@ -414,7 +431,7 @@ class Testdir:
self.plugins = []
self._savesyspath = (list(sys.path), list(sys.meta_path))
self._savemodulekeys = set(sys.modules)
- self.chdir() # always chdir
+ self.chdir() # always chdir
self.request.addfinalizer(self.finalize)
method = self.request.config.getoption("--runpytest")
if method == "inprocess":
@@ -446,9 +463,10 @@ class Testdir:
the module is re-imported.
"""
for name in set(sys.modules).difference(self._savemodulekeys):
- # it seems zope.interfaces is keeping some state
- # (used by twisted related tests)
- if name != "zope.interface":
+ # some zope modules used by twisted-related tests keeps internal
+ # state and can't be deleted; we had some trouble in the past
+ # with zope.interface for example
+ if not name.startswith("zope"):
del sys.modules[name]
def make_hook_recorder(self, pluginmanager):
@@ -468,7 +486,7 @@ class Testdir:
if not hasattr(self, '_olddir'):
self._olddir = old
- def _makefile(self, ext, args, kwargs):
+ def _makefile(self, ext, args, kwargs, encoding="utf-8"):
items = list(kwargs.items())
if args:
source = py.builtin._totext("\n").join(
@@ -488,8 +506,8 @@ class Testdir:
source_unicode = "\n".join([my_totext(line) for line in source.lines])
source = py.builtin._totext(source_unicode)
- content = source.strip().encode("utf-8") # + "\n"
- #content = content.rstrip() + "\n"
+ content = source.strip().encode(encoding) # + "\n"
+ # content = content.rstrip() + "\n"
p.write(content, "wb")
if ret is None:
ret = p
@@ -565,7 +583,7 @@ class Testdir:
def mkpydir(self, name):
"""Create a new python package.
- This creates a (sub)direcotry with an empty ``__init__.py``
+ This creates a (sub)directory with an empty ``__init__.py``
file so that is recognised as a python package.
"""
@@ -574,6 +592,7 @@ class Testdir:
return p
Session = Session
+
def getnode(self, config, arg):
"""Return the collection node of a file.
@@ -654,13 +673,13 @@ class Testdir:
"""
p = self.makepyfile(source)
- l = list(cmdlineargs) + [p]
- return self.inline_run(*l)
+ values = list(cmdlineargs) + [p]
+ return self.inline_run(*values)
def inline_genitems(self, *args):
"""Run ``pytest.main(['--collectonly'])`` in-process.
- Retuns a tuple of the collected items and a
+ Returns a tuple of the collected items and a
:py:class:`HookRecorder` instance.
This runs the :py:func:`pytest.main` function to run all of
@@ -733,7 +752,8 @@ class Testdir:
if kwargs.get("syspathinsert"):
self.syspathinsert()
now = time.time()
- capture = py.io.StdCapture()
+ capture = MultiCapture(Capture=SysCapture)
+ capture.start_capturing()
try:
try:
reprec = self.inline_run(*args, **kwargs)
@@ -748,13 +768,14 @@ class Testdir:
class reprec:
ret = 3
finally:
- out, err = capture.reset()
+ out, err = capture.readouterr()
+ capture.stop_capturing()
sys.stdout.write(out)
sys.stderr.write(err)
res = RunResult(reprec.ret,
out.split("\n"), err.split("\n"),
- time.time()-now)
+ time.time() - now)
res.reprec = reprec
return res
@@ -770,11 +791,11 @@ class Testdir:
args = [str(x) for x in args]
for x in args:
if str(x).startswith('--basetemp'):
- #print ("basedtemp exists: %s" %(args,))
+ # print("basedtemp exists: %s" %(args,))
break
else:
args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp'))
- #print ("added basetemp: %s" %(args,))
+ # print("added basetemp: %s" %(args,))
return args
def parseconfig(self, *args):
@@ -812,7 +833,7 @@ class Testdir:
self.request.addfinalizer(config._ensure_unconfigure)
return config
- def getitem(self, source, funcname="test_func"):
+ def getitem(self, source, funcname="test_func"):
"""Return the test item for a test function.
This writes the source to a python file and runs pytest's
@@ -829,10 +850,10 @@ class Testdir:
for item in items:
if item.name == funcname:
return item
- assert 0, "%r item not found in module:\n%s\nitems: %s" %(
+ assert 0, "%r item not found in module:\n%s\nitems: %s" % (
funcname, source, items)
- def getitems(self, source):
+ def getitems(self, source):
"""Return all test items collected from the module.
This writes the source to a python file and runs pytest's
@@ -843,7 +864,7 @@ class Testdir:
modcol = self.getmodulecol(source)
return self.genitems([modcol])
- def getmodulecol(self, source, configargs=(), withinit=False):
+ def getmodulecol(self, source, configargs=(), withinit=False):
"""Return the module collection node for ``source``.
This writes ``source`` to a file using :py:meth:`makepyfile`
@@ -856,15 +877,16 @@ class Testdir:
:py:meth:`parseconfigure`.
:param withinit: Whether to also write a ``__init__.py`` file
- to the temporarly directory to ensure it is a package.
+ to the temporary directory to ensure it is a package.
"""
kw = {self.request.function.__name__: Source(source).strip()}
path = self.makepyfile(**kw)
if withinit:
- self.makepyfile(__init__ = "#")
+ self.makepyfile(__init__="#")
self.config = config = self.parseconfigure(path, *configargs)
node = self.getnode(config, path)
+
return node
def collect_by_name(self, modcol, name):
@@ -879,7 +901,9 @@ class Testdir:
:param name: The name of the node to return.
"""
- for colitem in modcol._memocollect():
+ if modcol not in self._mod_collections:
+ self._mod_collections[modcol] = list(modcol.collect())
+ for colitem in self._mod_collections[modcol]:
if colitem.name == name:
return colitem
@@ -896,8 +920,11 @@ class Testdir:
env['PYTHONPATH'] = os.pathsep.join(filter(None, [
str(os.getcwd()), env.get('PYTHONPATH', '')]))
kw['env'] = env
- return subprocess.Popen(cmdargs,
- stdout=stdout, stderr=stderr, **kw)
+
+ popen = subprocess.Popen(cmdargs, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr, **kw)
+ popen.stdin.close()
+
+ return popen
def run(self, *cmdargs):
"""Run a command with arguments.
@@ -914,14 +941,14 @@ class Testdir:
cmdargs = [str(x) for x in cmdargs]
p1 = self.tmpdir.join("stdout")
p2 = self.tmpdir.join("stderr")
- print_("running:", ' '.join(cmdargs))
- print_(" in:", str(py.path.local()))
+ print("running:", ' '.join(cmdargs))
+ print(" in:", str(py.path.local()))
f1 = codecs.open(str(p1), "w", encoding="utf8")
f2 = codecs.open(str(p2), "w", encoding="utf8")
try:
now = time.time()
popen = self.popen(cmdargs, stdout=f1, stderr=f2,
- close_fds=(sys.platform != "win32"))
+ close_fds=(sys.platform != "win32"))
ret = popen.wait()
finally:
f1.close()
@@ -936,19 +963,19 @@ class Testdir:
f2.close()
self._dump_lines(out, sys.stdout)
self._dump_lines(err, sys.stderr)
- return RunResult(ret, out, err, time.time()-now)
+ return RunResult(ret, out, err, time.time() - now)
def _dump_lines(self, lines, fp):
try:
for line in lines:
- py.builtin.print_(line, file=fp)
+ print(line, file=fp)
except UnicodeEncodeError:
print("couldn't print to %s because of encoding" % (fp,))
def _getpytestargs(self):
# we cannot use "(sys.executable,script)"
# because on windows the script is e.g. a pytest.exe
- return (sys.executable, _pytest_fullpath,) # noqa
+ return (sys.executable, _pytest_fullpath,) # noqa
def runpython(self, script):
"""Run a python script using sys.executable as interpreter.
@@ -975,12 +1002,12 @@ class Testdir:
"""
p = py.path.local.make_numbered_dir(prefix="runpytest-",
- keep=None, rootdir=self.tmpdir)
+ keep=None, rootdir=self.tmpdir)
args = ('--basetemp=%s' % p, ) + args
- #for x in args:
+ # for x in args:
# if '--confcutdir' in str(x):
# break
- #else:
+ # else:
# pass
# args = ('--confcutdir=.',) + args
plugins = [x for x in self.plugins if isinstance(x, str)]
@@ -998,7 +1025,7 @@ class Testdir:
The pexpect child is returned.
"""
- basetemp = self.tmpdir.mkdir("pexpect")
+ basetemp = self.tmpdir.mkdir("temp-pexpect")
invoke = " ".join(map(str, self._getpytestargs()))
cmd = "%s --basetemp=%s %s" % (invoke, basetemp, string)
return self.spawn(cmd, expect_timeout=expect_timeout)
@@ -1019,12 +1046,13 @@ class Testdir:
child.timeout = expect_timeout
return child
+
def getdecoded(out):
- try:
- return out.decode("utf-8")
- except UnicodeDecodeError:
- return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (
- py.io.saferepr(out),)
+ try:
+ return out.decode("utf-8")
+ except UnicodeDecodeError:
+ return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (
+ py.io.saferepr(out),)
class LineComp:
@@ -1054,7 +1082,7 @@ class LineMatcher:
"""
- def __init__(self, lines):
+ def __init__(self, lines):
self.lines = lines
self._log_output = []
@@ -1093,7 +1121,7 @@ class LineMatcher:
"""
for i, line in enumerate(self.lines):
if fnline == line or fnmatch(line, fnline):
- return self.lines[i+1:]
+ return self.lines[i + 1:]
raise ValueError("line %r not found in output" % fnline)
def _log(self, *args):
diff --git a/lib/spack/external/_pytest/python.py b/lib/spack/external/_pytest/python.py
index 53815da2f0..41fd2bdb7f 100644
--- a/lib/spack/external/_pytest/python.py
+++ b/lib/spack/external/_pytest/python.py
@@ -1,26 +1,30 @@
""" Python test discovery, setup and run of test functions. """
+from __future__ import absolute_import, division, print_function
import fnmatch
import inspect
import sys
+import os
import collections
-import math
+from textwrap import dedent
from itertools import count
import py
-import pytest
from _pytest.mark import MarkerError
-
+from _pytest.config import hookimpl
import _pytest
import _pytest._pluggy as pluggy
from _pytest import fixtures
+from _pytest import main
from _pytest.compat import (
- isclass, isfunction, is_generator, _escape_strings,
+ isclass, isfunction, is_generator, _ascii_escaped,
REGEX_TYPE, STRING_TYPES, NoneType, NOTSET,
get_real_func, getfslineno, safe_getattr,
- getlocation, enum,
+ safe_str, getlocation, enum,
)
+from _pytest.outcomes import fail
+from _pytest.mark import transfer_markers
cutdir1 = py.path.local(pluggy.__file__.rstrip("oc"))
cutdir2 = py.path.local(_pytest.__file__).dirpath()
@@ -45,10 +49,9 @@ def filter_traceback(entry):
return p != cutdir1 and not p.relto(cutdir2) and not p.relto(cutdir3)
-
def pyobj_property(name):
def get(self):
- node = self.getparent(getattr(pytest, name))
+ node = self.getparent(getattr(__import__('pytest'), name))
if node is not None:
return node.obj
doc = "python %s object this node was collected from (can be None)." % (
@@ -59,8 +62,8 @@ def pyobj_property(name):
def pytest_addoption(parser):
group = parser.getgroup("general")
group.addoption('--fixtures', '--funcargs',
- action="store_true", dest="showfixtures", default=False,
- help="show available fixtures, sorted by plugin appearance")
+ action="store_true", dest="showfixtures", default=False,
+ help="show available fixtures, sorted by plugin appearance")
group.addoption(
'--fixtures-per-test',
action="store_true",
@@ -69,20 +72,20 @@ def pytest_addoption(parser):
help="show fixtures per test",
)
parser.addini("usefixtures", type="args", default=[],
- help="list of default fixtures to be used with this project")
+ help="list of default fixtures to be used with this project")
parser.addini("python_files", type="args",
- default=['test_*.py', '*_test.py'],
- help="glob-style file patterns for Python test module discovery")
- parser.addini("python_classes", type="args", default=["Test",],
- help="prefixes or glob names for Python test class discovery")
- parser.addini("python_functions", type="args", default=["test",],
- help="prefixes or glob names for Python test function and "
- "method discovery")
+ default=['test_*.py', '*_test.py'],
+ help="glob-style file patterns for Python test module discovery")
+ parser.addini("python_classes", type="args", default=["Test", ],
+ help="prefixes or glob names for Python test class discovery")
+ parser.addini("python_functions", type="args", default=["test", ],
+ help="prefixes or glob names for Python test function and "
+ "method discovery")
group.addoption("--import-mode", default="prepend",
- choices=["prepend", "append"], dest="importmode",
- help="prepend/append to sys.path when importing test modules, "
- "default is to prepend.")
+ choices=["prepend", "append"], dest="importmode",
+ help="prepend/append to sys.path when importing test modules, "
+ "default is to prepend.")
def pytest_cmdline_main(config):
@@ -109,39 +112,25 @@ def pytest_generate_tests(metafunc):
for marker in markers:
metafunc.parametrize(*marker.args, **marker.kwargs)
+
def pytest_configure(config):
config.addinivalue_line("markers",
- "parametrize(argnames, argvalues): call a test function multiple "
- "times passing in different arguments in turn. argvalues generally "
- "needs to be a list of values if argnames specifies only one name "
- "or a list of tuples of values if argnames specifies multiple names. "
- "Example: @parametrize('arg1', [1,2]) would lead to two calls of the "
- "decorated test function, one with arg1=1 and another with arg1=2."
- "see http://pytest.org/latest/parametrize.html for more info and "
- "examples."
- )
+ "parametrize(argnames, argvalues): call a test function multiple "
+ "times passing in different arguments in turn. argvalues generally "
+ "needs to be a list of values if argnames specifies only one name "
+ "or a list of tuples of values if argnames specifies multiple names. "
+ "Example: @parametrize('arg1', [1,2]) would lead to two calls of the "
+ "decorated test function, one with arg1=1 and another with arg1=2."
+ "see http://pytest.org/latest/parametrize.html for more info and "
+ "examples."
+ )
config.addinivalue_line("markers",
- "usefixtures(fixturename1, fixturename2, ...): mark tests as needing "
- "all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures "
- )
+ "usefixtures(fixturename1, fixturename2, ...): mark tests as needing "
+ "all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures "
+ )
+
-@pytest.hookimpl(trylast=True)
-def pytest_namespace():
- raises.Exception = pytest.fail.Exception
- return {
- 'raises': raises,
- 'approx': approx,
- 'collect': {
- 'Module': Module,
- 'Class': Class,
- 'Instance': Instance,
- 'Function': Function,
- 'Generator': Generator,
- }
- }
-
-
-@pytest.hookimpl(trylast=True)
+@hookimpl(trylast=True)
def pytest_pyfunc_call(pyfuncitem):
testfunction = pyfuncitem.obj
if pyfuncitem._isyieldedfunction():
@@ -154,6 +143,7 @@ def pytest_pyfunc_call(pyfuncitem):
testfunction(**testargs)
return True
+
def pytest_collect_file(path, parent):
ext = path.ext
if ext == ".py":
@@ -162,19 +152,21 @@ def pytest_collect_file(path, parent):
if path.fnmatch(pat):
break
else:
- return
+ return
ihook = parent.session.gethookproxy(path)
return ihook.pytest_pycollect_makemodule(path=path, parent=parent)
+
def pytest_pycollect_makemodule(path, parent):
return Module(path, parent)
-@pytest.hookimpl(hookwrapper=True)
+
+@hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem(collector, name, obj):
outcome = yield
res = outcome.get_result()
if res is not None:
- raise StopIteration
+ return
# nothing was collected elsewhere, let's do it here
if isclass(obj):
if collector.istestclass(obj, name):
@@ -187,9 +179,8 @@ def pytest_pycollect_makeitem(collector, name, obj):
# or a funtools.wrapped.
# We musn't if it's been wrapped with mock.patch (python 2 only)
if not (isfunction(obj) or isfunction(get_real_func(obj))):
- collector.warn(code="C2", message=
- "cannot collect %r because it is not a function."
- % name, )
+ collector.warn(code="C2", message="cannot collect %r because it is not a function."
+ % name, )
elif getattr(obj, "__test__", True):
if is_generator(obj):
res = Generator(name, parent=collector)
@@ -197,9 +188,9 @@ def pytest_pycollect_makeitem(collector, name, obj):
res = list(collector._genfunctions(name, obj))
outcome.force_result(res)
-def pytest_make_parametrize_id(config, val):
- return None
+def pytest_make_parametrize_id(config, val, argname=None):
+ return None
class PyobjContext(object):
@@ -207,6 +198,7 @@ class PyobjContext(object):
cls = pyobj_property("Class")
instance = pyobj_property("Instance")
+
class PyobjMixin(PyobjContext):
def obj():
def fget(self):
@@ -235,8 +227,7 @@ class PyobjMixin(PyobjContext):
continue
name = node.name
if isinstance(node, Module):
- assert name.endswith(".py")
- name = name[:-3]
+ name = os.path.splitext(name)[0]
if stopatmodule:
if includemodule:
parts.append(name)
@@ -265,7 +256,8 @@ class PyobjMixin(PyobjContext):
assert isinstance(lineno, int)
return fspath, lineno, modpath
-class PyCollector(PyobjMixin, pytest.Collector):
+
+class PyCollector(PyobjMixin, main.Collector):
def funcnamefilter(self, name):
return self._matches_prefix_or_glob_option('python_functions', name)
@@ -283,10 +275,22 @@ class PyCollector(PyobjMixin, pytest.Collector):
return self._matches_prefix_or_glob_option('python_classes', name)
def istestfunction(self, obj, name):
- return (
- (self.funcnamefilter(name) or self.isnosetest(obj)) and
- safe_getattr(obj, "__call__", False) and fixtures.getfixturemarker(obj) is None
- )
+ if self.funcnamefilter(name) or self.isnosetest(obj):
+ if isinstance(obj, staticmethod):
+ # static methods need to be unwrapped
+ obj = safe_getattr(obj, '__func__', False)
+ if obj is False:
+ # Python 2.6 wraps in a different way that we won't try to handle
+ msg = "cannot collect static method %r because " \
+ "it is not a function (always the case in Python 2.6)"
+ self.warn(
+ code="C2", message=msg % name)
+ return False
+ return (
+ safe_getattr(obj, "__call__", False) and fixtures.getfixturemarker(obj) is None
+ )
+ else:
+ return False
def istestclass(self, obj, name):
return self.classnamefilter(name) or self.isnosetest(obj)
@@ -317,7 +321,7 @@ class PyCollector(PyobjMixin, pytest.Collector):
for basecls in inspect.getmro(self.obj.__class__):
dicts.append(basecls.__dict__)
seen = {}
- l = []
+ values = []
for dic in dicts:
for name, obj in list(dic.items()):
if name in seen:
@@ -328,12 +332,12 @@ class PyCollector(PyobjMixin, pytest.Collector):
continue
if not isinstance(res, list):
res = [res]
- l.extend(res)
- l.sort(key=lambda item: item.reportinfo()[:2])
- return l
+ values.extend(res)
+ values.sort(key=lambda item: item.reportinfo()[:2])
+ return values
def makeitem(self, name, obj):
- #assert self.ihook.fspath == self.fspath, self
+ # assert self.ihook.fspath == self.fspath, self
return self.ihook.pytest_pycollect_makeitem(
collector=self, name=name, obj=obj)
@@ -369,43 +373,16 @@ class PyCollector(PyobjMixin, pytest.Collector):
yield Function(name=subname, parent=self,
callspec=callspec, callobj=funcobj,
fixtureinfo=fixtureinfo,
- keywords={callspec.id:True},
+ keywords={callspec.id: True},
originalname=name,
)
-def _marked(func, mark):
- """ Returns True if :func: is already marked with :mark:, False otherwise.
- This can happen if marker is applied to class and the test file is
- invoked more than once.
- """
- try:
- func_mark = getattr(func, mark.name)
- except AttributeError:
- return False
- return mark.args == func_mark.args and mark.kwargs == func_mark.kwargs
-
-
-def transfer_markers(funcobj, cls, mod):
- # XXX this should rather be code in the mark plugin or the mark
- # plugin should merge with the python plugin.
- for holder in (cls, mod):
- try:
- pytestmark = holder.pytestmark
- except AttributeError:
- continue
- if isinstance(pytestmark, list):
- for mark in pytestmark:
- if not _marked(funcobj, mark):
- mark(funcobj)
- else:
- if not _marked(funcobj, pytestmark):
- pytestmark(funcobj)
-
-class Module(pytest.File, PyCollector):
+class Module(main.File, PyCollector):
""" Collector for test classes and functions. """
+
def _getobj(self):
- return self._memoizedcall('_obj', self._importtestmodule)
+ return self._importtestmodule()
def collect(self):
self.session._fixturemanager.parsefactories(self)
@@ -429,7 +406,7 @@ class Module(pytest.File, PyCollector):
" %s\n"
"HINT: remove __pycache__ / .pyc files and/or use a "
"unique basename for your test file modules"
- % e.args
+ % e.args
)
except ImportError:
from _pytest._code.code import ExceptionInfo
@@ -437,7 +414,7 @@ class Module(pytest.File, PyCollector):
if self.config.getoption('verbose') < 2:
exc_info.traceback = exc_info.traceback.filter(filter_traceback)
exc_repr = exc_info.getrepr(style='short') if exc_info.traceback else exc_info.exconly()
- formatted_tb = py._builtin._totext(exc_repr)
+ formatted_tb = safe_str(exc_repr)
raise self.CollectError(
"ImportError while importing test module '{fspath}'.\n"
"Hint: make sure your test modules/packages have valid Python names.\n"
@@ -448,9 +425,10 @@ class Module(pytest.File, PyCollector):
if e.allow_module_level:
raise
raise self.CollectError(
- "Using pytest.skip outside of a test is not allowed. If you are "
- "trying to decorate a test function, use the @pytest.mark.skip "
- "or @pytest.mark.skipif decorators instead."
+ "Using pytest.skip outside of a test is not allowed. "
+ "To decorate a test function, use the @pytest.mark.skip "
+ "or @pytest.mark.skipif decorators instead, and to skip a "
+ "module use `pytestmark = pytest.mark.{skip,skipif}."
)
self.config.pluginmanager.consider_module(mod)
return mod
@@ -501,10 +479,13 @@ def _get_xunit_func(obj, name):
class Class(PyCollector):
""" Collector for test methods. """
+
def collect(self):
+ if not safe_getattr(self.obj, "__test__", True):
+ return []
if hasinit(self.obj):
self.warn("C1", "cannot collect test class %r because it has a "
- "__init__ constructor" % self.obj.__name__)
+ "__init__ constructor" % self.obj.__name__)
return []
elif hasnew(self.obj):
self.warn("C1", "cannot collect test class %r because it has a "
@@ -525,6 +506,7 @@ class Class(PyCollector):
fin_class = getattr(fin_class, '__func__', fin_class)
self.addfinalizer(lambda: fin_class(self.obj))
+
class Instance(PyCollector):
def _getobj(self):
return self.parent.obj()
@@ -537,6 +519,7 @@ class Instance(PyCollector):
self.obj = self._getobj()
return self.obj
+
class FunctionMixin(PyobjMixin):
""" mixin for the code common to Function and Generator.
"""
@@ -572,7 +555,7 @@ class FunctionMixin(PyobjMixin):
if ntraceback == traceback:
ntraceback = ntraceback.cut(path=path)
if ntraceback == traceback:
- #ntraceback = ntraceback.cut(excludepath=cutdir2)
+ # ntraceback = ntraceback.cut(excludepath=cutdir2)
ntraceback = ntraceback.filter(filter_traceback)
if not ntraceback:
ntraceback = traceback
@@ -586,11 +569,11 @@ class FunctionMixin(PyobjMixin):
entry.set_repr_style('short')
def _repr_failure_py(self, excinfo, style="long"):
- if excinfo.errisinstance(pytest.fail.Exception):
+ if excinfo.errisinstance(fail.Exception):
if not excinfo.value.pytrace:
return py._builtin._totext(excinfo.value)
return super(FunctionMixin, self)._repr_failure_py(excinfo,
- style=style)
+ style=style)
def repr_failure(self, excinfo, outerr=None):
assert outerr is None, "XXX outerr usage is deprecated"
@@ -609,27 +592,27 @@ class Generator(FunctionMixin, PyCollector):
self.session._setupstate.prepare(self)
# see FunctionMixin.setup and test_setupstate_is_preserved_134
self._preservedparent = self.parent.obj
- l = []
+ values = []
seen = {}
for i, x in enumerate(self.obj()):
name, call, args = self.getcallargs(x)
if not callable(call):
- raise TypeError("%r yielded non callable test %r" %(self.obj, call,))
+ raise TypeError("%r yielded non callable test %r" % (self.obj, call,))
if name is None:
name = "[%d]" % i
else:
name = "['%s']" % name
if name in seen:
- raise ValueError("%r generated tests with non-unique name %r" %(self, name))
+ raise ValueError("%r generated tests with non-unique name %r" % (self, name))
seen[name] = True
- l.append(self.Function(name, self, args=args, callobj=call))
- self.config.warn('C1', deprecated.YIELD_TESTS, fslocation=self.fspath)
- return l
+ values.append(self.Function(name, self, args=args, callobj=call))
+ self.warn('C1', deprecated.YIELD_TESTS)
+ return values
def getcallargs(self, obj):
if not isinstance(obj, (tuple, list)):
obj = (obj,)
- # explict naming
+ # explicit naming
if isinstance(obj[0], py.builtin._basestring):
name = obj[0]
obj = obj[1:]
@@ -679,7 +662,7 @@ class CallSpec2(object):
def _checkargnotcontained(self, arg):
if arg in self.params or arg in self.funcargs:
- raise ValueError("duplicate %r" %(arg,))
+ raise ValueError("duplicate %r" % (arg,))
def getparam(self, name):
try:
@@ -695,7 +678,7 @@ class CallSpec2(object):
def setmulti(self, valtypes, argnames, valset, id, keywords, scopenum,
param_index):
- for arg,val in zip(argnames, valset):
+ for arg, val in zip(argnames, valset):
self._checkargnotcontained(arg)
valtype_for_arg = valtypes[arg]
getattr(self, valtype_for_arg)[arg] = val
@@ -724,6 +707,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
test configuration or values specified in the class or module where a
test function is defined.
"""
+
def __init__(self, function, fixtureinfo, config, cls=None, module=None):
#: access to the :class:`_pytest.config.Config` object for the test session
self.config = config
@@ -745,7 +729,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
self._arg2fixturedefs = fixtureinfo.name2fixturedefs
def parametrize(self, argnames, argvalues, indirect=False, ids=None,
- scope=None):
+ scope=None):
""" Add new invocations to the underlying test function using the list
of argvalues for the given argnames. Parametrization is performed
during the collection phase. If you need to setup expensive resources
@@ -784,36 +768,34 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
to set a dynamic scope using test context or configuration.
"""
from _pytest.fixtures import scope2index
- from _pytest.mark import extract_argvalue
+ from _pytest.mark import MARK_GEN, ParameterSet
from py.io import saferepr
- unwrapped_argvalues = []
- newkeywords = []
- for maybe_marked_args in argvalues:
- argval, newmarks = extract_argvalue(maybe_marked_args)
- unwrapped_argvalues.append(argval)
- newkeywords.append(newmarks)
- argvalues = unwrapped_argvalues
-
if not isinstance(argnames, (tuple, list)):
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
- if len(argnames) == 1:
- argvalues = [(val,) for val in argvalues]
- if not argvalues:
- argvalues = [(NOTSET,) * len(argnames)]
- # we passed a empty list to parameterize, skip that test
- #
+ force_tuple = len(argnames) == 1
+ else:
+ force_tuple = False
+ parameters = [
+ ParameterSet.extract_from(x, legacy_force_tuple=force_tuple)
+ for x in argvalues]
+ del argvalues
+
+ if not parameters:
fs, lineno = getfslineno(self.function)
- newmark = pytest.mark.skip(
- reason="got empty parameter set %r, function %s at %s:%d" % (
- argnames, self.function.__name__, fs, lineno))
- newkeywords = [{newmark.markname: newmark}]
+ reason = "got empty parameter set %r, function %s at %s:%d" % (
+ argnames, self.function.__name__, fs, lineno)
+ mark = MARK_GEN.skip(reason=reason)
+ parameters.append(ParameterSet(
+ values=(NOTSET,) * len(argnames),
+ marks=[mark],
+ id=None,
+ ))
if scope is None:
scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
- scopenum = scope2index(
- scope, descr='call to {0}'.format(self.parametrize))
+ scopenum = scope2index(scope, descr='call to {0}'.format(self.parametrize))
valtypes = {}
for arg in argnames:
if arg not in self.fixturenames:
@@ -823,7 +805,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
name = 'fixture' if indirect else 'argument'
raise ValueError(
"%r uses no %s %r" % (
- self.function, name, arg))
+ self.function, name, arg))
if indirect is True:
valtypes = dict.fromkeys(argnames, "params")
@@ -841,22 +823,26 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
idfn = ids
ids = None
if ids:
- if len(ids) != len(argvalues):
- raise ValueError('%d tests specified with %d ids' %(
- len(argvalues), len(ids)))
+ if len(ids) != len(parameters):
+ raise ValueError('%d tests specified with %d ids' % (
+ len(parameters), len(ids)))
for id_value in ids:
if id_value is not None and not isinstance(id_value, py.builtin._basestring):
msg = 'ids must be list of strings, found: %s (type: %s)'
raise ValueError(msg % (saferepr(id_value), type(id_value).__name__))
- ids = idmaker(argnames, argvalues, idfn, ids, self.config)
+ ids = idmaker(argnames, parameters, idfn, ids, self.config)
newcalls = []
for callspec in self._calls or [CallSpec2(self)]:
- elements = zip(ids, argvalues, newkeywords, count())
- for a_id, valset, keywords, param_index in elements:
- assert len(valset) == len(argnames)
+ elements = zip(ids, parameters, count())
+ for a_id, param, param_index in elements:
+ if len(param.values) != len(argnames):
+ raise ValueError(
+ 'In "parametrize" the number of values ({0}) must be '
+ 'equal to the number of names ({1})'.format(
+ param.values, argnames))
newcallspec = callspec.copy(self)
- newcallspec.setmulti(valtypes, argnames, valset, a_id,
- keywords, scopenum, param_index)
+ newcallspec.setmulti(valtypes, argnames, param.values, a_id,
+ param.deprecated_arg_dict, scopenum, param_index)
newcalls.append(newcallspec)
self._calls = newcalls
@@ -880,7 +866,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
if funcargs is not None:
for name in funcargs:
if name not in self.fixturenames:
- pytest.fail("funcarg %r not used in this function." % name)
+ fail("funcarg %r not used in this function." % name)
else:
funcargs = {}
if id is None:
@@ -910,7 +896,7 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
from _pytest.fixtures import scopes
indirect_as_list = isinstance(indirect, (list, tuple))
all_arguments_are_fixtures = indirect is True or \
- indirect_as_list and len(indirect) == argnames
+ indirect_as_list and len(indirect) == argnames
if all_arguments_are_fixtures:
fixturedefs = arg2fixturedefs or {}
used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()]
@@ -925,41 +911,51 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
def _idval(val, argname, idx, idfn, config=None):
if idfn:
+ s = None
try:
s = idfn(val)
- if s:
- return _escape_strings(s)
except Exception:
- pass
+ # See issue https://github.com/pytest-dev/pytest/issues/2169
+ import warnings
+ msg = "Raised while trying to determine id of parameter %s at position %d." % (argname, idx)
+ msg += '\nUpdate your code as this will raise an error in pytest-4.0.'
+ warnings.warn(msg, DeprecationWarning)
+ if s:
+ return _ascii_escaped(s)
if config:
- hook_id = config.hook.pytest_make_parametrize_id(config=config, val=val)
+ hook_id = config.hook.pytest_make_parametrize_id(
+ config=config, val=val, argname=argname)
if hook_id:
return hook_id
if isinstance(val, STRING_TYPES):
- return _escape_strings(val)
+ return _ascii_escaped(val)
elif isinstance(val, (float, int, bool, NoneType)):
return str(val)
elif isinstance(val, REGEX_TYPE):
- return _escape_strings(val.pattern)
+ return _ascii_escaped(val.pattern)
elif enum is not None and isinstance(val, enum.Enum):
return str(val)
elif isclass(val) and hasattr(val, '__name__'):
return val.__name__
- return str(argname)+str(idx)
+ return str(argname) + str(idx)
-def _idvalset(idx, valset, argnames, idfn, ids, config=None):
+
+def _idvalset(idx, parameterset, argnames, idfn, ids, config=None):
+ if parameterset.id is not None:
+ return parameterset.id
if ids is None or (idx >= len(ids) or ids[idx] is None):
this_id = [_idval(val, argname, idx, idfn, config)
- for val, argname in zip(valset, argnames)]
+ for val, argname in zip(parameterset.values, argnames)]
return "-".join(this_id)
else:
- return _escape_strings(ids[idx])
+ return _ascii_escaped(ids[idx])
+
-def idmaker(argnames, argvalues, idfn=None, ids=None, config=None):
- ids = [_idvalset(valindex, valset, argnames, idfn, ids, config)
- for valindex, valset in enumerate(argvalues)]
+def idmaker(argnames, parametersets, idfn=None, ids=None, config=None):
+ ids = [_idvalset(valindex, parameterset, argnames, idfn, ids, config)
+ for valindex, parameterset in enumerate(parametersets)]
if len(set(ids)) != len(ids):
# The ids are not unique
duplicates = [testid for testid in ids if ids.count(testid) > 1]
@@ -983,58 +979,55 @@ def _show_fixtures_per_test(config, session):
tw = _pytest.config.create_terminal_writer(config)
verbose = config.getvalue("verbose")
- def get_best_rel(func):
+ def get_best_relpath(func):
loc = getlocation(func, curdir)
return curdir.bestrelpath(loc)
def write_fixture(fixture_def):
argname = fixture_def.argname
-
if verbose <= 0 and argname.startswith("_"):
return
if verbose > 0:
- bestrel = get_best_rel(fixture_def.func)
+ bestrel = get_best_relpath(fixture_def.func)
funcargspec = "{0} -- {1}".format(argname, bestrel)
else:
funcargspec = argname
tw.line(funcargspec, green=True)
-
- INDENT = ' {0}'
fixture_doc = fixture_def.func.__doc__
-
if fixture_doc:
- for line in fixture_doc.strip().split('\n'):
- tw.line(INDENT.format(line.strip()))
+ write_docstring(tw, fixture_doc)
else:
- tw.line(INDENT.format('no docstring available'), red=True)
+ tw.line(' no docstring available', red=True)
def write_item(item):
- name2fixturedefs = item._fixtureinfo.name2fixturedefs
-
- if not name2fixturedefs:
- # The given test item does not use any fixtures
+ try:
+ info = item._fixtureinfo
+ except AttributeError:
+ # doctests items have no _fixtureinfo attribute
+ return
+ if not info.name2fixturedefs:
+ # this test item does not use any fixtures
return
- bestrel = get_best_rel(item.function)
-
tw.line()
tw.sep('-', 'fixtures used by {0}'.format(item.name))
- tw.sep('-', '({0})'.format(bestrel))
- for argname, fixture_defs in sorted(name2fixturedefs.items()):
- assert fixture_defs is not None
- if not fixture_defs:
+ tw.sep('-', '({0})'.format(get_best_relpath(item.function)))
+ # dict key not used in loop but needed for sorting
+ for _, fixturedefs in sorted(info.name2fixturedefs.items()):
+ assert fixturedefs is not None
+ if not fixturedefs:
continue
- # The last fixture def item in the list is expected
- # to be the one used by the test item
- write_fixture(fixture_defs[-1])
+ # last item is expected to be the one used by the test item
+ write_fixture(fixturedefs[-1])
- for item in session.items:
- write_item(item)
+ for session_item in session.items:
+ write_item(session_item)
def showfixtures(config):
from _pytest.main import wrap_session
return wrap_session(config, _showfixtures_main)
+
def _showfixtures_main(config, session):
import _pytest.config
session.perform_collect()
@@ -1067,444 +1060,46 @@ def _showfixtures_main(config, session):
if currentmodule != module:
if not module.startswith("_pytest."):
tw.line()
- tw.sep("-", "fixtures defined from %s" %(module,))
+ tw.sep("-", "fixtures defined from %s" % (module,))
currentmodule = module
if verbose <= 0 and argname[0] == "_":
continue
if verbose > 0:
- funcargspec = "%s -- %s" %(argname, bestrel,)
+ funcargspec = "%s -- %s" % (argname, bestrel,)
else:
funcargspec = argname
tw.line(funcargspec, green=True)
loc = getlocation(fixturedef.func, curdir)
doc = fixturedef.func.__doc__ or ""
if doc:
- for line in doc.strip().split("\n"):
- tw.line(" " + line.strip())
+ write_docstring(tw, doc)
else:
- tw.line(" %s: no docstring available" %(loc,),
- red=True)
-
-
-# builtin pytest.raises helper
-
-def raises(expected_exception, *args, **kwargs):
- """
- Assert that a code block/function call raises ``expected_exception``
- and raise a failure exception otherwise.
-
- This helper produces a ``ExceptionInfo()`` object (see below).
-
- If using Python 2.5 or above, you may use this function as a
- context manager::
-
- >>> with raises(ZeroDivisionError):
- ... 1/0
-
- .. versionchanged:: 2.10
+ tw.line(" %s: no docstring available" % (loc,),
+ red=True)
- In the context manager form you may use the keyword argument
- ``message`` to specify a custom failure message::
- >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
- ... pass
- Traceback (most recent call last):
- ...
- Failed: Expecting ZeroDivisionError
-
-
- .. note::
-
- When using ``pytest.raises`` as a context manager, it's worthwhile to
- note that normal context manager rules apply and that the exception
- raised *must* be the final line in the scope of the context manager.
- Lines of code after that, within the scope of the context manager will
- not be executed. For example::
-
- >>> value = 15
- >>> with raises(ValueError) as exc_info:
- ... if value > 10:
- ... raise ValueError("value must be <= 10")
- ... assert str(exc_info.value) == "value must be <= 10" # this will not execute
-
- Instead, the following approach must be taken (note the difference in
- scope)::
-
- >>> with raises(ValueError) as exc_info:
- ... if value > 10:
- ... raise ValueError("value must be <= 10")
- ...
- >>> assert str(exc_info.value) == "value must be <= 10"
-
-
- Or you can specify a callable by passing a to-be-called lambda::
-
- >>> raises(ZeroDivisionError, lambda: 1/0)
- <ExceptionInfo ...>
-
- or you can specify an arbitrary callable with arguments::
-
- >>> def f(x): return 1/x
- ...
- >>> raises(ZeroDivisionError, f, 0)
- <ExceptionInfo ...>
- >>> raises(ZeroDivisionError, f, x=0)
- <ExceptionInfo ...>
-
- A third possibility is to use a string to be executed::
-
- >>> raises(ZeroDivisionError, "f(0)")
- <ExceptionInfo ...>
-
- .. autoclass:: _pytest._code.ExceptionInfo
- :members:
-
- .. note::
- Similar to caught exception objects in Python, explicitly clearing
- local references to returned ``ExceptionInfo`` objects can
- help the Python interpreter speed up its garbage collection.
-
- Clearing those references breaks a reference cycle
- (``ExceptionInfo`` --> caught exception --> frame stack raising
- the exception --> current frame stack --> local variables -->
- ``ExceptionInfo``) which makes Python keep all objects referenced
- from that cycle (including all local variables in the current
- frame) alive until the next cyclic garbage collection run. See the
- official Python ``try`` statement documentation for more detailed
- information.
-
- """
- __tracebackhide__ = True
- if expected_exception is AssertionError:
- # we want to catch a AssertionError
- # replace our subclass with the builtin one
- # see https://github.com/pytest-dev/pytest/issues/176
- from _pytest.assertion.util import BuiltinAssertionError \
- as expected_exception
- msg = ("exceptions must be old-style classes or"
- " derived from BaseException, not %s")
- if isinstance(expected_exception, tuple):
- for exc in expected_exception:
- if not isclass(exc):
- raise TypeError(msg % type(exc))
- elif not isclass(expected_exception):
- raise TypeError(msg % type(expected_exception))
-
- message = "DID NOT RAISE {0}".format(expected_exception)
-
- if not args:
- if "message" in kwargs:
- message = kwargs.pop("message")
- return RaisesContext(expected_exception, message)
- elif isinstance(args[0], str):
- code, = args
- assert isinstance(code, str)
- frame = sys._getframe(1)
- loc = frame.f_locals.copy()
- loc.update(kwargs)
- #print "raises frame scope: %r" % frame.f_locals
- try:
- code = _pytest._code.Source(code).compile()
- py.builtin.exec_(code, frame.f_globals, loc)
- # XXX didn'T mean f_globals == f_locals something special?
- # this is destroyed here ...
- except expected_exception:
- return _pytest._code.ExceptionInfo()
+def write_docstring(tw, doc):
+ INDENT = " "
+ doc = doc.rstrip()
+ if "\n" in doc:
+ firstline, rest = doc.split("\n", 1)
else:
- func = args[0]
- try:
- func(*args[1:], **kwargs)
- except expected_exception:
- return _pytest._code.ExceptionInfo()
- pytest.fail(message)
-
-class RaisesContext(object):
- def __init__(self, expected_exception, message):
- self.expected_exception = expected_exception
- self.message = message
- self.excinfo = None
-
- def __enter__(self):
- self.excinfo = object.__new__(_pytest._code.ExceptionInfo)
- return self.excinfo
-
- def __exit__(self, *tp):
- __tracebackhide__ = True
- if tp[0] is None:
- pytest.fail(self.message)
- if sys.version_info < (2, 7):
- # py26: on __exit__() exc_value often does not contain the
- # exception value.
- # http://bugs.python.org/issue7853
- if not isinstance(tp[1], BaseException):
- exc_type, value, traceback = tp
- tp = exc_type, exc_type(value), traceback
- self.excinfo.__init__(tp)
- suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
- if sys.version_info[0] == 2 and suppress_exception:
- sys.exc_clear()
- return suppress_exception
-
-
-# builtin pytest.approx helper
-
-class approx(object):
- """
- Assert that two numbers (or two sets of numbers) are equal to each other
- within some tolerance.
-
- Due to the `intricacies of floating-point arithmetic`__, numbers that we
- would intuitively expect to be equal are not always so::
-
- >>> 0.1 + 0.2 == 0.3
- False
-
- __ https://docs.python.org/3/tutorial/floatingpoint.html
-
- This problem is commonly encountered when writing tests, e.g. when making
- sure that floating-point values are what you expect them to be. One way to
- deal with this problem is to assert that two floating-point numbers are
- equal to within some appropriate tolerance::
-
- >>> abs((0.1 + 0.2) - 0.3) < 1e-6
- True
-
- However, comparisons like this are tedious to write and difficult to
- understand. Furthermore, absolute comparisons like the one above are
- usually discouraged because there's no tolerance that works well for all
- situations. ``1e-6`` is good for numbers around ``1``, but too small for
- very big numbers and too big for very small ones. It's better to express
- the tolerance as a fraction of the expected value, but relative comparisons
- like that are even more difficult to write correctly and concisely.
-
- The ``approx`` class performs floating-point comparisons using a syntax
- that's as intuitive as possible::
-
- >>> from pytest import approx
- >>> 0.1 + 0.2 == approx(0.3)
- True
-
- The same syntax also works on sequences of numbers::
-
- >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6))
- True
-
- By default, ``approx`` considers numbers within a relative tolerance of
- ``1e-6`` (i.e. one part in a million) of its expected value to be equal.
- This treatment would lead to surprising results if the expected value was
- ``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``.
- To handle this case less surprisingly, ``approx`` also considers numbers
- within an absolute tolerance of ``1e-12`` of its expected value to be
- equal. Infinite numbers are another special case. They are only
- considered equal to themselves, regardless of the relative tolerance. Both
- the relative and absolute tolerances can be changed by passing arguments to
- the ``approx`` constructor::
-
- >>> 1.0001 == approx(1)
- False
- >>> 1.0001 == approx(1, rel=1e-3)
- True
- >>> 1.0001 == approx(1, abs=1e-3)
- True
-
- If you specify ``abs`` but not ``rel``, the comparison will not consider
- the relative tolerance at all. In other words, two numbers that are within
- the default relative tolerance of ``1e-6`` will still be considered unequal
- if they exceed the specified absolute tolerance. If you specify both
- ``abs`` and ``rel``, the numbers will be considered equal if either
- tolerance is met::
-
- >>> 1 + 1e-8 == approx(1)
- True
- >>> 1 + 1e-8 == approx(1, abs=1e-12)
- False
- >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
- True
-
- If you're thinking about using ``approx``, then you might want to know how
- it compares to other good ways of comparing floating-point numbers. All of
- these algorithms are based on relative and absolute tolerances and should
- agree for the most part, but they do have meaningful differences:
-
- - ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``: True if the relative
- tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute
- tolerance is met. Because the relative tolerance is calculated w.r.t.
- both ``a`` and ``b``, this test is symmetric (i.e. neither ``a`` nor
- ``b`` is a "reference value"). You have to specify an absolute tolerance
- if you want to compare to ``0.0`` because there is no tolerance by
- default. Only available in python>=3.5. `More information...`__
-
- __ https://docs.python.org/3/library/math.html#math.isclose
-
- - ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference
- between ``a`` and ``b`` is less that the sum of the relative tolerance
- w.r.t. ``b`` and the absolute tolerance. Because the relative tolerance
- is only calculated w.r.t. ``b``, this test is asymmetric and you can
- think of ``b`` as the reference value. Support for comparing sequences
- is provided by ``numpy.allclose``. `More information...`__
-
- __ http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.isclose.html
-
- - ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b``
- are within an absolute tolerance of ``1e-7``. No relative tolerance is
- considered and the absolute tolerance cannot be changed, so this function
- is not appropriate for very large or very small numbers. Also, it's only
- available in subclasses of ``unittest.TestCase`` and it's ugly because it
- doesn't follow PEP8. `More information...`__
-
- __ https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertAlmostEqual
-
- - ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative
- tolerance is met w.r.t. ``b`` or if the absolute tolerance is met.
- Because the relative tolerance is only calculated w.r.t. ``b``, this test
- is asymmetric and you can think of ``b`` as the reference value. In the
- special case that you explicitly specify an absolute tolerance but not a
- relative tolerance, only the absolute tolerance is considered.
- """
-
- def __init__(self, expected, rel=None, abs=None):
- self.expected = expected
- self.abs = abs
- self.rel = rel
+ firstline, rest = doc, ""
- def __repr__(self):
- return ', '.join(repr(x) for x in self.expected)
-
- def __eq__(self, actual):
- from collections import Iterable
- if not isinstance(actual, Iterable):
- actual = [actual]
- if len(actual) != len(self.expected):
- return False
- return all(a == x for a, x in zip(actual, self.expected))
+ if firstline.strip():
+ tw.line(INDENT + firstline.strip())
- __hash__ = None
+ if rest:
+ for line in dedent(rest).split("\n"):
+ tw.write(INDENT + line + "\n")
- def __ne__(self, actual):
- return not (actual == self)
-
- @property
- def expected(self):
- # Regardless of whether the user-specified expected value is a number
- # or a sequence of numbers, return a list of ApproxNotIterable objects
- # that can be compared against.
- from collections import Iterable
- approx_non_iter = lambda x: ApproxNonIterable(x, self.rel, self.abs)
- if isinstance(self._expected, Iterable):
- return [approx_non_iter(x) for x in self._expected]
- else:
- return [approx_non_iter(self._expected)]
- @expected.setter
- def expected(self, expected):
- self._expected = expected
-
-
-class ApproxNonIterable(object):
- """
- Perform approximate comparisons for single numbers only.
-
- In other words, the ``expected`` attribute for objects of this class must
- be some sort of number. This is in contrast to the ``approx`` class, where
- the ``expected`` attribute can either be a number of a sequence of numbers.
- This class is responsible for making comparisons, while ``approx`` is
- responsible for abstracting the difference between numbers and sequences of
- numbers. Although this class can stand on its own, it's only meant to be
- used within ``approx``.
- """
-
- def __init__(self, expected, rel=None, abs=None):
- self.expected = expected
- self.abs = abs
- self.rel = rel
-
- def __repr__(self):
- if isinstance(self.expected, complex):
- return str(self.expected)
-
- # Infinities aren't compared using tolerances, so don't show a
- # tolerance.
- if math.isinf(self.expected):
- return str(self.expected)
-
- # If a sensible tolerance can't be calculated, self.tolerance will
- # raise a ValueError. In this case, display '???'.
- try:
- vetted_tolerance = '{:.1e}'.format(self.tolerance)
- except ValueError:
- vetted_tolerance = '???'
-
- if sys.version_info[0] == 2:
- return '{0} +- {1}'.format(self.expected, vetted_tolerance)
- else:
- return u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance)
-
- def __eq__(self, actual):
- # Short-circuit exact equality.
- if actual == self.expected:
- return True
-
- # Infinity shouldn't be approximately equal to anything but itself, but
- # if there's a relative tolerance, it will be infinite and infinity
- # will seem approximately equal to everything. The equal-to-itself
- # case would have been short circuited above, so here we can just
- # return false if the expected value is infinite. The abs() call is
- # for compatibility with complex numbers.
- if math.isinf(abs(self.expected)):
- return False
-
- # Return true if the two numbers are within the tolerance.
- return abs(self.expected - actual) <= self.tolerance
-
- __hash__ = None
-
- def __ne__(self, actual):
- return not (actual == self)
-
- @property
- def tolerance(self):
- set_default = lambda x, default: x if x is not None else default
-
- # Figure out what the absolute tolerance should be. ``self.abs`` is
- # either None or a value specified by the user.
- absolute_tolerance = set_default(self.abs, 1e-12)
-
- if absolute_tolerance < 0:
- raise ValueError("absolute tolerance can't be negative: {0}".format(absolute_tolerance))
- if math.isnan(absolute_tolerance):
- raise ValueError("absolute tolerance can't be NaN.")
-
- # If the user specified an absolute tolerance but not a relative one,
- # just return the absolute tolerance.
- if self.rel is None:
- if self.abs is not None:
- return absolute_tolerance
-
- # Figure out what the relative tolerance should be. ``self.rel`` is
- # either None or a value specified by the user. This is done after
- # we've made sure the user didn't ask for an absolute tolerance only,
- # because we don't want to raise errors about the relative tolerance if
- # we aren't even going to use it.
- relative_tolerance = set_default(self.rel, 1e-6) * abs(self.expected)
-
- if relative_tolerance < 0:
- raise ValueError("relative tolerance can't be negative: {0}".format(absolute_tolerance))
- if math.isnan(relative_tolerance):
- raise ValueError("relative tolerance can't be NaN.")
-
- # Return the larger of the relative and absolute tolerances.
- return max(relative_tolerance, absolute_tolerance)
-
-
-#
-# the basic pytest Function item
-#
-
-class Function(FunctionMixin, pytest.Item, fixtures.FuncargnamesCompatAttr):
+class Function(FunctionMixin, main.Item, fixtures.FuncargnamesCompatAttr):
""" a Function Item is responsible for setting up and executing a
Python test function.
"""
_genid = None
+
def __init__(self, name, parent, args=None, config=None,
callspec=None, callobj=NOTSET, keywords=None, session=None,
fixtureinfo=None, originalname=None):
@@ -1556,7 +1151,7 @@ class Function(FunctionMixin, pytest.Item, fixtures.FuncargnamesCompatAttr):
def _getobj(self):
name = self.name
- i = name.find("[") # parametrization
+ i = name.find("[") # parametrization
if i != -1:
name = name[:i]
return getattr(self.parent.obj, name)
diff --git a/lib/spack/external/_pytest/python_api.py b/lib/spack/external/_pytest/python_api.py
new file mode 100644
index 0000000000..cfc01193b0
--- /dev/null
+++ b/lib/spack/external/_pytest/python_api.py
@@ -0,0 +1,626 @@
+import math
+import sys
+
+import py
+
+from _pytest.compat import isclass, izip
+from _pytest.outcomes import fail
+import _pytest._code
+
+
+def _cmp_raises_type_error(self, other):
+ """__cmp__ implementation which raises TypeError. Used
+ by Approx base classes to implement only == and != and raise a
+ TypeError for other comparisons.
+
+ Needed in Python 2 only, Python 3 all it takes is not implementing the
+ other operators at all.
+ """
+ __tracebackhide__ = True
+ raise TypeError('Comparison operators other than == and != not supported by approx objects')
+
+
+# builtin pytest.approx helper
+
+
+class ApproxBase(object):
+ """
+ Provide shared utilities for making approximate comparisons between numbers
+ or sequences of numbers.
+ """
+
+ def __init__(self, expected, rel=None, abs=None, nan_ok=False):
+ self.expected = expected
+ self.abs = abs
+ self.rel = rel
+ self.nan_ok = nan_ok
+
+ def __repr__(self):
+ raise NotImplementedError
+
+ def __eq__(self, actual):
+ return all(
+ a == self._approx_scalar(x)
+ for a, x in self._yield_comparisons(actual))
+
+ __hash__ = None
+
+ def __ne__(self, actual):
+ return not (actual == self)
+
+ if sys.version_info[0] == 2:
+ __cmp__ = _cmp_raises_type_error
+
+ def _approx_scalar(self, x):
+ return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok)
+
+ def _yield_comparisons(self, actual):
+ """
+ Yield all the pairs of numbers to be compared. This is used to
+ implement the `__eq__` method.
+ """
+ raise NotImplementedError
+
+
+class ApproxNumpy(ApproxBase):
+ """
+ Perform approximate comparisons for numpy arrays.
+ """
+
+ # Tell numpy to use our `__eq__` operator instead of its.
+ __array_priority__ = 100
+
+ def __repr__(self):
+ # It might be nice to rewrite this function to account for the
+ # shape of the array...
+ return "approx({0!r})".format(list(
+ self._approx_scalar(x) for x in self.expected))
+
+ if sys.version_info[0] == 2:
+ __cmp__ = _cmp_raises_type_error
+
+ def __eq__(self, actual):
+ import numpy as np
+
+ try:
+ actual = np.asarray(actual)
+ except: # noqa
+ raise TypeError("cannot compare '{0}' to numpy.ndarray".format(actual))
+
+ if actual.shape != self.expected.shape:
+ return False
+
+ return ApproxBase.__eq__(self, actual)
+
+ def _yield_comparisons(self, actual):
+ import numpy as np
+
+ # We can be sure that `actual` is a numpy array, because it's
+ # casted in `__eq__` before being passed to `ApproxBase.__eq__`,
+ # which is the only method that calls this one.
+ for i in np.ndindex(self.expected.shape):
+ yield actual[i], self.expected[i]
+
+
+class ApproxMapping(ApproxBase):
+ """
+ Perform approximate comparisons for mappings where the values are numbers
+ (the keys can be anything).
+ """
+
+ def __repr__(self):
+ return "approx({0!r})".format(dict(
+ (k, self._approx_scalar(v))
+ for k, v in self.expected.items()))
+
+ def __eq__(self, actual):
+ if set(actual.keys()) != set(self.expected.keys()):
+ return False
+
+ return ApproxBase.__eq__(self, actual)
+
+ def _yield_comparisons(self, actual):
+ for k in self.expected.keys():
+ yield actual[k], self.expected[k]
+
+
+class ApproxSequence(ApproxBase):
+ """
+ Perform approximate comparisons for sequences of numbers.
+ """
+
+ # Tell numpy to use our `__eq__` operator instead of its.
+ __array_priority__ = 100
+
+ def __repr__(self):
+ seq_type = type(self.expected)
+ if seq_type not in (tuple, list, set):
+ seq_type = list
+ return "approx({0!r})".format(seq_type(
+ self._approx_scalar(x) for x in self.expected))
+
+ def __eq__(self, actual):
+ if len(actual) != len(self.expected):
+ return False
+ return ApproxBase.__eq__(self, actual)
+
+ def _yield_comparisons(self, actual):
+ return izip(actual, self.expected)
+
+
+class ApproxScalar(ApproxBase):
+ """
+ Perform approximate comparisons for single numbers only.
+ """
+
+ def __repr__(self):
+ """
+ Return a string communicating both the expected value and the tolerance
+ for the comparison being made, e.g. '1.0 +- 1e-6'. Use the unicode
+ plus/minus symbol if this is python3 (it's too hard to get right for
+ python2).
+ """
+ if isinstance(self.expected, complex):
+ return str(self.expected)
+
+ # Infinities aren't compared using tolerances, so don't show a
+ # tolerance.
+ if math.isinf(self.expected):
+ return str(self.expected)
+
+ # If a sensible tolerance can't be calculated, self.tolerance will
+ # raise a ValueError. In this case, display '???'.
+ try:
+ vetted_tolerance = '{:.1e}'.format(self.tolerance)
+ except ValueError:
+ vetted_tolerance = '???'
+
+ if sys.version_info[0] == 2:
+ return '{0} +- {1}'.format(self.expected, vetted_tolerance)
+ else:
+ return u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance)
+
+ def __eq__(self, actual):
+ """
+ Return true if the given value is equal to the expected value within
+ the pre-specified tolerance.
+ """
+
+ # Short-circuit exact equality.
+ if actual == self.expected:
+ return True
+
+ # Allow the user to control whether NaNs are considered equal to each
+ # other or not. The abs() calls are for compatibility with complex
+ # numbers.
+ if math.isnan(abs(self.expected)):
+ return self.nan_ok and math.isnan(abs(actual))
+
+ # Infinity shouldn't be approximately equal to anything but itself, but
+ # if there's a relative tolerance, it will be infinite and infinity
+ # will seem approximately equal to everything. The equal-to-itself
+ # case would have been short circuited above, so here we can just
+ # return false if the expected value is infinite. The abs() call is
+ # for compatibility with complex numbers.
+ if math.isinf(abs(self.expected)):
+ return False
+
+ # Return true if the two numbers are within the tolerance.
+ return abs(self.expected - actual) <= self.tolerance
+
+ __hash__ = None
+
+ @property
+ def tolerance(self):
+ """
+ Return the tolerance for the comparison. This could be either an
+ absolute tolerance or a relative tolerance, depending on what the user
+ specified or which would be larger.
+ """
+ def set_default(x, default):
+ return x if x is not None else default
+
+ # Figure out what the absolute tolerance should be. ``self.abs`` is
+ # either None or a value specified by the user.
+ absolute_tolerance = set_default(self.abs, 1e-12)
+
+ if absolute_tolerance < 0:
+ raise ValueError("absolute tolerance can't be negative: {0}".format(absolute_tolerance))
+ if math.isnan(absolute_tolerance):
+ raise ValueError("absolute tolerance can't be NaN.")
+
+ # If the user specified an absolute tolerance but not a relative one,
+ # just return the absolute tolerance.
+ if self.rel is None:
+ if self.abs is not None:
+ return absolute_tolerance
+
+ # Figure out what the relative tolerance should be. ``self.rel`` is
+ # either None or a value specified by the user. This is done after
+ # we've made sure the user didn't ask for an absolute tolerance only,
+ # because we don't want to raise errors about the relative tolerance if
+ # we aren't even going to use it.
+ relative_tolerance = set_default(self.rel, 1e-6) * abs(self.expected)
+
+ if relative_tolerance < 0:
+ raise ValueError("relative tolerance can't be negative: {0}".format(absolute_tolerance))
+ if math.isnan(relative_tolerance):
+ raise ValueError("relative tolerance can't be NaN.")
+
+ # Return the larger of the relative and absolute tolerances.
+ return max(relative_tolerance, absolute_tolerance)
+
+
+def approx(expected, rel=None, abs=None, nan_ok=False):
+ """
+ Assert that two numbers (or two sets of numbers) are equal to each other
+ within some tolerance.
+
+ Due to the `intricacies of floating-point arithmetic`__, numbers that we
+ would intuitively expect to be equal are not always so::
+
+ >>> 0.1 + 0.2 == 0.3
+ False
+
+ __ https://docs.python.org/3/tutorial/floatingpoint.html
+
+ This problem is commonly encountered when writing tests, e.g. when making
+ sure that floating-point values are what you expect them to be. One way to
+ deal with this problem is to assert that two floating-point numbers are
+ equal to within some appropriate tolerance::
+
+ >>> abs((0.1 + 0.2) - 0.3) < 1e-6
+ True
+
+ However, comparisons like this are tedious to write and difficult to
+ understand. Furthermore, absolute comparisons like the one above are
+ usually discouraged because there's no tolerance that works well for all
+ situations. ``1e-6`` is good for numbers around ``1``, but too small for
+ very big numbers and too big for very small ones. It's better to express
+ the tolerance as a fraction of the expected value, but relative comparisons
+ like that are even more difficult to write correctly and concisely.
+
+ The ``approx`` class performs floating-point comparisons using a syntax
+ that's as intuitive as possible::
+
+ >>> from pytest import approx
+ >>> 0.1 + 0.2 == approx(0.3)
+ True
+
+ The same syntax also works for sequences of numbers::
+
+ >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6))
+ True
+
+ Dictionary *values*::
+
+ >>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6})
+ True
+
+ And ``numpy`` arrays::
+
+ >>> import numpy as np # doctest: +SKIP
+ >>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP
+ True
+
+ By default, ``approx`` considers numbers within a relative tolerance of
+ ``1e-6`` (i.e. one part in a million) of its expected value to be equal.
+ This treatment would lead to surprising results if the expected value was
+ ``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``.
+ To handle this case less surprisingly, ``approx`` also considers numbers
+ within an absolute tolerance of ``1e-12`` of its expected value to be
+ equal. Infinity and NaN are special cases. Infinity is only considered
+ equal to itself, regardless of the relative tolerance. NaN is not
+ considered equal to anything by default, but you can make it be equal to
+ itself by setting the ``nan_ok`` argument to True. (This is meant to
+ facilitate comparing arrays that use NaN to mean "no data".)
+
+ Both the relative and absolute tolerances can be changed by passing
+ arguments to the ``approx`` constructor::
+
+ >>> 1.0001 == approx(1)
+ False
+ >>> 1.0001 == approx(1, rel=1e-3)
+ True
+ >>> 1.0001 == approx(1, abs=1e-3)
+ True
+
+ If you specify ``abs`` but not ``rel``, the comparison will not consider
+ the relative tolerance at all. In other words, two numbers that are within
+ the default relative tolerance of ``1e-6`` will still be considered unequal
+ if they exceed the specified absolute tolerance. If you specify both
+ ``abs`` and ``rel``, the numbers will be considered equal if either
+ tolerance is met::
+
+ >>> 1 + 1e-8 == approx(1)
+ True
+ >>> 1 + 1e-8 == approx(1, abs=1e-12)
+ False
+ >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
+ True
+
+ If you're thinking about using ``approx``, then you might want to know how
+ it compares to other good ways of comparing floating-point numbers. All of
+ these algorithms are based on relative and absolute tolerances and should
+ agree for the most part, but they do have meaningful differences:
+
+ - ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``: True if the relative
+ tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute
+ tolerance is met. Because the relative tolerance is calculated w.r.t.
+ both ``a`` and ``b``, this test is symmetric (i.e. neither ``a`` nor
+ ``b`` is a "reference value"). You have to specify an absolute tolerance
+ if you want to compare to ``0.0`` because there is no tolerance by
+ default. Only available in python>=3.5. `More information...`__
+
+ __ https://docs.python.org/3/library/math.html#math.isclose
+
+ - ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference
+ between ``a`` and ``b`` is less that the sum of the relative tolerance
+ w.r.t. ``b`` and the absolute tolerance. Because the relative tolerance
+ is only calculated w.r.t. ``b``, this test is asymmetric and you can
+ think of ``b`` as the reference value. Support for comparing sequences
+ is provided by ``numpy.allclose``. `More information...`__
+
+ __ http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.isclose.html
+
+ - ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b``
+ are within an absolute tolerance of ``1e-7``. No relative tolerance is
+ considered and the absolute tolerance cannot be changed, so this function
+ is not appropriate for very large or very small numbers. Also, it's only
+ available in subclasses of ``unittest.TestCase`` and it's ugly because it
+ doesn't follow PEP8. `More information...`__
+
+ __ https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertAlmostEqual
+
+ - ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative
+ tolerance is met w.r.t. ``b`` or if the absolute tolerance is met.
+ Because the relative tolerance is only calculated w.r.t. ``b``, this test
+ is asymmetric and you can think of ``b`` as the reference value. In the
+ special case that you explicitly specify an absolute tolerance but not a
+ relative tolerance, only the absolute tolerance is considered.
+
+ .. warning::
+
+ .. versionchanged:: 3.2
+
+ In order to avoid inconsistent behavior, ``TypeError`` is
+ raised for ``>``, ``>=``, ``<`` and ``<=`` comparisons.
+ The example below illustrates the problem::
+
+ assert approx(0.1) > 0.1 + 1e-10 # calls approx(0.1).__gt__(0.1 + 1e-10)
+ assert 0.1 + 1e-10 > approx(0.1) # calls approx(0.1).__lt__(0.1 + 1e-10)
+
+ In the second example one expects ``approx(0.1).__le__(0.1 + 1e-10)``
+ to be called. But instead, ``approx(0.1).__lt__(0.1 + 1e-10)`` is used to
+ comparison. This is because the call hierarchy of rich comparisons
+ follows a fixed behavior. `More information...`__
+
+ __ https://docs.python.org/3/reference/datamodel.html#object.__ge__
+ """
+
+ from collections import Mapping, Sequence
+ from _pytest.compat import STRING_TYPES as String
+
+ # Delegate the comparison to a class that knows how to deal with the type
+ # of the expected value (e.g. int, float, list, dict, numpy.array, etc).
+ #
+ # This architecture is really driven by the need to support numpy arrays.
+ # The only way to override `==` for arrays without requiring that approx be
+ # the left operand is to inherit the approx object from `numpy.ndarray`.
+ # But that can't be a general solution, because it requires (1) numpy to be
+ # installed and (2) the expected value to be a numpy array. So the general
+ # solution is to delegate each type of expected value to a different class.
+ #
+ # This has the advantage that it made it easy to support mapping types
+ # (i.e. dict). The old code accepted mapping types, but would only compare
+ # their keys, which is probably not what most people would expect.
+
+ if _is_numpy_array(expected):
+ cls = ApproxNumpy
+ elif isinstance(expected, Mapping):
+ cls = ApproxMapping
+ elif isinstance(expected, Sequence) and not isinstance(expected, String):
+ cls = ApproxSequence
+ else:
+ cls = ApproxScalar
+
+ return cls(expected, rel, abs, nan_ok)
+
+
+def _is_numpy_array(obj):
+ """
+ Return true if the given object is a numpy array. Make a special effort to
+ avoid importing numpy unless it's really necessary.
+ """
+ import inspect
+
+ for cls in inspect.getmro(type(obj)):
+ if cls.__module__ == 'numpy':
+ try:
+ import numpy as np
+ return isinstance(obj, np.ndarray)
+ except ImportError:
+ pass
+
+ return False
+
+
+# builtin pytest.raises helper
+
+def raises(expected_exception, *args, **kwargs):
+ """
+ Assert that a code block/function call raises ``expected_exception``
+ and raise a failure exception otherwise.
+
+ This helper produces a ``ExceptionInfo()`` object (see below).
+
+ If using Python 2.5 or above, you may use this function as a
+ context manager::
+
+ >>> with raises(ZeroDivisionError):
+ ... 1/0
+
+ .. versionchanged:: 2.10
+
+ In the context manager form you may use the keyword argument
+ ``message`` to specify a custom failure message::
+
+ >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
+ ... pass
+ Traceback (most recent call last):
+ ...
+ Failed: Expecting ZeroDivisionError
+
+ .. note::
+
+ When using ``pytest.raises`` as a context manager, it's worthwhile to
+ note that normal context manager rules apply and that the exception
+ raised *must* be the final line in the scope of the context manager.
+ Lines of code after that, within the scope of the context manager will
+ not be executed. For example::
+
+ >>> value = 15
+ >>> with raises(ValueError) as exc_info:
+ ... if value > 10:
+ ... raise ValueError("value must be <= 10")
+ ... assert exc_info.type == ValueError # this will not execute
+
+ Instead, the following approach must be taken (note the difference in
+ scope)::
+
+ >>> with raises(ValueError) as exc_info:
+ ... if value > 10:
+ ... raise ValueError("value must be <= 10")
+ ...
+ >>> assert exc_info.type == ValueError
+
+
+ Since version ``3.1`` you can use the keyword argument ``match`` to assert that the
+ exception matches a text or regex::
+
+ >>> with raises(ValueError, match='must be 0 or None'):
+ ... raise ValueError("value must be 0 or None")
+
+ >>> with raises(ValueError, match=r'must be \d+$'):
+ ... raise ValueError("value must be 42")
+
+ **Legacy forms**
+
+ The forms below are fully supported but are discouraged for new code because the
+ context manager form is regarded as more readable and less error-prone.
+
+ It is possible to specify a callable by passing a to-be-called lambda::
+
+ >>> raises(ZeroDivisionError, lambda: 1/0)
+ <ExceptionInfo ...>
+
+ or you can specify an arbitrary callable with arguments::
+
+ >>> def f(x): return 1/x
+ ...
+ >>> raises(ZeroDivisionError, f, 0)
+ <ExceptionInfo ...>
+ >>> raises(ZeroDivisionError, f, x=0)
+ <ExceptionInfo ...>
+
+ It is also possible to pass a string to be evaluated at runtime::
+
+ >>> raises(ZeroDivisionError, "f(0)")
+ <ExceptionInfo ...>
+
+ The string will be evaluated using the same ``locals()`` and ``globals()``
+ at the moment of the ``raises`` call.
+
+ .. autoclass:: _pytest._code.ExceptionInfo
+ :members:
+
+ .. note::
+ Similar to caught exception objects in Python, explicitly clearing
+ local references to returned ``ExceptionInfo`` objects can
+ help the Python interpreter speed up its garbage collection.
+
+ Clearing those references breaks a reference cycle
+ (``ExceptionInfo`` --> caught exception --> frame stack raising
+ the exception --> current frame stack --> local variables -->
+ ``ExceptionInfo``) which makes Python keep all objects referenced
+ from that cycle (including all local variables in the current
+ frame) alive until the next cyclic garbage collection run. See the
+ official Python ``try`` statement documentation for more detailed
+ information.
+
+ """
+ __tracebackhide__ = True
+ msg = ("exceptions must be old-style classes or"
+ " derived from BaseException, not %s")
+ if isinstance(expected_exception, tuple):
+ for exc in expected_exception:
+ if not isclass(exc):
+ raise TypeError(msg % type(exc))
+ elif not isclass(expected_exception):
+ raise TypeError(msg % type(expected_exception))
+
+ message = "DID NOT RAISE {0}".format(expected_exception)
+ match_expr = None
+
+ if not args:
+ if "message" in kwargs:
+ message = kwargs.pop("message")
+ if "match" in kwargs:
+ match_expr = kwargs.pop("match")
+ message += " matching '{0}'".format(match_expr)
+ return RaisesContext(expected_exception, message, match_expr)
+ elif isinstance(args[0], str):
+ code, = args
+ assert isinstance(code, str)
+ frame = sys._getframe(1)
+ loc = frame.f_locals.copy()
+ loc.update(kwargs)
+ # print "raises frame scope: %r" % frame.f_locals
+ try:
+ code = _pytest._code.Source(code).compile()
+ py.builtin.exec_(code, frame.f_globals, loc)
+ # XXX didn'T mean f_globals == f_locals something special?
+ # this is destroyed here ...
+ except expected_exception:
+ return _pytest._code.ExceptionInfo()
+ else:
+ func = args[0]
+ try:
+ func(*args[1:], **kwargs)
+ except expected_exception:
+ return _pytest._code.ExceptionInfo()
+ fail(message)
+
+
+raises.Exception = fail.Exception
+
+
+class RaisesContext(object):
+ def __init__(self, expected_exception, message, match_expr):
+ self.expected_exception = expected_exception
+ self.message = message
+ self.match_expr = match_expr
+ self.excinfo = None
+
+ def __enter__(self):
+ self.excinfo = object.__new__(_pytest._code.ExceptionInfo)
+ return self.excinfo
+
+ def __exit__(self, *tp):
+ __tracebackhide__ = True
+ if tp[0] is None:
+ fail(self.message)
+ if sys.version_info < (2, 7):
+ # py26: on __exit__() exc_value often does not contain the
+ # exception value.
+ # http://bugs.python.org/issue7853
+ if not isinstance(tp[1], BaseException):
+ exc_type, value, traceback = tp
+ tp = exc_type, exc_type(value), traceback
+ self.excinfo.__init__(tp)
+ suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
+ if sys.version_info[0] == 2 and suppress_exception:
+ sys.exc_clear()
+ if self.match_expr:
+ self.excinfo.match(self.match_expr)
+ return suppress_exception
diff --git a/lib/spack/external/_pytest/recwarn.py b/lib/spack/external/_pytest/recwarn.py
index 87823bfbc6..c9fa872c07 100644
--- a/lib/spack/external/_pytest/recwarn.py
+++ b/lib/spack/external/_pytest/recwarn.py
@@ -1,4 +1,5 @@
""" recording warnings during test function execution. """
+from __future__ import absolute_import, division, print_function
import inspect
@@ -6,11 +7,13 @@ import _pytest._code
import py
import sys
import warnings
-import pytest
+from _pytest.fixtures import yield_fixture
+from _pytest.outcomes import fail
-@pytest.yield_fixture
-def recwarn(request):
+
+@yield_fixture
+def recwarn():
"""Return a WarningsRecorder instance that provides these methods:
* ``pop(category=None)``: return last warning matching the category.
@@ -25,16 +28,9 @@ def recwarn(request):
yield wrec
-def pytest_namespace():
- return {'deprecated_call': deprecated_call,
- 'warns': warns}
-
-
def deprecated_call(func=None, *args, **kwargs):
- """ assert that calling ``func(*args, **kwargs)`` triggers a
- ``DeprecationWarning`` or ``PendingDeprecationWarning``.
-
- This function can be used as a context manager::
+ """context manager that can be used to ensure a block of code triggers a
+ ``DeprecationWarning`` or ``PendingDeprecationWarning``::
>>> import warnings
>>> def api_call_v2():
@@ -44,40 +40,47 @@ def deprecated_call(func=None, *args, **kwargs):
>>> with deprecated_call():
... assert api_call_v2() == 200
- Note: we cannot use WarningsRecorder here because it is still subject
- to the mechanism that prevents warnings of the same type from being
- triggered twice for the same module. See #1190.
+ ``deprecated_call`` can also be used by passing a function and ``*args`` and ``*kwargs``,
+ in which case it will ensure calling ``func(*args, **kwargs)`` produces one of the warnings
+ types above.
"""
if not func:
- return WarningsChecker(expected_warning=DeprecationWarning)
+ return _DeprecatedCallContext()
+ else:
+ __tracebackhide__ = True
+ with _DeprecatedCallContext():
+ return func(*args, **kwargs)
+
- categories = []
+class _DeprecatedCallContext(object):
+ """Implements the logic to capture deprecation warnings as a context manager."""
- def warn_explicit(message, category, *args, **kwargs):
- categories.append(category)
- old_warn_explicit(message, category, *args, **kwargs)
+ def __enter__(self):
+ self._captured_categories = []
+ self._old_warn = warnings.warn
+ self._old_warn_explicit = warnings.warn_explicit
+ warnings.warn_explicit = self._warn_explicit
+ warnings.warn = self._warn
- def warn(message, category=None, *args, **kwargs):
+ def _warn_explicit(self, message, category, *args, **kwargs):
+ self._captured_categories.append(category)
+
+ def _warn(self, message, category=None, *args, **kwargs):
if isinstance(message, Warning):
- categories.append(message.__class__)
+ self._captured_categories.append(message.__class__)
else:
- categories.append(category)
- old_warn(message, category, *args, **kwargs)
-
- old_warn = warnings.warn
- old_warn_explicit = warnings.warn_explicit
- warnings.warn_explicit = warn_explicit
- warnings.warn = warn
- try:
- ret = func(*args, **kwargs)
- finally:
- warnings.warn_explicit = old_warn_explicit
- warnings.warn = old_warn
- deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
- if not any(issubclass(c, deprecation_categories) for c in categories):
- __tracebackhide__ = True
- raise AssertionError("%r did not produce DeprecationWarning" % (func,))
- return ret
+ self._captured_categories.append(category)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ warnings.warn_explicit = self._old_warn_explicit
+ warnings.warn = self._old_warn
+
+ if exc_type is None:
+ deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
+ if not any(issubclass(c, deprecation_categories) for c in self._captured_categories):
+ __tracebackhide__ = True
+ msg = "Did not produce DeprecationWarning or PendingDeprecationWarning"
+ raise AssertionError(msg)
def warns(expected_warning, *args, **kwargs):
@@ -115,24 +118,14 @@ def warns(expected_warning, *args, **kwargs):
return func(*args[1:], **kwargs)
-class RecordedWarning(object):
- def __init__(self, message, category, filename, lineno, file, line):
- self.message = message
- self.category = category
- self.filename = filename
- self.lineno = lineno
- self.file = file
- self.line = line
-
-
-class WarningsRecorder(object):
+class WarningsRecorder(warnings.catch_warnings):
"""A context manager to record raised warnings.
Adapted from `warnings.catch_warnings`.
"""
- def __init__(self, module=None):
- self._module = sys.modules['warnings'] if module is None else module
+ def __init__(self):
+ super(WarningsRecorder, self).__init__(record=True)
self._entered = False
self._list = []
@@ -169,38 +162,20 @@ class WarningsRecorder(object):
if self._entered:
__tracebackhide__ = True
raise RuntimeError("Cannot enter %r twice" % self)
- self._entered = True
- self._filters = self._module.filters
- self._module.filters = self._filters[:]
- self._showwarning = self._module.showwarning
-
- def showwarning(message, category, filename, lineno,
- file=None, line=None):
- self._list.append(RecordedWarning(
- message, category, filename, lineno, file, line))
-
- # still perform old showwarning functionality
- self._showwarning(
- message, category, filename, lineno, file=file, line=line)
-
- self._module.showwarning = showwarning
-
- # allow the same warning to be raised more than once
-
- self._module.simplefilter('always')
+ self._list = super(WarningsRecorder, self).__enter__()
+ warnings.simplefilter('always')
return self
def __exit__(self, *exc_info):
if not self._entered:
__tracebackhide__ = True
raise RuntimeError("Cannot exit %r without entering first" % self)
- self._module.filters = self._filters
- self._module.showwarning = self._showwarning
+ super(WarningsRecorder, self).__exit__(*exc_info)
class WarningsChecker(WarningsRecorder):
- def __init__(self, expected_warning=None, module=None):
- super(WarningsChecker, self).__init__(module=module)
+ def __init__(self, expected_warning=None):
+ super(WarningsChecker, self).__init__()
msg = ("exceptions must be old-style classes or "
"derived from Warning, not %s")
@@ -221,6 +196,10 @@ class WarningsChecker(WarningsRecorder):
# only check if we're not currently handling an exception
if all(a is None for a in exc_info):
if self.expected_warning is not None:
- if not any(r.category in self.expected_warning for r in self):
+ if not any(issubclass(r.category, self.expected_warning)
+ for r in self):
__tracebackhide__ = True
- pytest.fail("DID NOT WARN")
+ fail("DID NOT WARN. No warnings of type {0} was emitted. "
+ "The list of emitted warnings is: {1}.".format(
+ self.expected_warning,
+ [each.message for each in self]))
diff --git a/lib/spack/external/_pytest/resultlog.py b/lib/spack/external/_pytest/resultlog.py
index fc00259834..9f9c2d1f65 100644
--- a/lib/spack/external/_pytest/resultlog.py
+++ b/lib/spack/external/_pytest/resultlog.py
@@ -1,15 +1,18 @@
""" log machine-parseable test session result information in a plain
text file.
"""
+from __future__ import absolute_import, division, print_function
import py
import os
+
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "resultlog plugin options")
group.addoption('--resultlog', '--result-log', action="store",
- metavar="path", default=None,
- help="DEPRECATED path for machine-readable result log.")
+ metavar="path", default=None,
+ help="DEPRECATED path for machine-readable result log.")
+
def pytest_configure(config):
resultlog = config.option.resultlog
@@ -18,13 +21,14 @@ def pytest_configure(config):
dirname = os.path.dirname(os.path.abspath(resultlog))
if not os.path.isdir(dirname):
os.makedirs(dirname)
- logfile = open(resultlog, 'w', 1) # line buffered
+ logfile = open(resultlog, 'w', 1) # line buffered
config._resultlog = ResultLog(config, logfile)
config.pluginmanager.register(config._resultlog)
from _pytest.deprecated import RESULT_LOG
config.warn('C1', RESULT_LOG)
+
def pytest_unconfigure(config):
resultlog = getattr(config, '_resultlog', None)
if resultlog:
@@ -32,6 +36,7 @@ def pytest_unconfigure(config):
del config._resultlog
config.pluginmanager.unregister(resultlog)
+
def generic_path(item):
chain = item.listchain()
gpath = [chain[0].name]
@@ -55,15 +60,16 @@ def generic_path(item):
fspath = newfspath
return ''.join(gpath)
+
class ResultLog(object):
def __init__(self, config, logfile):
self.config = config
- self.logfile = logfile # preferably line buffered
+ self.logfile = logfile # preferably line buffered
def write_log_entry(self, testpath, lettercode, longrepr):
- py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
+ print("%s %s" % (lettercode, testpath), file=self.logfile)
for line in longrepr.splitlines():
- py.builtin.print_(" %s" % line, file=self.logfile)
+ print(" %s" % line, file=self.logfile)
def log_outcome(self, report, lettercode, longrepr):
testpath = getattr(report, 'nodeid', None)
diff --git a/lib/spack/external/_pytest/runner.py b/lib/spack/external/_pytest/runner.py
index eb29e7370c..b643fa3c91 100644
--- a/lib/spack/external/_pytest/runner.py
+++ b/lib/spack/external/_pytest/runner.py
@@ -1,29 +1,26 @@
""" basic collect and runtest protocol implementations """
+from __future__ import absolute_import, division, print_function
+
import bdb
+import os
import sys
from time import time
import py
-import pytest
+from _pytest.compat import _PY2
from _pytest._code.code import TerminalRepr, ExceptionInfo
-
-
-def pytest_namespace():
- return {
- 'fail' : fail,
- 'skip' : skip,
- 'importorskip' : importorskip,
- 'exit' : exit,
- }
+from _pytest.outcomes import skip, Skipped, TEST_OUTCOME
#
# pytest plugin hooks
+
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
group.addoption('--durations',
- action="store", type=int, default=None, metavar="N",
- help="show N slowest setup/test durations (N=0 for all)."),
+ action="store", type=int, default=None, metavar="N",
+ help="show N slowest setup/test durations (N=0 for all)."),
+
def pytest_terminal_summary(terminalreporter):
durations = terminalreporter.config.option.durations
@@ -48,16 +45,16 @@ def pytest_terminal_summary(terminalreporter):
for rep in dlist:
nodeid = rep.nodeid.replace("::()::", "::")
tr.write_line("%02.2fs %-8s %s" %
- (rep.duration, rep.when, nodeid))
+ (rep.duration, rep.when, nodeid))
+
def pytest_sessionstart(session):
session._setupstate = SetupState()
+
+
def pytest_sessionfinish(session):
session._setupstate.teardown_all()
-class NodeInfo:
- def __init__(self, location):
- self.location = location
def pytest_runtest_protocol(item, nextitem):
item.ihook.pytest_runtest_logstart(
@@ -66,6 +63,7 @@ def pytest_runtest_protocol(item, nextitem):
runtestprotocol(item, nextitem=nextitem)
return True
+
def runtestprotocol(item, log=True, nextitem=None):
hasrequest = hasattr(item, "_request")
if hasrequest and not item._request:
@@ -78,7 +76,7 @@ def runtestprotocol(item, log=True, nextitem=None):
if not item.config.option.setuponly:
reports.append(call_and_report(item, "call", log))
reports.append(call_and_report(item, "teardown", log,
- nextitem=nextitem))
+ nextitem=nextitem))
# after all teardown hooks have been called
# want funcargs and request info to go away
if hasrequest:
@@ -86,6 +84,7 @@ def runtestprotocol(item, log=True, nextitem=None):
item.funcargs = None
return reports
+
def show_test_item(item):
"""Show test function, parameters and the fixtures of the test item."""
tw = item.config.get_terminal_writer()
@@ -96,10 +95,14 @@ def show_test_item(item):
if used_fixtures:
tw.write(' (fixtures used: {0})'.format(', '.join(used_fixtures)))
+
def pytest_runtest_setup(item):
+ _update_current_test_var(item, 'setup')
item.session._setupstate.prepare(item)
+
def pytest_runtest_call(item):
+ _update_current_test_var(item, 'call')
try:
item.runtest()
except Exception:
@@ -112,8 +115,29 @@ def pytest_runtest_call(item):
del tb # Get rid of it in this namespace
raise
+
def pytest_runtest_teardown(item, nextitem):
+ _update_current_test_var(item, 'teardown')
item.session._setupstate.teardown_exact(item, nextitem)
+ _update_current_test_var(item, None)
+
+
+def _update_current_test_var(item, when):
+ """
+ Update PYTEST_CURRENT_TEST to reflect the current item and stage.
+
+ If ``when`` is None, delete PYTEST_CURRENT_TEST from the environment.
+ """
+ var_name = 'PYTEST_CURRENT_TEST'
+ if when:
+ value = '{0} ({1})'.format(item.nodeid, when)
+ if _PY2:
+ # python 2 doesn't like null bytes on environment variables (see #2644)
+ value = value.replace('\x00', '(null)')
+ os.environ[var_name] = value
+ else:
+ os.environ.pop(var_name)
+
def pytest_report_teststatus(report):
if report.when in ("setup", "teardown"):
@@ -139,21 +163,25 @@ def call_and_report(item, when, log=True, **kwds):
hook.pytest_exception_interact(node=item, call=call, report=report)
return report
+
def check_interactive_exception(call, report):
return call.excinfo and not (
- hasattr(report, "wasxfail") or
- call.excinfo.errisinstance(skip.Exception) or
- call.excinfo.errisinstance(bdb.BdbQuit))
+ hasattr(report, "wasxfail") or
+ call.excinfo.errisinstance(skip.Exception) or
+ call.excinfo.errisinstance(bdb.BdbQuit))
+
def call_runtest_hook(item, when, **kwds):
hookname = "pytest_runtest_" + when
ihook = getattr(item.ihook, hookname)
return CallInfo(lambda: ihook(item=item, **kwds), when=when)
+
class CallInfo:
""" Result/Exception info a function invocation. """
#: None or ExceptionInfo object.
excinfo = None
+
def __init__(self, func, when):
#: context of invocation: one of "setup", "call",
#: "teardown", "memocollect"
@@ -164,7 +192,7 @@ class CallInfo:
except KeyboardInterrupt:
self.stop = time()
raise
- except:
+ except: # noqa
self.excinfo = ExceptionInfo()
self.stop = time()
@@ -175,6 +203,7 @@ class CallInfo:
status = "result: %r" % (self.result,)
return "<CallInfo when=%r %s>" % (self.when, status)
+
def getslaveinfoline(node):
try:
return node._slaveinfocache
@@ -185,6 +214,7 @@ def getslaveinfoline(node):
d['id'], d['sysplatform'], ver, d['executable'])
return s
+
class BaseReport(object):
def __init__(self, **kw):
@@ -249,10 +279,11 @@ class BaseReport(object):
def fspath(self):
return self.nodeid.split("::")[0]
+
def pytest_runtest_makereport(item, call):
when = call.when
- duration = call.stop-call.start
- keywords = dict([(x,1) for x in item.keywords])
+ duration = call.stop - call.start
+ keywords = dict([(x, 1) for x in item.keywords])
excinfo = call.excinfo
sections = []
if not call.excinfo:
@@ -262,7 +293,7 @@ def pytest_runtest_makereport(item, call):
if not isinstance(excinfo, ExceptionInfo):
outcome = "failed"
longrepr = excinfo
- elif excinfo.errisinstance(pytest.skip.Exception):
+ elif excinfo.errisinstance(skip.Exception):
outcome = "skipped"
r = excinfo._getreprcrash()
longrepr = (str(r.path), r.lineno, r.message)
@@ -270,19 +301,21 @@ def pytest_runtest_makereport(item, call):
outcome = "failed"
if call.when == "call":
longrepr = item.repr_failure(excinfo)
- else: # exception in setup or teardown
+ else: # exception in setup or teardown
longrepr = item._repr_failure_py(excinfo,
- style=item.config.option.tbstyle)
+ style=item.config.option.tbstyle)
for rwhen, key, content in item._report_sections:
- sections.append(("Captured %s %s" %(key, rwhen), content))
+ sections.append(("Captured %s %s" % (key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
sections, duration)
+
class TestReport(BaseReport):
""" Basic test report object (also used for setup and teardown calls if
they fail).
"""
+
def __init__(self, nodeid, location, keywords, outcome,
longrepr, when, sections=(), duration=0, **extra):
#: normalized collection node id
@@ -321,16 +354,21 @@ class TestReport(BaseReport):
return "<TestReport %r when=%r outcome=%r>" % (
self.nodeid, self.when, self.outcome)
+
class TeardownErrorReport(BaseReport):
outcome = "failed"
when = "teardown"
+
def __init__(self, longrepr, **extra):
self.longrepr = longrepr
self.sections = []
self.__dict__.update(extra)
+
def pytest_make_collect_report(collector):
- call = CallInfo(collector._memocollect, "memocollect")
+ call = CallInfo(
+ lambda: list(collector.collect()),
+ 'collect')
longrepr = None
if not call.excinfo:
outcome = "passed"
@@ -348,7 +386,7 @@ def pytest_make_collect_report(collector):
errorinfo = CollectErrorRepr(errorinfo)
longrepr = errorinfo
rep = CollectReport(collector.nodeid, outcome, longrepr,
- getattr(call, 'result', None))
+ getattr(call, 'result', None))
rep.call = call # see collect_one_node
return rep
@@ -369,16 +407,20 @@ class CollectReport(BaseReport):
def __repr__(self):
return "<CollectReport %r lenresult=%s outcome=%r>" % (
- self.nodeid, len(self.result), self.outcome)
+ self.nodeid, len(self.result), self.outcome)
+
class CollectErrorRepr(TerminalRepr):
def __init__(self, msg):
self.longrepr = msg
+
def toterminal(self, out):
out.line(self.longrepr, red=True)
+
class SetupState(object):
""" shared state for setting up/tearing down test items or collectors. """
+
def __init__(self):
self.stack = []
self._finalizers = {}
@@ -390,7 +432,7 @@ class SetupState(object):
"""
assert colitem and not isinstance(colitem, tuple)
assert py.builtin.callable(finalizer)
- #assert colitem in self.stack # some unit tests don't setup stack :/
+ # assert colitem in self.stack # some unit tests don't setup stack :/
self._finalizers.setdefault(colitem, []).append(finalizer)
def _pop_and_teardown(self):
@@ -404,7 +446,7 @@ class SetupState(object):
fin = finalizers.pop()
try:
fin()
- except Exception:
+ except TEST_OUTCOME:
# XXX Only first exception will be seen by user,
# ideally all should be reported.
if exc is None:
@@ -418,7 +460,7 @@ class SetupState(object):
colitem.teardown()
for colitem in self._finalizers:
assert colitem is None or colitem in self.stack \
- or isinstance(colitem, tuple)
+ or isinstance(colitem, tuple)
def teardown_all(self):
while self.stack:
@@ -451,10 +493,11 @@ class SetupState(object):
self.stack.append(col)
try:
col.setup()
- except Exception:
+ except TEST_OUTCOME:
col._prepare_exc = sys.exc_info()
raise
+
def collect_one_node(collector):
ihook = collector.ihook
ihook.pytest_collectstart(collector=collector)
@@ -463,116 +506,3 @@ def collect_one_node(collector):
if call and check_interactive_exception(call, rep):
ihook.pytest_exception_interact(node=collector, call=call, report=rep)
return rep
-
-
-# =============================================================
-# Test OutcomeExceptions and helpers for creating them.
-
-
-class OutcomeException(Exception):
- """ OutcomeException and its subclass instances indicate and
- contain info about test and collection outcomes.
- """
- def __init__(self, msg=None, pytrace=True):
- Exception.__init__(self, msg)
- self.msg = msg
- self.pytrace = pytrace
-
- def __repr__(self):
- if self.msg:
- val = self.msg
- if isinstance(val, bytes):
- val = py._builtin._totext(val, errors='replace')
- return val
- return "<%s instance>" %(self.__class__.__name__,)
- __str__ = __repr__
-
-class Skipped(OutcomeException):
- # XXX hackish: on 3k we fake to live in the builtins
- # in order to have Skipped exception printing shorter/nicer
- __module__ = 'builtins'
-
- def __init__(self, msg=None, pytrace=True, allow_module_level=False):
- OutcomeException.__init__(self, msg=msg, pytrace=pytrace)
- self.allow_module_level = allow_module_level
-
-
-class Failed(OutcomeException):
- """ raised from an explicit call to pytest.fail() """
- __module__ = 'builtins'
-
-
-class Exit(KeyboardInterrupt):
- """ raised for immediate program exits (no tracebacks/summaries)"""
- def __init__(self, msg="unknown reason"):
- self.msg = msg
- KeyboardInterrupt.__init__(self, msg)
-
-# exposed helper methods
-
-def exit(msg):
- """ exit testing process as if KeyboardInterrupt was triggered. """
- __tracebackhide__ = True
- raise Exit(msg)
-
-
-exit.Exception = Exit
-
-
-def skip(msg=""):
- """ skip an executing test with the given message. Note: it's usually
- better to use the pytest.mark.skipif marker to declare a test to be
- skipped under certain conditions like mismatching platforms or
- dependencies. See the pytest_skipping plugin for details.
- """
- __tracebackhide__ = True
- raise Skipped(msg=msg)
-
-
-skip.Exception = Skipped
-
-
-def fail(msg="", pytrace=True):
- """ explicitly fail an currently-executing test with the given Message.
-
- :arg pytrace: if false the msg represents the full failure information
- and no python traceback will be reported.
- """
- __tracebackhide__ = True
- raise Failed(msg=msg, pytrace=pytrace)
-
-
-fail.Exception = Failed
-
-
-def importorskip(modname, minversion=None):
- """ return imported module if it has at least "minversion" as its
- __version__ attribute. If no minversion is specified the a skip
- is only triggered if the module can not be imported.
- """
- __tracebackhide__ = True
- compile(modname, '', 'eval') # to catch syntaxerrors
- should_skip = False
- try:
- __import__(modname)
- except ImportError:
- # Do not raise chained exception here(#1485)
- should_skip = True
- if should_skip:
- raise Skipped("could not import %r" %(modname,), allow_module_level=True)
- mod = sys.modules[modname]
- if minversion is None:
- return mod
- verattr = getattr(mod, '__version__', None)
- if minversion is not None:
- try:
- from pkg_resources import parse_version as pv
- except ImportError:
- raise Skipped("we have a required version for %r but can not import "
- "pkg_resources to parse version strings." % (modname,),
- allow_module_level=True)
- if verattr is None or pv(verattr) < pv(minversion):
- raise Skipped("module %r has __version__ %r, required is: %r" %(
- modname, verattr, minversion), allow_module_level=True)
- return mod
-
diff --git a/lib/spack/external/_pytest/setuponly.py b/lib/spack/external/_pytest/setuponly.py
index 1752c575f5..15e195ad5a 100644
--- a/lib/spack/external/_pytest/setuponly.py
+++ b/lib/spack/external/_pytest/setuponly.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import, division, print_function
+
import pytest
import sys
diff --git a/lib/spack/external/_pytest/setupplan.py b/lib/spack/external/_pytest/setupplan.py
index f0853dee54..e11bd40698 100644
--- a/lib/spack/external/_pytest/setupplan.py
+++ b/lib/spack/external/_pytest/setupplan.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import, division, print_function
+
import pytest
diff --git a/lib/spack/external/_pytest/skipping.py b/lib/spack/external/_pytest/skipping.py
index a8eaea98aa..b92800d10b 100644
--- a/lib/spack/external/_pytest/skipping.py
+++ b/lib/spack/external/_pytest/skipping.py
@@ -1,18 +1,21 @@
""" support for skip/xfail functions and markers. """
+from __future__ import absolute_import, division, print_function
+
import os
import sys
import traceback
import py
-import pytest
+from _pytest.config import hookimpl
from _pytest.mark import MarkInfo, MarkDecorator
+from _pytest.outcomes import fail, skip, xfail, TEST_OUTCOME
def pytest_addoption(parser):
group = parser.getgroup("general")
group.addoption('--runxfail',
- action="store_true", dest="runxfail", default=False,
- help="run tests even if they are marked xfail")
+ action="store_true", dest="runxfail", default=False,
+ help="run tests even if they are marked xfail")
parser.addini("xfail_strict", "default for the strict parameter of xfail "
"markers when not given explicitly (default: "
@@ -23,53 +26,38 @@ def pytest_addoption(parser):
def pytest_configure(config):
if config.option.runxfail:
+ # yay a hack
+ import pytest
old = pytest.xfail
config._cleanup.append(lambda: setattr(pytest, "xfail", old))
def nop(*args, **kwargs):
pass
- nop.Exception = XFailed
+ nop.Exception = xfail.Exception
setattr(pytest, "xfail", nop)
config.addinivalue_line("markers",
- "skip(reason=None): skip the given test function with an optional reason. "
- "Example: skip(reason=\"no way of currently testing this\") skips the "
- "test."
- )
+ "skip(reason=None): skip the given test function with an optional reason. "
+ "Example: skip(reason=\"no way of currently testing this\") skips the "
+ "test."
+ )
config.addinivalue_line("markers",
- "skipif(condition): skip the given test function if eval(condition) "
- "results in a True value. Evaluation happens within the "
- "module global context. Example: skipif('sys.platform == \"win32\"') "
- "skips the test if we are on the win32 platform. see "
- "http://pytest.org/latest/skipping.html"
- )
+ "skipif(condition): skip the given test function if eval(condition) "
+ "results in a True value. Evaluation happens within the "
+ "module global context. Example: skipif('sys.platform == \"win32\"') "
+ "skips the test if we are on the win32 platform. see "
+ "http://pytest.org/latest/skipping.html"
+ )
config.addinivalue_line("markers",
- "xfail(condition, reason=None, run=True, raises=None, strict=False): "
- "mark the the test function as an expected failure if eval(condition) "
- "has a True value. Optionally specify a reason for better reporting "
- "and run=False if you don't even want to execute the test function. "
- "If only specific exception(s) are expected, you can list them in "
- "raises, and if the test fails in other ways, it will be reported as "
- "a true failure. See http://pytest.org/latest/skipping.html"
- )
-
-
-def pytest_namespace():
- return dict(xfail=xfail)
-
-
-class XFailed(pytest.fail.Exception):
- """ raised from an explicit call to pytest.xfail() """
-
-
-def xfail(reason=""):
- """ xfail an executing test or setup functions with the given reason."""
- __tracebackhide__ = True
- raise XFailed(reason)
-
-
-xfail.Exception = XFailed
+ "xfail(condition, reason=None, run=True, raises=None, strict=False): "
+ "mark the test function as an expected failure if eval(condition) "
+ "has a True value. Optionally specify a reason for better reporting "
+ "and run=False if you don't even want to execute the test function. "
+ "If only specific exception(s) are expected, you can list them in "
+ "raises, and if the test fails in other ways, it will be reported as "
+ "a true failure. See http://pytest.org/latest/skipping.html"
+ )
class MarkEvaluator:
@@ -97,51 +85,50 @@ class MarkEvaluator:
def istrue(self):
try:
return self._istrue()
- except Exception:
+ except TEST_OUTCOME:
self.exc = sys.exc_info()
if isinstance(self.exc[1], SyntaxError):
- msg = [" " * (self.exc[1].offset + 4) + "^",]
+ msg = [" " * (self.exc[1].offset + 4) + "^", ]
msg.append("SyntaxError: invalid syntax")
else:
msg = traceback.format_exception_only(*self.exc[:2])
- pytest.fail("Error evaluating %r expression\n"
- " %s\n"
- "%s"
- %(self.name, self.expr, "\n".join(msg)),
- pytrace=False)
+ fail("Error evaluating %r expression\n"
+ " %s\n"
+ "%s"
+ % (self.name, self.expr, "\n".join(msg)),
+ pytrace=False)
def _getglobals(self):
d = {'os': os, 'sys': sys, 'config': self.item.config}
- d.update(self.item.obj.__globals__)
+ if hasattr(self.item, 'obj'):
+ d.update(self.item.obj.__globals__)
return d
def _istrue(self):
if hasattr(self, 'result'):
return self.result
if self.holder:
- d = self._getglobals()
if self.holder.args or 'condition' in self.holder.kwargs:
self.result = False
# "holder" might be a MarkInfo or a MarkDecorator; only
# MarkInfo keeps track of all parameters it received in an
# _arglist attribute
- if hasattr(self.holder, '_arglist'):
- arglist = self.holder._arglist
- else:
- arglist = [(self.holder.args, self.holder.kwargs)]
- for args, kwargs in arglist:
+ marks = getattr(self.holder, '_marks', None) \
+ or [self.holder.mark]
+ for _, args, kwargs in marks:
if 'condition' in kwargs:
args = (kwargs['condition'],)
for expr in args:
self.expr = expr
if isinstance(expr, py.builtin._basestring):
+ d = self._getglobals()
result = cached_eval(self.item.config, expr, d)
else:
if "reason" not in kwargs:
# XXX better be checked at collection time
msg = "you need to specify reason=STRING " \
"when using booleans as conditions."
- pytest.fail(msg)
+ fail(msg)
result = bool(expr)
if result:
self.result = True
@@ -165,7 +152,7 @@ class MarkEvaluator:
return expl
-@pytest.hookimpl(tryfirst=True)
+@hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
# Check if skip or skipif are specified as pytest marks
@@ -174,23 +161,23 @@ def pytest_runtest_setup(item):
eval_skipif = MarkEvaluator(item, 'skipif')
if eval_skipif.istrue():
item._evalskip = eval_skipif
- pytest.skip(eval_skipif.getexplanation())
+ skip(eval_skipif.getexplanation())
skip_info = item.keywords.get('skip')
if isinstance(skip_info, (MarkInfo, MarkDecorator)):
item._evalskip = True
if 'reason' in skip_info.kwargs:
- pytest.skip(skip_info.kwargs['reason'])
+ skip(skip_info.kwargs['reason'])
elif skip_info.args:
- pytest.skip(skip_info.args[0])
+ skip(skip_info.args[0])
else:
- pytest.skip("unconditional skip")
+ skip("unconditional skip")
item._evalxfail = MarkEvaluator(item, 'xfail')
check_xfail_no_run(item)
-@pytest.mark.hookwrapper
+@hookimpl(hookwrapper=True)
def pytest_pyfunc_call(pyfuncitem):
check_xfail_no_run(pyfuncitem)
outcome = yield
@@ -205,7 +192,7 @@ def check_xfail_no_run(item):
evalxfail = item._evalxfail
if evalxfail.istrue():
if not evalxfail.get('run', True):
- pytest.xfail("[NOTRUN] " + evalxfail.getexplanation())
+ xfail("[NOTRUN] " + evalxfail.getexplanation())
def check_strict_xfail(pyfuncitem):
@@ -217,10 +204,10 @@ def check_strict_xfail(pyfuncitem):
if is_strict_xfail:
del pyfuncitem._evalxfail
explanation = evalxfail.getexplanation()
- pytest.fail('[XPASS(strict)] ' + explanation, pytrace=False)
+ fail('[XPASS(strict)] ' + explanation, pytrace=False)
-@pytest.hookimpl(hookwrapper=True)
+@hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
@@ -240,11 +227,11 @@ def pytest_runtest_makereport(item, call):
rep.wasxfail = rep.longrepr
elif item.config.option.runxfail:
pass # don't interefere
- elif call.excinfo and call.excinfo.errisinstance(pytest.xfail.Exception):
+ elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
rep.wasxfail = "reason: " + call.excinfo.value.msg
rep.outcome = "skipped"
elif evalxfail and not rep.skipped and evalxfail.wasvalid() and \
- evalxfail.istrue():
+ evalxfail.istrue():
if call.excinfo:
if evalxfail.invalidraise(call.excinfo.value):
rep.outcome = "failed"
@@ -270,6 +257,8 @@ def pytest_runtest_makereport(item, call):
rep.longrepr = filename, line, reason
# called by terminalreporter progress reporting
+
+
def pytest_report_teststatus(report):
if hasattr(report, "wasxfail"):
if report.skipped:
@@ -278,10 +267,12 @@ def pytest_report_teststatus(report):
return "xpassed", "X", ("XPASS", {'yellow': True})
# called by the terminalreporter instance/plugin
+
+
def pytest_terminal_summary(terminalreporter):
tr = terminalreporter
if not tr.reportchars:
- #for name in "xfailed skipped failed xpassed":
+ # for name in "xfailed skipped failed xpassed":
# if not tr.stats.get(name, 0):
# tr.write_line("HINT: use '-r' option to see extra "
# "summary info about tests")
@@ -308,12 +299,14 @@ def pytest_terminal_summary(terminalreporter):
for line in lines:
tr._tw.line(line)
+
def show_simple(terminalreporter, lines, stat, format):
failed = terminalreporter.stats.get(stat)
if failed:
for rep in failed:
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
- lines.append(format %(pos,))
+ lines.append(format % (pos,))
+
def show_xfailed(terminalreporter, lines):
xfailed = terminalreporter.stats.get("xfailed")
@@ -325,13 +318,15 @@ def show_xfailed(terminalreporter, lines):
if reason:
lines.append(" " + str(reason))
+
def show_xpassed(terminalreporter, lines):
xpassed = terminalreporter.stats.get("xpassed")
if xpassed:
for rep in xpassed:
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
reason = rep.wasxfail
- lines.append("XPASS %s %s" %(pos, reason))
+ lines.append("XPASS %s %s" % (pos, reason))
+
def cached_eval(config, expr, d):
if not hasattr(config, '_evalcache'):
@@ -351,25 +346,27 @@ def folded_skips(skipped):
key = event.longrepr
assert len(key) == 3, (event, key)
d.setdefault(key, []).append(event)
- l = []
+ values = []
for key, events in d.items():
- l.append((len(events),) + key)
- return l
+ values.append((len(events),) + key)
+ return values
+
def show_skipped(terminalreporter, lines):
tr = terminalreporter
skipped = tr.stats.get('skipped', [])
if skipped:
- #if not tr.hasopt('skipped'):
+ # if not tr.hasopt('skipped'):
# tr.write_line(
# "%d skipped tests, specify -rs for more info" %
# len(skipped))
# return
fskips = folded_skips(skipped)
if fskips:
- #tr.write_sep("_", "skipped test summary")
+ # tr.write_sep("_", "skipped test summary")
for num, fspath, lineno, reason in fskips:
if reason.startswith("Skipped: "):
reason = reason[9:]
- lines.append("SKIP [%d] %s:%d: %s" %
- (num, fspath, lineno, reason))
+ lines.append(
+ "SKIP [%d] %s:%d: %s" %
+ (num, fspath, lineno + 1, reason))
diff --git a/lib/spack/external/_pytest/terminal.py b/lib/spack/external/_pytest/terminal.py
index 16bf757338..9da94d0c91 100644
--- a/lib/spack/external/_pytest/terminal.py
+++ b/lib/spack/external/_pytest/terminal.py
@@ -2,6 +2,9 @@
This is a good source for looking at the various reporting hooks.
"""
+from __future__ import absolute_import, division, print_function
+
+import itertools
from _pytest.main import EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, \
EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED
import pytest
@@ -10,39 +13,41 @@ import sys
import time
import platform
+from _pytest import nodes
import _pytest._pluggy as pluggy
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
group._addoption('-v', '--verbose', action="count",
- dest="verbose", default=0, help="increase verbosity."),
+ dest="verbose", default=0, help="increase verbosity."),
group._addoption('-q', '--quiet', action="count",
- dest="quiet", default=0, help="decrease verbosity."),
+ dest="quiet", default=0, help="decrease verbosity."),
group._addoption('-r',
- action="store", dest="reportchars", default='', metavar="chars",
- help="show extra test summary info as specified by chars (f)ailed, "
- "(E)error, (s)skipped, (x)failed, (X)passed, "
- "(p)passed, (P)passed with output, (a)all except pP. "
- "The pytest warnings are displayed at all times except when "
- "--disable-pytest-warnings is set")
- group._addoption('--disable-pytest-warnings', default=False,
- dest='disablepytestwarnings', action='store_true',
- help='disable warnings summary, overrides -r w flag')
+ action="store", dest="reportchars", default='', metavar="chars",
+ help="show extra test summary info as specified by chars (f)ailed, "
+ "(E)error, (s)skipped, (x)failed, (X)passed, "
+ "(p)passed, (P)passed with output, (a)all except pP. "
+ "Warnings are displayed at all times except when "
+ "--disable-warnings is set")
+ group._addoption('--disable-warnings', '--disable-pytest-warnings', default=False,
+ dest='disable_warnings', action='store_true',
+ help='disable warnings summary')
group._addoption('-l', '--showlocals',
- action="store_true", dest="showlocals", default=False,
- help="show locals in tracebacks (disabled by default).")
+ action="store_true", dest="showlocals", default=False,
+ help="show locals in tracebacks (disabled by default).")
group._addoption('--tb', metavar="style",
- action="store", dest="tbstyle", default='auto',
- choices=['auto', 'long', 'short', 'no', 'line', 'native'],
- help="traceback print mode (auto/long/short/line/native/no).")
+ action="store", dest="tbstyle", default='auto',
+ choices=['auto', 'long', 'short', 'no', 'line', 'native'],
+ help="traceback print mode (auto/long/short/line/native/no).")
group._addoption('--fulltrace', '--full-trace',
- action="store_true", default=False,
- help="don't cut any tracebacks (default is to cut).")
+ action="store_true", default=False,
+ help="don't cut any tracebacks (default is to cut).")
group._addoption('--color', metavar="color",
- action="store", dest="color", default='auto',
- choices=['yes', 'no', 'auto'],
- help="color terminal output (yes/no/auto).")
+ action="store", dest="color", default='auto',
+ choices=['yes', 'no', 'auto'],
+ help="color terminal output (yes/no/auto).")
+
def pytest_configure(config):
config.option.verbose -= config.option.quiet
@@ -54,12 +59,13 @@ def pytest_configure(config):
reporter.write_line("[traceconfig] " + msg)
config.trace.root.setprocessor("pytest:config", mywriter)
+
def getreportopt(config):
reportopts = ""
reportchars = config.option.reportchars
- if not config.option.disablepytestwarnings and 'w' not in reportchars:
+ if not config.option.disable_warnings and 'w' not in reportchars:
reportchars += 'w'
- elif config.option.disablepytestwarnings and 'w' in reportchars:
+ elif config.option.disable_warnings and 'w' in reportchars:
reportchars = reportchars.replace('w', '')
if reportchars:
for char in reportchars:
@@ -69,6 +75,7 @@ def getreportopt(config):
reportopts = 'fEsxXw'
return reportopts
+
def pytest_report_teststatus(report):
if report.passed:
letter = "."
@@ -80,13 +87,41 @@ def pytest_report_teststatus(report):
letter = "f"
return report.outcome, letter, report.outcome.upper()
+
class WarningReport:
+ """
+ Simple structure to hold warnings information captured by ``pytest_logwarning``.
+ """
+
def __init__(self, code, message, nodeid=None, fslocation=None):
+ """
+ :param code: unused
+ :param str message: user friendly message about the warning
+ :param str|None nodeid: node id that generated the warning (see ``get_location``).
+ :param tuple|py.path.local fslocation:
+ file system location of the source of the warning (see ``get_location``).
+ """
self.code = code
self.message = message
self.nodeid = nodeid
self.fslocation = fslocation
+ def get_location(self, config):
+ """
+ Returns the more user-friendly information about the location
+ of a warning, or None.
+ """
+ if self.nodeid:
+ return self.nodeid
+ if self.fslocation:
+ if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2:
+ filename, linenum = self.fslocation[:2]
+ relpath = py.path.local(filename).relto(config.invocation_dir)
+ return '%s:%s' % (relpath, linenum)
+ else:
+ return str(self.fslocation)
+ return None
+
class TerminalReporter:
def __init__(self, config, file=None):
@@ -146,8 +181,22 @@ class TerminalReporter:
self._tw.line(line, **markup)
def rewrite(self, line, **markup):
+ """
+ Rewinds the terminal cursor to the beginning and writes the given line.
+
+ :kwarg erase: if True, will also add spaces until the full terminal width to ensure
+ previous lines are properly erased.
+
+ The rest of the keyword arguments are markup instructions.
+ """
+ erase = markup.pop('erase', False)
+ if erase:
+ fill_count = self._tw.fullwidth - len(line)
+ fill = ' ' * fill_count
+ else:
+ fill = ''
line = str(line)
- self._tw.write("\r" + line, **markup)
+ self._tw.write("\r" + line + fill, **markup)
def write_sep(self, sep, title=None, **markup):
self.ensure_newline()
@@ -166,8 +215,6 @@ class TerminalReporter:
def pytest_logwarning(self, code, fslocation, message, nodeid):
warnings = self.stats.setdefault("warnings", [])
- if isinstance(fslocation, tuple):
- fslocation = "%s:%d" % fslocation
warning = WarningReport(code=code, fslocation=fslocation,
message=message, nodeid=nodeid)
warnings.append(warning)
@@ -212,15 +259,15 @@ class TerminalReporter:
word, markup = word
else:
if rep.passed:
- markup = {'green':True}
+ markup = {'green': True}
elif rep.failed:
- markup = {'red':True}
+ markup = {'red': True}
elif rep.skipped:
- markup = {'yellow':True}
+ markup = {'yellow': True}
line = self._locationline(rep.nodeid, *rep.location)
if not hasattr(rep, 'node'):
self.write_ensure_prefix(line, word, **markup)
- #self._tw.write(word, **markup)
+ # self._tw.write(word, **markup)
else:
self.ensure_newline()
if hasattr(rep, 'node'):
@@ -241,7 +288,7 @@ class TerminalReporter:
items = [x for x in report.result if isinstance(x, pytest.Item)]
self._numcollected += len(items)
if self.isatty:
- #self.write_fspath_result(report.nodeid, 'E')
+ # self.write_fspath_result(report.nodeid, 'E')
self.report_collect()
def report_collect(self, final=False):
@@ -254,15 +301,15 @@ class TerminalReporter:
line = "collected "
else:
line = "collecting "
- line += str(self._numcollected) + " items"
+ line += str(self._numcollected) + " item" + ('' if self._numcollected == 1 else 's')
if errors:
line += " / %d errors" % errors
if skipped:
line += " / %d skipped" % skipped
if self.isatty:
+ self.rewrite(line, bold=True, erase=True)
if final:
- line += " \n"
- self.rewrite(line, bold=True)
+ self.write('\n')
else:
self.write_line(line)
@@ -288,6 +335,9 @@ class TerminalReporter:
self.write_line(msg)
lines = self.config.hook.pytest_report_header(
config=self.config, startdir=self.startdir)
+ self._write_report_lines_from_hooks(lines)
+
+ def _write_report_lines_from_hooks(self, lines):
lines.reverse()
for line in flatten(lines):
self.write_line(line)
@@ -295,8 +345,8 @@ class TerminalReporter:
def pytest_report_header(self, config):
inifile = ""
if config.inifile:
- inifile = config.rootdir.bestrelpath(config.inifile)
- lines = ["rootdir: %s, inifile: %s" %(config.rootdir, inifile)]
+ inifile = " " + config.rootdir.bestrelpath(config.inifile)
+ lines = ["rootdir: %s, inifile:%s" % (config.rootdir, inifile)]
plugininfo = config.pluginmanager.list_plugin_distinfo()
if plugininfo:
@@ -314,10 +364,9 @@ class TerminalReporter:
rep.toterminal(self._tw)
return 1
return 0
- if not self.showheader:
- return
- #for i, testarg in enumerate(self.config.args):
- # self.write_line("test path %d: %s" %(i+1, testarg))
+ lines = self.config.hook.pytest_report_collectionfinish(
+ config=self.config, startdir=self.startdir, items=session.items)
+ self._write_report_lines_from_hooks(lines)
def _printcollecteditems(self, items):
# to print out items and their parent collectors
@@ -340,14 +389,14 @@ class TerminalReporter:
stack = []
indent = ""
for item in items:
- needed_collectors = item.listchain()[1:] # strip root node
+ needed_collectors = item.listchain()[1:] # strip root node
while stack:
if stack == needed_collectors[:len(stack)]:
break
stack.pop()
for col in needed_collectors[len(stack):]:
stack.append(col)
- #if col.name == "()":
+ # if col.name == "()":
# continue
indent = (len(stack) - 1) * " "
self._tw.line("%s%s" % (indent, col))
@@ -396,15 +445,15 @@ class TerminalReporter:
line = self.config.cwd_relative_nodeid(nodeid)
if domain and line.endswith(domain):
line = line[:-len(domain)]
- l = domain.split("[")
- l[0] = l[0].replace('.', '::') # don't replace '.' in params
- line += "[".join(l)
+ values = domain.split("[")
+ values[0] = values[0].replace('.', '::') # don't replace '.' in params
+ line += "[".join(values)
return line
# collect_fspath comes from testid which has a "/"-normalized path
if fspath:
res = mkrel(nodeid).replace("::()", "") # parens-normalization
- if nodeid.split("::")[0] != fspath.replace("\\", "/"):
+ if nodeid.split("::")[0] != fspath.replace("\\", nodes.SEP):
res += " <- " + self.startdir.bestrelpath(fspath)
else:
res = "[location]"
@@ -415,7 +464,7 @@ class TerminalReporter:
fspath, lineno, domain = rep.location
return domain
else:
- return "test session" # XXX?
+ return "test session" # XXX?
def _getcrashline(self, rep):
try:
@@ -430,21 +479,29 @@ class TerminalReporter:
# summaries for sessionfinish
#
def getreports(self, name):
- l = []
+ values = []
for x in self.stats.get(name, []):
if not hasattr(x, '_pdbshown'):
- l.append(x)
- return l
+ values.append(x)
+ return values
def summary_warnings(self):
if self.hasopt("w"):
- warnings = self.stats.get("warnings")
- if not warnings:
+ all_warnings = self.stats.get("warnings")
+ if not all_warnings:
return
- self.write_sep("=", "pytest-warning summary")
- for w in warnings:
- self._tw.line("W%s %s %s" % (w.code,
- w.fslocation, w.message))
+
+ grouped = itertools.groupby(all_warnings, key=lambda wr: wr.get_location(self.config))
+
+ self.write_sep("=", "warnings summary", yellow=True, bold=False)
+ for location, warnings in grouped:
+ self._tw.line(str(location) or '<undetermined location>')
+ for w in warnings:
+ lines = w.message.splitlines()
+ indented = '\n'.join(' ' + x for x in lines)
+ self._tw.line(indented)
+ self._tw.line()
+ self._tw.line('-- Docs: http://doc.pytest.org/en/latest/warnings.html')
def summary_passes(self):
if self.config.option.tbstyle != "no":
@@ -466,7 +523,6 @@ class TerminalReporter:
content = content[:-1]
self._tw.line(content)
-
def summary_failures(self):
if self.config.option.tbstyle != "no":
reports = self.getreports('failed')
@@ -528,6 +584,7 @@ class TerminalReporter:
self.write_sep("=", "%d tests deselected" % (
len(self.stats['deselected'])), bold=True)
+
def repr_pythonversion(v=None):
if v is None:
v = sys.version_info
@@ -536,30 +593,30 @@ def repr_pythonversion(v=None):
except (TypeError, ValueError):
return str(v)
-def flatten(l):
- for x in l:
+
+def flatten(values):
+ for x in values:
if isinstance(x, (list, tuple)):
for y in flatten(x):
yield y
else:
yield x
+
def build_summary_stats_line(stats):
keys = ("failed passed skipped deselected "
- "xfailed xpassed warnings error").split()
- key_translation = {'warnings': 'pytest-warnings'}
+ "xfailed xpassed warnings error").split()
unknown_key_seen = False
for key in stats.keys():
if key not in keys:
- if key: # setup/teardown reports have an empty key, ignore them
+ if key: # setup/teardown reports have an empty key, ignore them
keys.append(key)
unknown_key_seen = True
parts = []
for key in keys:
val = stats.get(key, None)
if val:
- key_name = key_translation.get(key, key)
- parts.append("%d %s" % (len(val), key_name))
+ parts.append("%d %s" % (len(val), key))
if parts:
line = ", ".join(parts)
@@ -579,7 +636,7 @@ def build_summary_stats_line(stats):
def _plugin_nameversions(plugininfo):
- l = []
+ values = []
for plugin, dist in plugininfo:
# gets us name and version!
name = '{dist.project_name}-{dist.version}'.format(dist=dist)
@@ -588,6 +645,6 @@ def _plugin_nameversions(plugininfo):
name = name[7:]
# we decided to print python package names
# they can have more than one plugin
- if name not in l:
- l.append(name)
- return l
+ if name not in values:
+ values.append(name)
+ return values
diff --git a/lib/spack/external/_pytest/tmpdir.py b/lib/spack/external/_pytest/tmpdir.py
index 28a6b06366..da1b032237 100644
--- a/lib/spack/external/_pytest/tmpdir.py
+++ b/lib/spack/external/_pytest/tmpdir.py
@@ -1,4 +1,6 @@
""" support for providing temporary directories to test functions. """
+from __future__ import absolute_import, division, print_function
+
import re
import pytest
@@ -23,7 +25,7 @@ class TempdirFactory:
provides an empty unique-per-test-invocation directory
and is guaranteed to be empty.
"""
- #py.log._apiwarn(">1.1", "use tmpdir function argument")
+ # py.log._apiwarn(">1.1", "use tmpdir function argument")
return self.getbasetemp().ensure(string, dir=dir)
def mktemp(self, basename, numbered=True):
@@ -36,7 +38,7 @@ class TempdirFactory:
p = basetemp.mkdir(basename)
else:
p = py.path.local.make_numbered_dir(prefix=basename,
- keep=0, rootdir=basetemp, lock_timeout=None)
+ keep=0, rootdir=basetemp, lock_timeout=None)
self.trace("mktemp", p)
return p
@@ -116,7 +118,7 @@ def tmpdir(request, tmpdir_factory):
path object.
"""
name = request.node.name
- name = re.sub("[\W]", "_", name)
+ name = re.sub(r"[\W]", "_", name)
MAXVAL = 30
if len(name) > MAXVAL:
name = name[:MAXVAL]
diff --git a/lib/spack/external/_pytest/unittest.py b/lib/spack/external/_pytest/unittest.py
index 73224010b2..52c9813e8b 100644
--- a/lib/spack/external/_pytest/unittest.py
+++ b/lib/spack/external/_pytest/unittest.py
@@ -1,13 +1,14 @@
""" discovery and running of std-library "unittest" style tests. """
-from __future__ import absolute_import
+from __future__ import absolute_import, division, print_function
import sys
import traceback
-import pytest
-# for transfering markers
+# for transferring markers
import _pytest._code
-from _pytest.python import transfer_markers
+from _pytest.config import hookimpl
+from _pytest.outcomes import fail, skip, xfail
+from _pytest.python import transfer_markers, Class, Module, Function
from _pytest.skipping import MarkEvaluator
@@ -22,11 +23,11 @@ def pytest_pycollect_makeitem(collector, name, obj):
return UnitTestCase(name, parent=collector)
-class UnitTestCase(pytest.Class):
+class UnitTestCase(Class):
# marker for fixturemanger.getfixtureinfo()
# to declare that our children do not support funcargs
nofuncargs = True
-
+
def setup(self):
cls = self.obj
if getattr(cls, '__unittest_skip__', False):
@@ -46,7 +47,7 @@ class UnitTestCase(pytest.Class):
return
self.session._fixturemanager.parsefactories(self, unittest=True)
loader = TestLoader()
- module = self.getparent(pytest.Module).obj
+ module = self.getparent(Module).obj
foundsomething = False
for name in loader.getTestCaseNames(self.obj):
x = getattr(self.obj, name)
@@ -65,8 +66,7 @@ class UnitTestCase(pytest.Class):
yield TestCaseFunction('runTest', parent=self)
-
-class TestCaseFunction(pytest.Function):
+class TestCaseFunction(Function):
_excinfo = None
def setup(self):
@@ -109,38 +109,39 @@ class TestCaseFunction(pytest.Function):
except TypeError:
try:
try:
- l = traceback.format_exception(*rawexcinfo)
- l.insert(0, "NOTE: Incompatible Exception Representation, "
- "displaying natively:\n\n")
- pytest.fail("".join(l), pytrace=False)
- except (pytest.fail.Exception, KeyboardInterrupt):
+ values = traceback.format_exception(*rawexcinfo)
+ values.insert(0, "NOTE: Incompatible Exception Representation, "
+ "displaying natively:\n\n")
+ fail("".join(values), pytrace=False)
+ except (fail.Exception, KeyboardInterrupt):
raise
- except:
- pytest.fail("ERROR: Unknown Incompatible Exception "
- "representation:\n%r" %(rawexcinfo,), pytrace=False)
+ except: # noqa
+ fail("ERROR: Unknown Incompatible Exception "
+ "representation:\n%r" % (rawexcinfo,), pytrace=False)
except KeyboardInterrupt:
raise
- except pytest.fail.Exception:
+ except fail.Exception:
excinfo = _pytest._code.ExceptionInfo()
self.__dict__.setdefault('_excinfo', []).append(excinfo)
def addError(self, testcase, rawexcinfo):
self._addexcinfo(rawexcinfo)
+
def addFailure(self, testcase, rawexcinfo):
self._addexcinfo(rawexcinfo)
def addSkip(self, testcase, reason):
try:
- pytest.skip(reason)
- except pytest.skip.Exception:
+ skip(reason)
+ except skip.Exception:
self._evalskip = MarkEvaluator(self, 'SkipTest')
self._evalskip.result = True
self._addexcinfo(sys.exc_info())
def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
try:
- pytest.xfail(str(reason))
- except pytest.xfail.Exception:
+ xfail(str(reason))
+ except xfail.Exception:
self._addexcinfo(sys.exc_info())
def addUnexpectedSuccess(self, testcase, reason=""):
@@ -152,22 +153,42 @@ class TestCaseFunction(pytest.Function):
def stopTest(self, testcase):
pass
+ def _handle_skip(self):
+ # implements the skipping machinery (see #2137)
+ # analog to pythons Lib/unittest/case.py:run
+ testMethod = getattr(self._testcase, self._testcase._testMethodName)
+ if (getattr(self._testcase.__class__, "__unittest_skip__", False) or
+ getattr(testMethod, "__unittest_skip__", False)):
+ # If the class or method was skipped.
+ skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') or
+ getattr(testMethod, '__unittest_skip_why__', ''))
+ try: # PY3, unittest2 on PY2
+ self._testcase._addSkip(self, self._testcase, skip_why)
+ except TypeError: # PY2
+ if sys.version_info[0] != 2:
+ raise
+ self._testcase._addSkip(self, skip_why)
+ return True
+ return False
+
def runtest(self):
if self.config.pluginmanager.get_plugin("pdbinvoke") is None:
self._testcase(result=self)
else:
# disables tearDown and cleanups for post mortem debugging (see #1890)
+ if self._handle_skip():
+ return
self._testcase.debug()
-
def _prunetraceback(self, excinfo):
- pytest.Function._prunetraceback(self, excinfo)
+ Function._prunetraceback(self, excinfo)
traceback = excinfo.traceback.filter(
- lambda x:not x.frame.f_globals.get('__unittest'))
+ lambda x: not x.frame.f_globals.get('__unittest'))
if traceback:
excinfo.traceback = traceback
-@pytest.hookimpl(tryfirst=True)
+
+@hookimpl(tryfirst=True)
def pytest_runtest_makereport(item, call):
if isinstance(item, TestCaseFunction):
if item._excinfo:
@@ -179,7 +200,8 @@ def pytest_runtest_makereport(item, call):
# twisted trial support
-@pytest.hookimpl(hookwrapper=True)
+
+@hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item):
if isinstance(item, TestCaseFunction) and \
'twisted.trial.unittest' in sys.modules:
@@ -188,7 +210,7 @@ def pytest_runtest_protocol(item):
check_testcase_implements_trial_reporter()
def excstore(self, exc_value=None, exc_type=None, exc_tb=None,
- captureVars=None):
+ captureVars=None):
if exc_value is None:
self._rawexcinfo = sys.exc_info()
else:
@@ -197,7 +219,7 @@ def pytest_runtest_protocol(item):
self._rawexcinfo = (exc_type, exc_value, exc_tb)
try:
Failure__init__(self, exc_value, exc_type, exc_tb,
- captureVars=captureVars)
+ captureVars=captureVars)
except TypeError:
Failure__init__(self, exc_value, exc_type, exc_tb)
diff --git a/lib/spack/external/_pytest/vendored_packages/pluggy.py b/lib/spack/external/_pytest/vendored_packages/pluggy.py
index 9c13932b36..aebddad01d 100644
--- a/lib/spack/external/_pytest/vendored_packages/pluggy.py
+++ b/lib/spack/external/_pytest/vendored_packages/pluggy.py
@@ -540,7 +540,7 @@ class PluginManager(object):
of HookImpl instances and the keyword arguments for the hook call.
``after(outcome, hook_name, hook_impls, kwargs)`` receives the
- same arguments as ``before`` but also a :py:class:`_CallOutcome`` object
+ same arguments as ``before`` but also a :py:class:`_CallOutcome <_pytest.vendored_packages.pluggy._CallOutcome>` object
which represents the result of the overall hook call.
"""
return _TracedHookExecution(self, before, after).undo
diff --git a/lib/spack/external/_pytest/warnings.py b/lib/spack/external/_pytest/warnings.py
new file mode 100644
index 0000000000..926b1f5811
--- /dev/null
+++ b/lib/spack/external/_pytest/warnings.py
@@ -0,0 +1,94 @@
+from __future__ import absolute_import, division, print_function
+
+import warnings
+from contextlib import contextmanager
+
+import pytest
+
+from _pytest import compat
+
+
+def _setoption(wmod, arg):
+ """
+ Copy of the warning._setoption function but does not escape arguments.
+ """
+ parts = arg.split(':')
+ if len(parts) > 5:
+ raise wmod._OptionError("too many fields (max 5): %r" % (arg,))
+ while len(parts) < 5:
+ parts.append('')
+ action, message, category, module, lineno = [s.strip()
+ for s in parts]
+ action = wmod._getaction(action)
+ category = wmod._getcategory(category)
+ if lineno:
+ try:
+ lineno = int(lineno)
+ if lineno < 0:
+ raise ValueError
+ except (ValueError, OverflowError):
+ raise wmod._OptionError("invalid lineno %r" % (lineno,))
+ else:
+ lineno = 0
+ wmod.filterwarnings(action, message, category, module, lineno)
+
+
+def pytest_addoption(parser):
+ group = parser.getgroup("pytest-warnings")
+ group.addoption(
+ '-W', '--pythonwarnings', action='append',
+ help="set which warnings to report, see -W option of python itself.")
+ parser.addini("filterwarnings", type="linelist",
+ help="Each line specifies a pattern for "
+ "warnings.filterwarnings. "
+ "Processed after -W and --pythonwarnings.")
+
+
+@contextmanager
+def catch_warnings_for_item(item):
+ """
+ catches the warnings generated during setup/call/teardown execution
+ of the given item and after it is done posts them as warnings to this
+ item.
+ """
+ args = item.config.getoption('pythonwarnings') or []
+ inifilters = item.config.getini("filterwarnings")
+ with warnings.catch_warnings(record=True) as log:
+ for arg in args:
+ warnings._setoption(arg)
+
+ for arg in inifilters:
+ _setoption(warnings, arg)
+
+ mark = item.get_marker('filterwarnings')
+ if mark:
+ for arg in mark.args:
+ warnings._setoption(arg)
+
+ yield
+
+ for warning in log:
+ warn_msg = warning.message
+ unicode_warning = False
+
+ if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args):
+ new_args = [compat.safe_str(m) for m in warn_msg.args]
+ unicode_warning = warn_msg.args != new_args
+ warn_msg.args = new_args
+
+ msg = warnings.formatwarning(
+ warn_msg, warning.category,
+ warning.filename, warning.lineno, warning.line)
+ item.warn("unused", msg)
+
+ if unicode_warning:
+ warnings.warn(
+ "Warning is using unicode non convertible to ascii, "
+ "converting to a safe representation:\n %s" % msg,
+ UnicodeWarning)
+
+
+@pytest.hookimpl(hookwrapper=True)
+def pytest_runtest_protocol(item):
+ with catch_warnings_for_item(item):
+ yield
diff --git a/lib/spack/external/argparse.py b/lib/spack/external/argparse.py
index ec9a9ee738..d2d232d51e 100644
--- a/lib/spack/external/argparse.py
+++ b/lib/spack/external/argparse.py
@@ -1,25 +1,6 @@
-# argparse is (c) 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>.
-#
-# The argparse module was contributed to Python as of Python 2.7 and thus
-# was licensed under the Python license. Same license applies to all files in
-# the argparse package project.
-#
-# For details about the Python License, please see doc/Python-License.txt.
-#
-# History
-# -------
-#
-# Before (and including) argparse 1.1, the argparse package was licensed under
-# Apache License v2.0.
-#
-# After argparse 1.1, all project files from the argparse project were deleted
-# due to license compatibility issues between Apache License 2.0 and GNU GPL v2.
-#
-# The project repository then had a clean start with some files taken from
-# Python 2.7.1, so definitely all files are under Python License now.
-#
# Author: Steven J. Bethard <steven.bethard@gmail.com>.
-#
+# Maintainer: Thomas Waldmann <tw@waldmann-edv.de>
+
"""Command-line parsing library
This module is an optparse-inspired command-line parsing library that:
@@ -81,7 +62,12 @@ considered public as object names -- the API of the formatter objects is
still considered an implementation detail.)
"""
-__version__ = '1.2.1'
+__version__ = '1.4.0' # we use our own version number independant of the
+ # one in stdlib and we release this on pypi.
+
+__external_lib__ = True # to make sure the tests really test THIS lib,
+ # not the builtin one in Python stdlib
+
__all__ = [
'ArgumentParser',
'ArgumentError',
@@ -370,8 +356,6 @@ class HelpFormatter(object):
pos_usage = format(positionals, groups)
opt_parts = _re.findall(part_regexp, opt_usage)
pos_parts = _re.findall(part_regexp, pos_usage)
- assert ' '.join(opt_parts) == opt_usage
- assert ' '.join(pos_parts) == pos_usage
# helper for wrapping lines
def get_lines(parts, indent, prefix=None):
@@ -1073,7 +1057,7 @@ class _SubParsersAction(Action):
metavar += ' (%s)' % ', '.join(aliases)
sup = super(_SubParsersAction._ChoicesPseudoAction, self)
sup.__init__(option_strings=[], dest=dest, help=help,
- metavar=metavar)
+ metavar=metavar)
def __init__(self,
option_strings,
@@ -1134,9 +1118,8 @@ class _SubParsersAction(Action):
try:
parser = self._name_parser_map[parser_name]
except KeyError:
- args = {'parser_name': parser_name,
- 'choices': ', '.join(self._name_parser_map)}
- msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
+ tup = parser_name, ', '.join(self._name_parser_map)
+ msg = _('unknown parser %r (choices: %s)' % tup)
raise ArgumentError(self, msg)
# parse all the remaining options into the namespace
@@ -1180,11 +1163,16 @@ class FileType(object):
msg = _('argument "-" with mode %r' % self._mode)
raise ValueError(msg)
- # all other arguments are used as file names
- if self._bufsize:
- return open(string, self._mode, self._bufsize)
- else:
- return open(string, self._mode)
+ try:
+ # all other arguments are used as file names
+ if self._bufsize:
+ return open(string, self._mode, self._bufsize)
+ else:
+ return open(string, self._mode)
+ except IOError:
+ err = _sys.exc_info()[1]
+ message = _("can't open '%s': %s")
+ raise ArgumentTypeError(message % (string, err))
def __repr__(self):
args = [self._mode, self._bufsize]
@@ -1720,21 +1708,6 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
self._positionals._add_action(action)
return action
-
- def get_subparser(self, name):
- """Gets a subparser added with the supplied name.
- This is an extension to the standard argparse API.
- """
- subpasrsers_actions = [
- action for action in self._actions
- if isinstance(action, _SubParsersAction)]
- for action in subpasrsers_actions:
- for choice, subparser in action.choices.items():
- if choice == name:
- return subparser
- return None
-
-
def _get_optional_actions(self):
return [action
for action in self._actions
@@ -1769,10 +1742,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if action.dest is not SUPPRESS:
if not hasattr(namespace, action.dest):
if action.default is not SUPPRESS:
- default = action.default
- if isinstance(action.default, basestring):
- default = self._get_value(action, default)
- setattr(namespace, action.dest, default)
+ setattr(namespace, action.dest, action.default)
# add any parser defaults that aren't present
for dest in self._defaults:
@@ -2000,12 +1970,23 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if positionals:
self.error(_('too few arguments'))
- # make sure all required actions were present
+ # make sure all required actions were present, and convert defaults.
for action in self._actions:
- if action.required:
- if action not in seen_actions:
+ if action not in seen_actions:
+ if action.required:
name = _get_action_name(action)
self.error(_('argument %s is required') % name)
+ else:
+ # Convert action default now instead of doing it before
+ # parsing arguments to avoid calling convert functions
+ # twice (which may fail) if the argument was given, but
+ # only if it was defined already in the namespace
+ if (action.default is not None and
+ isinstance(action.default, basestring) and
+ hasattr(namespace, action.dest) and
+ action.default is getattr(namespace, action.dest)):
+ setattr(namespace, action.dest,
+ self._get_value(action, action.default))
# make sure all required groups had one option present
for group in self._mutually_exclusive_groups:
diff --git a/lib/spack/external/ctest_log_parser.py b/lib/spack/external/ctest_log_parser.py
index 6ef9642d85..0437b6e524 100644
--- a/lib/spack/external/ctest_log_parser.py
+++ b/lib/spack/external/ctest_log_parser.py
@@ -65,30 +65,72 @@ algorithms that duplicate the way CTest scrapes log files. To keep this
up to date with CTest, just make sure the ``*_matches`` and
``*_exceptions`` lists are kept up to date with CTest's build handler.
"""
+from __future__ import print_function
+from __future__ import division
+
import re
+import math
+import multiprocessing
+import time
+from contextlib import contextmanager
+
from six import StringIO
from six import string_types
+class prefilter(object):
+ """Make regular expressions faster with a simple prefiltering predicate.
+
+ Some regular expressions seem to be much more costly than others. In
+ most cases, we can evaluate a simple precondition, e.g.::
+
+ lambda x: "error" in x
+
+ to avoid evaluating expensive regexes on all lines in a file. This
+ can reduce parse time for large files by orders of magnitude when
+ evaluating lots of expressions.
+
+ A ``prefilter`` object is designed to act like a regex,, but
+ ``search`` and ``match`` check the precondition before bothering to
+ evaluate the regular expression.
-error_matches = [
+ Note that ``match`` and ``search`` just return ``True`` and ``False``
+ at the moment. Make them return a ``MatchObject`` or ``None`` if it
+ becomes necessary.
+ """
+ def __init__(self, precondition, *patterns):
+ self.patterns = [re.compile(p) for p in patterns]
+ self.pre = precondition
+ self.pattern = "\n ".join(
+ ('MERGED:',) + patterns)
+
+ def search(self, text):
+ return self.pre(text) and any(p.search(text) for p in self.patterns)
+
+ def match(self, text):
+ return self.pre(text) and any(p.match(text) for p in self.patterns)
+
+
+_error_matches = [
+ prefilter(
+ lambda x: any(s in x for s in (
+ 'Error:', 'error', 'undefined reference', 'multiply defined')),
+ "([^:]+): error[ \\t]*[0-9]+[ \\t]*:",
+ "([^:]+): (Error:|error|undefined reference|multiply defined)",
+ "([^ :]+) ?: (error|fatal error|catastrophic error)",
+ "([^:]+)\\(([^\\)]+)\\) ?: (error|fatal error|catastrophic error)"),
"^[Bb]us [Ee]rror",
"^[Ss]egmentation [Vv]iolation",
"^[Ss]egmentation [Ff]ault",
":.*[Pp]ermission [Dd]enied",
- "([^ :]+):([0-9]+): ([^ \\t])",
- "([^:]+): error[ \\t]*[0-9]+[ \\t]*:",
"^Error ([0-9]+):",
"^Fatal",
- "^Error: ",
+ "^[Ee]rror: ",
"^Error ",
"[0-9] ERROR: ",
"^\"[^\"]+\", line [0-9]+: [^Ww]",
"^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
"^ld([^:])*:([ \\t])*ERROR([^:])*:",
"^ild:([ \\t])*\\(undefined symbol\\)",
- "([^ :]+) : (error|fatal error|catastrophic error)",
- "([^:]+): (Error:|error|undefined reference|multiply defined)",
- "([^:]+)\\(([^\\)]+)\\) ?: (error|fatal error|catastrophic error)",
"^fatal error C[0-9]+:",
": syntax error ",
"^collect2: ld returned 1 exit status",
@@ -128,7 +170,7 @@ error_matches = [
"^Command .* failed with exit code",
]
-error_exceptions = [
+_error_exceptions = [
"instantiated from ",
"candidates are:",
": warning",
@@ -143,32 +185,38 @@ error_exceptions = [
]
#: Regexes to match file/line numbers in error/warning messages
-warning_matches = [
- "([^ :]+):([0-9]+): warning:",
- "([^ :]+):([0-9]+): note:",
+_warning_matches = [
+ prefilter(
+ lambda x: 'warning' in x,
+ "([^ :]+):([0-9]+): warning:",
+ "([^:]+): warning ([0-9]+):",
+ "([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
+ "([^ :]+) : warning",
+ "([^:]+): warning"),
+ prefilter(
+ lambda x: 'note:' in x,
+ "^([^ :]+):([0-9]+): note:"),
+ prefilter(
+ lambda x: any(s in x for s in ('Warning', 'Warnung')),
+ "^(Warning|Warnung) ([0-9]+):",
+ "^(Warning|Warnung)[ :]",
+ "^cxx: Warning:",
+ "([^ :]+):([0-9]+): (Warning|Warnung)",
+ "^CMake Warning.*:"),
+ "file: .* has no symbols",
"^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
"^ld([^:])*:([ \\t])*WARNING([^:])*:",
- "([^:]+): warning ([0-9]+):",
"^\"[^\"]+\", line [0-9]+: [Ww](arning|arnung)",
- "([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
- "^(Warning|Warnung) ([0-9]+):",
- "^(Warning|Warnung)[ :]",
"WARNING: ",
- "([^ :]+) : warning",
- "([^:]+): warning",
"\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([WI]\\)",
- "^cxx: Warning:",
- ".*file: .* has no symbols",
- "([^ :]+):([0-9]+): (Warning|Warnung)",
"\\([0-9]*\\): remark #[0-9]*",
"\".*\", line [0-9]+: remark\\([0-9]*\\):",
"cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
- "^CMake Warning.*:",
"^\\[WARNING\\]",
]
#: Regexes to match file/line numbers in error/warning messages
-warning_exceptions = [
+_warning_exceptions = [
"/usr/.*/X11/Xlib\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
"/usr/.*/X11/Xutil\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
"/usr/.*/X11/XResource\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
@@ -188,7 +236,7 @@ warning_exceptions = [
]
#: Regexes to match file/line numbers in error/warning messages
-file_line_matches = [
+_file_line_matches = [
"^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):",
"^([a-zA-Z./0-9_+ ~-]+):([0-9]+):",
"^([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)",
@@ -250,25 +298,120 @@ class BuildWarning(LogEvent):
"""LogEvent subclass for build warnings."""
+def chunks(l, n):
+ """Divide l into n approximately-even chunks."""
+ chunksize = int(math.ceil(len(l) / n))
+ return [l[i:i + chunksize] for i in range(0, len(l), chunksize)]
+
+
+@contextmanager
+def _time(times, i):
+ start = time.time()
+ yield
+ end = time.time()
+ times[i] += end - start
+
+
def _match(matches, exceptions, line):
"""True if line matches a regex in matches and none in exceptions."""
return (any(m.search(line) for m in matches) and
not any(e.search(line) for e in exceptions))
-class CTestLogParser(object):
- """Log file parser that extracts errors and warnings."""
- def __init__(self):
- def compile(regex_array):
- return [re.compile(regex) for regex in regex_array]
+def _profile_match(matches, exceptions, line, match_times, exc_times):
+ """Profiled version of match().
+
+ Timing is expensive so we have two whole functions. This is much
+ longer because we have to break up the ``any()`` calls.
+
+ """
+ for i, m in enumerate(matches):
+ with _time(match_times, i):
+ if m.search(line):
+ break
+ else:
+ return False
+
+ for i, m in enumerate(exceptions):
+ with _time(exc_times, i):
+ if m.search(line):
+ return False
+ else:
+ return True
+
+
+def _parse(lines, offset, profile):
+ def compile(regex_array):
+ return [regex if isinstance(regex, prefilter) else re.compile(regex)
+ for regex in regex_array]
+
+ error_matches = compile(_error_matches)
+ error_exceptions = compile(_error_exceptions)
+ warning_matches = compile(_warning_matches)
+ warning_exceptions = compile(_warning_exceptions)
+ file_line_matches = compile(_file_line_matches)
+
+ matcher, args = _match, []
+ timings = []
+ if profile:
+ matcher = _profile_match
+ timings = [
+ [0.0] * len(error_matches), [0.0] * len(error_exceptions),
+ [0.0] * len(warning_matches), [0.0] * len(warning_exceptions)]
+
+ errors = []
+ warnings = []
+ for i, line in enumerate(lines):
+ # use CTest's regular expressions to scrape the log for events
+ if matcher(error_matches, error_exceptions, line, *timings[:2]):
+ event = BuildError(line.strip(), offset + i + 1)
+ errors.append(event)
+ elif matcher(warning_matches, warning_exceptions, line, *timings[2:]):
+ event = BuildWarning(line.strip(), offset + i + 1)
+ warnings.append(event)
+ else:
+ continue
+
+ # get file/line number for each event, if possible
+ for flm in file_line_matches:
+ match = flm.search(line)
+ if match:
+ event.source_file, event.source_line_no = match.groups()
+
+ return errors, warnings, timings
+
+
+def _parse_unpack(args):
+ return _parse(*args)
- self.error_matches = compile(error_matches)
- self.error_exceptions = compile(error_exceptions)
- self.warning_matches = compile(warning_matches)
- self.warning_exceptions = compile(warning_exceptions)
- self.file_line_matches = compile(file_line_matches)
- def parse(self, stream, context=6):
+class CTestLogParser(object):
+ """Log file parser that extracts errors and warnings."""
+ def __init__(self, profile=False):
+ # whether to record timing information
+ self.timings = []
+ self.profile = profile
+
+ def print_timings(self):
+ """Print out profile of time spent in different regular expressions."""
+ def stringify(elt):
+ return elt if isinstance(elt, str) else elt.pattern
+
+ index = 0
+ for name, arr in [('error_matches', _error_matches),
+ ('error_exceptions', _error_exceptions),
+ ('warning_matches', _warning_matches),
+ ('warning_exceptions', _warning_exceptions)]:
+
+ print()
+ print(name)
+ for i, elt in enumerate(arr):
+ print("%16.2f %s" % (
+ self.timings[index][i] * 1e6, stringify(elt)))
+ index += 1
+
+
+ def parse(self, stream, context=6, jobs=None):
"""Parse a log file by searching each line for errors and warnings.
Args:
@@ -276,35 +419,50 @@ class CTestLogParser(object):
context (int): lines of context to extract around each log event
Returns:
- (tuple): two lists containig ``BuildError`` and
+ (tuple): two lists containing ``BuildError`` and
``BuildWarning`` objects.
"""
if isinstance(stream, string_types):
with open(stream) as f:
- return self.parse(f)
+ return self.parse(f, context, jobs)
lines = [line for line in stream]
- errors = []
- warnings = []
- for i, line in enumerate(lines):
- # use CTest's regular expressions to scrape the log for events
- if _match(self.error_matches, self.error_exceptions, line):
- event = BuildError(line.strip(), i + 1)
- errors.append(event)
- elif _match(self.warning_matches, self.warning_exceptions, line):
- event = BuildWarning(line.strip(), i + 1)
- warnings.append(event)
- else:
- continue
-
- # get file/line number for each event, if possible
- for flm in self.file_line_matches:
- match = flm.search(line)
- if match:
- event.source_file, source_line_no = match.groups()
-
- # add log context, as well
+ if jobs is None:
+ jobs = multiprocessing.cpu_count()
+
+ # single-thread small logs
+ if len(lines) < 10 * jobs:
+ errors, warnings, self.timings = _parse(lines, 0, self.profile)
+
+ else:
+ # Build arguments for parallel jobs
+ args = []
+ offset = 0
+ for chunk in chunks(lines, jobs):
+ args.append((chunk, offset, self.profile))
+ offset += len(chunk)
+
+ # create a pool and farm out the matching job
+ pool = multiprocessing.Pool(jobs)
+ try:
+ # this is a workaround for a Python bug in Pool with ctrl-C
+ results = pool.map_async(_parse_unpack, args, 1).get(9999999)
+ errors, warnings, timings = zip(*results)
+ finally:
+ pool.terminate()
+
+ # merge results
+ errors = sum(errors, [])
+ warnings = sum(warnings, [])
+
+ if self.profile:
+ self.timings = [
+ [sum(i) for i in zip(*t)] for t in zip(*timings)]
+
+ # add log context to all events
+ for event in (errors + warnings):
+ i = event.line_no - 1
event.pre_context = [
l.rstrip() for l in lines[i - context:i]]
event.post_context = [
diff --git a/lib/spack/external/distro.py b/lib/spack/external/distro.py
index c4905c25a5..b63451640a 100644
--- a/lib/spack/external/distro.py
+++ b/lib/spack/external/distro.py
@@ -41,7 +41,7 @@ import subprocess
if not sys.platform.startswith('linux'):
raise ImportError('Unsupported platform: {0}'.format(sys.platform))
-_UNIXCONFDIR = '/etc'
+_UNIXCONFDIR = os.environ.get('UNIXCONFDIR', '/etc')
_OS_RELEASE_BASENAME = 'os-release'
#: Translation table for normalizing the "ID" attribute defined in os-release
@@ -983,28 +983,41 @@ class LinuxDistribution(object):
distro_info['id'] = match.group(1)
return distro_info
else:
- basenames = os.listdir(_UNIXCONFDIR)
- # We sort for repeatability in cases where there are multiple
- # distro specific files; e.g. CentOS, Oracle, Enterprise all
- # containing `redhat-release` on top of their own.
- basenames.sort()
+ try:
+ basenames = os.listdir(_UNIXCONFDIR)
+ # We sort for repeatability in cases where there are multiple
+ # distro specific files; e.g. CentOS, Oracle, Enterprise all
+ # containing `redhat-release` on top of their own.
+ basenames.sort()
+ except OSError:
+ # This may occur when /etc is not readable but we can't be
+ # sure about the *-release files. Check common entries of
+ # /etc for information. If they turn out to not be there the
+ # error is handled in `_parse_distro_release_file()`.
+ basenames = ['SuSE-release',
+ 'arch-release',
+ 'base-release',
+ 'centos-release',
+ 'fedora-release',
+ 'gentoo-release',
+ 'mageia-release',
+ 'manjaro-release',
+ 'oracle-release',
+ 'redhat-release',
+ 'sl-release',
+ 'slackware-version']
for basename in basenames:
if basename in _DISTRO_RELEASE_IGNORE_BASENAMES:
continue
match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
if match:
- try:
- filepath = os.path.join(_UNIXCONFDIR, basename)
- distro_info = self._parse_distro_release_file(filepath)
- if 'name' in distro_info:
- # The name is always present if the pattern matches
- self.distro_release_file = filepath
- distro_info['id'] = match.group(1)
- return distro_info
- except IOError:
- # We found a file we do not have permission to read
- # Continue checking candidate files for distro file.
- continue
+ filepath = os.path.join(_UNIXCONFDIR, basename)
+ distro_info = self._parse_distro_release_file(filepath)
+ if 'name' in distro_info:
+ # The name is always present if the pattern matches
+ self.distro_release_file = filepath
+ distro_info['id'] = match.group(1)
+ return distro_info
return {}
def _parse_distro_release_file(self, filepath):
@@ -1018,12 +1031,16 @@ class LinuxDistribution(object):
Returns:
A dictionary containing all information items.
"""
- if os.path.isfile(filepath):
+ try:
with open(filepath) as fp:
# Only parse the first line. For instance, on SLES there
# are multiple lines. We don't want them...
return self._parse_distro_release_content(fp.readline())
- return {}
+ except (OSError, IOError):
+ # Ignore not being able to read a specific, seemingly version
+ # related file.
+ # See https://github.com/nir0s/distro/issues/162
+ return {}
@staticmethod
def _parse_distro_release_content(line):
@@ -1075,11 +1092,9 @@ def main():
else:
logger.info('Name: %s', name(pretty=True))
distribution_version = version(pretty=True)
- if distribution_version:
- logger.info('Version: %s', distribution_version)
+ logger.info('Version: %s', distribution_version)
distribution_codename = codename()
- if distribution_codename:
- logger.info('Codename: %s', distribution_codename)
+ logger.info('Codename: %s', distribution_codename)
if __name__ == '__main__':
diff --git a/lib/spack/external/jinja2/AUTHORS b/lib/spack/external/jinja2/AUTHORS
deleted file mode 100644
index 943f625f87..0000000000
--- a/lib/spack/external/jinja2/AUTHORS
+++ /dev/null
@@ -1,33 +0,0 @@
-Jinja is written and maintained by the Jinja Team and various
-contributors:
-
-Lead Developer:
-
-- Armin Ronacher <armin.ronacher@active-4.com>
-
-Developers:
-
-- Christoph Hack
-- Georg Brandl
-
-Contributors:
-
-- Bryan McLemore
-- Mickaël Guérin <kael@crocobox.org>
-- Cameron Knight
-- Lawrence Journal-World.
-- David Cramer
-
-Patches and suggestions:
-
-- Ronny Pfannschmidt
-- Axel Böhm
-- Alexey Melchakov
-- Bryan McLemore
-- Clovis Fabricio (nosklo)
-- Cameron Knight
-- Peter van Dijk (Habbie)
-- Stefan Ebner
-- Rene Leonhardt
-- Thomas Waldmann
-- Cory Benfield (Lukasa)
diff --git a/lib/spack/external/jinja2/LICENSE b/lib/spack/external/jinja2/LICENSE
deleted file mode 100644
index 10145a2643..0000000000
--- a/lib/spack/external/jinja2/LICENSE
+++ /dev/null
@@ -1,31 +0,0 @@
-Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.
-
-Some rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
-
- * The names of the contributors may not be used to endorse or
- promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/spack/external/jinja2/README.rst b/lib/spack/external/jinja2/README.rst
deleted file mode 100644
index c36b9426d6..0000000000
--- a/lib/spack/external/jinja2/README.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-Jinja2
-~~~~~~
-
-Jinja2 is a template engine written in pure Python. It provides a
-`Django`_ inspired non-XML syntax but supports inline expressions and
-an optional `sandboxed`_ environment.
-
-Nutshell
---------
-
-Here a small example of a Jinja template:
-
-.. code-block:: jinja
-
- {% extends 'base.html' %}
- {% block title %}Memberlist{% endblock %}
- {% block content %}
- <ul>
- {% for user in users %}
- <li><a href="{{ user.url }}">{{ user.username }}</a></li>
- {% endfor %}
- </ul>
- {% endblock %}
-
-Philosophy
-----------
-
-Application logic is for the controller, but don't make the template designer's
-life difficult by restricting functionality too much.
-
-For more information visit the new `Jinja2 webpage`_ and `documentation`_.
-
-The `Jinja2 tip`_ is installable via ``pip`` with ``pip install
-https://github.com/pallets/jinja/zipball/master``.
-
-.. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security)
-.. _Django: http://www.djangoproject.com/
-.. _Jinja2 webpage: http://jinja.pocoo.org/
-.. _documentation: http://jinja.pocoo.org/docs/
-.. _Jinja2 tip: http://jinja.pocoo.org/docs/intro/#as-a-python-egg-via-easy-install
-
-Builds
-------
-
-+---------------------+------------------------------------------------------------------------------+
-| ``master`` | .. image:: https://travis-ci.org/pallets/jinja.svg?branch=master |
-| | :target: https://travis-ci.org/pallets/jinja |
-+---------------------+------------------------------------------------------------------------------+
-| ``2.9-maintenance`` | .. image:: https://travis-ci.org/pallets/jinja.svg?branch=2.9-maintenance |
-| | :target: https://travis-ci.org/pallets/jinja |
-+---------------------+------------------------------------------------------------------------------+
diff --git a/lib/spack/external/jinja2/__init__.py b/lib/spack/external/jinja2/__init__.py
index 4b0b7a8d7f..42aa763d57 100644
--- a/lib/spack/external/jinja2/__init__.py
+++ b/lib/spack/external/jinja2/__init__.py
@@ -27,7 +27,7 @@
:license: BSD, see LICENSE for more details.
"""
__docformat__ = 'restructuredtext en'
-__version__ = '2.9.6'
+__version__ = '2.10'
# high level interface
from jinja2.environment import Environment, Template
@@ -48,7 +48,7 @@ from jinja2.runtime import Undefined, DebugUndefined, StrictUndefined, \
# exceptions
from jinja2.exceptions import TemplateError, UndefinedError, \
TemplateNotFound, TemplatesNotFound, TemplateSyntaxError, \
- TemplateAssertionError
+ TemplateAssertionError, TemplateRuntimeError
# decorators and public utilities
from jinja2.filters import environmentfilter, contextfilter, \
@@ -64,6 +64,7 @@ __all__ = [
'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
'TemplatesNotFound', 'TemplateSyntaxError', 'TemplateAssertionError',
+ 'TemplateRuntimeError',
'ModuleLoader', 'environmentfilter', 'contextfilter', 'Markup', 'escape',
'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined',
'evalcontextfilter', 'evalcontextfunction', 'make_logging_undefined',
diff --git a/lib/spack/external/jinja2/_identifier.py b/lib/spack/external/jinja2/_identifier.py
new file mode 100644
index 0000000000..2eac35d5c3
--- /dev/null
+++ b/lib/spack/external/jinja2/_identifier.py
@@ -0,0 +1,2 @@
+# generated by scripts/generate_identifier_pattern.py
+pattern = '·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯'
diff --git a/lib/spack/external/jinja2/_stringdefs.py b/lib/spack/external/jinja2/_stringdefs.py
deleted file mode 100644
index a5689f6695..0000000000
--- a/lib/spack/external/jinja2/_stringdefs.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- jinja2._stringdefs
- ~~~~~~~~~~~~~~~~~~
-
- Strings of all Unicode characters of a certain category.
- Used for matching in Unicode-aware languages. Run to regenerate.
-
- Inspired by chartypes_create.py from the MoinMoin project, original
- implementation from Pygments.
-
- :copyright: Copyright 2006-2017 by the Jinja team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-# Generated code start
-
-xid_start = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz\xaa\xb5\xba\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\u0100\u0101\u0102\u0103\u0104\u0105\u0106\u0107\u0108\u0109\u010a\u010b\u010c\u010d\u010e\u010f\u0110\u0111\u0112\u0113\u0114\u0115\u0116\u0117\u0118\u0119\u011a\u011b\u011c\u011d\u011e\u011f\u0120\u0121\u0122\u0123\u0124\u0125\u0126\u0127\u0128\u0129\u012a\u012b\u012c\u012d\u012e\u012f\u0130\u0131\u0134\u0135\u0136\u0137\u0138\u0139\u013a\u013b\u013c\u013d\u013e\u0141\u0142\u0143\u0144\u0145\u0146\u0147\u0148\u014a\u014b\u014c\u014d\u014e\u014f\u0150\u0151\u0152\u0153\u0154\u0155\u0156\u0157\u0158\u0159\u015a\u015b\u015c\u015d\u015e\u015f\u0160\u0161\u0162\u0163\u0164\u0165\u0166\u0167\u0168\u0169\u016a\u016b\u016c\u016d\u016e\u016f\u0170\u0171\u0172\u0173\u0174\u0175\u0176\u0177\u0178\u0179\u017a\u017b\u017c\u017d\u017e\u017f\u0180\u0181\u0182\u0183\u0184\u0185\u0186\u0187\u0188\u0189\u018a\u018b\u018c\u018d\u018e\u018f\u0190\u0191\u0192\u0193\u0194\u0195\u0196\u0197\u0198\u0199\u019a\u019b\u019c\u019d\u019e\u019f\u01a0\u01a1\u01a2\u01a3\u01a4\u01a5\u01a6\u01a7\u01a8\u01a9\u01aa\u01ab\u01ac\u01ad\u01ae\u01af\u01b0\u01b1\u01b2\u01b3\u01b4\u01b5\u01b6\u01b7\u01b8\u01b9\u01ba\u01bb\u01bc\u01bd\u01be\u01bf\u01c0\u01c1\u01c2\u01c3\u01cd\u01ce\u01cf\u01d0\u01d1\u01d2\u01d3\u01d4\u01d5\u01d6\u01d7\u01d8\u01d9\u01da\u01db\u01dc\u01dd\u01de\u01df\u01e0\u01e1\u01e2\u01e3\u01e4\u01e5\u01e6\u01e7\u01e8\u01e9\u01ea\u01eb\u01ec\u01ed\u01ee\u01ef\u01f0\u01f4\u01f5\u01f6\u01f7\u01f8\u01f9\u01fa\u01fb\u01fc\u01fd\u01fe\u01ff\u0200\u0201\u0202\u0203\u0204\u0205\u0206\u0207\u0208\u0209\u020a\u020b\u020c\u020d\u020e\u020f\u0210\u0211\u0212\u0213\u0214\u0215\u0216\u0217\u0218\u0219\u021a\u021b\u021c\u021d\u021e\u021f\u0220\u0221\u0222\u0223\u0224\u0225\u0226\u0227\u0228\u0229\u022a\u022b\u022c\u022d\u022e\u022f\u0230\u0231\u0232\u0233\u0234\u0235\u0236\u0237\u0238\u0239\u023a\u023b\u023c\u023d\u023e\u023f\u0240\u0241\u0242\u0243\u0244\u0245\u0246\u0247\u0248\u0249\u024a\u024b\u024c\u024d\u024e\u024f\u0250\u0251\u0252\u0253\u0254\u0255\u0256\u0257\u0258\u0259\u025a\u025b\u025c\u025d\u025e\u025f\u0260\u0261\u0262\u0263\u0264\u0265\u0266\u0267\u0268\u0269\u026a\u026b\u026c\u026d\u026e\u026f\u0270\u0271\u0272\u0273\u0274\u0275\u0276\u0277\u0278\u0279\u027a\u027b\u027c\u027d\u027e\u027f\u0280\u0281\u0282\u0283\u0284\u0285\u0286\u0287\u0288\u0289\u028a\u028b\u028c\u028d\u028e\u028f\u0290\u0291\u0292\u0293\u0294\u0295\u0296\u0297\u0298\u0299\u029a\u029b\u029c\u029d\u029e\u029f\u02a0\u02a1\u02a2\u02a3\u02a4\u02a5\u02a6\u02a7\u02a8\u02a9\u02aa\u02ab\u02ac\u02ad\u02ae\u02af\u02b0\u02b1\u02b2\u02b3\u02b4\u02b5\u02b6\u02b7\u02b8\u02b9\u02ba\u02bb\u02bc\u02bd\u02be\u02bf\u02c0\u02c1\u02c6\u02c7\u02c8\u02c9\u02ca\u02cb\u02cc\u02cd\u02ce\u02cf\u02d0\u02d1\u02e0\u02e1\u02e2\u02e3\u02e4\u02ec\u02ee\u0370\u0371\u0372\u0373\u0374\u0376\u0377\u037b\u037c\u037d\u037f\u0386\u0388\u0389\u038a\u038c\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\u03cf\u03d0\u03d1\u03d2\u03d3\u03d4\u03d5\u03d6\u03d7\u03d8\u03d9\u03da\u03db\u03dc\u03dd\u03de\u03df\u03e0\u03e1\u03e2\u03e3\u03e4\u03e5\u03e6\u03e7\u03e8\u03e9\u03ea\u03eb\u03ec\u03ed\u03ee\u03ef\u03f0\u03f1\u03f2\u03f3\u03f4\u03f5\u03f7\u03f8\u03f9\u03fa\u03fb\u03fc\u03fd\u03fe\u03ff\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u040d\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0450\u0451\u0452\u0453\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u045d\u045e\u045f\u0460\u0461\u0462\u0463\u0464\u0465\u0466\u0467\u0468\u0469\u046a\u046b\u046c\u046d\u046e\u046f\u0470\u0471\u0472\u0473\u0474\u0475\u0476\u0477\u0478\u0479\u047a\u047b\u047c\u047d\u047e\u047f\u0480\u0481\u048a\u048b\u048c\u048d\u048e\u048f\u0490\u0491\u0492\u0493\u0494\u0495\u0496\u0497\u0498\u0499\u049a\u049b\u049c\u049d\u049e\u049f\u04a0\u04a1\u04a2\u04a3\u04a4\u04a5\u04a6\u04a7\u04a8\u04a9\u04aa\u04ab\u04ac\u04ad\u04ae\u04af\u04b0\u04b1\u04b2\u04b3\u04b4\u04b5\u04b6\u04b7\u04b8\u04b9\u04ba\u04bb\u04bc\u04bd\u04be\u04bf\u04c0\u04c1\u04c2\u04c3\u04c4\u04c5\u04c6\u04c7\u04c8\u04c9\u04ca\u04cb\u04cc\u04cd\u04ce\u04cf\u04d0\u04d1\u04d2\u04d3\u04d4\u04d5\u04d6\u04d7\u04d8\u04d9\u04da\u04db\u04dc\u04dd\u04de\u04df\u04e0\u04e1\u04e2\u04e3\u04e4\u04e5\u04e6\u04e7\u04e8\u04e9\u04ea\u04eb\u04ec\u04ed\u04ee\u04ef\u04f0\u04f1\u04f2\u04f3\u04f4\u04f5\u04f6\u04f7\u04f8\u04f9\u04fa\u04fb\u04fc\u04fd\u04fe\u04ff\u0500\u0501\u0502\u0503\u0504\u0505\u0506\u0507\u0508\u0509\u050a\u050b\u050c\u050d\u050e\u050f\u0510\u0511\u0512\u0513\u0514\u0515\u0516\u0517\u0518\u0519\u051a\u051b\u051c\u051d\u051e\u051f\u0520\u0521\u0522\u0523\u0524\u0525\u0526\u0527\u0528\u0529\u052a\u052b\u052c\u052d\u052e\u052f\u0531\u0532\u0533\u0534\u0535\u0536\u0537\u0538\u0539\u053a\u053b\u053c\u053d\u053e\u053f\u0540\u0541\u0542\u0543\u0544\u0545\u0546\u0547\u0548\u0549\u054a\u054b\u054c\u054d\u054e\u054f\u0550\u0551\u0552\u0553\u0554\u0555\u0556\u0559\u0561\u0562\u0563\u0564\u0565\u0566\u0567\u0568\u0569\u056a\u056b\u056c\u056d\u056e\u056f\u0570\u0571\u0572\u0573\u0574\u0575\u0576\u0577\u0578\u0579\u057a\u057b\u057c\u057d\u057e\u057f\u0580\u0581\u0582\u0583\u0584\u0585\u0586\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u05f0\u05f1\u05f2\u0620\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\u063b\u063c\u063d\u063e\u063f\u0640\u0641\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u066e\u066f\u0671\u0672\u0673\u0674\u0679\u067a\u067b\u067c\u067d\u067e\u067f\u0680\u0681\u0682\u0683\u0684\u0685\u0686\u0687\u0688\u0689\u068a\u068b\u068c\u068d\u068e\u068f\u0690\u0691\u0692\u0693\u0694\u0695\u0696\u0697\u0698\u0699\u069a\u069b\u069c\u069d\u069e\u069f\u06a0\u06a1\u06a2\u06a3\u06a4\u06a5\u06a6\u06a7\u06a8\u06a9\u06aa\u06ab\u06ac\u06ad\u06ae\u06af\u06b0\u06b1\u06b2\u06b3\u06b4\u06b5\u06b6\u06b7\u06b8\u06b9\u06ba\u06bb\u06bc\u06bd\u06be\u06bf\u06c0\u06c1\u06c2\u06c3\u06c4\u06c5\u06c6\u06c7\u06c8\u06c9\u06ca\u06cb\u06cc\u06cd\u06ce\u06cf\u06d0\u06d1\u06d2\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa\u06fb\u06fc\u06ff\u0710\u0712\u0713\u0714\u0715\u0716\u0717\u0718\u0719\u071a\u071b\u071c\u071d\u071e\u071f\u0720\u0721\u0722\u0723\u0724\u0725\u0726\u0727\u0728\u0729\u072a\u072b\u072c\u072d\u072e\u072f\u074d\u074e\u074f\u0750\u0751\u0752\u0753\u0754\u0755\u0756\u0757\u0758\u0759\u075a\u075b\u075c\u075d\u075e\u075f\u0760\u0761\u0762\u0763\u0764\u0765\u0766\u0767\u0768\u0769\u076a\u076b\u076c\u076d\u076e\u076f\u0770\u0771\u0772\u0773\u0774\u0775\u0776\u0777\u0778\u0779\u077a\u077b\u077c\u077d\u077e\u077f\u0780\u0781\u0782\u0783\u0784\u0785\u0786\u0787\u0788\u0789\u078a\u078b\u078c\u078d\u078e\u078f\u0790\u0791\u0792\u0793\u0794\u0795\u0796\u0797\u0798\u0799\u079a\u079b\u079c\u079d\u079e\u079f\u07a0\u07a1\u07a2\u07a3\u07a4\u07a5\u07b1\u07ca\u07cb\u07cc\u07cd\u07ce\u07cf\u07d0\u07d1\u07d2\u07d3\u07d4\u07d5\u07d6\u07d7\u07d8\u07d9\u07da\u07db\u07dc\u07dd\u07de\u07df\u07e0\u07e1\u07e2\u07e3\u07e4\u07e5\u07e6\u07e7\u07e8\u07e9\u07ea\u07f4\u07f5\u07fa\u0800\u0801\u0802\u0803\u0804\u0805\u0806\u0807\u0808\u0809\u080a\u080b\u080c\u080d\u080e\u080f\u0810\u0811\u0812\u0813\u0814\u0815\u081a\u0824\u0828\u0840\u0841\u0842\u0843\u0844\u0845\u0846\u0847\u0848\u0849\u084a\u084b\u084c\u084d\u084e\u084f\u0850\u0851\u0852\u0853\u0854\u0855\u0856\u0857\u0858\u08a0\u08a1\u08a2\u08a3\u08a4\u08a5\u08a6\u08a7\u08a8\u08a9\u08aa\u08ab\u08ac\u08ad\u08ae\u08af\u08b0\u08b1\u08b2\u08b3\u08b4\u08b6\u08b7\u08b8\u08b9\u08ba\u08bb\u08bc\u08bd\u0904\u0905\u0906\u0907\u0908\u0909\u090a\u090b\u090c\u090d\u090e\u090f\u0910\u0911\u0912\u0913\u0914\u0915\u0916\u0917\u0918\u0919\u091a\u091b\u091c\u091d\u091e\u091f\u0920\u0921\u0922\u0923\u0924\u0925\u0926\u0927\u0928\u0929\u092a\u092b\u092c\u092d\u092e\u092f\u0930\u0931\u0932\u0933\u0934\u0935\u0936\u0937\u0938\u0939\u093d\u0950\u0960\u0961\u0971\u0972\u0973\u0974\u0975\u0976\u0977\u0978\u0979\u097a\u097b\u097c\u097d\u097e\u097f\u0980\u0985\u0986\u0987\u0988\u0989\u098a\u098b\u098c\u098f\u0990\u0993\u0994\u0995\u0996\u0997\u0998\u0999\u099a\u099b\u099c\u099d\u099e\u099f\u09a0\u09a1\u09a2\u09a3\u09a4\u09a5\u09a6\u09a7\u09a8\u09aa\u09ab\u09ac\u09ad\u09ae\u09af\u09b0\u09b2\u09b6\u09b7\u09b8\u09b9\u09bd\u09ce\u09e0\u09e1\u09f0\u09f1\u0a05\u0a06\u0a07\u0a08\u0a09\u0a0a\u0a0f\u0a10\u0a13\u0a14\u0a15\u0a16\u0a17\u0a18\u0a19\u0a1a\u0a1b\u0a1c\u0a1d\u0a1e\u0a1f\u0a20\u0a21\u0a22\u0a23\u0a24\u0a25\u0a26\u0a27\u0a28\u0a2a\u0a2b\u0a2c\u0a2d\u0a2e\u0a2f\u0a30\u0a32\u0a35\u0a38\u0a39\u0a5c\u0a72\u0a73\u0a74\u0a85\u0a86\u0a87\u0a88\u0a89\u0a8a\u0a8b\u0a8c\u0a8d\u0a8f\u0a90\u0a91\u0a93\u0a94\u0a95\u0a96\u0a97\u0a98\u0a99\u0a9a\u0a9b\u0a9c\u0a9d\u0a9e\u0a9f\u0aa0\u0aa1\u0aa2\u0aa3\u0aa4\u0aa5\u0aa6\u0aa7\u0aa8\u0aaa\u0aab\u0aac\u0aad\u0aae\u0aaf\u0ab0\u0ab2\u0ab3\u0ab5\u0ab6\u0ab7\u0ab8\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05\u0b06\u0b07\u0b08\u0b09\u0b0a\u0b0b\u0b0c\u0b0f\u0b10\u0b13\u0b14\u0b15\u0b16\u0b17\u0b18\u0b19\u0b1a\u0b1b\u0b1c\u0b1d\u0b1e\u0b1f\u0b20\u0b21\u0b22\u0b23\u0b24\u0b25\u0b26\u0b27\u0b28\u0b2a\u0b2b\u0b2c\u0b2d\u0b2e\u0b2f\u0b30\u0b32\u0b33\u0b35\u0b36\u0b37\u0b38\u0b39\u0b3d\u0b5f\u0b60\u0b61\u0b71\u0b83\u0b85\u0b86\u0b87\u0b88\u0b89\u0b8a\u0b8e\u0b8f\u0b90\u0b92\u0b93\u0b94\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8\u0ba9\u0baa\u0bae\u0baf\u0bb0\u0bb1\u0bb2\u0bb3\u0bb4\u0bb5\u0bb6\u0bb7\u0bb8\u0bb9\u0bd0\u0c05\u0c06\u0c07\u0c08\u0c09\u0c0a\u0c0b\u0c0c\u0c0e\u0c0f\u0c10\u0c12\u0c13\u0c14\u0c15\u0c16\u0c17\u0c18\u0c19\u0c1a\u0c1b\u0c1c\u0c1d\u0c1e\u0c1f\u0c20\u0c21\u0c22\u0c23\u0c24\u0c25\u0c26\u0c27\u0c28\u0c2a\u0c2b\u0c2c\u0c2d\u0c2e\u0c2f\u0c30\u0c31\u0c32\u0c33\u0c34\u0c35\u0c36\u0c37\u0c38\u0c39\u0c3d\u0c58\u0c59\u0c5a\u0c60\u0c61\u0c80\u0c85\u0c86\u0c87\u0c88\u0c89\u0c8a\u0c8b\u0c8c\u0c8e\u0c8f\u0c90\u0c92\u0c93\u0c94\u0c95\u0c96\u0c97\u0c98\u0c99\u0c9a\u0c9b\u0c9c\u0c9d\u0c9e\u0c9f\u0ca0\u0ca1\u0ca2\u0ca3\u0ca4\u0ca5\u0ca6\u0ca7\u0ca8\u0caa\u0cab\u0cac\u0cad\u0cae\u0caf\u0cb0\u0cb1\u0cb2\u0cb3\u0cb5\u0cb6\u0cb7\u0cb8\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05\u0d06\u0d07\u0d08\u0d09\u0d0a\u0d0b\u0d0c\u0d0e\u0d0f\u0d10\u0d12\u0d13\u0d14\u0d15\u0d16\u0d17\u0d18\u0d19\u0d1a\u0d1b\u0d1c\u0d1d\u0d1e\u0d1f\u0d20\u0d21\u0d22\u0d23\u0d24\u0d25\u0d26\u0d27\u0d28\u0d29\u0d2a\u0d2b\u0d2c\u0d2d\u0d2e\u0d2f\u0d30\u0d31\u0d32\u0d33\u0d34\u0d35\u0d36\u0d37\u0d38\u0d39\u0d3a\u0d3d\u0d4e\u0d54\u0d55\u0d56\u0d5f\u0d60\u0d61\u0d7a\u0d7b\u0d7c\u0d7d\u0d7e\u0d7f\u0d85\u0d86\u0d87\u0d88\u0d89\u0d8a\u0d8b\u0d8c\u0d8d\u0d8e\u0d8f\u0d90\u0d91\u0d92\u0d93\u0d94\u0d95\u0d96\u0d9a\u0d9b\u0d9c\u0d9d\u0d9e\u0d9f\u0da0\u0da1\u0da2\u0da3\u0da4\u0da5\u0da6\u0da7\u0da8\u0da9\u0daa\u0dab\u0dac\u0dad\u0dae\u0daf\u0db0\u0db1\u0db3\u0db4\u0db5\u0db6\u0db7\u0db8\u0db9\u0dba\u0dbb\u0dbd\u0dc0\u0dc1\u0dc2\u0dc3\u0dc4\u0dc5\u0dc6\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e32\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94\u0e95\u0e96\u0e97\u0e99\u0e9a\u0e9b\u0e9c\u0e9d\u0e9e\u0e9f\u0ea1\u0ea2\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead\u0eae\u0eaf\u0eb0\u0eb2\u0ebd\u0ec0\u0ec1\u0ec2\u0ec3\u0ec4\u0ec6\u0ede\u0edf\u0f00\u0f40\u0f41\u0f42\u0f44\u0f45\u0f46\u0f47\u0f49\u0f4a\u0f4b\u0f4c\u0f4e\u0f4f\u0f50\u0f51\u0f53\u0f54\u0f55\u0f56\u0f58\u0f59\u0f5a\u0f5b\u0f5d\u0f5e\u0f5f\u0f60\u0f61\u0f62\u0f63\u0f64\u0f65\u0f66\u0f67\u0f68\u0f6a\u0f6b\u0f6c\u0f88\u0f89\u0f8a\u0f8b\u0f8c\u1000\u1001\u1002\u1003\u1004\u1005\u1006\u1007\u1008\u1009\u100a\u100b\u100c\u100d\u100e\u100f\u1010\u1011\u1012\u1013\u1014\u1015\u1016\u1017\u1018\u1019\u101a\u101b\u101c\u101d\u101e\u101f\u1020\u1021\u1022\u1023\u1024\u1025\u1026\u1027\u1028\u1029\u102a\u103f\u1050\u1051\u1052\u1053\u1054\u1055\u105a\u105b\u105c\u105d\u1061\u1065\u1066\u106e\u106f\u1070\u1075\u1076\u1077\u1078\u1079\u107a\u107b\u107c\u107d\u107e\u107f\u1080\u1081\u108e\u10a0\u10a1\u10a2\u10a3\u10a4\u10a5\u10a6\u10a7\u10a8\u10a9\u10aa\u10ab\u10ac\u10ad\u10ae\u10af\u10b0\u10b1\u10b2\u10b3\u10b4\u10b5\u10b6\u10b7\u10b8\u10b9\u10ba\u10bb\u10bc\u10bd\u10be\u10bf\u10c0\u10c1\u10c2\u10c3\u10c4\u10c5\u10c7\u10cd\u10d0\u10d1\u10d2\u10d3\u10d4\u10d5\u10d6\u10d7\u10d8\u10d9\u10da\u10db\u10dc\u10dd\u10de\u10df\u10e0\u10e1\u10e2\u10e3\u10e4\u10e5\u10e6\u10e7\u10e8\u10e9\u10ea\u10eb\u10ec\u10ed\u10ee\u10ef\u10f0\u10f1\u10f2\u10f3\u10f4\u10f5\u10f6\u10f7\u10f8\u10f9\u10fa\u10fc\u10fd\u10fe\u10ff\u1100\u1101\u1102\u1103\u1104\u1105\u1106\u1107\u1108\u1109\u110a\u110b\u110c\u110d\u110e\u110f\u1110\u1111\u1112\u1113\u1114\u1115\u1116\u1117\u1118\u1119\u111a\u111b\u111c\u111d\u111e\u111f\u1120\u1121\u1122\u1123\u1124\u1125\u1126\u1127\u1128\u1129\u112a\u112b\u112c\u112d\u112e\u112f\u1130\u1131\u1132\u1133\u1134\u1135\u1136\u1137\u1138\u1139\u113a\u113b\u113c\u113d\u113e\u113f\u1140\u1141\u1142\u1143\u1144\u1145\u1146\u1147\u1148\u1149\u114a\u114b\u114c\u114d\u114e\u114f\u1150\u1151\u1152\u1153\u1154\u1155\u1156\u1157\u1158\u1159\u115a\u115b\u115c\u115d\u115e\u115f\u1160\u1161\u1162\u1163\u1164\u1165\u1166\u1167\u1168\u1169\u116a\u116b\u116c\u116d\u116e\u116f\u1170\u1171\u1172\u1173\u1174\u1175\u1176\u1177\u1178\u1179\u117a\u117b\u117c\u117d\u117e\u117f\u1180\u1181\u1182\u1183\u1184\u1185\u1186\u1187\u1188\u1189\u118a\u118b\u118c\u118d\u118e\u118f\u1190\u1191\u1192\u1193\u1194\u1195\u1196\u1197\u1198\u1199\u119a\u119b\u119c\u119d\u119e\u119f\u11a0\u11a1\u11a2\u11a3\u11a4\u11a5\u11a6\u11a7\u11a8\u11a9\u11aa\u11ab\u11ac\u11ad\u11ae\u11af\u11b0\u11b1\u11b2\u11b3\u11b4\u11b5\u11b6\u11b7\u11b8\u11b9\u11ba\u11bb\u11bc\u11bd\u11be\u11bf\u11c0\u11c1\u11c2\u11c3\u11c4\u11c5\u11c6\u11c7\u11c8\u11c9\u11ca\u11cb\u11cc\u11cd\u11ce\u11cf\u11d0\u11d1\u11d2\u11d3\u11d4\u11d5\u11d6\u11d7\u11d8\u11d9\u11da\u11db\u11dc\u11dd\u11de\u11df\u11e0\u11e1\u11e2\u11e3\u11e4\u11e5\u11e6\u11e7\u11e8\u11e9\u11ea\u11eb\u11ec\u11ed\u11ee\u11ef\u11f0\u11f1\u11f2\u11f3\u11f4\u11f5\u11f6\u11f7\u11f8\u11f9\u11fa\u11fb\u11fc\u11fd\u11fe\u11ff\u1200\u1201\u1202\u1203\u1204\u1205\u1206\u1207\u1208\u1209\u120a\u120b\u120c\u120d\u120e\u120f\u1210\u1211\u1212\u1213\u1214\u1215\u1216\u1217\u1218\u1219\u121a\u121b\u121c\u121d\u121e\u121f\u1220\u1221\u1222\u1223\u1224\u1225\u1226\u1227\u1228\u1229\u122a\u122b\u122c\u122d\u122e\u122f\u1230\u1231\u1232\u1233\u1234\u1235\u1236\u1237\u1238\u1239\u123a\u123b\u123c\u123d\u123e\u123f\u1240\u1241\u1242\u1243\u1244\u1245\u1246\u1247\u1248\u124a\u124b\u124c\u124d\u1250\u1251\u1252\u1253\u1254\u1255\u1256\u1258\u125a\u125b\u125c\u125d\u1260\u1261\u1262\u1263\u1264\u1265\u1266\u1267\u1268\u1269\u126a\u126b\u126c\u126d\u126e\u126f\u1270\u1271\u1272\u1273\u1274\u1275\u1276\u1277\u1278\u1279\u127a\u127b\u127c\u127d\u127e\u127f\u1280\u1281\u1282\u1283\u1284\u1285\u1286\u1287\u1288\u128a\u128b\u128c\u128d\u1290\u1291\u1292\u1293\u1294\u1295\u1296\u1297\u1298\u1299\u129a\u129b\u129c\u129d\u129e\u129f\u12a0\u12a1\u12a2\u12a3\u12a4\u12a5\u12a6\u12a7\u12a8\u12a9\u12aa\u12ab\u12ac\u12ad\u12ae\u12af\u12b0\u12b2\u12b3\u12b4\u12b5\u12b8\u12b9\u12ba\u12bb\u12bc\u12bd\u12be\u12c0\u12c2\u12c3\u12c4\u12c5\u12c8\u12c9\u12ca\u12cb\u12cc\u12cd\u12ce\u12cf\u12d0\u12d1\u12d2\u12d3\u12d4\u12d5\u12d6\u12d8\u12d9\u12da\u12db\u12dc\u12dd\u12de\u12df\u12e0\u12e1\u12e2\u12e3\u12e4\u12e5\u12e6\u12e7\u12e8\u12e9\u12ea\u12eb\u12ec\u12ed\u12ee\u12ef\u12f0\u12f1\u12f2\u12f3\u12f4\u12f5\u12f6\u12f7\u12f8\u12f9\u12fa\u12fb\u12fc\u12fd\u12fe\u12ff\u1300\u1301\u1302\u1303\u1304\u1305\u1306\u1307\u1308\u1309\u130a\u130b\u130c\u130d\u130e\u130f\u1310\u1312\u1313\u1314\u1315\u1318\u1319\u131a\u131b\u131c\u131d\u131e\u131f\u1320\u1321\u1322\u1323\u1324\u1325\u1326\u1327\u1328\u1329\u132a\u132b\u132c\u132d\u132e\u132f\u1330\u1331\u1332\u1333\u1334\u1335\u1336\u1337\u1338\u1339\u133a\u133b\u133c\u133d\u133e\u133f\u1340\u1341\u1342\u1343\u1344\u1345\u1346\u1347\u1348\u1349\u134a\u134b\u134c\u134d\u134e\u134f\u1350\u1351\u1352\u1353\u1354\u1355\u1356\u1357\u1358\u1359\u135a\u1380\u1381\u1382\u1383\u1384\u1385\u1386\u1387\u1388\u1389\u138a\u138b\u138c\u138d\u138e\u138f\u13a0\u13a1\u13a2\u13a3\u13a4\u13a5\u13a6\u13a7\u13a8\u13a9\u13aa\u13ab\u13ac\u13ad\u13ae\u13af\u13b0\u13b1\u13b2\u13b3\u13b4\u13b5\u13b6\u13b7\u13b8\u13b9\u13ba\u13bb\u13bc\u13bd\u13be\u13bf\u13c0\u13c1\u13c2\u13c3\u13c4\u13c5\u13c6\u13c7\u13c8\u13c9\u13ca\u13cb\u13cc\u13cd\u13ce\u13cf\u13d0\u13d1\u13d2\u13d3\u13d4\u13d5\u13d6\u13d7\u13d8\u13d9\u13da\u13db\u13dc\u13dd\u13de\u13df\u13e0\u13e1\u13e2\u13e3\u13e4\u13e5\u13e6\u13e7\u13e8\u13e9\u13ea\u13eb\u13ec\u13ed\u13ee\u13ef\u13f0\u13f1\u13f2\u13f3\u13f4\u13f5\u13f8\u13f9\u13fa\u13fb\u13fc\u13fd\u1401\u1402\u1403\u1404\u1405\u1406\u1407\u1408\u1409\u140a\u140b\u140c\u140d\u140e\u140f\u1410\u1411\u1412\u1413\u1414\u1415\u1416\u1417\u1418\u1419\u141a\u141b\u141c\u141d\u141e\u141f\u1420\u1421\u1422\u1423\u1424\u1425\u1426\u1427\u1428\u1429\u142a\u142b\u142c\u142d\u142e\u142f\u1430\u1431\u1432\u1433\u1434\u1435\u1436\u1437\u1438\u1439\u143a\u143b\u143c\u143d\u143e\u143f\u1440\u1441\u1442\u1443\u1444\u1445\u1446\u1447\u1448\u1449\u144a\u144b\u144c\u144d\u144e\u144f\u1450\u1451\u1452\u1453\u1454\u1455\u1456\u1457\u1458\u1459\u145a\u145b\u145c\u145d\u145e\u145f\u1460\u1461\u1462\u1463\u1464\u1465\u1466\u1467\u1468\u1469\u146a\u146b\u146c\u146d\u146e\u146f\u1470\u1471\u1472\u1473\u1474\u1475\u1476\u1477\u1478\u1479\u147a\u147b\u147c\u147d\u147e\u147f\u1480\u1481\u1482\u1483\u1484\u1485\u1486\u1487\u1488\u1489\u148a\u148b\u148c\u148d\u148e\u148f\u1490\u1491\u1492\u1493\u1494\u1495\u1496\u1497\u1498\u1499\u149a\u149b\u149c\u149d\u149e\u149f\u14a0\u14a1\u14a2\u14a3\u14a4\u14a5\u14a6\u14a7\u14a8\u14a9\u14aa\u14ab\u14ac\u14ad\u14ae\u14af\u14b0\u14b1\u14b2\u14b3\u14b4\u14b5\u14b6\u14b7\u14b8\u14b9\u14ba\u14bb\u14bc\u14bd\u14be\u14bf\u14c0\u14c1\u14c2\u14c3\u14c4\u14c5\u14c6\u14c7\u14c8\u14c9\u14ca\u14cb\u14cc\u14cd\u14ce\u14cf\u14d0\u14d1\u14d2\u14d3\u14d4\u14d5\u14d6\u14d7\u14d8\u14d9\u14da\u14db\u14dc\u14dd\u14de\u14df\u14e0\u14e1\u14e2\u14e3\u14e4\u14e5\u14e6\u14e7\u14e8\u14e9\u14ea\u14eb\u14ec\u14ed\u14ee\u14ef\u14f0\u14f1\u14f2\u14f3\u14f4\u14f5\u14f6\u14f7\u14f8\u14f9\u14fa\u14fb\u14fc\u14fd\u14fe\u14ff\u1500\u1501\u1502\u1503\u1504\u1505\u1506\u1507\u1508\u1509\u150a\u150b\u150c\u150d\u150e\u150f\u1510\u1511\u1512\u1513\u1514\u1515\u1516\u1517\u1518\u1519\u151a\u151b\u151c\u151d\u151e\u151f\u1520\u1521\u1522\u1523\u1524\u1525\u1526\u1527\u1528\u1529\u152a\u152b\u152c\u152d\u152e\u152f\u1530\u1531\u1532\u1533\u1534\u1535\u1536\u1537\u1538\u1539\u153a\u153b\u153c\u153d\u153e\u153f\u1540\u1541\u1542\u1543\u1544\u1545\u1546\u1547\u1548\u1549\u154a\u154b\u154c\u154d\u154e\u154f\u1550\u1551\u1552\u1553\u1554\u1555\u1556\u1557\u1558\u1559\u155a\u155b\u155c\u155d\u155e\u155f\u1560\u1561\u1562\u1563\u1564\u1565\u1566\u1567\u1568\u1569\u156a\u156b\u156c\u156d\u156e\u156f\u1570\u1571\u1572\u1573\u1574\u1575\u1576\u1577\u1578\u1579\u157a\u157b\u157c\u157d\u157e\u157f\u1580\u1581\u1582\u1583\u1584\u1585\u1586\u1587\u1588\u1589\u158a\u158b\u158c\u158d\u158e\u158f\u1590\u1591\u1592\u1593\u1594\u1595\u1596\u1597\u1598\u1599\u159a\u159b\u159c\u159d\u159e\u159f\u15a0\u15a1\u15a2\u15a3\u15a4\u15a5\u15a6\u15a7\u15a8\u15a9\u15aa\u15ab\u15ac\u15ad\u15ae\u15af\u15b0\u15b1\u15b2\u15b3\u15b4\u15b5\u15b6\u15b7\u15b8\u15b9\u15ba\u15bb\u15bc\u15bd\u15be\u15bf\u15c0\u15c1\u15c2\u15c3\u15c4\u15c5\u15c6\u15c7\u15c8\u15c9\u15ca\u15cb\u15cc\u15cd\u15ce\u15cf\u15d0\u15d1\u15d2\u15d3\u15d4\u15d5\u15d6\u15d7\u15d8\u15d9\u15da\u15db\u15dc\u15dd\u15de\u15df\u15e0\u15e1\u15e2\u15e3\u15e4\u15e5\u15e6\u15e7\u15e8\u15e9\u15ea\u15eb\u15ec\u15ed\u15ee\u15ef\u15f0\u15f1\u15f2\u15f3\u15f4\u15f5\u15f6\u15f7\u15f8\u15f9\u15fa\u15fb\u15fc\u15fd\u15fe\u15ff\u1600\u1601\u1602\u1603\u1604\u1605\u1606\u1607\u1608\u1609\u160a\u160b\u160c\u160d\u160e\u160f\u1610\u1611\u1612\u1613\u1614\u1615\u1616\u1617\u1618\u1619\u161a\u161b\u161c\u161d\u161e\u161f\u1620\u1621\u1622\u1623\u1624\u1625\u1626\u1627\u1628\u1629\u162a\u162b\u162c\u162d\u162e\u162f\u1630\u1631\u1632\u1633\u1634\u1635\u1636\u1637\u1638\u1639\u163a\u163b\u163c\u163d\u163e\u163f\u1640\u1641\u1642\u1643\u1644\u1645\u1646\u1647\u1648\u1649\u164a\u164b\u164c\u164d\u164e\u164f\u1650\u1651\u1652\u1653\u1654\u1655\u1656\u1657\u1658\u1659\u165a\u165b\u165c\u165d\u165e\u165f\u1660\u1661\u1662\u1663\u1664\u1665\u1666\u1667\u1668\u1669\u166a\u166b\u166c\u166f\u1670\u1671\u1672\u1673\u1674\u1675\u1676\u1677\u1678\u1679\u167a\u167b\u167c\u167d\u167e\u167f\u1681\u1682\u1683\u1684\u1685\u1686\u1687\u1688\u1689\u168a\u168b\u168c\u168d\u168e\u168f\u1690\u1691\u1692\u1693\u1694\u1695\u1696\u1697\u1698\u1699\u169a\u16a0\u16a1\u16a2\u16a3\u16a4\u16a5\u16a6\u16a7\u16a8\u16a9\u16aa\u16ab\u16ac\u16ad\u16ae\u16af\u16b0\u16b1\u16b2\u16b3\u16b4\u16b5\u16b6\u16b7\u16b8\u16b9\u16ba\u16bb\u16bc\u16bd\u16be\u16bf\u16c0\u16c1\u16c2\u16c3\u16c4\u16c5\u16c6\u16c7\u16c8\u16c9\u16ca\u16cb\u16cc\u16cd\u16ce\u16cf\u16d0\u16d1\u16d2\u16d3\u16d4\u16d5\u16d6\u16d7\u16d8\u16d9\u16da\u16db\u16dc\u16dd\u16de\u16df\u16e0\u16e1\u16e2\u16e3\u16e4\u16e5\u16e6\u16e7\u16e8\u16e9\u16ea\u16ee\u16ef\u16f0\u16f1\u16f2\u16f3\u16f4\u16f5\u16f6\u16f7\u16f8\u1700\u1701\u1702\u1703\u1704\u1705\u1706\u1707\u1708\u1709\u170a\u170b\u170c\u170e\u170f\u1710\u1711\u1720\u1721\u1722\u1723\u1724\u1725\u1726\u1727\u1728\u1729\u172a\u172b\u172c\u172d\u172e\u172f\u1730\u1731\u1740\u1741\u1742\u1743\u1744\u1745\u1746\u1747\u1748\u1749\u174a\u174b\u174c\u174d\u174e\u174f\u1750\u1751\u1760\u1761\u1762\u1763\u1764\u1765\u1766\u1767\u1768\u1769\u176a\u176b\u176c\u176e\u176f\u1770\u1780\u1781\u1782\u1783\u1784\u1785\u1786\u1787\u1788\u1789\u178a\u178b\u178c\u178d\u178e\u178f\u1790\u1791\u1792\u1793\u1794\u1795\u1796\u1797\u1798\u1799\u179a\u179b\u179c\u179d\u179e\u179f\u17a0\u17a1\u17a2\u17a3\u17a4\u17a5\u17a6\u17a7\u17a8\u17a9\u17aa\u17ab\u17ac\u17ad\u17ae\u17af\u17b0\u17b1\u17b2\u17b3\u17d7\u17dc\u1820\u1821\u1822\u1823\u1824\u1825\u1826\u1827\u1828\u1829\u182a\u182b\u182c\u182d\u182e\u182f\u1830\u1831\u1832\u1833\u1834\u1835\u1836\u1837\u1838\u1839\u183a\u183b\u183c\u183d\u183e\u183f\u1840\u1841\u1842\u1843\u1844\u1845\u1846\u1847\u1848\u1849\u184a\u184b\u184c\u184d\u184e\u184f\u1850\u1851\u1852\u1853\u1854\u1855\u1856\u1857\u1858\u1859\u185a\u185b\u185c\u185d\u185e\u185f\u1860\u1861\u1862\u1863\u1864\u1865\u1866\u1867\u1868\u1869\u186a\u186b\u186c\u186d\u186e\u186f\u1870\u1871\u1872\u1873\u1874\u1875\u1876\u1877\u1880\u1881\u1882\u1883\u1884\u1887\u1888\u1889\u188a\u188b\u188c\u188d\u188e\u188f\u1890\u1891\u1892\u1893\u1894\u1895\u1896\u1897\u1898\u1899\u189a\u189b\u189c\u189d\u189e\u189f\u18a0\u18a1\u18a2\u18a3\u18a4\u18a5\u18a6\u18a7\u18a8\u18aa\u18b0\u18b1\u18b2\u18b3\u18b4\u18b5\u18b6\u18b7\u18b8\u18b9\u18ba\u18bb\u18bc\u18bd\u18be\u18bf\u18c0\u18c1\u18c2\u18c3\u18c4\u18c5\u18c6\u18c7\u18c8\u18c9\u18ca\u18cb\u18cc\u18cd\u18ce\u18cf\u18d0\u18d1\u18d2\u18d3\u18d4\u18d5\u18d6\u18d7\u18d8\u18d9\u18da\u18db\u18dc\u18dd\u18de\u18df\u18e0\u18e1\u18e2\u18e3\u18e4\u18e5\u18e6\u18e7\u18e8\u18e9\u18ea\u18eb\u18ec\u18ed\u18ee\u18ef\u18f0\u18f1\u18f2\u18f3\u18f4\u18f5\u1900\u1901\u1902\u1903\u1904\u1905\u1906\u1907\u1908\u1909\u190a\u190b\u190c\u190d\u190e\u190f\u1910\u1911\u1912\u1913\u1914\u1915\u1916\u1917\u1918\u1919\u191a\u191b\u191c\u191d\u191e\u1950\u1951\u1952\u1953\u1954\u1955\u1956\u1957\u1958\u1959\u195a\u195b\u195c\u195d\u195e\u195f\u1960\u1961\u1962\u1963\u1964\u1965\u1966\u1967\u1968\u1969\u196a\u196b\u196c\u196d\u1970\u1971\u1972\u1973\u1974\u1980\u1981\u1982\u1983\u1984\u1985\u1986\u1987\u1988\u1989\u198a\u198b\u198c\u198d\u198e\u198f\u1990\u1991\u1992\u1993\u1994\u1995\u1996\u1997\u1998\u1999\u199a\u199b\u199c\u199d\u199e\u199f\u19a0\u19a1\u19a2\u19a3\u19a4\u19a5\u19a6\u19a7\u19a8\u19a9\u19aa\u19ab\u19b0\u19b1\u19b2\u19b3\u19b4\u19b5\u19b6\u19b7\u19b8\u19b9\u19ba\u19bb\u19bc\u19bd\u19be\u19bf\u19c0\u19c1\u19c2\u19c3\u19c4\u19c5\u19c6\u19c7\u19c8\u19c9\u1a00\u1a01\u1a02\u1a03\u1a04\u1a05\u1a06\u1a07\u1a08\u1a09\u1a0a\u1a0b\u1a0c\u1a0d\u1a0e\u1a0f\u1a10\u1a11\u1a12\u1a13\u1a14\u1a15\u1a16\u1a20\u1a21\u1a22\u1a23\u1a24\u1a25\u1a26\u1a27\u1a28\u1a29\u1a2a\u1a2b\u1a2c\u1a2d\u1a2e\u1a2f\u1a30\u1a31\u1a32\u1a33\u1a34\u1a35\u1a36\u1a37\u1a38\u1a39\u1a3a\u1a3b\u1a3c\u1a3d\u1a3e\u1a3f\u1a40\u1a41\u1a42\u1a43\u1a44\u1a45\u1a46\u1a47\u1a48\u1a49\u1a4a\u1a4b\u1a4c\u1a4d\u1a4e\u1a4f\u1a50\u1a51\u1a52\u1a53\u1a54\u1aa7\u1b05\u1b06\u1b07\u1b08\u1b09\u1b0a\u1b0b\u1b0c\u1b0d\u1b0e\u1b0f\u1b10\u1b11\u1b12\u1b13\u1b14\u1b15\u1b16\u1b17\u1b18\u1b19\u1b1a\u1b1b\u1b1c\u1b1d\u1b1e\u1b1f\u1b20\u1b21\u1b22\u1b23\u1b24\u1b25\u1b26\u1b27\u1b28\u1b29\u1b2a\u1b2b\u1b2c\u1b2d\u1b2e\u1b2f\u1b30\u1b31\u1b32\u1b33\u1b45\u1b46\u1b47\u1b48\u1b49\u1b4a\u1b4b\u1b83\u1b84\u1b85\u1b86\u1b87\u1b88\u1b89\u1b8a\u1b8b\u1b8c\u1b8d\u1b8e\u1b8f\u1b90\u1b91\u1b92\u1b93\u1b94\u1b95\u1b96\u1b97\u1b98\u1b99\u1b9a\u1b9b\u1b9c\u1b9d\u1b9e\u1b9f\u1ba0\u1bae\u1baf\u1bba\u1bbb\u1bbc\u1bbd\u1bbe\u1bbf\u1bc0\u1bc1\u1bc2\u1bc3\u1bc4\u1bc5\u1bc6\u1bc7\u1bc8\u1bc9\u1bca\u1bcb\u1bcc\u1bcd\u1bce\u1bcf\u1bd0\u1bd1\u1bd2\u1bd3\u1bd4\u1bd5\u1bd6\u1bd7\u1bd8\u1bd9\u1bda\u1bdb\u1bdc\u1bdd\u1bde\u1bdf\u1be0\u1be1\u1be2\u1be3\u1be4\u1be5\u1c00\u1c01\u1c02\u1c03\u1c04\u1c05\u1c06\u1c07\u1c08\u1c09\u1c0a\u1c0b\u1c0c\u1c0d\u1c0e\u1c0f\u1c10\u1c11\u1c12\u1c13\u1c14\u1c15\u1c16\u1c17\u1c18\u1c19\u1c1a\u1c1b\u1c1c\u1c1d\u1c1e\u1c1f\u1c20\u1c21\u1c22\u1c23\u1c4d\u1c4e\u1c4f\u1c5a\u1c5b\u1c5c\u1c5d\u1c5e\u1c5f\u1c60\u1c61\u1c62\u1c63\u1c64\u1c65\u1c66\u1c67\u1c68\u1c69\u1c6a\u1c6b\u1c6c\u1c6d\u1c6e\u1c6f\u1c70\u1c71\u1c72\u1c73\u1c74\u1c75\u1c76\u1c77\u1c78\u1c79\u1c7a\u1c7b\u1c7c\u1c7d\u1c80\u1c81\u1c82\u1c83\u1c84\u1c85\u1c86\u1c87\u1c88\u1ce9\u1cea\u1ceb\u1cec\u1cee\u1cef\u1cf0\u1cf1\u1cf5\u1cf6\u1d00\u1d01\u1d02\u1d03\u1d04\u1d05\u1d06\u1d07\u1d08\u1d09\u1d0a\u1d0b\u1d0c\u1d0d\u1d0e\u1d0f\u1d10\u1d11\u1d12\u1d13\u1d14\u1d15\u1d16\u1d17\u1d18\u1d19\u1d1a\u1d1b\u1d1c\u1d1d\u1d1e\u1d1f\u1d20\u1d21\u1d22\u1d23\u1d24\u1d25\u1d26\u1d27\u1d28\u1d29\u1d2a\u1d2b\u1d2c\u1d2d\u1d2e\u1d2f\u1d30\u1d31\u1d32\u1d33\u1d34\u1d35\u1d36\u1d37\u1d38\u1d39\u1d3a\u1d3b\u1d3c\u1d3d\u1d3e\u1d3f\u1d40\u1d41\u1d42\u1d43\u1d44\u1d45\u1d46\u1d47\u1d48\u1d49\u1d4a\u1d4b\u1d4c\u1d4d\u1d4e\u1d4f\u1d50\u1d51\u1d52\u1d53\u1d54\u1d55\u1d56\u1d57\u1d58\u1d59\u1d5a\u1d5b\u1d5c\u1d5d\u1d5e\u1d5f\u1d60\u1d61\u1d62\u1d63\u1d64\u1d65\u1d66\u1d67\u1d68\u1d69\u1d6a\u1d6b\u1d6c\u1d6d\u1d6e\u1d6f\u1d70\u1d71\u1d72\u1d73\u1d74\u1d75\u1d76\u1d77\u1d78\u1d79\u1d7a\u1d7b\u1d7c\u1d7d\u1d7e\u1d7f\u1d80\u1d81\u1d82\u1d83\u1d84\u1d85\u1d86\u1d87\u1d88\u1d89\u1d8a\u1d8b\u1d8c\u1d8d\u1d8e\u1d8f\u1d90\u1d91\u1d92\u1d93\u1d94\u1d95\u1d96\u1d97\u1d98\u1d99\u1d9a\u1d9b\u1d9c\u1d9d\u1d9e\u1d9f\u1da0\u1da1\u1da2\u1da3\u1da4\u1da5\u1da6\u1da7\u1da8\u1da9\u1daa\u1dab\u1dac\u1dad\u1dae\u1daf\u1db0\u1db1\u1db2\u1db3\u1db4\u1db5\u1db6\u1db7\u1db8\u1db9\u1dba\u1dbb\u1dbc\u1dbd\u1dbe\u1dbf\u1e00\u1e01\u1e02\u1e03\u1e04\u1e05\u1e06\u1e07\u1e08\u1e09\u1e0a\u1e0b\u1e0c\u1e0d\u1e0e\u1e0f\u1e10\u1e11\u1e12\u1e13\u1e14\u1e15\u1e16\u1e17\u1e18\u1e19\u1e1a\u1e1b\u1e1c\u1e1d\u1e1e\u1e1f\u1e20\u1e21\u1e22\u1e23\u1e24\u1e25\u1e26\u1e27\u1e28\u1e29\u1e2a\u1e2b\u1e2c\u1e2d\u1e2e\u1e2f\u1e30\u1e31\u1e32\u1e33\u1e34\u1e35\u1e36\u1e37\u1e38\u1e39\u1e3a\u1e3b\u1e3c\u1e3d\u1e3e\u1e3f\u1e40\u1e41\u1e42\u1e43\u1e44\u1e45\u1e46\u1e47\u1e48\u1e49\u1e4a\u1e4b\u1e4c\u1e4d\u1e4e\u1e4f\u1e50\u1e51\u1e52\u1e53\u1e54\u1e55\u1e56\u1e57\u1e58\u1e59\u1e5a\u1e5b\u1e5c\u1e5d\u1e5e\u1e5f\u1e60\u1e61\u1e62\u1e63\u1e64\u1e65\u1e66\u1e67\u1e68\u1e69\u1e6a\u1e6b\u1e6c\u1e6d\u1e6e\u1e6f\u1e70\u1e71\u1e72\u1e73\u1e74\u1e75\u1e76\u1e77\u1e78\u1e79\u1e7a\u1e7b\u1e7c\u1e7d\u1e7e\u1e7f\u1e80\u1e81\u1e82\u1e83\u1e84\u1e85\u1e86\u1e87\u1e88\u1e89\u1e8a\u1e8b\u1e8c\u1e8d\u1e8e\u1e8f\u1e90\u1e91\u1e92\u1e93\u1e94\u1e95\u1e96\u1e97\u1e98\u1e99\u1e9b\u1e9c\u1e9d\u1e9e\u1e9f\u1ea0\u1ea1\u1ea2\u1ea3\u1ea4\u1ea5\u1ea6\u1ea7\u1ea8\u1ea9\u1eaa\u1eab\u1eac\u1ead\u1eae\u1eaf\u1eb0\u1eb1\u1eb2\u1eb3\u1eb4\u1eb5\u1eb6\u1eb7\u1eb8\u1eb9\u1eba\u1ebb\u1ebc\u1ebd\u1ebe\u1ebf\u1ec0\u1ec1\u1ec2\u1ec3\u1ec4\u1ec5\u1ec6\u1ec7\u1ec8\u1ec9\u1eca\u1ecb\u1ecc\u1ecd\u1ece\u1ecf\u1ed0\u1ed1\u1ed2\u1ed3\u1ed4\u1ed5\u1ed6\u1ed7\u1ed8\u1ed9\u1eda\u1edb\u1edc\u1edd\u1ede\u1edf\u1ee0\u1ee1\u1ee2\u1ee3\u1ee4\u1ee5\u1ee6\u1ee7\u1ee8\u1ee9\u1eea\u1eeb\u1eec\u1eed\u1eee\u1eef\u1ef0\u1ef1\u1ef2\u1ef3\u1ef4\u1ef5\u1ef6\u1ef7\u1ef8\u1ef9\u1efa\u1efb\u1efc\u1efd\u1efe\u1eff\u1f00\u1f01\u1f02\u1f03\u1f04\u1f05\u1f06\u1f07\u1f08\u1f09\u1f0a\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1f10\u1f11\u1f12\u1f13\u1f14\u1f15\u1f18\u1f19\u1f1a\u1f1b\u1f1c\u1f1d\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u1f27\u1f28\u1f29\u1f2a\u1f2b\u1f2c\u1f2d\u1f2e\u1f2f\u1f30\u1f31\u1f32\u1f33\u1f34\u1f35\u1f36\u1f37\u1f38\u1f39\u1f3a\u1f3b\u1f3c\u1f3d\u1f3e\u1f3f\u1f40\u1f41\u1f42\u1f43\u1f44\u1f45\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f50\u1f51\u1f52\u1f53\u1f54\u1f55\u1f56\u1f57\u1f59\u1f5b\u1f5d\u1f5f\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u1f66\u1f67\u1f68\u1f69\u1f6a\u1f6b\u1f6c\u1f6d\u1f6e\u1f6f\u1f70\u1f71\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u1f7b\u1f7c\u1f7d\u1f80\u1f81\u1f82\u1f83\u1f84\u1f85\u1f86\u1f87\u1f88\u1f89\u1f8a\u1f8b\u1f8c\u1f8d\u1f8e\u1f8f\u1f90\u1f91\u1f92\u1f93\u1f94\u1f95\u1f96\u1f97\u1f98\u1f99\u1f9a\u1f9b\u1f9c\u1f9d\u1f9e\u1f9f\u1fa0\u1fa1\u1fa2\u1fa3\u1fa4\u1fa5\u1fa6\u1fa7\u1fa8\u1fa9\u1faa\u1fab\u1fac\u1fad\u1fae\u1faf\u1fb0\u1fb1\u1fb2\u1fb3\u1fb4\u1fb6\u1fb7\u1fb8\u1fb9\u1fba\u1fbb\u1fbc\u1fbe\u1fc2\u1fc3\u1fc4\u1fc6\u1fc7\u1fc8\u1fc9\u1fca\u1fcb\u1fcc\u1fd0\u1fd1\u1fd2\u1fd3\u1fd6\u1fd7\u1fd8\u1fd9\u1fda\u1fdb\u1fe0\u1fe1\u1fe2\u1fe3\u1fe4\u1fe5\u1fe6\u1fe7\u1fe8\u1fe9\u1fea\u1feb\u1fec\u1ff2\u1ff3\u1ff4\u1ff6\u1ff7\u1ff8\u1ff9\u1ffa\u1ffb\u1ffc\u2071\u207f\u2090\u2091\u2092\u2093\u2094\u2095\u2096\u2097\u2098\u2099\u209a\u209b\u209c\u2102\u2107\u210a\u210b\u210c\u210d\u210e\u210f\u2110\u2111\u2112\u2113\u2115\u2118\u2119\u211a\u211b\u211c\u211d\u2124\u2126\u2128\u212a\u212b\u212c\u212d\u212e\u212f\u2130\u2131\u2132\u2133\u2134\u2135\u2136\u2137\u2138\u2139\u213c\u213d\u213e\u213f\u2145\u2146\u2147\u2148\u2149\u214e\u2160\u2164\u2169\u216c\u216d\u216e\u216f\u2170\u2174\u2179\u217c\u217d\u217e\u217f\u2180\u2181\u2182\u2183\u2184\u2185\u2186\u2187\u2188\u2c00\u2c01\u2c02\u2c03\u2c04\u2c05\u2c06\u2c07\u2c08\u2c09\u2c0a\u2c0b\u2c0c\u2c0d\u2c0e\u2c0f\u2c10\u2c11\u2c12\u2c13\u2c14\u2c15\u2c16\u2c17\u2c18\u2c19\u2c1a\u2c1b\u2c1c\u2c1d\u2c1e\u2c1f\u2c20\u2c21\u2c22\u2c23\u2c24\u2c25\u2c26\u2c27\u2c28\u2c29\u2c2a\u2c2b\u2c2c\u2c2d\u2c2e\u2c30\u2c31\u2c32\u2c33\u2c34\u2c35\u2c36\u2c37\u2c38\u2c39\u2c3a\u2c3b\u2c3c\u2c3d\u2c3e\u2c3f\u2c40\u2c41\u2c42\u2c43\u2c44\u2c45\u2c46\u2c47\u2c48\u2c49\u2c4a\u2c4b\u2c4c\u2c4d\u2c4e\u2c4f\u2c50\u2c51\u2c52\u2c53\u2c54\u2c55\u2c56\u2c57\u2c58\u2c59\u2c5a\u2c5b\u2c5c\u2c5d\u2c5e\u2c60\u2c61\u2c62\u2c63\u2c64\u2c65\u2c66\u2c67\u2c68\u2c69\u2c6a\u2c6b\u2c6c\u2c6d\u2c6e\u2c6f\u2c70\u2c71\u2c72\u2c73\u2c74\u2c75\u2c76\u2c77\u2c78\u2c79\u2c7a\u2c7b\u2c7c\u2c7d\u2c7e\u2c7f\u2c80\u2c81\u2c82\u2c83\u2c84\u2c85\u2c86\u2c87\u2c88\u2c89\u2c8a\u2c8b\u2c8c\u2c8d\u2c8e\u2c8f\u2c90\u2c91\u2c92\u2c93\u2c94\u2c95\u2c96\u2c97\u2c98\u2c99\u2c9a\u2c9b\u2c9c\u2c9d\u2c9e\u2c9f\u2ca0\u2ca1\u2ca2\u2ca3\u2ca4\u2ca5\u2ca6\u2ca7\u2ca8\u2ca9\u2caa\u2cab\u2cac\u2cad\u2cae\u2caf\u2cb0\u2cb1\u2cb2\u2cb3\u2cb4\u2cb5\u2cb6\u2cb7\u2cb8\u2cb9\u2cba\u2cbb\u2cbc\u2cbd\u2cbe\u2cbf\u2cc0\u2cc1\u2cc2\u2cc3\u2cc4\u2cc5\u2cc6\u2cc7\u2cc8\u2cc9\u2cca\u2ccb\u2ccc\u2ccd\u2cce\u2ccf\u2cd0\u2cd1\u2cd2\u2cd3\u2cd4\u2cd5\u2cd6\u2cd7\u2cd8\u2cd9\u2cda\u2cdb\u2cdc\u2cdd\u2cde\u2cdf\u2ce0\u2ce1\u2ce2\u2ce3\u2ce4\u2ceb\u2cec\u2ced\u2cee\u2cf2\u2cf3\u2d00\u2d01\u2d02\u2d03\u2d04\u2d05\u2d06\u2d07\u2d08\u2d09\u2d0a\u2d0b\u2d0c\u2d0d\u2d0e\u2d0f\u2d10\u2d11\u2d12\u2d13\u2d14\u2d15\u2d16\u2d17\u2d18\u2d19\u2d1a\u2d1b\u2d1c\u2d1d\u2d1e\u2d1f\u2d20\u2d21\u2d22\u2d23\u2d24\u2d25\u2d27\u2d2d\u2d30\u2d31\u2d32\u2d33\u2d34\u2d35\u2d36\u2d37\u2d38\u2d39\u2d3a\u2d3b\u2d3c\u2d3d\u2d3e\u2d3f\u2d40\u2d41\u2d42\u2d43\u2d44\u2d45\u2d46\u2d47\u2d48\u2d49\u2d4a\u2d4b\u2d4c\u2d4d\u2d4e\u2d4f\u2d50\u2d51\u2d52\u2d53\u2d54\u2d55\u2d56\u2d57\u2d58\u2d59\u2d5a\u2d5b\u2d5c\u2d5d\u2d5e\u2d5f\u2d60\u2d61\u2d62\u2d63\u2d64\u2d65\u2d66\u2d67\u2d6f\u2d80\u2d81\u2d82\u2d83\u2d84\u2d85\u2d86\u2d87\u2d88\u2d89\u2d8a\u2d8b\u2d8c\u2d8d\u2d8e\u2d8f\u2d90\u2d91\u2d92\u2d93\u2d94\u2d95\u2d96\u2da0\u2da1\u2da2\u2da3\u2da4\u2da5\u2da6\u2da8\u2da9\u2daa\u2dab\u2dac\u2dad\u2dae\u2db0\u2db1\u2db2\u2db3\u2db4\u2db5\u2db6\u2db8\u2db9\u2dba\u2dbb\u2dbc\u2dbd\u2dbe\u2dc0\u2dc1\u2dc2\u2dc3\u2dc4\u2dc5\u2dc6\u2dc8\u2dc9\u2dca\u2dcb\u2dcc\u2dcd\u2dce\u2dd0\u2dd1\u2dd2\u2dd3\u2dd4\u2dd5\u2dd6\u2dd8\u2dd9\u2dda\u2ddb\u2ddc\u2ddd\u2dde\u2e2f\u3005\u3006\u3007\u3021\u3022\u3023\u3024\u3025\u3026\u3027\u3028\u3029\u3031\u3032\u3033\u3034\u3035\u3038\u3039\u303a\u303b\u303c\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048\u3049\u304a\u304b\u304c\u304d\u304e\u304f\u3050\u3051\u3052\u3053\u3054\u3055\u3056\u3057\u3058\u3059\u305a\u305b\u305c\u305d\u305e\u305f\u3060\u3061\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306a\u306b\u306c\u306d\u306e\u306f\u3070\u3071\u3072\u3073\u3074\u3075\u3076\u3077\u3078\u3079\u307a\u307b\u307c\u307d\u307e\u307f\u3080\u3081\u3082\u3083\u3084\u3085\u3086\u3087\u3088\u3089\u308a\u308b\u308c\u308d\u308e\u308f\u3090\u3091\u3092\u3093\u3094\u3095\u3096\u309d\u309e\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8\u30a9\u30aa\u30ab\u30ac\u30ad\u30ae\u30af\u30b0\u30b1\u30b2\u30b3\u30b4\u30b5\u30b6\u30b7\u30b8\u30b9\u30ba\u30bb\u30bc\u30bd\u30be\u30bf\u30c0\u30c1\u30c2\u30c3\u30c4\u30c5\u30c6\u30c7\u30c8\u30c9\u30ca\u30cb\u30cc\u30cd\u30ce\u30cf\u30d0\u30d1\u30d2\u30d3\u30d4\u30d5\u30d6\u30d7\u30d8\u30d9\u30da\u30db\u30dc\u30dd\u30de\u30df\u30e0\u30e1\u30e2\u30e3\u30e4\u30e5\u30e6\u30e7\u30e8\u30e9\u30ea\u30eb\u30ec\u30ed\u30ee\u30ef\u30f0\u30f1\u30f2\u30f3\u30f4\u30f5\u30f6\u30f7\u30f8\u30f9\u30fa\u30fc\u30fd\u30fe\u3105\u3106\u3107\u3108\u3109\u310a\u310b\u310c\u310d\u310e\u310f\u3110\u3111\u3112\u3113\u3114\u3115\u3116\u3117\u3118\u3119\u311a\u311b\u311c\u311d\u311e\u311f\u3120\u3121\u3122\u3123\u3124\u3125\u3126\u3127\u3128\u3129\u312a\u312b\u312c\u312d\u3131\u3132\u3133\u3134\u3135\u3136\u3137\u3138\u3139\u313a\u313b\u313c\u313d\u313e\u313f\u3140\u3141\u3142\u3143\u3144\u3145\u3146\u3147\u3148\u3149\u314a\u314b\u314c\u314d\u314e\u314f\u3150\u3151\u3152\u3153\u3154\u3155\u3156\u3157\u3158\u3159\u315a\u315b\u315c\u315d\u315e\u315f\u3160\u3161\u3162\u3163\u3164\u3165\u3166\u3167\u3168\u3169\u316a\u316b\u316c\u316d\u316e\u316f\u3170\u3171\u3172\u3173\u3174\u3175\u3176\u3177\u3178\u3179\u317a\u317b\u317c\u317d\u317e\u317f\u3180\u3181\u3182\u3183\u3184\u3185\u3186\u3187\u3188\u3189\u318a\u318b\u318c\u318d\u318e\u31a0\u31a1\u31a2\u31a3\u31a4\u31a5\u31a6\u31a7\u31a8\u31a9\u31aa\u31ab\u31ac\u31ad\u31ae\u31af\u31b0\u31b1\u31b2\u31b3\u31b4\u31b5\u31b6\u31b7\u31b8\u31b9\u31ba\u31f0\u31f1\u31f2\u31f3\u31f4\u31f5\u31f6\u31f7\u31f8\u31f9\u31fa\u31fb\u31fc\u31fd\u31fe\u31ff\u3400\u3401\u3402\u3403\u3404\u3405\u3406\u3407\u3408\u3409\u340a\u340b\u340c\u340d\u340e\u340f\u3410\u3411\u3412\u3413\u3414\u3415\u3416\u3417\u3418\u3419\u341a\u341b\u341c\u341d\u341e\u341f\u3420\u3421\u3422\u3423\u3424\u3425\u3426\u3427\u3428\u3429\u342a\u342b\u342c\u342d\u342e\u342f\u3430\u3431\u3432\u3433\u3434\u3435\u3436\u3437\u3438\u3439\u343a\u343b\u343c\u343d\u343e\u343f\u3440\u3441\u3442\u3443\u3444\u3445\u3446\u3447\u3448\u3449\u344a\u344b\u344c\u344d\u344e\u344f\u3450\u3451\u3452\u3453\u3454\u3455\u3456\u3457\u3458\u3459\u345a\u345b\u345c\u345d\u345e\u345f\u3460\u3461\u3462\u3463\u3464\u3465\u3466\u3467\u3468\u3469\u346a\u346b\u346c\u346d\u346e\u346f\u3470\u3471\u3472\u3473\u3474\u3475\u3476\u3477\u3478\u3479\u347a\u347b\u347c\u347d\u347e\u347f\u3480\u3481\u3482\u3483\u3484\u3485\u3486\u3487\u3488\u3489\u348a\u348b\u348c\u348d\u348e\u348f\u3490\u3491\u3492\u3493\u3494\u3495\u3496\u3497\u3498\u3499\u349a\u349b\u349c\u349d\u349e\u349f\u34a0\u34a1\u34a2\u34a3\u34a4\u34a5\u34a6\u34a7\u34a8\u34a9\u34aa\u34ab\u34ac\u34ad\u34ae\u34af\u34b0\u34b1\u34b2\u34b3\u34b4\u34b5\u34b6\u34b7\u34b8\u34b9\u34ba\u34bb\u34bc\u34bd\u34be\u34bf\u34c0\u34c1\u34c2\u34c3\u34c4\u34c5\u34c6\u34c7\u34c8\u34c9\u34ca\u34cb\u34cc\u34cd\u34ce\u34cf\u34d0\u34d1\u34d2\u34d3\u34d4\u34d5\u34d6\u34d7\u34d8\u34d9\u34da\u34db\u34dc\u34dd\u34de\u34df\u34e0\u34e1\u34e2\u34e3\u34e4\u34e5\u34e6\u34e7\u34e8\u34e9\u34ea\u34eb\u34ec\u34ed\u34ee\u34ef\u34f0\u34f1\u34f2\u34f3\u34f4\u34f5\u34f6\u34f7\u34f8\u34f9\u34fa\u34fb\u34fc\u34fd\u34fe\u34ff\u3500\u3501\u3502\u3503\u3504\u3505\u3506\u3507\u3508\u3509\u350a\u350b\u350c\u350d\u350e\u350f\u3510\u3511\u3512\u3513\u3514\u3515\u3516\u3517\u3518\u3519\u351a\u351b\u351c\u351d\u351e\u351f\u3520\u3521\u3522\u3523\u3524\u3525\u3526\u3527\u3528\u3529\u352a\u352b\u352c\u352d\u352e\u352f\u3530\u3531\u3532\u3533\u3534\u3535\u3536\u3537\u3538\u3539\u353a\u353b\u353c\u353d\u353e\u353f\u3540\u3541\u3542\u3543\u3544\u3545\u3546\u3547\u3548\u3549\u354a\u354b\u354c\u354d\u354e\u354f\u3550\u3551\u3552\u3553\u3554\u3555\u3556\u3557\u3558\u3559\u355a\u355b\u355c\u355d\u355e\u355f\u3560\u3561\u3562\u3563\u3564\u3565\u3566\u3567\u3568\u3569\u356a\u356b\u356c\u356d\u356e\u356f\u3570\u3571\u3572\u3573\u3574\u3575\u3576\u3577\u3578\u3579\u357a\u357b\u357c\u357d\u357e\u357f\u3580\u3581\u3582\u3583\u3584\u3585\u3586\u3587\u3588\u3589\u358a\u358b\u358c\u358d\u358e\u358f\u3590\u3591\u3592\u3593\u3594\u3595\u3596\u3597\u3598\u3599\u359a\u359b\u359c\u359d\u359e\u359f\u35a0\u35a1\u35a2\u35a3\u35a4\u35a5\u35a6\u35a7\u35a8\u35a9\u35aa\u35ab\u35ac\u35ad\u35ae\u35af\u35b0\u35b1\u35b2\u35b3\u35b4\u35b5\u35b6\u35b7\u35b8\u35b9\u35ba\u35bb\u35bc\u35bd\u35be\u35bf\u35c0\u35c1\u35c2\u35c3\u35c4\u35c5\u35c6\u35c7\u35c8\u35c9\u35ca\u35cb\u35cc\u35cd\u35ce\u35cf\u35d0\u35d1\u35d2\u35d3\u35d4\u35d5\u35d6\u35d7\u35d8\u35d9\u35da\u35db\u35dc\u35dd\u35de\u35df\u35e0\u35e1\u35e2\u35e3\u35e4\u35e5\u35e6\u35e7\u35e8\u35e9\u35ea\u35eb\u35ec\u35ed\u35ee\u35ef\u35f0\u35f1\u35f2\u35f3\u35f4\u35f5\u35f6\u35f7\u35f8\u35f9\u35fa\u35fb\u35fc\u35fd\u35fe\u35ff\u3600\u3601\u3602\u3603\u3604\u3605\u3606\u3607\u3608\u3609\u360a\u360b\u360c\u360d\u360e\u360f\u3610\u3611\u3612\u3613\u3614\u3615\u3616\u3617\u3618\u3619\u361a\u361b\u361c\u361d\u361e\u361f\u3620\u3621\u3622\u3623\u3624\u3625\u3626\u3627\u3628\u3629\u362a\u362b\u362c\u362d\u362e\u362f\u3630\u3631\u3632\u3633\u3634\u3635\u3636\u3637\u3638\u3639\u363a\u363b\u363c\u363d\u363e\u363f\u3640\u3641\u3642\u3643\u3644\u3645\u3646\u3647\u3648\u3649\u364a\u364b\u364c\u364d\u364e\u364f\u3650\u3651\u3652\u3653\u3654\u3655\u3656\u3657\u3658\u3659\u365a\u365b\u365c\u365d\u365e\u365f\u3660\u3661\u3662\u3663\u3664\u3665\u3666\u3667\u3668\u3669\u366a\u366b\u366c\u366d\u366e\u366f\u3670\u3671\u3672\u3673\u3674\u3675\u3676\u3677\u3678\u3679\u367a\u367b\u367c\u367d\u367e\u367f\u3680\u3681\u3682\u3683\u3684\u3685\u3686\u3687\u3688\u3689\u368a\u368b\u368c\u368d\u368e\u368f\u3690\u3691\u3692\u3693\u3694\u3695\u3696\u3697\u3698\u3699\u369a\u369b\u369c\u369d\u369e\u369f\u36a0\u36a1\u36a2\u36a3\u36a4\u36a5\u36a6\u36a7\u36a8\u36a9\u36aa\u36ab\u36ac\u36ad\u36ae\u36af\u36b0\u36b1\u36b2\u36b3\u36b4\u36b5\u36b6\u36b7\u36b8\u36b9\u36ba\u36bb\u36bc\u36bd\u36be\u36bf\u36c0\u36c1\u36c2\u36c3\u36c4\u36c5\u36c6\u36c7\u36c8\u36c9\u36ca\u36cb\u36cc\u36cd\u36ce\u36cf\u36d0\u36d1\u36d2\u36d3\u36d4\u36d5\u36d6\u36d7\u36d8\u36d9\u36da\u36db\u36dc\u36dd\u36de\u36df\u36e0\u36e1\u36e2\u36e3\u36e4\u36e5\u36e6\u36e7\u36e8\u36e9\u36ea\u36eb\u36ec\u36ed\u36ee\u36ef\u36f0\u36f1\u36f2\u36f3\u36f4\u36f5\u36f6\u36f7\u36f8\u36f9\u36fa\u36fb\u36fc\u36fd\u36fe\u36ff\u3700\u3701\u3702\u3703\u3704\u3705\u3706\u3707\u3708\u3709\u370a\u370b\u370c\u370d\u370e\u370f\u3710\u3711\u3712\u3713\u3714\u3715\u3716\u3717\u3718\u3719\u371a\u371b\u371c\u371d\u371e\u371f\u3720\u3721\u3722\u3723\u3724\u3725\u3726\u3727\u3728\u3729\u372a\u372b\u372c\u372d\u372e\u372f\u3730\u3731\u3732\u3733\u3734\u3735\u3736\u3737\u3738\u3739\u373a\u373b\u373c\u373d\u373e\u373f\u3740\u3741\u3742\u3743\u3744\u3745\u3746\u3747\u3748\u3749\u374a\u374b\u374c\u374d\u374e\u374f\u3750\u3751\u3752\u3753\u3754\u3755\u3756\u3757\u3758\u3759\u375a\u375b\u375c\u375d\u375e\u375f\u3760\u3761\u3762\u3763\u3764\u3765\u3766\u3767\u3768\u3769\u376a\u376b\u376c\u376d\u376e\u376f\u3770\u3771\u3772\u3773\u3774\u3775\u3776\u3777\u3778\u3779\u377a\u377b\u377c\u377d\u377e\u377f\u3780\u3781\u3782\u3783\u3784\u3785\u3786\u3787\u3788\u3789\u378a\u378b\u378c\u378d\u378e\u378f\u3790\u3791\u3792\u3793\u3794\u3795\u3796\u3797\u3798\u3799\u379a\u379b\u379c\u379d\u379e\u379f\u37a0\u37a1\u37a2\u37a3\u37a4\u37a5\u37a6\u37a7\u37a8\u37a9\u37aa\u37ab\u37ac\u37ad\u37ae\u37af\u37b0\u37b1\u37b2\u37b3\u37b4\u37b5\u37b6\u37b7\u37b8\u37b9\u37ba\u37bb\u37bc\u37bd\u37be\u37bf\u37c0\u37c1\u37c2\u37c3\u37c4\u37c5\u37c6\u37c7\u37c8\u37c9\u37ca\u37cb\u37cc\u37cd\u37ce\u37cf\u37d0\u37d1\u37d2\u37d3\u37d4\u37d5\u37d6\u37d7\u37d8\u37d9\u37da\u37db\u37dc\u37dd\u37de\u37df\u37e0\u37e1\u37e2\u37e3\u37e4\u37e5\u37e6\u37e7\u37e8\u37e9\u37ea\u37eb\u37ec\u37ed\u37ee\u37ef\u37f0\u37f1\u37f2\u37f3\u37f4\u37f5\u37f6\u37f7\u37f8\u37f9\u37fa\u37fb\u37fc\u37fd\u37fe\u37ff\u3800\u3801\u3802\u3803\u3804\u3805\u3806\u3807\u3808\u3809\u380a\u380b\u380c\u380d\u380e\u380f\u3810\u3811\u3812\u3813\u3814\u3815\u3816\u3817\u3818\u3819\u381a\u381b\u381c\u381d\u381e\u381f\u3820\u3821\u3822\u3823\u3824\u3825\u3826\u3827\u3828\u3829\u382a\u382b\u382c\u382d\u382e\u382f\u3830\u3831\u3832\u3833\u3834\u3835\u3836\u3837\u3838\u3839\u383a\u383b\u383c\u383d\u383e\u383f\u3840\u3841\u3842\u3843\u3844\u3845\u3846\u3847\u3848\u3849\u384a\u384b\u384c\u384d\u384e\u384f\u3850\u3851\u3852\u3853\u3854\u3855\u3856\u3857\u3858\u3859\u385a\u385b\u385c\u385d\u385e\u385f\u3860\u3861\u3862\u3863\u3864\u3865\u3866\u3867\u3868\u3869\u386a\u386b\u386c\u386d\u386e\u386f\u3870\u3871\u3872\u3873\u3874\u3875\u3876\u3877\u3878\u3879\u387a\u387b\u387c\u387d\u387e\u387f\u3880\u3881\u3882\u3883\u3884\u3885\u3886\u3887\u3888\u3889\u388a\u388b\u388c\u388d\u388e\u388f\u3890\u3891\u3892\u3893\u3894\u3895\u3896\u3897\u3898\u3899\u389a\u389b\u389c\u389d\u389e\u389f\u38a0\u38a1\u38a2\u38a3\u38a4\u38a5\u38a6\u38a7\u38a8\u38a9\u38aa\u38ab\u38ac\u38ad\u38ae\u38af\u38b0\u38b1\u38b2\u38b3\u38b4\u38b5\u38b6\u38b7\u38b8\u38b9\u38ba\u38bb\u38bc\u38bd\u38be\u38bf\u38c0\u38c1\u38c2\u38c3\u38c4\u38c5\u38c6\u38c7\u38c8\u38c9\u38ca\u38cb\u38cc\u38cd\u38ce\u38cf\u38d0\u38d1\u38d2\u38d3\u38d4\u38d5\u38d6\u38d7\u38d8\u38d9\u38da\u38db\u38dc\u38dd\u38de\u38df\u38e0\u38e1\u38e2\u38e3\u38e4\u38e5\u38e6\u38e7\u38e8\u38e9\u38ea\u38eb\u38ec\u38ed\u38ee\u38ef\u38f0\u38f1\u38f2\u38f3\u38f4\u38f5\u38f6\u38f7\u38f8\u38f9\u38fa\u38fb\u38fc\u38fd\u38fe\u38ff\u3900\u3901\u3902\u3903\u3904\u3905\u3906\u3907\u3908\u3909\u390a\u390b\u390c\u390d\u390e\u390f\u3910\u3911\u3912\u3913\u3914\u3915\u3916\u3917\u3918\u3919\u391a\u391b\u391c\u391d\u391e\u391f\u3920\u3921\u3922\u3923\u3924\u3925\u3926\u3927\u3928\u3929\u392a\u392b\u392c\u392d\u392e\u392f\u3930\u3931\u3932\u3933\u3934\u3935\u3936\u3937\u3938\u3939\u393a\u393b\u393c\u393d\u393e\u393f\u3940\u3941\u3942\u3943\u3944\u3945\u3946\u3947\u3948\u3949\u394a\u394b\u394c\u394d\u394e\u394f\u3950\u3951\u3952\u3953\u3954\u3955\u3956\u3957\u3958\u3959\u395a\u395b\u395c\u395d\u395e\u395f\u3960\u3961\u3962\u3963\u3964\u3965\u3966\u3967\u3968\u3969\u396a\u396b\u396c\u396d\u396e\u396f\u3970\u3971\u3972\u3973\u3974\u3975\u3976\u3977\u3978\u3979\u397a\u397b\u397c\u397d\u397e\u397f\u3980\u3981\u3982\u3983\u3984\u3985\u3986\u3987\u3988\u3989\u398a\u398b\u398c\u398d\u398e\u398f\u3990\u3991\u3992\u3993\u3994\u3995\u3996\u3997\u3998\u3999\u399a\u399b\u399c\u399d\u399e\u399f\u39a0\u39a1\u39a2\u39a3\u39a4\u39a5\u39a6\u39a7\u39a8\u39a9\u39aa\u39ab\u39ac\u39ad\u39ae\u39af\u39b0\u39b1\u39b2\u39b3\u39b4\u39b5\u39b6\u39b7\u39b8\u39b9\u39ba\u39bb\u39bc\u39bd\u39be\u39bf\u39c0\u39c1\u39c2\u39c3\u39c4\u39c5\u39c6\u39c7\u39c8\u39c9\u39ca\u39cb\u39cc\u39cd\u39ce\u39cf\u39d0\u39d1\u39d2\u39d3\u39d4\u39d5\u39d6\u39d7\u39d8\u39d9\u39da\u39db\u39dc\u39dd\u39de\u39df\u39e0\u39e1\u39e2\u39e3\u39e4\u39e5\u39e6\u39e7\u39e8\u39e9\u39ea\u39eb\u39ec\u39ed\u39ee\u39ef\u39f0\u39f1\u39f2\u39f3\u39f4\u39f5\u39f6\u39f7\u39f8\u39f9\u39fa\u39fb\u39fc\u39fd\u39fe\u39ff\u3a00\u3a01\u3a02\u3a03\u3a04\u3a05\u3a06\u3a07\u3a08\u3a09\u3a0a\u3a0b\u3a0c\u3a0d\u3a0e\u3a0f\u3a10\u3a11\u3a12\u3a13\u3a14\u3a15\u3a16\u3a17\u3a18\u3a19\u3a1a\u3a1b\u3a1c\u3a1d\u3a1e\u3a1f\u3a20\u3a21\u3a22\u3a23\u3a24\u3a25\u3a26\u3a27\u3a28\u3a29\u3a2a\u3a2b\u3a2c\u3a2d\u3a2e\u3a2f\u3a30\u3a31\u3a32\u3a33\u3a34\u3a35\u3a36\u3a37\u3a38\u3a39\u3a3a\u3a3b\u3a3c\u3a3d\u3a3e\u3a3f\u3a40\u3a41\u3a42\u3a43\u3a44\u3a45\u3a46\u3a47\u3a48\u3a49\u3a4a\u3a4b\u3a4c\u3a4d\u3a4e\u3a4f\u3a50\u3a51\u3a52\u3a53\u3a54\u3a55\u3a56\u3a57\u3a58\u3a59\u3a5a\u3a5b\u3a5c\u3a5d\u3a5e\u3a5f\u3a60\u3a61\u3a62\u3a63\u3a64\u3a65\u3a66\u3a67\u3a68\u3a69\u3a6a\u3a6b\u3a6c\u3a6d\u3a6e\u3a6f\u3a70\u3a71\u3a72\u3a73\u3a74\u3a75\u3a76\u3a77\u3a78\u3a79\u3a7a\u3a7b\u3a7c\u3a7d\u3a7e\u3a7f\u3a80\u3a81\u3a82\u3a83\u3a84\u3a85\u3a86\u3a87\u3a88\u3a89\u3a8a\u3a8b\u3a8c\u3a8d\u3a8e\u3a8f\u3a90\u3a91\u3a92\u3a93\u3a94\u3a95\u3a96\u3a97\u3a98\u3a99\u3a9a\u3a9b\u3a9c\u3a9d\u3a9e\u3a9f\u3aa0\u3aa1\u3aa2\u3aa3\u3aa4\u3aa5\u3aa6\u3aa7\u3aa8\u3aa9\u3aaa\u3aab\u3aac\u3aad\u3aae\u3aaf\u3ab0\u3ab1\u3ab2\u3ab3\u3ab4\u3ab5\u3ab6\u3ab7\u3ab8\u3ab9\u3aba\u3abb\u3abc\u3abd\u3abe\u3abf\u3ac0\u3ac1\u3ac2\u3ac3\u3ac4\u3ac5\u3ac6\u3ac7\u3ac8\u3ac9\u3aca\u3acb\u3acc\u3acd\u3ace\u3acf\u3ad0\u3ad1\u3ad2\u3ad3\u3ad4\u3ad5\u3ad6\u3ad7\u3ad8\u3ad9\u3ada\u3adb\u3adc\u3add\u3ade\u3adf\u3ae0\u3ae1\u3ae2\u3ae3\u3ae4\u3ae5\u3ae6\u3ae7\u3ae8\u3ae9\u3aea\u3aeb\u3aec\u3aed\u3aee\u3aef\u3af0\u3af1\u3af2\u3af3\u3af4\u3af5\u3af6\u3af7\u3af8\u3af9\u3afa\u3afb\u3afc\u3afd\u3afe\u3aff\u3b00\u3b01\u3b02\u3b03\u3b04\u3b05\u3b06\u3b07\u3b08\u3b09\u3b0a\u3b0b\u3b0c\u3b0d\u3b0e\u3b0f\u3b10\u3b11\u3b12\u3b13\u3b14\u3b15\u3b16\u3b17\u3b18\u3b19\u3b1a\u3b1b\u3b1c\u3b1d\u3b1e\u3b1f\u3b20\u3b21\u3b22\u3b23\u3b24\u3b25\u3b26\u3b27\u3b28\u3b29\u3b2a\u3b2b\u3b2c\u3b2d\u3b2e\u3b2f\u3b30\u3b31\u3b32\u3b33\u3b34\u3b35\u3b36\u3b37\u3b38\u3b39\u3b3a\u3b3b\u3b3c\u3b3d\u3b3e\u3b3f\u3b40\u3b41\u3b42\u3b43\u3b44\u3b45\u3b46\u3b47\u3b48\u3b49\u3b4a\u3b4b\u3b4c\u3b4d\u3b4e\u3b4f\u3b50\u3b51\u3b52\u3b53\u3b54\u3b55\u3b56\u3b57\u3b58\u3b59\u3b5a\u3b5b\u3b5c\u3b5d\u3b5e\u3b5f\u3b60\u3b61\u3b62\u3b63\u3b64\u3b65\u3b66\u3b67\u3b68\u3b69\u3b6a\u3b6b\u3b6c\u3b6d\u3b6e\u3b6f\u3b70\u3b71\u3b72\u3b73\u3b74\u3b75\u3b76\u3b77\u3b78\u3b79\u3b7a\u3b7b\u3b7c\u3b7d\u3b7e\u3b7f\u3b80\u3b81\u3b82\u3b83\u3b84\u3b85\u3b86\u3b87\u3b88\u3b89\u3b8a\u3b8b\u3b8c\u3b8d\u3b8e\u3b8f\u3b90\u3b91\u3b92\u3b93\u3b94\u3b95\u3b96\u3b97\u3b98\u3b99\u3b9a\u3b9b\u3b9c\u3b9d\u3b9e\u3b9f\u3ba0\u3ba1\u3ba2\u3ba3\u3ba4\u3ba5\u3ba6\u3ba7\u3ba8\u3ba9\u3baa\u3bab\u3bac\u3bad\u3bae\u3baf\u3bb0\u3bb1\u3bb2\u3bb3\u3bb4\u3bb5\u3bb6\u3bb7\u3bb8\u3bb9\u3bba\u3bbb\u3bbc\u3bbd\u3bbe\u3bbf\u3bc0\u3bc1\u3bc2\u3bc3\u3bc4\u3bc5\u3bc6\u3bc7\u3bc8\u3bc9\u3bca\u3bcb\u3bcc\u3bcd\u3bce\u3bcf\u3bd0\u3bd1\u3bd2\u3bd3\u3bd4\u3bd5\u3bd6\u3bd7\u3bd8\u3bd9\u3bda\u3bdb\u3bdc\u3bdd\u3bde\u3bdf\u3be0\u3be1\u3be2\u3be3\u3be4\u3be5\u3be6\u3be7\u3be8\u3be9\u3bea\u3beb\u3bec\u3bed\u3bee\u3bef\u3bf0\u3bf1\u3bf2\u3bf3\u3bf4\u3bf5\u3bf6\u3bf7\u3bf8\u3bf9\u3bfa\u3bfb\u3bfc\u3bfd\u3bfe\u3bff\u3c00\u3c01\u3c02\u3c03\u3c04\u3c05\u3c06\u3c07\u3c08\u3c09\u3c0a\u3c0b\u3c0c\u3c0d\u3c0e\u3c0f\u3c10\u3c11\u3c12\u3c13\u3c14\u3c15\u3c16\u3c17\u3c18\u3c19\u3c1a\u3c1b\u3c1c\u3c1d\u3c1e\u3c1f\u3c20\u3c21\u3c22\u3c23\u3c24\u3c25\u3c26\u3c27\u3c28\u3c29\u3c2a\u3c2b\u3c2c\u3c2d\u3c2e\u3c2f\u3c30\u3c31\u3c32\u3c33\u3c34\u3c35\u3c36\u3c37\u3c38\u3c39\u3c3a\u3c3b\u3c3c\u3c3d\u3c3e\u3c3f\u3c40\u3c41\u3c42\u3c43\u3c44\u3c45\u3c46\u3c47\u3c48\u3c49\u3c4a\u3c4b\u3c4c\u3c4d\u3c4e\u3c4f\u3c50\u3c51\u3c52\u3c53\u3c54\u3c55\u3c56\u3c57\u3c58\u3c59\u3c5a\u3c5b\u3c5c\u3c5d\u3c5e\u3c5f\u3c60\u3c61\u3c62\u3c63\u3c64\u3c65\u3c66\u3c67\u3c68\u3c69\u3c6a\u3c6b\u3c6c\u3c6d\u3c6e\u3c6f\u3c70\u3c71\u3c72\u3c73\u3c74\u3c75\u3c76\u3c77\u3c78\u3c79\u3c7a\u3c7b\u3c7c\u3c7d\u3c7e\u3c7f\u3c80\u3c81\u3c82\u3c83\u3c84\u3c85\u3c86\u3c87\u3c88\u3c89\u3c8a\u3c8b\u3c8c\u3c8d\u3c8e\u3c8f\u3c90\u3c91\u3c92\u3c93\u3c94\u3c95\u3c96\u3c97\u3c98\u3c99\u3c9a\u3c9b\u3c9c\u3c9d\u3c9e\u3c9f\u3ca0\u3ca1\u3ca2\u3ca3\u3ca4\u3ca5\u3ca6\u3ca7\u3ca8\u3ca9\u3caa\u3cab\u3cac\u3cad\u3cae\u3caf\u3cb0\u3cb1\u3cb2\u3cb3\u3cb4\u3cb5\u3cb6\u3cb7\u3cb8\u3cb9\u3cba\u3cbb\u3cbc\u3cbd\u3cbe\u3cbf\u3cc0\u3cc1\u3cc2\u3cc3\u3cc4\u3cc5\u3cc6\u3cc7\u3cc8\u3cc9\u3cca\u3ccb\u3ccc\u3ccd\u3cce\u3ccf\u3cd0\u3cd1\u3cd2\u3cd3\u3cd4\u3cd5\u3cd6\u3cd7\u3cd8\u3cd9\u3cda\u3cdb\u3cdc\u3cdd\u3cde\u3cdf\u3ce0\u3ce1\u3ce2\u3ce3\u3ce4\u3ce5\u3ce6\u3ce7\u3ce8\u3ce9\u3cea\u3ceb\u3cec\u3ced\u3cee\u3cef\u3cf0\u3cf1\u3cf2\u3cf3\u3cf4\u3cf5\u3cf6\u3cf7\u3cf8\u3cf9\u3cfa\u3cfb\u3cfc\u3cfd\u3cfe\u3cff\u3d00\u3d01\u3d02\u3d03\u3d04\u3d05\u3d06\u3d07\u3d08\u3d09\u3d0a\u3d0b\u3d0c\u3d0d\u3d0e\u3d0f\u3d10\u3d11\u3d12\u3d13\u3d14\u3d15\u3d16\u3d17\u3d18\u3d19\u3d1a\u3d1b\u3d1c\u3d1d\u3d1e\u3d1f\u3d20\u3d21\u3d22\u3d23\u3d24\u3d25\u3d26\u3d27\u3d28\u3d29\u3d2a\u3d2b\u3d2c\u3d2d\u3d2e\u3d2f\u3d30\u3d31\u3d32\u3d33\u3d34\u3d35\u3d36\u3d37\u3d38\u3d39\u3d3a\u3d3b\u3d3c\u3d3d\u3d3e\u3d3f\u3d40\u3d41\u3d42\u3d43\u3d44\u3d45\u3d46\u3d47\u3d48\u3d49\u3d4a\u3d4b\u3d4c\u3d4d\u3d4e\u3d4f\u3d50\u3d51\u3d52\u3d53\u3d54\u3d55\u3d56\u3d57\u3d58\u3d59\u3d5a\u3d5b\u3d5c\u3d5d\u3d5e\u3d5f\u3d60\u3d61\u3d62\u3d63\u3d64\u3d65\u3d66\u3d67\u3d68\u3d69\u3d6a\u3d6b\u3d6c\u3d6d\u3d6e\u3d6f\u3d70\u3d71\u3d72\u3d73\u3d74\u3d75\u3d76\u3d77\u3d78\u3d79\u3d7a\u3d7b\u3d7c\u3d7d\u3d7e\u3d7f\u3d80\u3d81\u3d82\u3d83\u3d84\u3d85\u3d86\u3d87\u3d88\u3d89\u3d8a\u3d8b\u3d8c\u3d8d\u3d8e\u3d8f\u3d90\u3d91\u3d92\u3d93\u3d94\u3d95\u3d96\u3d97\u3d98\u3d99\u3d9a\u3d9b\u3d9c\u3d9d\u3d9e\u3d9f\u3da0\u3da1\u3da2\u3da3\u3da4\u3da5\u3da6\u3da7\u3da8\u3da9\u3daa\u3dab\u3dac\u3dad\u3dae\u3daf\u3db0\u3db1\u3db2\u3db3\u3db4\u3db5\u3db6\u3db7\u3db8\u3db9\u3dba\u3dbb\u3dbc\u3dbd\u3dbe\u3dbf\u3dc0\u3dc1\u3dc2\u3dc3\u3dc4\u3dc5\u3dc6\u3dc7\u3dc8\u3dc9\u3dca\u3dcb\u3dcc\u3dcd\u3dce\u3dcf\u3dd0\u3dd1\u3dd2\u3dd3\u3dd4\u3dd5\u3dd6\u3dd7\u3dd8\u3dd9\u3dda\u3ddb\u3ddc\u3ddd\u3dde\u3ddf\u3de0\u3de1\u3de2\u3de3\u3de4\u3de5\u3de6\u3de7\u3de8\u3de9\u3dea\u3deb\u3dec\u3ded\u3dee\u3def\u3df0\u3df1\u3df2\u3df3\u3df4\u3df5\u3df6\u3df7\u3df8\u3df9\u3dfa\u3dfb\u3dfc\u3dfd\u3dfe\u3dff\u3e00\u3e01\u3e02\u3e03\u3e04\u3e05\u3e06\u3e07\u3e08\u3e09\u3e0a\u3e0b\u3e0c\u3e0d\u3e0e\u3e0f\u3e10\u3e11\u3e12\u3e13\u3e14\u3e15\u3e16\u3e17\u3e18\u3e19\u3e1a\u3e1b\u3e1c\u3e1d\u3e1e\u3e1f\u3e20\u3e21\u3e22\u3e23\u3e24\u3e25\u3e26\u3e27\u3e28\u3e29\u3e2a\u3e2b\u3e2c\u3e2d\u3e2e\u3e2f\u3e30\u3e31\u3e32\u3e33\u3e34\u3e35\u3e36\u3e37\u3e38\u3e39\u3e3a\u3e3b\u3e3c\u3e3d\u3e3e\u3e3f\u3e40\u3e41\u3e42\u3e43\u3e44\u3e45\u3e46\u3e47\u3e48\u3e49\u3e4a\u3e4b\u3e4c\u3e4d\u3e4e\u3e4f\u3e50\u3e51\u3e52\u3e53\u3e54\u3e55\u3e56\u3e57\u3e58\u3e59\u3e5a\u3e5b\u3e5c\u3e5d\u3e5e\u3e5f\u3e60\u3e61\u3e62\u3e63\u3e64\u3e65\u3e66\u3e67\u3e68\u3e69\u3e6a\u3e6b\u3e6c\u3e6d\u3e6e\u3e6f\u3e70\u3e71\u3e72\u3e73\u3e74\u3e75\u3e76\u3e77\u3e78\u3e79\u3e7a\u3e7b\u3e7c\u3e7d\u3e7e\u3e7f\u3e80\u3e81\u3e82\u3e83\u3e84\u3e85\u3e86\u3e87\u3e88\u3e89\u3e8a\u3e8b\u3e8c\u3e8d\u3e8e\u3e8f\u3e90\u3e91\u3e92\u3e93\u3e94\u3e95\u3e96\u3e97\u3e98\u3e99\u3e9a\u3e9b\u3e9c\u3e9d\u3e9e\u3e9f\u3ea0\u3ea1\u3ea2\u3ea3\u3ea4\u3ea5\u3ea6\u3ea7\u3ea8\u3ea9\u3eaa\u3eab\u3eac\u3ead\u3eae\u3eaf\u3eb0\u3eb1\u3eb2\u3eb3\u3eb4\u3eb5\u3eb6\u3eb7\u3eb8\u3eb9\u3eba\u3ebb\u3ebc\u3ebd\u3ebe\u3ebf\u3ec0\u3ec1\u3ec2\u3ec3\u3ec4\u3ec5\u3ec6\u3ec7\u3ec8\u3ec9\u3eca\u3ecb\u3ecc\u3ecd\u3ece\u3ecf\u3ed0\u3ed1\u3ed2\u3ed3\u3ed4\u3ed5\u3ed6\u3ed7\u3ed8\u3ed9\u3eda\u3edb\u3edc\u3edd\u3ede\u3edf\u3ee0\u3ee1\u3ee2\u3ee3\u3ee4\u3ee5\u3ee6\u3ee7\u3ee8\u3ee9\u3eea\u3eeb\u3eec\u3eed\u3eee\u3eef\u3ef0\u3ef1\u3ef2\u3ef3\u3ef4\u3ef5\u3ef6\u3ef7\u3ef8\u3ef9\u3efa\u3efb\u3efc\u3efd\u3efe\u3eff\u3f00\u3f01\u3f02\u3f03\u3f04\u3f05\u3f06\u3f07\u3f08\u3f09\u3f0a\u3f0b\u3f0c\u3f0d\u3f0e\u3f0f\u3f10\u3f11\u3f12\u3f13\u3f14\u3f15\u3f16\u3f17\u3f18\u3f19\u3f1a\u3f1b\u3f1c\u3f1d\u3f1e\u3f1f\u3f20\u3f21\u3f22\u3f23\u3f24\u3f25\u3f26\u3f27\u3f28\u3f29\u3f2a\u3f2b\u3f2c\u3f2d\u3f2e\u3f2f\u3f30\u3f31\u3f32\u3f33\u3f34\u3f35\u3f36\u3f37\u3f38\u3f39\u3f3a\u3f3b\u3f3c\u3f3d\u3f3e\u3f3f\u3f40\u3f41\u3f42\u3f43\u3f44\u3f45\u3f46\u3f47\u3f48\u3f49\u3f4a\u3f4b\u3f4c\u3f4d\u3f4e\u3f4f\u3f50\u3f51\u3f52\u3f53\u3f54\u3f55\u3f56\u3f57\u3f58\u3f59\u3f5a\u3f5b\u3f5c\u3f5d\u3f5e\u3f5f\u3f60\u3f61\u3f62\u3f63\u3f64\u3f65\u3f66\u3f67\u3f68\u3f69\u3f6a\u3f6b\u3f6c\u3f6d\u3f6e\u3f6f\u3f70\u3f71\u3f72\u3f73\u3f74\u3f75\u3f76\u3f77\u3f78\u3f79\u3f7a\u3f7b\u3f7c\u3f7d\u3f7e\u3f7f\u3f80\u3f81\u3f82\u3f83\u3f84\u3f85\u3f86\u3f87\u3f88\u3f89\u3f8a\u3f8b\u3f8c\u3f8d\u3f8e\u3f8f\u3f90\u3f91\u3f92\u3f93\u3f94\u3f95\u3f96\u3f97\u3f98\u3f99\u3f9a\u3f9b\u3f9c\u3f9d\u3f9e\u3f9f\u3fa0\u3fa1\u3fa2\u3fa3\u3fa4\u3fa5\u3fa6\u3fa7\u3fa8\u3fa9\u3faa\u3fab\u3fac\u3fad\u3fae\u3faf\u3fb0\u3fb1\u3fb2\u3fb3\u3fb4\u3fb5\u3fb6\u3fb7\u3fb8\u3fb9\u3fba\u3fbb\u3fbc\u3fbd\u3fbe\u3fbf\u3fc0\u3fc1\u3fc2\u3fc3\u3fc4\u3fc5\u3fc6\u3fc7\u3fc8\u3fc9\u3fca\u3fcb\u3fcc\u3fcd\u3fce\u3fcf\u3fd0\u3fd1\u3fd2\u3fd3\u3fd4\u3fd5\u3fd6\u3fd7\u3fd8\u3fd9\u3fda\u3fdb\u3fdc\u3fdd\u3fde\u3fdf\u3fe0\u3fe1\u3fe2\u3fe3\u3fe4\u3fe5\u3fe6\u3fe7\u3fe8\u3fe9\u3fea\u3feb\u3fec\u3fed\u3fee\u3fef\u3ff0\u3ff1\u3ff2\u3ff3\u3ff4\u3ff5\u3ff6\u3ff7\u3ff8\u3ff9\u3ffa\u3ffb\u3ffc\u3ffd\u3ffe\u3fff\u4000\u4001\u4002\u4003\u4004\u4005\u4006\u4007\u4008\u4009\u400a\u400b\u400c\u400d\u400e\u400f\u4010\u4011\u4012\u4013\u4014\u4015\u4016\u4017\u4018\u4019\u401a\u401b\u401c\u401d\u401e\u401f\u4020\u4021\u4022\u4023\u4024\u4025\u4026\u4027\u4028\u4029\u402a\u402b\u402c\u402d\u402e\u402f\u4030\u4031\u4032\u4033\u4034\u4035\u4036\u4037\u4038\u4039\u403a\u403b\u403c\u403d\u403e\u403f\u4040\u4041\u4042\u4043\u4044\u4045\u4046\u4047\u4048\u4049\u404a\u404b\u404c\u404d\u404e\u404f\u4050\u4051\u4052\u4053\u4054\u4055\u4056\u4057\u4058\u4059\u405a\u405b\u405c\u405d\u405e\u405f\u4060\u4061\u4062\u4063\u4064\u4065\u4066\u4067\u4068\u4069\u406a\u406b\u406c\u406d\u406e\u406f\u4070\u4071\u4072\u4073\u4074\u4075\u4076\u4077\u4078\u4079\u407a\u407b\u407c\u407d\u407e\u407f\u4080\u4081\u4082\u4083\u4084\u4085\u4086\u4087\u4088\u4089\u408a\u408b\u408c\u408d\u408e\u408f\u4090\u4091\u4092\u4093\u4094\u4095\u4096\u4097\u4098\u4099\u409a\u409b\u409c\u409d\u409e\u409f\u40a0\u40a1\u40a2\u40a3\u40a4\u40a5\u40a6\u40a7\u40a8\u40a9\u40aa\u40ab\u40ac\u40ad\u40ae\u40af\u40b0\u40b1\u40b2\u40b3\u40b4\u40b5\u40b6\u40b7\u40b8\u40b9\u40ba\u40bb\u40bc\u40bd\u40be\u40bf\u40c0\u40c1\u40c2\u40c3\u40c4\u40c5\u40c6\u40c7\u40c8\u40c9\u40ca\u40cb\u40cc\u40cd\u40ce\u40cf\u40d0\u40d1\u40d2\u40d3\u40d4\u40d5\u40d6\u40d7\u40d8\u40d9\u40da\u40db\u40dc\u40dd\u40de\u40df\u40e0\u40e1\u40e2\u40e3\u40e4\u40e5\u40e6\u40e7\u40e8\u40e9\u40ea\u40eb\u40ec\u40ed\u40ee\u40ef\u40f0\u40f1\u40f2\u40f3\u40f4\u40f5\u40f6\u40f7\u40f8\u40f9\u40fa\u40fb\u40fc\u40fd\u40fe\u40ff\u4100\u4101\u4102\u4103\u4104\u4105\u4106\u4107\u4108\u4109\u410a\u410b\u410c\u410d\u410e\u410f\u4110\u4111\u4112\u4113\u4114\u4115\u4116\u4117\u4118\u4119\u411a\u411b\u411c\u411d\u411e\u411f\u4120\u4121\u4122\u4123\u4124\u4125\u4126\u4127\u4128\u4129\u412a\u412b\u412c\u412d\u412e\u412f\u4130\u4131\u4132\u4133\u4134\u4135\u4136\u4137\u4138\u4139\u413a\u413b\u413c\u413d\u413e\u413f\u4140\u4141\u4142\u4143\u4144\u4145\u4146\u4147\u4148\u4149\u414a\u414b\u414c\u414d\u414e\u414f\u4150\u4151\u4152\u4153\u4154\u4155\u4156\u4157\u4158\u4159\u415a\u415b\u415c\u415d\u415e\u415f\u4160\u4161\u4162\u4163\u4164\u4165\u4166\u4167\u4168\u4169\u416a\u416b\u416c\u416d\u416e\u416f\u4170\u4171\u4172\u4173\u4174\u4175\u4176\u4177\u4178\u4179\u417a\u417b\u417c\u417d\u417e\u417f\u4180\u4181\u4182\u4183\u4184\u4185\u4186\u4187\u4188\u4189\u418a\u418b\u418c\u418d\u418e\u418f\u4190\u4191\u4192\u4193\u4194\u4195\u4196\u4197\u4198\u4199\u419a\u419b\u419c\u419d\u419e\u419f\u41a0\u41a1\u41a2\u41a3\u41a4\u41a5\u41a6\u41a7\u41a8\u41a9\u41aa\u41ab\u41ac\u41ad\u41ae\u41af\u41b0\u41b1\u41b2\u41b3\u41b4\u41b5\u41b6\u41b7\u41b8\u41b9\u41ba\u41bb\u41bc\u41bd\u41be\u41bf\u41c0\u41c1\u41c2\u41c3\u41c4\u41c5\u41c6\u41c7\u41c8\u41c9\u41ca\u41cb\u41cc\u41cd\u41ce\u41cf\u41d0\u41d1\u41d2\u41d3\u41d4\u41d5\u41d6\u41d7\u41d8\u41d9\u41da\u41db\u41dc\u41dd\u41de\u41df\u41e0\u41e1\u41e2\u41e3\u41e4\u41e5\u41e6\u41e7\u41e8\u41e9\u41ea\u41eb\u41ec\u41ed\u41ee\u41ef\u41f0\u41f1\u41f2\u41f3\u41f4\u41f5\u41f6\u41f7\u41f8\u41f9\u41fa\u41fb\u41fc\u41fd\u41fe\u41ff\u4200\u4201\u4202\u4203\u4204\u4205\u4206\u4207\u4208\u4209\u420a\u420b\u420c\u420d\u420e\u420f\u4210\u4211\u4212\u4213\u4214\u4215\u4216\u4217\u4218\u4219\u421a\u421b\u421c\u421d\u421e\u421f\u4220\u4221\u4222\u4223\u4224\u4225\u4226\u4227\u4228\u4229\u422a\u422b\u422c\u422d\u422e\u422f\u4230\u4231\u4232\u4233\u4234\u4235\u4236\u4237\u4238\u4239\u423a\u423b\u423c\u423d\u423e\u423f\u4240\u4241\u4242\u4243\u4244\u4245\u4246\u4247\u4248\u4249\u424a\u424b\u424c\u424d\u424e\u424f\u4250\u4251\u4252\u4253\u4254\u4255\u4256\u4257\u4258\u4259\u425a\u425b\u425c\u425d\u425e\u425f\u4260\u4261\u4262\u4263\u4264\u4265\u4266\u4267\u4268\u4269\u426a\u426b\u426c\u426d\u426e\u426f\u4270\u4271\u4272\u4273\u4274\u4275\u4276\u4277\u4278\u4279\u427a\u427b\u427c\u427d\u427e\u427f\u4280\u4281\u4282\u4283\u4284\u4285\u4286\u4287\u4288\u4289\u428a\u428b\u428c\u428d\u428e\u428f\u4290\u4291\u4292\u4293\u4294\u4295\u4296\u4297\u4298\u4299\u429a\u429b\u429c\u429d\u429e\u429f\u42a0\u42a1\u42a2\u42a3\u42a4\u42a5\u42a6\u42a7\u42a8\u42a9\u42aa\u42ab\u42ac\u42ad\u42ae\u42af\u42b0\u42b1\u42b2\u42b3\u42b4\u42b5\u42b6\u42b7\u42b8\u42b9\u42ba\u42bb\u42bc\u42bd\u42be\u42bf\u42c0\u42c1\u42c2\u42c3\u42c4\u42c5\u42c6\u42c7\u42c8\u42c9\u42ca\u42cb\u42cc\u42cd\u42ce\u42cf\u42d0\u42d1\u42d2\u42d3\u42d4\u42d5\u42d6\u42d7\u42d8\u42d9\u42da\u42db\u42dc\u42dd\u42de\u42df\u42e0\u42e1\u42e2\u42e3\u42e4\u42e5\u42e6\u42e7\u42e8\u42e9\u42ea\u42eb\u42ec\u42ed\u42ee\u42ef\u42f0\u42f1\u42f2\u42f3\u42f4\u42f5\u42f6\u42f7\u42f8\u42f9\u42fa\u42fb\u42fc\u42fd\u42fe\u42ff\u4300\u4301\u4302\u4303\u4304\u4305\u4306\u4307\u4308\u4309\u430a\u430b\u430c\u430d\u430e\u430f\u4310\u4311\u4312\u4313\u4314\u4315\u4316\u4317\u4318\u4319\u431a\u431b\u431c\u431d\u431e\u431f\u4320\u4321\u4322\u4323\u4324\u4325\u4326\u4327\u4328\u4329\u432a\u432b\u432c\u432d\u432e\u432f\u4330\u4331\u4332\u4333\u4334\u4335\u4336\u4337\u4338\u4339\u433a\u433b\u433c\u433d\u433e\u433f\u4340\u4341\u4342\u4343\u4344\u4345\u4346\u4347\u4348\u4349\u434a\u434b\u434c\u434d\u434e\u434f\u4350\u4351\u4352\u4353\u4354\u4355\u4356\u4357\u4358\u4359\u435a\u435b\u435c\u435d\u435e\u435f\u4360\u4361\u4362\u4363\u4364\u4365\u4366\u4367\u4368\u4369\u436a\u436b\u436c\u436d\u436e\u436f\u4370\u4371\u4372\u4373\u4374\u4375\u4376\u4377\u4378\u4379\u437a\u437b\u437c\u437d\u437e\u437f\u4380\u4381\u4382\u4383\u4384\u4385\u4386\u4387\u4388\u4389\u438a\u438b\u438c\u438d\u438e\u438f\u4390\u4391\u4392\u4393\u4394\u4395\u4396\u4397\u4398\u4399\u439a\u439b\u439c\u439d\u439e\u439f\u43a0\u43a1\u43a2\u43a3\u43a4\u43a5\u43a6\u43a7\u43a8\u43a9\u43aa\u43ab\u43ac\u43ad\u43ae\u43af\u43b0\u43b1\u43b2\u43b3\u43b4\u43b5\u43b6\u43b7\u43b8\u43b9\u43ba\u43bb\u43bc\u43bd\u43be\u43bf\u43c0\u43c1\u43c2\u43c3\u43c4\u43c5\u43c6\u43c7\u43c8\u43c9\u43ca\u43cb\u43cc\u43cd\u43ce\u43cf\u43d0\u43d1\u43d2\u43d3\u43d4\u43d5\u43d6\u43d7\u43d8\u43d9\u43da\u43db\u43dc\u43dd\u43de\u43df\u43e0\u43e1\u43e2\u43e3\u43e4\u43e5\u43e6\u43e7\u43e8\u43e9\u43ea\u43eb\u43ec\u43ed\u43ee\u43ef\u43f0\u43f1\u43f2\u43f3\u43f4\u43f5\u43f6\u43f7\u43f8\u43f9\u43fa\u43fb\u43fc\u43fd\u43fe\u43ff\u4400\u4401\u4402\u4403\u4404\u4405\u4406\u4407\u4408\u4409\u440a\u440b\u440c\u440d\u440e\u440f\u4410\u4411\u4412\u4413\u4414\u4415\u4416\u4417\u4418\u4419\u441a\u441b\u441c\u441d\u441e\u441f\u4420\u4421\u4422\u4423\u4424\u4425\u4426\u4427\u4428\u4429\u442a\u442b\u442c\u442d\u442e\u442f\u4430\u4431\u4432\u4433\u4434\u4435\u4436\u4437\u4438\u4439\u443a\u443b\u443c\u443d\u443e\u443f\u4440\u4441\u4442\u4443\u4444\u4445\u4446\u4447\u4448\u4449\u444a\u444b\u444c\u444d\u444e\u444f\u4450\u4451\u4452\u4453\u4454\u4455\u4456\u4457\u4458\u4459\u445a\u445b\u445c\u445d\u445e\u445f\u4460\u4461\u4462\u4463\u4464\u4465\u4466\u4467\u4468\u4469\u446a\u446b\u446c\u446d\u446e\u446f\u4470\u4471\u4472\u4473\u4474\u4475\u4476\u4477\u4478\u4479\u447a\u447b\u447c\u447d\u447e\u447f\u4480\u4481\u4482\u4483\u4484\u4485\u4486\u4487\u4488\u4489\u448a\u448b\u448c\u448d\u448e\u448f\u4490\u4491\u4492\u4493\u4494\u4495\u4496\u4497\u4498\u4499\u449a\u449b\u449c\u449d\u449e\u449f\u44a0\u44a1\u44a2\u44a3\u44a4\u44a5\u44a6\u44a7\u44a8\u44a9\u44aa\u44ab\u44ac\u44ad\u44ae\u44af\u44b0\u44b1\u44b2\u44b3\u44b4\u44b5\u44b6\u44b7\u44b8\u44b9\u44ba\u44bb\u44bc\u44bd\u44be\u44bf\u44c0\u44c1\u44c2\u44c3\u44c4\u44c5\u44c6\u44c7\u44c8\u44c9\u44ca\u44cb\u44cc\u44cd\u44ce\u44cf\u44d0\u44d1\u44d2\u44d3\u44d4\u44d5\u44d6\u44d7\u44d8\u44d9\u44da\u44db\u44dc\u44dd\u44de\u44df\u44e0\u44e1\u44e2\u44e3\u44e4\u44e5\u44e6\u44e7\u44e8\u44e9\u44ea\u44eb\u44ec\u44ed\u44ee\u44ef\u44f0\u44f1\u44f2\u44f3\u44f4\u44f5\u44f6\u44f7\u44f8\u44f9\u44fa\u44fb\u44fc\u44fd\u44fe\u44ff\u4500\u4501\u4502\u4503\u4504\u4505\u4506\u4507\u4508\u4509\u450a\u450b\u450c\u450d\u450e\u450f\u4510\u4511\u4512\u4513\u4514\u4515\u4516\u4517\u4518\u4519\u451a\u451b\u451c\u451d\u451e\u451f\u4520\u4521\u4522\u4523\u4524\u4525\u4526\u4527\u4528\u4529\u452a\u452b\u452c\u452d\u452e\u452f\u4530\u4531\u4532\u4533\u4534\u4535\u4536\u4537\u4538\u4539\u453a\u453b\u453c\u453d\u453e\u453f\u4540\u4541\u4542\u4543\u4544\u4545\u4546\u4547\u4548\u4549\u454a\u454b\u454c\u454d\u454e\u454f\u4550\u4551\u4552\u4553\u4554\u4555\u4556\u4557\u4558\u4559\u455a\u455b\u455c\u455d\u455e\u455f\u4560\u4561\u4562\u4563\u4564\u4565\u4566\u4567\u4568\u4569\u456a\u456b\u456c\u456d\u456e\u456f\u4570\u4571\u4572\u4573\u4574\u4575\u4576\u4577\u4578\u4579\u457a\u457b\u457c\u457d\u457e\u457f\u4580\u4581\u4582\u4583\u4584\u4585\u4586\u4587\u4588\u4589\u458a\u458b\u458c\u458d\u458e\u458f\u4590\u4591\u4592\u4593\u4594\u4595\u4596\u4597\u4598\u4599\u459a\u459b\u459c\u459d\u459e\u459f\u45a0\u45a1\u45a2\u45a3\u45a4\u45a5\u45a6\u45a7\u45a8\u45a9\u45aa\u45ab\u45ac\u45ad\u45ae\u45af\u45b0\u45b1\u45b2\u45b3\u45b4\u45b5\u45b6\u45b7\u45b8\u45b9\u45ba\u45bb\u45bc\u45bd\u45be\u45bf\u45c0\u45c1\u45c2\u45c3\u45c4\u45c5\u45c6\u45c7\u45c8\u45c9\u45ca\u45cb\u45cc\u45cd\u45ce\u45cf\u45d0\u45d1\u45d2\u45d3\u45d4\u45d5\u45d6\u45d7\u45d8\u45d9\u45da\u45db\u45dc\u45dd\u45de\u45df\u45e0\u45e1\u45e2\u45e3\u45e4\u45e5\u45e6\u45e7\u45e8\u45e9\u45ea\u45eb\u45ec\u45ed\u45ee\u45ef\u45f0\u45f1\u45f2\u45f3\u45f4\u45f5\u45f6\u45f7\u45f8\u45f9\u45fa\u45fb\u45fc\u45fd\u45fe\u45ff\u4600\u4601\u4602\u4603\u4604\u4605\u4606\u4607\u4608\u4609\u460a\u460b\u460c\u460d\u460e\u460f\u4610\u4611\u4612\u4613\u4614\u4615\u4616\u4617\u4618\u4619\u461a\u461b\u461c\u461d\u461e\u461f\u4620\u4621\u4622\u4623\u4624\u4625\u4626\u4627\u4628\u4629\u462a\u462b\u462c\u462d\u462e\u462f\u4630\u4631\u4632\u4633\u4634\u4635\u4636\u4637\u4638\u4639\u463a\u463b\u463c\u463d\u463e\u463f\u4640\u4641\u4642\u4643\u4644\u4645\u4646\u4647\u4648\u4649\u464a\u464b\u464c\u464d\u464e\u464f\u4650\u4651\u4652\u4653\u4654\u4655\u4656\u4657\u4658\u4659\u465a\u465b\u465c\u465d\u465e\u465f\u4660\u4661\u4662\u4663\u4664\u4665\u4666\u4667\u4668\u4669\u466a\u466b\u466c\u466d\u466e\u466f\u4670\u4671\u4672\u4673\u4674\u4675\u4676\u4677\u4678\u4679\u467a\u467b\u467c\u467d\u467e\u467f\u4680\u4681\u4682\u4683\u4684\u4685\u4686\u4687\u4688\u4689\u468a\u468b\u468c\u468d\u468e\u468f\u4690\u4691\u4692\u4693\u4694\u4695\u4696\u4697\u4698\u4699\u469a\u469b\u469c\u469d\u469e\u469f\u46a0\u46a1\u46a2\u46a3\u46a4\u46a5\u46a6\u46a7\u46a8\u46a9\u46aa\u46ab\u46ac\u46ad\u46ae\u46af\u46b0\u46b1\u46b2\u46b3\u46b4\u46b5\u46b6\u46b7\u46b8\u46b9\u46ba\u46bb\u46bc\u46bd\u46be\u46bf\u46c0\u46c1\u46c2\u46c3\u46c4\u46c5\u46c6\u46c7\u46c8\u46c9\u46ca\u46cb\u46cc\u46cd\u46ce\u46cf\u46d0\u46d1\u46d2\u46d3\u46d4\u46d5\u46d6\u46d7\u46d8\u46d9\u46da\u46db\u46dc\u46dd\u46de\u46df\u46e0\u46e1\u46e2\u46e3\u46e4\u46e5\u46e6\u46e7\u46e8\u46e9\u46ea\u46eb\u46ec\u46ed\u46ee\u46ef\u46f0\u46f1\u46f2\u46f3\u46f4\u46f5\u46f6\u46f7\u46f8\u46f9\u46fa\u46fb\u46fc\u46fd\u46fe\u46ff\u4700\u4701\u4702\u4703\u4704\u4705\u4706\u4707\u4708\u4709\u470a\u470b\u470c\u470d\u470e\u470f\u4710\u4711\u4712\u4713\u4714\u4715\u4716\u4717\u4718\u4719\u471a\u471b\u471c\u471d\u471e\u471f\u4720\u4721\u4722\u4723\u4724\u4725\u4726\u4727\u4728\u4729\u472a\u472b\u472c\u472d\u472e\u472f\u4730\u4731\u4732\u4733\u4734\u4735\u4736\u4737\u4738\u4739\u473a\u473b\u473c\u473d\u473e\u473f\u4740\u4741\u4742\u4743\u4744\u4745\u4746\u4747\u4748\u4749\u474a\u474b\u474c\u474d\u474e\u474f\u4750\u4751\u4752\u4753\u4754\u4755\u4756\u4757\u4758\u4759\u475a\u475b\u475c\u475d\u475e\u475f\u4760\u4761\u4762\u4763\u4764\u4765\u4766\u4767\u4768\u4769\u476a\u476b\u476c\u476d\u476e\u476f\u4770\u4771\u4772\u4773\u4774\u4775\u4776\u4777\u4778\u4779\u477a\u477b\u477c\u477d\u477e\u477f\u4780\u4781\u4782\u4783\u4784\u4785\u4786\u4787\u4788\u4789\u478a\u478b\u478c\u478d\u478e\u478f\u4790\u4791\u4792\u4793\u4794\u4795\u4796\u4797\u4798\u4799\u479a\u479b\u479c\u479d\u479e\u479f\u47a0\u47a1\u47a2\u47a3\u47a4\u47a5\u47a6\u47a7\u47a8\u47a9\u47aa\u47ab\u47ac\u47ad\u47ae\u47af\u47b0\u47b1\u47b2\u47b3\u47b4\u47b5\u47b6\u47b7\u47b8\u47b9\u47ba\u47bb\u47bc\u47bd\u47be\u47bf\u47c0\u47c1\u47c2\u47c3\u47c4\u47c5\u47c6\u47c7\u47c8\u47c9\u47ca\u47cb\u47cc\u47cd\u47ce\u47cf\u47d0\u47d1\u47d2\u47d3\u47d4\u47d5\u47d6\u47d7\u47d8\u47d9\u47da\u47db\u47dc\u47dd\u47de\u47df\u47e0\u47e1\u47e2\u47e3\u47e4\u47e5\u47e6\u47e7\u47e8\u47e9\u47ea\u47eb\u47ec\u47ed\u47ee\u47ef\u47f0\u47f1\u47f2\u47f3\u47f4\u47f5\u47f6\u47f7\u47f8\u47f9\u47fa\u47fb\u47fc\u47fd\u47fe\u47ff\u4800\u4801\u4802\u4803\u4804\u4805\u4806\u4807\u4808\u4809\u480a\u480b\u480c\u480d\u480e\u480f\u4810\u4811\u4812\u4813\u4814\u4815\u4816\u4817\u4818\u4819\u481a\u481b\u481c\u481d\u481e\u481f\u4820\u4821\u4822\u4823\u4824\u4825\u4826\u4827\u4828\u4829\u482a\u482b\u482c\u482d\u482e\u482f\u4830\u4831\u4832\u4833\u4834\u4835\u4836\u4837\u4838\u4839\u483a\u483b\u483c\u483d\u483e\u483f\u4840\u4841\u4842\u4843\u4844\u4845\u4846\u4847\u4848\u4849\u484a\u484b\u484c\u484d\u484e\u484f\u4850\u4851\u4852\u4853\u4854\u4855\u4856\u4857\u4858\u4859\u485a\u485b\u485c\u485d\u485e\u485f\u4860\u4861\u4862\u4863\u4864\u4865\u4866\u4867\u4868\u4869\u486a\u486b\u486c\u486d\u486e\u486f\u4870\u4871\u4872\u4873\u4874\u4875\u4876\u4877\u4878\u4879\u487a\u487b\u487c\u487d\u487e\u487f\u4880\u4881\u4882\u4883\u4884\u4885\u4886\u4887\u4888\u4889\u488a\u488b\u488c\u488d\u488e\u488f\u4890\u4891\u4892\u4893\u4894\u4895\u4896\u4897\u4898\u4899\u489a\u489b\u489c\u489d\u489e\u489f\u48a0\u48a1\u48a2\u48a3\u48a4\u48a5\u48a6\u48a7\u48a8\u48a9\u48aa\u48ab\u48ac\u48ad\u48ae\u48af\u48b0\u48b1\u48b2\u48b3\u48b4\u48b5\u48b6\u48b7\u48b8\u48b9\u48ba\u48bb\u48bc\u48bd\u48be\u48bf\u48c0\u48c1\u48c2\u48c3\u48c4\u48c5\u48c6\u48c7\u48c8\u48c9\u48ca\u48cb\u48cc\u48cd\u48ce\u48cf\u48d0\u48d1\u48d2\u48d3\u48d4\u48d5\u48d6\u48d7\u48d8\u48d9\u48da\u48db\u48dc\u48dd\u48de\u48df\u48e0\u48e1\u48e2\u48e3\u48e4\u48e5\u48e6\u48e7\u48e8\u48e9\u48ea\u48eb\u48ec\u48ed\u48ee\u48ef\u48f0\u48f1\u48f2\u48f3\u48f4\u48f5\u48f6\u48f7\u48f8\u48f9\u48fa\u48fb\u48fc\u48fd\u48fe\u48ff\u4900\u4901\u4902\u4903\u4904\u4905\u4906\u4907\u4908\u4909\u490a\u490b\u490c\u490d\u490e\u490f\u4910\u4911\u4912\u4913\u4914\u4915\u4916\u4917\u4918\u4919\u491a\u491b\u491c\u491d\u491e\u491f\u4920\u4921\u4922\u4923\u4924\u4925\u4926\u4927\u4928\u4929\u492a\u492b\u492c\u492d\u492e\u492f\u4930\u4931\u4932\u4933\u4934\u4935\u4936\u4937\u4938\u4939\u493a\u493b\u493c\u493d\u493e\u493f\u4940\u4941\u4942\u4943\u4944\u4945\u4946\u4947\u4948\u4949\u494a\u494b\u494c\u494d\u494e\u494f\u4950\u4951\u4952\u4953\u4954\u4955\u4956\u4957\u4958\u4959\u495a\u495b\u495c\u495d\u495e\u495f\u4960\u4961\u4962\u4963\u4964\u4965\u4966\u4967\u4968\u4969\u496a\u496b\u496c\u496d\u496e\u496f\u4970\u4971\u4972\u4973\u4974\u4975\u4976\u4977\u4978\u4979\u497a\u497b\u497c\u497d\u497e\u497f\u4980\u4981\u4982\u4983\u4984\u4985\u4986\u4987\u4988\u4989\u498a\u498b\u498c\u498d\u498e\u498f\u4990\u4991\u4992\u4993\u4994\u4995\u4996\u4997\u4998\u4999\u499a\u499b\u499c\u499d\u499e\u499f\u49a0\u49a1\u49a2\u49a3\u49a4\u49a5\u49a6\u49a7\u49a8\u49a9\u49aa\u49ab\u49ac\u49ad\u49ae\u49af\u49b0\u49b1\u49b2\u49b3\u49b4\u49b5\u49b6\u49b7\u49b8\u49b9\u49ba\u49bb\u49bc\u49bd\u49be\u49bf\u49c0\u49c1\u49c2\u49c3\u49c4\u49c5\u49c6\u49c7\u49c8\u49c9\u49ca\u49cb\u49cc\u49cd\u49ce\u49cf\u49d0\u49d1\u49d2\u49d3\u49d4\u49d5\u49d6\u49d7\u49d8\u49d9\u49da\u49db\u49dc\u49dd\u49de\u49df\u49e0\u49e1\u49e2\u49e3\u49e4\u49e5\u49e6\u49e7\u49e8\u49e9\u49ea\u49eb\u49ec\u49ed\u49ee\u49ef\u49f0\u49f1\u49f2\u49f3\u49f4\u49f5\u49f6\u49f7\u49f8\u49f9\u49fa\u49fb\u49fc\u49fd\u49fe\u49ff\u4a00\u4a01\u4a02\u4a03\u4a04\u4a05\u4a06\u4a07\u4a08\u4a09\u4a0a\u4a0b\u4a0c\u4a0d\u4a0e\u4a0f\u4a10\u4a11\u4a12\u4a13\u4a14\u4a15\u4a16\u4a17\u4a18\u4a19\u4a1a\u4a1b\u4a1c\u4a1d\u4a1e\u4a1f\u4a20\u4a21\u4a22\u4a23\u4a24\u4a25\u4a26\u4a27\u4a28\u4a29\u4a2a\u4a2b\u4a2c\u4a2d\u4a2e\u4a2f\u4a30\u4a31\u4a32\u4a33\u4a34\u4a35\u4a36\u4a37\u4a38\u4a39\u4a3a\u4a3b\u4a3c\u4a3d\u4a3e\u4a3f\u4a40\u4a41\u4a42\u4a43\u4a44\u4a45\u4a46\u4a47\u4a48\u4a49\u4a4a\u4a4b\u4a4c\u4a4d\u4a4e\u4a4f\u4a50\u4a51\u4a52\u4a53\u4a54\u4a55\u4a56\u4a57\u4a58\u4a59\u4a5a\u4a5b\u4a5c\u4a5d\u4a5e\u4a5f\u4a60\u4a61\u4a62\u4a63\u4a64\u4a65\u4a66\u4a67\u4a68\u4a69\u4a6a\u4a6b\u4a6c\u4a6d\u4a6e\u4a6f\u4a70\u4a71\u4a72\u4a73\u4a74\u4a75\u4a76\u4a77\u4a78\u4a79\u4a7a\u4a7b\u4a7c\u4a7d\u4a7e\u4a7f\u4a80\u4a81\u4a82\u4a83\u4a84\u4a85\u4a86\u4a87\u4a88\u4a89\u4a8a\u4a8b\u4a8c\u4a8d\u4a8e\u4a8f\u4a90\u4a91\u4a92\u4a93\u4a94\u4a95\u4a96\u4a97\u4a98\u4a99\u4a9a\u4a9b\u4a9c\u4a9d\u4a9e\u4a9f\u4aa0\u4aa1\u4aa2\u4aa3\u4aa4\u4aa5\u4aa6\u4aa7\u4aa8\u4aa9\u4aaa\u4aab\u4aac\u4aad\u4aae\u4aaf\u4ab0\u4ab1\u4ab2\u4ab3\u4ab4\u4ab5\u4ab6\u4ab7\u4ab8\u4ab9\u4aba\u4abb\u4abc\u4abd\u4abe\u4abf\u4ac0\u4ac1\u4ac2\u4ac3\u4ac4\u4ac5\u4ac6\u4ac7\u4ac8\u4ac9\u4aca\u4acb\u4acc\u4acd\u4ace\u4acf\u4ad0\u4ad1\u4ad2\u4ad3\u4ad4\u4ad5\u4ad6\u4ad7\u4ad8\u4ad9\u4ada\u4adb\u4adc\u4add\u4ade\u4adf\u4ae0\u4ae1\u4ae2\u4ae3\u4ae4\u4ae5\u4ae6\u4ae7\u4ae8\u4ae9\u4aea\u4aeb\u4aec\u4aed\u4aee\u4aef\u4af0\u4af1\u4af2\u4af3\u4af4\u4af5\u4af6\u4af7\u4af8\u4af9\u4afa\u4afb\u4afc\u4afd\u4afe\u4aff\u4b00\u4b01\u4b02\u4b03\u4b04\u4b05\u4b06\u4b07\u4b08\u4b09\u4b0a\u4b0b\u4b0c\u4b0d\u4b0e\u4b0f\u4b10\u4b11\u4b12\u4b13\u4b14\u4b15\u4b16\u4b17\u4b18\u4b19\u4b1a\u4b1b\u4b1c\u4b1d\u4b1e\u4b1f\u4b20\u4b21\u4b22\u4b23\u4b24\u4b25\u4b26\u4b27\u4b28\u4b29\u4b2a\u4b2b\u4b2c\u4b2d\u4b2e\u4b2f\u4b30\u4b31\u4b32\u4b33\u4b34\u4b35\u4b36\u4b37\u4b38\u4b39\u4b3a\u4b3b\u4b3c\u4b3d\u4b3e\u4b3f\u4b40\u4b41\u4b42\u4b43\u4b44\u4b45\u4b46\u4b47\u4b48\u4b49\u4b4a\u4b4b\u4b4c\u4b4d\u4b4e\u4b4f\u4b50\u4b51\u4b52\u4b53\u4b54\u4b55\u4b56\u4b57\u4b58\u4b59\u4b5a\u4b5b\u4b5c\u4b5d\u4b5e\u4b5f\u4b60\u4b61\u4b62\u4b63\u4b64\u4b65\u4b66\u4b67\u4b68\u4b69\u4b6a\u4b6b\u4b6c\u4b6d\u4b6e\u4b6f\u4b70\u4b71\u4b72\u4b73\u4b74\u4b75\u4b76\u4b77\u4b78\u4b79\u4b7a\u4b7b\u4b7c\u4b7d\u4b7e\u4b7f\u4b80\u4b81\u4b82\u4b83\u4b84\u4b85\u4b86\u4b87\u4b88\u4b89\u4b8a\u4b8b\u4b8c\u4b8d\u4b8e\u4b8f\u4b90\u4b91\u4b92\u4b93\u4b94\u4b95\u4b96\u4b97\u4b98\u4b99\u4b9a\u4b9b\u4b9c\u4b9d\u4b9e\u4b9f\u4ba0\u4ba1\u4ba2\u4ba3\u4ba4\u4ba5\u4ba6\u4ba7\u4ba8\u4ba9\u4baa\u4bab\u4bac\u4bad\u4bae\u4baf\u4bb0\u4bb1\u4bb2\u4bb3\u4bb4\u4bb5\u4bb6\u4bb7\u4bb8\u4bb9\u4bba\u4bbb\u4bbc\u4bbd\u4bbe\u4bbf\u4bc0\u4bc1\u4bc2\u4bc3\u4bc4\u4bc5\u4bc6\u4bc7\u4bc8\u4bc9\u4bca\u4bcb\u4bcc\u4bcd\u4bce\u4bcf\u4bd0\u4bd1\u4bd2\u4bd3\u4bd4\u4bd5\u4bd6\u4bd7\u4bd8\u4bd9\u4bda\u4bdb\u4bdc\u4bdd\u4bde\u4bdf\u4be0\u4be1\u4be2\u4be3\u4be4\u4be5\u4be6\u4be7\u4be8\u4be9\u4bea\u4beb\u4bec\u4bed\u4bee\u4bef\u4bf0\u4bf1\u4bf2\u4bf3\u4bf4\u4bf5\u4bf6\u4bf7\u4bf8\u4bf9\u4bfa\u4bfb\u4bfc\u4bfd\u4bfe\u4bff\u4c00\u4c01\u4c02\u4c03\u4c04\u4c05\u4c06\u4c07\u4c08\u4c09\u4c0a\u4c0b\u4c0c\u4c0d\u4c0e\u4c0f\u4c10\u4c11\u4c12\u4c13\u4c14\u4c15\u4c16\u4c17\u4c18\u4c19\u4c1a\u4c1b\u4c1c\u4c1d\u4c1e\u4c1f\u4c20\u4c21\u4c22\u4c23\u4c24\u4c25\u4c26\u4c27\u4c28\u4c29\u4c2a\u4c2b\u4c2c\u4c2d\u4c2e\u4c2f\u4c30\u4c31\u4c32\u4c33\u4c34\u4c35\u4c36\u4c37\u4c38\u4c39\u4c3a\u4c3b\u4c3c\u4c3d\u4c3e\u4c3f\u4c40\u4c41\u4c42\u4c43\u4c44\u4c45\u4c46\u4c47\u4c48\u4c49\u4c4a\u4c4b\u4c4c\u4c4d\u4c4e\u4c4f\u4c50\u4c51\u4c52\u4c53\u4c54\u4c55\u4c56\u4c57\u4c58\u4c59\u4c5a\u4c5b\u4c5c\u4c5d\u4c5e\u4c5f\u4c60\u4c61\u4c62\u4c63\u4c64\u4c65\u4c66\u4c67\u4c68\u4c69\u4c6a\u4c6b\u4c6c\u4c6d\u4c6e\u4c6f\u4c70\u4c71\u4c72\u4c73\u4c74\u4c75\u4c76\u4c77\u4c78\u4c79\u4c7a\u4c7b\u4c7c\u4c7d\u4c7e\u4c7f\u4c80\u4c81\u4c82\u4c83\u4c84\u4c85\u4c86\u4c87\u4c88\u4c89\u4c8a\u4c8b\u4c8c\u4c8d\u4c8e\u4c8f\u4c90\u4c91\u4c92\u4c93\u4c94\u4c95\u4c96\u4c97\u4c98\u4c99\u4c9a\u4c9b\u4c9c\u4c9d\u4c9e\u4c9f\u4ca0\u4ca1\u4ca2\u4ca3\u4ca4\u4ca5\u4ca6\u4ca7\u4ca8\u4ca9\u4caa\u4cab\u4cac\u4cad\u4cae\u4caf\u4cb0\u4cb1\u4cb2\u4cb3\u4cb4\u4cb5\u4cb6\u4cb7\u4cb8\u4cb9\u4cba\u4cbb\u4cbc\u4cbd\u4cbe\u4cbf\u4cc0\u4cc1\u4cc2\u4cc3\u4cc4\u4cc5\u4cc6\u4cc7\u4cc8\u4cc9\u4cca\u4ccb\u4ccc\u4ccd\u4cce\u4ccf\u4cd0\u4cd1\u4cd2\u4cd3\u4cd4\u4cd5\u4cd6\u4cd7\u4cd8\u4cd9\u4cda\u4cdb\u4cdc\u4cdd\u4cde\u4cdf\u4ce0\u4ce1\u4ce2\u4ce3\u4ce4\u4ce5\u4ce6\u4ce7\u4ce8\u4ce9\u4cea\u4ceb\u4cec\u4ced\u4cee\u4cef\u4cf0\u4cf1\u4cf2\u4cf3\u4cf4\u4cf5\u4cf6\u4cf7\u4cf8\u4cf9\u4cfa\u4cfb\u4cfc\u4cfd\u4cfe\u4cff\u4d00\u4d01\u4d02\u4d03\u4d04\u4d05\u4d06\u4d07\u4d08\u4d09\u4d0a\u4d0b\u4d0c\u4d0d\u4d0e\u4d0f\u4d10\u4d11\u4d12\u4d13\u4d14\u4d15\u4d16\u4d17\u4d18\u4d19\u4d1a\u4d1b\u4d1c\u4d1d\u4d1e\u4d1f\u4d20\u4d21\u4d22\u4d23\u4d24\u4d25\u4d26\u4d27\u4d28\u4d29\u4d2a\u4d2b\u4d2c\u4d2d\u4d2e\u4d2f\u4d30\u4d31\u4d32\u4d33\u4d34\u4d35\u4d36\u4d37\u4d38\u4d39\u4d3a\u4d3b\u4d3c\u4d3d\u4d3e\u4d3f\u4d40\u4d41\u4d42\u4d43\u4d44\u4d45\u4d46\u4d47\u4d48\u4d49\u4d4a\u4d4b\u4d4c\u4d4d\u4d4e\u4d4f\u4d50\u4d51\u4d52\u4d53\u4d54\u4d55\u4d56\u4d57\u4d58\u4d59\u4d5a\u4d5b\u4d5c\u4d5d\u4d5e\u4d5f\u4d60\u4d61\u4d62\u4d63\u4d64\u4d65\u4d66\u4d67\u4d68\u4d69\u4d6a\u4d6b\u4d6c\u4d6d\u4d6e\u4d6f\u4d70\u4d71\u4d72\u4d73\u4d74\u4d75\u4d76\u4d77\u4d78\u4d79\u4d7a\u4d7b\u4d7c\u4d7d\u4d7e\u4d7f\u4d80\u4d81\u4d82\u4d83\u4d84\u4d85\u4d86\u4d87\u4d88\u4d89\u4d8a\u4d8b\u4d8c\u4d8d\u4d8e\u4d8f\u4d90\u4d91\u4d92\u4d93\u4d94\u4d95\u4d96\u4d97\u4d98\u4d99\u4d9a\u4d9b\u4d9c\u4d9d\u4d9e\u4d9f\u4da0\u4da1\u4da2\u4da3\u4da4\u4da5\u4da6\u4da7\u4da8\u4da9\u4daa\u4dab\u4dac\u4dad\u4dae\u4daf\u4db0\u4db1\u4db2\u4db3\u4db4\u4db5\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d\u4e0e\u4e0f\u4e10\u4e11\u4e12\u4e13\u4e14\u4e15\u4e16\u4e17\u4e18\u4e19\u4e1a\u4e1b\u4e1c\u4e1d\u4e1e\u4e1f\u4e20\u4e21\u4e22\u4e23\u4e24\u4e25\u4e26\u4e27\u4e28\u4e29\u4e2a\u4e2b\u4e2c\u4e2d\u4e2e\u4e2f\u4e30\u4e31\u4e32\u4e33\u4e34\u4e35\u4e36\u4e37\u4e38\u4e39\u4e3a\u4e3b\u4e3c\u4e3d\u4e3e\u4e3f\u4e40\u4e41\u4e42\u4e43\u4e44\u4e45\u4e46\u4e47\u4e48\u4e49\u4e4a\u4e4b\u4e4c\u4e4d\u4e4e\u4e4f\u4e50\u4e51\u4e52\u4e53\u4e54\u4e55\u4e56\u4e57\u4e58\u4e59\u4e5a\u4e5b\u4e5c\u4e5d\u4e5e\u4e5f\u4e60\u4e61\u4e62\u4e63\u4e64\u4e65\u4e66\u4e67\u4e68\u4e69\u4e6a\u4e6b\u4e6c\u4e6d\u4e6e\u4e6f\u4e70\u4e71\u4e72\u4e73\u4e74\u4e75\u4e76\u4e77\u4e78\u4e79\u4e7a\u4e7b\u4e7c\u4e7d\u4e7e\u4e7f\u4e80\u4e81\u4e82\u4e83\u4e84\u4e85\u4e86\u4e87\u4e88\u4e89\u4e8a\u4e8b\u4e8c\u4e8d\u4e8e\u4e8f\u4e90\u4e91\u4e92\u4e93\u4e94\u4e95\u4e96\u4e97\u4e98\u4e99\u4e9a\u4e9b\u4e9c\u4e9d\u4e9e\u4e9f\u4ea0\u4ea1\u4ea2\u4ea3\u4ea4\u4ea5\u4ea6\u4ea7\u4ea8\u4ea9\u4eaa\u4eab\u4eac\u4ead\u4eae\u4eaf\u4eb0\u4eb1\u4eb2\u4eb3\u4eb4\u4eb5\u4eb6\u4eb7\u4eb8\u4eb9\u4eba\u4ebb\u4ebc\u4ebd\u4ebe\u4ebf\u4ec0\u4ec1\u4ec2\u4ec3\u4ec4\u4ec5\u4ec6\u4ec7\u4ec8\u4ec9\u4eca\u4ecb\u4ecc\u4ecd\u4ece\u4ecf\u4ed0\u4ed1\u4ed2\u4ed3\u4ed4\u4ed5\u4ed6\u4ed7\u4ed8\u4ed9\u4eda\u4edb\u4edc\u4edd\u4ede\u4edf\u4ee0\u4ee1\u4ee2\u4ee3\u4ee4\u4ee5\u4ee6\u4ee7\u4ee8\u4ee9\u4eea\u4eeb\u4eec\u4eed\u4eee\u4eef\u4ef0\u4ef1\u4ef2\u4ef3\u4ef4\u4ef5\u4ef6\u4ef7\u4ef8\u4ef9\u4efa\u4efb\u4efc\u4efd\u4efe\u4eff\u4f00\u4f01\u4f02\u4f03\u4f04\u4f05\u4f06\u4f07\u4f08\u4f09\u4f0a\u4f0b\u4f0c\u4f0d\u4f0e\u4f0f\u4f10\u4f11\u4f12\u4f13\u4f14\u4f15\u4f16\u4f17\u4f18\u4f19\u4f1a\u4f1b\u4f1c\u4f1d\u4f1e\u4f1f\u4f20\u4f21\u4f22\u4f23\u4f24\u4f25\u4f26\u4f27\u4f28\u4f29\u4f2a\u4f2b\u4f2c\u4f2d\u4f2e\u4f2f\u4f30\u4f31\u4f32\u4f33\u4f34\u4f35\u4f36\u4f37\u4f38\u4f39\u4f3a\u4f3b\u4f3c\u4f3d\u4f3e\u4f3f\u4f40\u4f41\u4f42\u4f43\u4f44\u4f45\u4f46\u4f47\u4f48\u4f49\u4f4a\u4f4b\u4f4c\u4f4d\u4f4e\u4f4f\u4f50\u4f51\u4f52\u4f53\u4f54\u4f55\u4f56\u4f57\u4f58\u4f59\u4f5a\u4f5b\u4f5c\u4f5d\u4f5e\u4f5f\u4f60\u4f61\u4f62\u4f63\u4f64\u4f65\u4f66\u4f67\u4f68\u4f69\u4f6a\u4f6b\u4f6c\u4f6d\u4f6e\u4f6f\u4f70\u4f71\u4f72\u4f73\u4f74\u4f75\u4f76\u4f77\u4f78\u4f79\u4f7a\u4f7b\u4f7c\u4f7d\u4f7e\u4f7f\u4f80\u4f81\u4f82\u4f83\u4f84\u4f85\u4f86\u4f87\u4f88\u4f89\u4f8a\u4f8b\u4f8c\u4f8d\u4f8e\u4f8f\u4f90\u4f91\u4f92\u4f93\u4f94\u4f95\u4f96\u4f97\u4f98\u4f99\u4f9a\u4f9b\u4f9c\u4f9d\u4f9e\u4f9f\u4fa0\u4fa1\u4fa2\u4fa3\u4fa4\u4fa5\u4fa6\u4fa7\u4fa8\u4fa9\u4faa\u4fab\u4fac\u4fad\u4fae\u4faf\u4fb0\u4fb1\u4fb2\u4fb3\u4fb4\u4fb5\u4fb6\u4fb7\u4fb8\u4fb9\u4fba\u4fbb\u4fbc\u4fbd\u4fbe\u4fbf\u4fc0\u4fc1\u4fc2\u4fc3\u4fc4\u4fc5\u4fc6\u4fc7\u4fc8\u4fc9\u4fca\u4fcb\u4fcc\u4fcd\u4fce\u4fcf\u4fd0\u4fd1\u4fd2\u4fd3\u4fd4\u4fd5\u4fd6\u4fd7\u4fd8\u4fd9\u4fda\u4fdb\u4fdc\u4fdd\u4fde\u4fdf\u4fe0\u4fe1\u4fe2\u4fe3\u4fe4\u4fe5\u4fe6\u4fe7\u4fe8\u4fe9\u4fea\u4feb\u4fec\u4fed\u4fee\u4fef\u4ff0\u4ff1\u4ff2\u4ff3\u4ff4\u4ff5\u4ff6\u4ff7\u4ff8\u4ff9\u4ffa\u4ffb\u4ffc\u4ffd\u4ffe\u4fff\u5000\u5001\u5002\u5003\u5004\u5005\u5006\u5007\u5008\u5009\u500a\u500b\u500c\u500d\u500e\u500f\u5010\u5011\u5012\u5013\u5014\u5015\u5016\u5017\u5018\u5019\u501a\u501b\u501c\u501d\u501e\u501f\u5020\u5021\u5022\u5023\u5024\u5025\u5026\u5027\u5028\u5029\u502a\u502b\u502c\u502d\u502e\u502f\u5030\u5031\u5032\u5033\u5034\u5035\u5036\u5037\u5038\u5039\u503a\u503b\u503c\u503d\u503e\u503f\u5040\u5041\u5042\u5043\u5044\u5045\u5046\u5047\u5048\u5049\u504a\u504b\u504c\u504d\u504e\u504f\u5050\u5051\u5052\u5053\u5054\u5055\u5056\u5057\u5058\u5059\u505a\u505b\u505c\u505d\u505e\u505f\u5060\u5061\u5062\u5063\u5064\u5065\u5066\u5067\u5068\u5069\u506a\u506b\u506c\u506d\u506e\u506f\u5070\u5071\u5072\u5073\u5074\u5075\u5076\u5077\u5078\u5079\u507a\u507b\u507c\u507d\u507e\u507f\u5080\u5081\u5082\u5083\u5084\u5085\u5086\u5087\u5088\u5089\u508a\u508b\u508c\u508d\u508e\u508f\u5090\u5091\u5092\u5093\u5094\u5095\u5096\u5097\u5098\u5099\u509a\u509b\u509c\u509d\u509e\u509f\u50a0\u50a1\u50a2\u50a3\u50a4\u50a5\u50a6\u50a7\u50a8\u50a9\u50aa\u50ab\u50ac\u50ad\u50ae\u50af\u50b0\u50b1\u50b2\u50b3\u50b4\u50b5\u50b6\u50b7\u50b8\u50b9\u50ba\u50bb\u50bc\u50bd\u50be\u50bf\u50c0\u50c1\u50c2\u50c3\u50c4\u50c5\u50c6\u50c7\u50c8\u50c9\u50ca\u50cb\u50cc\u50cd\u50ce\u50cf\u50d0\u50d1\u50d2\u50d3\u50d4\u50d5\u50d6\u50d7\u50d8\u50d9\u50da\u50db\u50dc\u50dd\u50de\u50df\u50e0\u50e1\u50e2\u50e3\u50e4\u50e5\u50e6\u50e7\u50e8\u50e9\u50ea\u50eb\u50ec\u50ed\u50ee\u50ef\u50f0\u50f1\u50f2\u50f3\u50f4\u50f5\u50f6\u50f7\u50f8\u50f9\u50fa\u50fb\u50fc\u50fd\u50fe\u50ff\u5100\u5101\u5102\u5103\u5104\u5105\u5106\u5107\u5108\u5109\u510a\u510b\u510c\u510d\u510e\u510f\u5110\u5111\u5112\u5113\u5114\u5115\u5116\u5117\u5118\u5119\u511a\u511b\u511c\u511d\u511e\u511f\u5120\u5121\u5122\u5123\u5124\u5125\u5126\u5127\u5128\u5129\u512a\u512b\u512c\u512d\u512e\u512f\u5130\u5131\u5132\u5133\u5134\u5135\u5136\u5137\u5138\u5139\u513a\u513b\u513c\u513d\u513e\u513f\u5140\u5141\u5142\u5143\u5144\u5145\u5146\u5147\u5148\u5149\u514a\u514b\u514c\u514d\u514e\u514f\u5150\u5151\u5152\u5153\u5154\u5155\u5156\u5157\u5158\u5159\u515a\u515b\u515c\u515d\u515e\u515f\u5160\u5161\u5162\u5163\u5164\u5165\u5166\u5167\u5168\u5169\u516a\u516b\u516c\u516d\u516e\u516f\u5170\u5171\u5172\u5173\u5174\u5175\u5176\u5177\u5178\u5179\u517a\u517b\u517c\u517d\u517e\u517f\u5180\u5181\u5182\u5183\u5184\u5185\u5186\u5187\u5188\u5189\u518a\u518b\u518c\u518d\u518e\u518f\u5190\u5191\u5192\u5193\u5194\u5195\u5196\u5197\u5198\u5199\u519a\u519b\u519c\u519d\u519e\u519f\u51a0\u51a1\u51a2\u51a3\u51a4\u51a5\u51a6\u51a7\u51a8\u51a9\u51aa\u51ab\u51ac\u51ad\u51ae\u51af\u51b0\u51b1\u51b2\u51b3\u51b4\u51b5\u51b6\u51b7\u51b8\u51b9\u51ba\u51bb\u51bc\u51bd\u51be\u51bf\u51c0\u51c1\u51c2\u51c3\u51c4\u51c5\u51c6\u51c7\u51c8\u51c9\u51ca\u51cb\u51cc\u51cd\u51ce\u51cf\u51d0\u51d1\u51d2\u51d3\u51d4\u51d5\u51d6\u51d7\u51d8\u51d9\u51da\u51db\u51dc\u51dd\u51de\u51df\u51e0\u51e1\u51e2\u51e3\u51e4\u51e5\u51e6\u51e7\u51e8\u51e9\u51ea\u51eb\u51ec\u51ed\u51ee\u51ef\u51f0\u51f1\u51f2\u51f3\u51f4\u51f5\u51f6\u51f7\u51f8\u51f9\u51fa\u51fb\u51fc\u51fd\u51fe\u51ff\u5200\u5201\u5202\u5203\u5204\u5205\u5206\u5207\u5208\u5209\u520a\u520b\u520c\u520d\u520e\u520f\u5210\u5211\u5212\u5213\u5214\u5215\u5216\u5217\u5218\u5219\u521a\u521b\u521c\u521d\u521e\u521f\u5220\u5221\u5222\u5223\u5224\u5225\u5226\u5227\u5228\u5229\u522a\u522b\u522c\u522d\u522e\u522f\u5230\u5231\u5232\u5233\u5234\u5235\u5236\u5237\u5238\u5239\u523a\u523b\u523c\u523d\u523e\u523f\u5240\u5241\u5242\u5243\u5244\u5245\u5246\u5247\u5248\u5249\u524a\u524b\u524c\u524d\u524e\u524f\u5250\u5251\u5252\u5253\u5254\u5255\u5256\u5257\u5258\u5259\u525a\u525b\u525c\u525d\u525e\u525f\u5260\u5261\u5262\u5263\u5264\u5265\u5266\u5267\u5268\u5269\u526a\u526b\u526c\u526d\u526e\u526f\u5270\u5271\u5272\u5273\u5274\u5275\u5276\u5277\u5278\u5279\u527a\u527b\u527c\u527d\u527e\u527f\u5280\u5281\u5282\u5283\u5284\u5285\u5286\u5287\u5288\u5289\u528a\u528b\u528c\u528d\u528e\u528f\u5290\u5291\u5292\u5293\u5294\u5295\u5296\u5297\u5298\u5299\u529a\u529b\u529c\u529d\u529e\u529f\u52a0\u52a1\u52a2\u52a3\u52a4\u52a5\u52a6\u52a7\u52a8\u52a9\u52aa\u52ab\u52ac\u52ad\u52ae\u52af\u52b0\u52b1\u52b2\u52b3\u52b4\u52b5\u52b6\u52b7\u52b8\u52b9\u52ba\u52bb\u52bc\u52bd\u52be\u52bf\u52c0\u52c1\u52c2\u52c3\u52c4\u52c5\u52c6\u52c7\u52c8\u52c9\u52ca\u52cb\u52cc\u52cd\u52ce\u52cf\u52d0\u52d1\u52d2\u52d3\u52d4\u52d5\u52d6\u52d7\u52d8\u52d9\u52da\u52db\u52dc\u52dd\u52de\u52df\u52e0\u52e1\u52e2\u52e3\u52e4\u52e5\u52e6\u52e7\u52e8\u52e9\u52ea\u52eb\u52ec\u52ed\u52ee\u52ef\u52f0\u52f1\u52f2\u52f3\u52f4\u52f5\u52f6\u52f7\u52f8\u52f9\u52fa\u52fb\u52fc\u52fd\u52fe\u52ff\u5300\u5301\u5302\u5303\u5304\u5305\u5306\u5307\u5308\u5309\u530a\u530b\u530c\u530d\u530e\u530f\u5310\u5311\u5312\u5313\u5314\u5315\u5316\u5317\u5318\u5319\u531a\u531b\u531c\u531d\u531e\u531f\u5320\u5321\u5322\u5323\u5324\u5325\u5326\u5327\u5328\u5329\u532a\u532b\u532c\u532d\u532e\u532f\u5330\u5331\u5332\u5333\u5334\u5335\u5336\u5337\u5338\u5339\u533a\u533b\u533c\u533d\u533e\u533f\u5340\u5341\u5342\u5343\u5344\u5345\u5346\u5347\u5348\u5349\u534a\u534b\u534c\u534d\u534e\u534f\u5350\u5351\u5352\u5353\u5354\u5355\u5356\u5357\u5358\u5359\u535a\u535b\u535c\u535d\u535e\u535f\u5360\u5361\u5362\u5363\u5364\u5365\u5366\u5367\u5368\u5369\u536a\u536b\u536c\u536d\u536e\u536f\u5370\u5371\u5372\u5373\u5374\u5375\u5376\u5377\u5378\u5379\u537a\u537b\u537c\u537d\u537e\u537f\u5380\u5381\u5382\u5383\u5384\u5385\u5386\u5387\u5388\u5389\u538a\u538b\u538c\u538d\u538e\u538f\u5390\u5391\u5392\u5393\u5394\u5395\u5396\u5397\u5398\u5399\u539a\u539b\u539c\u539d\u539e\u539f\u53a0\u53a1\u53a2\u53a3\u53a4\u53a5\u53a6\u53a7\u53a8\u53a9\u53aa\u53ab\u53ac\u53ad\u53ae\u53af\u53b0\u53b1\u53b2\u53b3\u53b4\u53b5\u53b6\u53b7\u53b8\u53b9\u53ba\u53bb\u53bc\u53bd\u53be\u53bf\u53c0\u53c1\u53c2\u53c3\u53c4\u53c5\u53c6\u53c7\u53c8\u53c9\u53ca\u53cb\u53cc\u53cd\u53ce\u53cf\u53d0\u53d1\u53d2\u53d3\u53d4\u53d5\u53d6\u53d7\u53d8\u53d9\u53da\u53db\u53dc\u53dd\u53de\u53df\u53e0\u53e1\u53e2\u53e3\u53e4\u53e5\u53e6\u53e7\u53e8\u53e9\u53ea\u53eb\u53ec\u53ed\u53ee\u53ef\u53f0\u53f1\u53f2\u53f3\u53f4\u53f5\u53f6\u53f7\u53f8\u53f9\u53fa\u53fb\u53fc\u53fd\u53fe\u53ff\u5400\u5401\u5402\u5403\u5404\u5405\u5406\u5407\u5408\u5409\u540a\u540b\u540c\u540d\u540e\u540f\u5410\u5411\u5412\u5413\u5414\u5415\u5416\u5417\u5418\u5419\u541a\u541b\u541c\u541d\u541e\u541f\u5420\u5421\u5422\u5423\u5424\u5425\u5426\u5427\u5428\u5429\u542a\u542b\u542c\u542d\u542e\u542f\u5430\u5431\u5432\u5433\u5434\u5435\u5436\u5437\u5438\u5439\u543a\u543b\u543c\u543d\u543e\u543f\u5440\u5441\u5442\u5443\u5444\u5445\u5446\u5447\u5448\u5449\u544a\u544b\u544c\u544d\u544e\u544f\u5450\u5451\u5452\u5453\u5454\u5455\u5456\u5457\u5458\u5459\u545a\u545b\u545c\u545d\u545e\u545f\u5460\u5461\u5462\u5463\u5464\u5465\u5466\u5467\u5468\u5469\u546a\u546b\u546c\u546d\u546e\u546f\u5470\u5471\u5472\u5473\u5474\u5475\u5476\u5477\u5478\u5479\u547a\u547b\u547c\u547d\u547e\u547f\u5480\u5481\u5482\u5483\u5484\u5485\u5486\u5487\u5488\u5489\u548a\u548b\u548c\u548d\u548e\u548f\u5490\u5491\u5492\u5493\u5494\u5495\u5496\u5497\u5498\u5499\u549a\u549b\u549c\u549d\u549e\u549f\u54a0\u54a1\u54a2\u54a3\u54a4\u54a5\u54a6\u54a7\u54a8\u54a9\u54aa\u54ab\u54ac\u54ad\u54ae\u54af\u54b0\u54b1\u54b2\u54b3\u54b4\u54b5\u54b6\u54b7\u54b8\u54b9\u54ba\u54bb\u54bc\u54bd\u54be\u54bf\u54c0\u54c1\u54c2\u54c3\u54c4\u54c5\u54c6\u54c7\u54c8\u54c9\u54ca\u54cb\u54cc\u54cd\u54ce\u54cf\u54d0\u54d1\u54d2\u54d3\u54d4\u54d5\u54d6\u54d7\u54d8\u54d9\u54da\u54db\u54dc\u54dd\u54de\u54df\u54e0\u54e1\u54e2\u54e3\u54e4\u54e5\u54e6\u54e7\u54e8\u54e9\u54ea\u54eb\u54ec\u54ed\u54ee\u54ef\u54f0\u54f1\u54f2\u54f3\u54f4\u54f5\u54f6\u54f7\u54f8\u54f9\u54fa\u54fb\u54fc\u54fd\u54fe\u54ff\u5500\u5501\u5502\u5503\u5504\u5505\u5506\u5507\u5508\u5509\u550a\u550b\u550c\u550d\u550e\u550f\u5510\u5511\u5512\u5513\u5514\u5515\u5516\u5517\u5518\u5519\u551a\u551b\u551c\u551d\u551e\u551f\u5520\u5521\u5522\u5523\u5524\u5525\u5526\u5527\u5528\u5529\u552a\u552b\u552c\u552d\u552e\u552f\u5530\u5531\u5532\u5533\u5534\u5535\u5536\u5537\u5538\u5539\u553a\u553b\u553c\u553d\u553e\u553f\u5540\u5541\u5542\u5543\u5544\u5545\u5546\u5547\u5548\u5549\u554a\u554b\u554c\u554d\u554e\u554f\u5550\u5551\u5552\u5553\u5554\u5555\u5556\u5557\u5558\u5559\u555a\u555b\u555c\u555d\u555e\u555f\u5560\u5561\u5562\u5563\u5564\u5565\u5566\u5567\u5568\u5569\u556a\u556b\u556c\u556d\u556e\u556f\u5570\u5571\u5572\u5573\u5574\u5575\u5576\u5577\u5578\u5579\u557a\u557b\u557c\u557d\u557e\u557f\u5580\u5581\u5582\u5583\u5584\u5585\u5586\u5587\u5588\u5589\u558a\u558b\u558c\u558d\u558e\u558f\u5590\u5591\u5592\u5593\u5594\u5595\u5596\u5597\u5598\u5599\u559a\u559b\u559c\u559d\u559e\u559f\u55a0\u55a1\u55a2\u55a3\u55a4\u55a5\u55a6\u55a7\u55a8\u55a9\u55aa\u55ab\u55ac\u55ad\u55ae\u55af\u55b0\u55b1\u55b2\u55b3\u55b4\u55b5\u55b6\u55b7\u55b8\u55b9\u55ba\u55bb\u55bc\u55bd\u55be\u55bf\u55c0\u55c1\u55c2\u55c3\u55c4\u55c5\u55c6\u55c7\u55c8\u55c9\u55ca\u55cb\u55cc\u55cd\u55ce\u55cf\u55d0\u55d1\u55d2\u55d3\u55d4\u55d5\u55d6\u55d7\u55d8\u55d9\u55da\u55db\u55dc\u55dd\u55de\u55df\u55e0\u55e1\u55e2\u55e3\u55e4\u55e5\u55e6\u55e7\u55e8\u55e9\u55ea\u55eb\u55ec\u55ed\u55ee\u55ef\u55f0\u55f1\u55f2\u55f3\u55f4\u55f5\u55f6\u55f7\u55f8\u55f9\u55fa\u55fb\u55fc\u55fd\u55fe\u55ff\u5600\u5601\u5602\u5603\u5604\u5605\u5606\u5607\u5608\u5609\u560a\u560b\u560c\u560d\u560e\u560f\u5610\u5611\u5612\u5613\u5614\u5615\u5616\u5617\u5618\u5619\u561a\u561b\u561c\u561d\u561e\u561f\u5620\u5621\u5622\u5623\u5624\u5625\u5626\u5627\u5628\u5629\u562a\u562b\u562c\u562d\u562e\u562f\u5630\u5631\u5632\u5633\u5634\u5635\u5636\u5637\u5638\u5639\u563a\u563b\u563c\u563d\u563e\u563f\u5640\u5641\u5642\u5643\u5644\u5645\u5646\u5647\u5648\u5649\u564a\u564b\u564c\u564d\u564e\u564f\u5650\u5651\u5652\u5653\u5654\u5655\u5656\u5657\u5658\u5659\u565a\u565b\u565c\u565d\u565e\u565f\u5660\u5661\u5662\u5663\u5664\u5665\u5666\u5667\u5668\u5669\u566a\u566b\u566c\u566d\u566e\u566f\u5670\u5671\u5672\u5673\u5674\u5675\u5676\u5677\u5678\u5679\u567a\u567b\u567c\u567d\u567e\u567f\u5680\u5681\u5682\u5683\u5684\u5685\u5686\u5687\u5688\u5689\u568a\u568b\u568c\u568d\u568e\u568f\u5690\u5691\u5692\u5693\u5694\u5695\u5696\u5697\u5698\u5699\u569a\u569b\u569c\u569d\u569e\u569f\u56a0\u56a1\u56a2\u56a3\u56a4\u56a5\u56a6\u56a7\u56a8\u56a9\u56aa\u56ab\u56ac\u56ad\u56ae\u56af\u56b0\u56b1\u56b2\u56b3\u56b4\u56b5\u56b6\u56b7\u56b8\u56b9\u56ba\u56bb\u56bc\u56bd\u56be\u56bf\u56c0\u56c1\u56c2\u56c3\u56c4\u56c5\u56c6\u56c7\u56c8\u56c9\u56ca\u56cb\u56cc\u56cd\u56ce\u56cf\u56d0\u56d1\u56d2\u56d3\u56d4\u56d5\u56d6\u56d7\u56d8\u56d9\u56da\u56db\u56dc\u56dd\u56de\u56df\u56e0\u56e1\u56e2\u56e3\u56e4\u56e5\u56e6\u56e7\u56e8\u56e9\u56ea\u56eb\u56ec\u56ed\u56ee\u56ef\u56f0\u56f1\u56f2\u56f3\u56f4\u56f5\u56f6\u56f7\u56f8\u56f9\u56fa\u56fb\u56fc\u56fd\u56fe\u56ff\u5700\u5701\u5702\u5703\u5704\u5705\u5706\u5707\u5708\u5709\u570a\u570b\u570c\u570d\u570e\u570f\u5710\u5711\u5712\u5713\u5714\u5715\u5716\u5717\u5718\u5719\u571a\u571b\u571c\u571d\u571e\u571f\u5720\u5721\u5722\u5723\u5724\u5725\u5726\u5727\u5728\u5729\u572a\u572b\u572c\u572d\u572e\u572f\u5730\u5731\u5732\u5733\u5734\u5735\u5736\u5737\u5738\u5739\u573a\u573b\u573c\u573d\u573e\u573f\u5740\u5741\u5742\u5743\u5744\u5745\u5746\u5747\u5748\u5749\u574a\u574b\u574c\u574d\u574e\u574f\u5750\u5751\u5752\u5753\u5754\u5755\u5756\u5757\u5758\u5759\u575a\u575b\u575c\u575d\u575e\u575f\u5760\u5761\u5762\u5763\u5764\u5765\u5766\u5767\u5768\u5769\u576a\u576b\u576c\u576d\u576e\u576f\u5770\u5771\u5772\u5773\u5774\u5775\u5776\u5777\u5778\u5779\u577a\u577b\u577c\u577d\u577e\u577f\u5780\u5781\u5782\u5783\u5784\u5785\u5786\u5787\u5788\u5789\u578a\u578b\u578c\u578d\u578e\u578f\u5790\u5791\u5792\u5793\u5794\u5795\u5796\u5797\u5798\u5799\u579a\u579b\u579c\u579d\u579e\u579f\u57a0\u57a1\u57a2\u57a3\u57a4\u57a5\u57a6\u57a7\u57a8\u57a9\u57aa\u57ab\u57ac\u57ad\u57ae\u57af\u57b0\u57b1\u57b2\u57b3\u57b4\u57b5\u57b6\u57b7\u57b8\u57b9\u57ba\u57bb\u57bc\u57bd\u57be\u57bf\u57c0\u57c1\u57c2\u57c3\u57c4\u57c5\u57c6\u57c7\u57c8\u57c9\u57ca\u57cb\u57cc\u57cd\u57ce\u57cf\u57d0\u57d1\u57d2\u57d3\u57d4\u57d5\u57d6\u57d7\u57d8\u57d9\u57da\u57db\u57dc\u57dd\u57de\u57df\u57e0\u57e1\u57e2\u57e3\u57e4\u57e5\u57e6\u57e7\u57e8\u57e9\u57ea\u57eb\u57ec\u57ed\u57ee\u57ef\u57f0\u57f1\u57f2\u57f3\u57f4\u57f5\u57f6\u57f7\u57f8\u57f9\u57fa\u57fb\u57fc\u57fd\u57fe\u57ff\u5800\u5801\u5802\u5803\u5804\u5805\u5806\u5807\u5808\u5809\u580a\u580b\u580c\u580d\u580e\u580f\u5810\u5811\u5812\u5813\u5814\u5815\u5816\u5817\u5818\u5819\u581a\u581b\u581c\u581d\u581e\u581f\u5820\u5821\u5822\u5823\u5824\u5825\u5826\u5827\u5828\u5829\u582a\u582b\u582c\u582d\u582e\u582f\u5830\u5831\u5832\u5833\u5834\u5835\u5836\u5837\u5838\u5839\u583a\u583b\u583c\u583d\u583e\u583f\u5840\u5841\u5842\u5843\u5844\u5845\u5846\u5847\u5848\u5849\u584a\u584b\u584c\u584d\u584e\u584f\u5850\u5851\u5852\u5853\u5854\u5855\u5856\u5857\u5858\u5859\u585a\u585b\u585c\u585d\u585e\u585f\u5860\u5861\u5862\u5863\u5864\u5865\u5866\u5867\u5868\u5869\u586a\u586b\u586c\u586d\u586e\u586f\u5870\u5871\u5872\u5873\u5874\u5875\u5876\u5877\u5878\u5879\u587a\u587b\u587c\u587d\u587e\u587f\u5880\u5881\u5882\u5883\u5884\u5885\u5886\u5887\u5888\u5889\u588a\u588b\u588c\u588d\u588e\u588f\u5890\u5891\u5892\u5893\u5894\u5895\u5896\u5897\u5898\u5899\u589a\u589b\u589c\u589d\u589e\u589f\u58a0\u58a1\u58a2\u58a3\u58a4\u58a5\u58a6\u58a7\u58a8\u58a9\u58aa\u58ab\u58ac\u58ad\u58ae\u58af\u58b0\u58b1\u58b2\u58b3\u58b4\u58b5\u58b6\u58b7\u58b8\u58b9\u58ba\u58bb\u58bc\u58bd\u58be\u58bf\u58c0\u58c1\u58c2\u58c3\u58c4\u58c5\u58c6\u58c7\u58c8\u58c9\u58ca\u58cb\u58cc\u58cd\u58ce\u58cf\u58d0\u58d1\u58d2\u58d3\u58d4\u58d5\u58d6\u58d7\u58d8\u58d9\u58da\u58db\u58dc\u58dd\u58de\u58df\u58e0\u58e1\u58e2\u58e3\u58e4\u58e5\u58e6\u58e7\u58e8\u58e9\u58ea\u58eb\u58ec\u58ed\u58ee\u58ef\u58f0\u58f1\u58f2\u58f3\u58f4\u58f5\u58f6\u58f7\u58f8\u58f9\u58fa\u58fb\u58fc\u58fd\u58fe\u58ff\u5900\u5901\u5902\u5903\u5904\u5905\u5906\u5907\u5908\u5909\u590a\u590b\u590c\u590d\u590e\u590f\u5910\u5911\u5912\u5913\u5914\u5915\u5916\u5917\u5918\u5919\u591a\u591b\u591c\u591d\u591e\u591f\u5920\u5921\u5922\u5923\u5924\u5925\u5926\u5927\u5928\u5929\u592a\u592b\u592c\u592d\u592e\u592f\u5930\u5931\u5932\u5933\u5934\u5935\u5936\u5937\u5938\u5939\u593a\u593b\u593c\u593d\u593e\u593f\u5940\u5941\u5942\u5943\u5944\u5945\u5946\u5947\u5948\u5949\u594a\u594b\u594c\u594d\u594e\u594f\u5950\u5951\u5952\u5953\u5954\u5955\u5956\u5957\u5958\u5959\u595a\u595b\u595c\u595d\u595e\u595f\u5960\u5961\u5962\u5963\u5964\u5965\u5966\u5967\u5968\u5969\u596a\u596b\u596c\u596d\u596e\u596f\u5970\u5971\u5972\u5973\u5974\u5975\u5976\u5977\u5978\u5979\u597a\u597b\u597c\u597d\u597e\u597f\u5980\u5981\u5982\u5983\u5984\u5985\u5986\u5987\u5988\u5989\u598a\u598b\u598c\u598d\u598e\u598f\u5990\u5991\u5992\u5993\u5994\u5995\u5996\u5997\u5998\u5999\u599a\u599b\u599c\u599d\u599e\u599f\u59a0\u59a1\u59a2\u59a3\u59a4\u59a5\u59a6\u59a7\u59a8\u59a9\u59aa\u59ab\u59ac\u59ad\u59ae\u59af\u59b0\u59b1\u59b2\u59b3\u59b4\u59b5\u59b6\u59b7\u59b8\u59b9\u59ba\u59bb\u59bc\u59bd\u59be\u59bf\u59c0\u59c1\u59c2\u59c3\u59c4\u59c5\u59c6\u59c7\u59c8\u59c9\u59ca\u59cb\u59cc\u59cd\u59ce\u59cf\u59d0\u59d1\u59d2\u59d3\u59d4\u59d5\u59d6\u59d7\u59d8\u59d9\u59da\u59db\u59dc\u59dd\u59de\u59df\u59e0\u59e1\u59e2\u59e3\u59e4\u59e5\u59e6\u59e7\u59e8\u59e9\u59ea\u59eb\u59ec\u59ed\u59ee\u59ef\u59f0\u59f1\u59f2\u59f3\u59f4\u59f5\u59f6\u59f7\u59f8\u59f9\u59fa\u59fb\u59fc\u59fd\u59fe\u59ff\u5a00\u5a01\u5a02\u5a03\u5a04\u5a05\u5a06\u5a07\u5a08\u5a09\u5a0a\u5a0b\u5a0c\u5a0d\u5a0e\u5a0f\u5a10\u5a11\u5a12\u5a13\u5a14\u5a15\u5a16\u5a17\u5a18\u5a19\u5a1a\u5a1b\u5a1c\u5a1d\u5a1e\u5a1f\u5a20\u5a21\u5a22\u5a23\u5a24\u5a25\u5a26\u5a27\u5a28\u5a29\u5a2a\u5a2b\u5a2c\u5a2d\u5a2e\u5a2f\u5a30\u5a31\u5a32\u5a33\u5a34\u5a35\u5a36\u5a37\u5a38\u5a39\u5a3a\u5a3b\u5a3c\u5a3d\u5a3e\u5a3f\u5a40\u5a41\u5a42\u5a43\u5a44\u5a45\u5a46\u5a47\u5a48\u5a49\u5a4a\u5a4b\u5a4c\u5a4d\u5a4e\u5a4f\u5a50\u5a51\u5a52\u5a53\u5a54\u5a55\u5a56\u5a57\u5a58\u5a59\u5a5a\u5a5b\u5a5c\u5a5d\u5a5e\u5a5f\u5a60\u5a61\u5a62\u5a63\u5a64\u5a65\u5a66\u5a67\u5a68\u5a69\u5a6a\u5a6b\u5a6c\u5a6d\u5a6e\u5a6f\u5a70\u5a71\u5a72\u5a73\u5a74\u5a75\u5a76\u5a77\u5a78\u5a79\u5a7a\u5a7b\u5a7c\u5a7d\u5a7e\u5a7f\u5a80\u5a81\u5a82\u5a83\u5a84\u5a85\u5a86\u5a87\u5a88\u5a89\u5a8a\u5a8b\u5a8c\u5a8d\u5a8e\u5a8f\u5a90\u5a91\u5a92\u5a93\u5a94\u5a95\u5a96\u5a97\u5a98\u5a99\u5a9a\u5a9b\u5a9c\u5a9d\u5a9e\u5a9f\u5aa0\u5aa1\u5aa2\u5aa3\u5aa4\u5aa5\u5aa6\u5aa7\u5aa8\u5aa9\u5aaa\u5aab\u5aac\u5aad\u5aae\u5aaf\u5ab0\u5ab1\u5ab2\u5ab3\u5ab4\u5ab5\u5ab6\u5ab7\u5ab8\u5ab9\u5aba\u5abb\u5abc\u5abd\u5abe\u5abf\u5ac0\u5ac1\u5ac2\u5ac3\u5ac4\u5ac5\u5ac6\u5ac7\u5ac8\u5ac9\u5aca\u5acb\u5acc\u5acd\u5ace\u5acf\u5ad0\u5ad1\u5ad2\u5ad3\u5ad4\u5ad5\u5ad6\u5ad7\u5ad8\u5ad9\u5ada\u5adb\u5adc\u5add\u5ade\u5adf\u5ae0\u5ae1\u5ae2\u5ae3\u5ae4\u5ae5\u5ae6\u5ae7\u5ae8\u5ae9\u5aea\u5aeb\u5aec\u5aed\u5aee\u5aef\u5af0\u5af1\u5af2\u5af3\u5af4\u5af5\u5af6\u5af7\u5af8\u5af9\u5afa\u5afb\u5afc\u5afd\u5afe\u5aff\u5b00\u5b01\u5b02\u5b03\u5b04\u5b05\u5b06\u5b07\u5b08\u5b09\u5b0a\u5b0b\u5b0c\u5b0d\u5b0e\u5b0f\u5b10\u5b11\u5b12\u5b13\u5b14\u5b15\u5b16\u5b17\u5b18\u5b19\u5b1a\u5b1b\u5b1c\u5b1d\u5b1e\u5b1f\u5b20\u5b21\u5b22\u5b23\u5b24\u5b25\u5b26\u5b27\u5b28\u5b29\u5b2a\u5b2b\u5b2c\u5b2d\u5b2e\u5b2f\u5b30\u5b31\u5b32\u5b33\u5b34\u5b35\u5b36\u5b37\u5b38\u5b39\u5b3a\u5b3b\u5b3c\u5b3d\u5b3e\u5b3f\u5b40\u5b41\u5b42\u5b43\u5b44\u5b45\u5b46\u5b47\u5b48\u5b49\u5b4a\u5b4b\u5b4c\u5b4d\u5b4e\u5b4f\u5b50\u5b51\u5b52\u5b53\u5b54\u5b55\u5b56\u5b57\u5b58\u5b59\u5b5a\u5b5b\u5b5c\u5b5d\u5b5e\u5b5f\u5b60\u5b61\u5b62\u5b63\u5b64\u5b65\u5b66\u5b67\u5b68\u5b69\u5b6a\u5b6b\u5b6c\u5b6d\u5b6e\u5b6f\u5b70\u5b71\u5b72\u5b73\u5b74\u5b75\u5b76\u5b77\u5b78\u5b79\u5b7a\u5b7b\u5b7c\u5b7d\u5b7e\u5b7f\u5b80\u5b81\u5b82\u5b83\u5b84\u5b85\u5b86\u5b87\u5b88\u5b89\u5b8a\u5b8b\u5b8c\u5b8d\u5b8e\u5b8f\u5b90\u5b91\u5b92\u5b93\u5b94\u5b95\u5b96\u5b97\u5b98\u5b99\u5b9a\u5b9b\u5b9c\u5b9d\u5b9e\u5b9f\u5ba0\u5ba1\u5ba2\u5ba3\u5ba4\u5ba5\u5ba6\u5ba7\u5ba8\u5ba9\u5baa\u5bab\u5bac\u5bad\u5bae\u5baf\u5bb0\u5bb1\u5bb2\u5bb3\u5bb4\u5bb5\u5bb6\u5bb7\u5bb8\u5bb9\u5bba\u5bbb\u5bbc\u5bbd\u5bbe\u5bbf\u5bc0\u5bc1\u5bc2\u5bc3\u5bc4\u5bc5\u5bc6\u5bc7\u5bc8\u5bc9\u5bca\u5bcb\u5bcc\u5bcd\u5bce\u5bcf\u5bd0\u5bd1\u5bd2\u5bd3\u5bd4\u5bd5\u5bd6\u5bd7\u5bd8\u5bd9\u5bda\u5bdb\u5bdc\u5bdd\u5bde\u5bdf\u5be0\u5be1\u5be2\u5be3\u5be4\u5be5\u5be6\u5be7\u5be8\u5be9\u5bea\u5beb\u5bec\u5bed\u5bee\u5bef\u5bf0\u5bf1\u5bf2\u5bf3\u5bf4\u5bf5\u5bf6\u5bf7\u5bf8\u5bf9\u5bfa\u5bfb\u5bfc\u5bfd\u5bfe\u5bff\u5c00\u5c01\u5c02\u5c03\u5c04\u5c05\u5c06\u5c07\u5c08\u5c09\u5c0a\u5c0b\u5c0c\u5c0d\u5c0e\u5c0f\u5c10\u5c11\u5c12\u5c13\u5c14\u5c15\u5c16\u5c17\u5c18\u5c19\u5c1a\u5c1b\u5c1c\u5c1d\u5c1e\u5c1f\u5c20\u5c21\u5c22\u5c23\u5c24\u5c25\u5c26\u5c27\u5c28\u5c29\u5c2a\u5c2b\u5c2c\u5c2d\u5c2e\u5c2f\u5c30\u5c31\u5c32\u5c33\u5c34\u5c35\u5c36\u5c37\u5c38\u5c39\u5c3a\u5c3b\u5c3c\u5c3d\u5c3e\u5c3f\u5c40\u5c41\u5c42\u5c43\u5c44\u5c45\u5c46\u5c47\u5c48\u5c49\u5c4a\u5c4b\u5c4c\u5c4d\u5c4e\u5c4f\u5c50\u5c51\u5c52\u5c53\u5c54\u5c55\u5c56\u5c57\u5c58\u5c59\u5c5a\u5c5b\u5c5c\u5c5d\u5c5e\u5c5f\u5c60\u5c61\u5c62\u5c63\u5c64\u5c65\u5c66\u5c67\u5c68\u5c69\u5c6a\u5c6b\u5c6c\u5c6d\u5c6e\u5c6f\u5c70\u5c71\u5c72\u5c73\u5c74\u5c75\u5c76\u5c77\u5c78\u5c79\u5c7a\u5c7b\u5c7c\u5c7d\u5c7e\u5c7f\u5c80\u5c81\u5c82\u5c83\u5c84\u5c85\u5c86\u5c87\u5c88\u5c89\u5c8a\u5c8b\u5c8c\u5c8d\u5c8e\u5c8f\u5c90\u5c91\u5c92\u5c93\u5c94\u5c95\u5c96\u5c97\u5c98\u5c99\u5c9a\u5c9b\u5c9c\u5c9d\u5c9e\u5c9f\u5ca0\u5ca1\u5ca2\u5ca3\u5ca4\u5ca5\u5ca6\u5ca7\u5ca8\u5ca9\u5caa\u5cab\u5cac\u5cad\u5cae\u5caf\u5cb0\u5cb1\u5cb2\u5cb3\u5cb4\u5cb5\u5cb6\u5cb7\u5cb8\u5cb9\u5cba\u5cbb\u5cbc\u5cbd\u5cbe\u5cbf\u5cc0\u5cc1\u5cc2\u5cc3\u5cc4\u5cc5\u5cc6\u5cc7\u5cc8\u5cc9\u5cca\u5ccb\u5ccc\u5ccd\u5cce\u5ccf\u5cd0\u5cd1\u5cd2\u5cd3\u5cd4\u5cd5\u5cd6\u5cd7\u5cd8\u5cd9\u5cda\u5cdb\u5cdc\u5cdd\u5cde\u5cdf\u5ce0\u5ce1\u5ce2\u5ce3\u5ce4\u5ce5\u5ce6\u5ce7\u5ce8\u5ce9\u5cea\u5ceb\u5cec\u5ced\u5cee\u5cef\u5cf0\u5cf1\u5cf2\u5cf3\u5cf4\u5cf5\u5cf6\u5cf7\u5cf8\u5cf9\u5cfa\u5cfb\u5cfc\u5cfd\u5cfe\u5cff\u5d00\u5d01\u5d02\u5d03\u5d04\u5d05\u5d06\u5d07\u5d08\u5d09\u5d0a\u5d0b\u5d0c\u5d0d\u5d0e\u5d0f\u5d10\u5d11\u5d12\u5d13\u5d14\u5d15\u5d16\u5d17\u5d18\u5d19\u5d1a\u5d1b\u5d1c\u5d1d\u5d1e\u5d1f\u5d20\u5d21\u5d22\u5d23\u5d24\u5d25\u5d26\u5d27\u5d28\u5d29\u5d2a\u5d2b\u5d2c\u5d2d\u5d2e\u5d2f\u5d30\u5d31\u5d32\u5d33\u5d34\u5d35\u5d36\u5d37\u5d38\u5d39\u5d3a\u5d3b\u5d3c\u5d3d\u5d3e\u5d3f\u5d40\u5d41\u5d42\u5d43\u5d44\u5d45\u5d46\u5d47\u5d48\u5d49\u5d4a\u5d4b\u5d4c\u5d4d\u5d4e\u5d4f\u5d50\u5d51\u5d52\u5d53\u5d54\u5d55\u5d56\u5d57\u5d58\u5d59\u5d5a\u5d5b\u5d5c\u5d5d\u5d5e\u5d5f\u5d60\u5d61\u5d62\u5d63\u5d64\u5d65\u5d66\u5d67\u5d68\u5d69\u5d6a\u5d6b\u5d6c\u5d6d\u5d6e\u5d6f\u5d70\u5d71\u5d72\u5d73\u5d74\u5d75\u5d76\u5d77\u5d78\u5d79\u5d7a\u5d7b\u5d7c\u5d7d\u5d7e\u5d7f\u5d80\u5d81\u5d82\u5d83\u5d84\u5d85\u5d86\u5d87\u5d88\u5d89\u5d8a\u5d8b\u5d8c\u5d8d\u5d8e\u5d8f\u5d90\u5d91\u5d92\u5d93\u5d94\u5d95\u5d96\u5d97\u5d98\u5d99\u5d9a\u5d9b\u5d9c\u5d9d\u5d9e\u5d9f\u5da0\u5da1\u5da2\u5da3\u5da4\u5da5\u5da6\u5da7\u5da8\u5da9\u5daa\u5dab\u5dac\u5dad\u5dae\u5daf\u5db0\u5db1\u5db2\u5db3\u5db4\u5db5\u5db6\u5db7\u5db8\u5db9\u5dba\u5dbb\u5dbc\u5dbd\u5dbe\u5dbf\u5dc0\u5dc1\u5dc2\u5dc3\u5dc4\u5dc5\u5dc6\u5dc7\u5dc8\u5dc9\u5dca\u5dcb\u5dcc\u5dcd\u5dce\u5dcf\u5dd0\u5dd1\u5dd2\u5dd3\u5dd4\u5dd5\u5dd6\u5dd7\u5dd8\u5dd9\u5dda\u5ddb\u5ddc\u5ddd\u5dde\u5ddf\u5de0\u5de1\u5de2\u5de3\u5de4\u5de5\u5de6\u5de7\u5de8\u5de9\u5dea\u5deb\u5dec\u5ded\u5dee\u5def\u5df0\u5df1\u5df2\u5df3\u5df4\u5df5\u5df6\u5df7\u5df8\u5df9\u5dfa\u5dfb\u5dfc\u5dfd\u5dfe\u5dff\u5e00\u5e01\u5e02\u5e03\u5e04\u5e05\u5e06\u5e07\u5e08\u5e09\u5e0a\u5e0b\u5e0c\u5e0d\u5e0e\u5e0f\u5e10\u5e11\u5e12\u5e13\u5e14\u5e15\u5e16\u5e17\u5e18\u5e19\u5e1a\u5e1b\u5e1c\u5e1d\u5e1e\u5e1f\u5e20\u5e21\u5e22\u5e23\u5e24\u5e25\u5e26\u5e27\u5e28\u5e29\u5e2a\u5e2b\u5e2c\u5e2d\u5e2e\u5e2f\u5e30\u5e31\u5e32\u5e33\u5e34\u5e35\u5e36\u5e37\u5e38\u5e39\u5e3a\u5e3b\u5e3c\u5e3d\u5e3e\u5e3f\u5e40\u5e41\u5e42\u5e43\u5e44\u5e45\u5e46\u5e47\u5e48\u5e49\u5e4a\u5e4b\u5e4c\u5e4d\u5e4e\u5e4f\u5e50\u5e51\u5e52\u5e53\u5e54\u5e55\u5e56\u5e57\u5e58\u5e59\u5e5a\u5e5b\u5e5c\u5e5d\u5e5e\u5e5f\u5e60\u5e61\u5e62\u5e63\u5e64\u5e65\u5e66\u5e67\u5e68\u5e69\u5e6a\u5e6b\u5e6c\u5e6d\u5e6e\u5e6f\u5e70\u5e71\u5e72\u5e73\u5e74\u5e75\u5e76\u5e77\u5e78\u5e79\u5e7a\u5e7b\u5e7c\u5e7d\u5e7e\u5e7f\u5e80\u5e81\u5e82\u5e83\u5e84\u5e85\u5e86\u5e87\u5e88\u5e89\u5e8a\u5e8b\u5e8c\u5e8d\u5e8e\u5e8f\u5e90\u5e91\u5e92\u5e93\u5e94\u5e95\u5e96\u5e97\u5e98\u5e99\u5e9a\u5e9b\u5e9c\u5e9d\u5e9e\u5e9f\u5ea0\u5ea1\u5ea2\u5ea3\u5ea4\u5ea5\u5ea6\u5ea7\u5ea8\u5ea9\u5eaa\u5eab\u5eac\u5ead\u5eae\u5eaf\u5eb0\u5eb1\u5eb2\u5eb3\u5eb4\u5eb5\u5eb6\u5eb7\u5eb8\u5eb9\u5eba\u5ebb\u5ebc\u5ebd\u5ebe\u5ebf\u5ec0\u5ec1\u5ec2\u5ec3\u5ec4\u5ec5\u5ec6\u5ec7\u5ec8\u5ec9\u5eca\u5ecb\u5ecc\u5ecd\u5ece\u5ecf\u5ed0\u5ed1\u5ed2\u5ed3\u5ed4\u5ed5\u5ed6\u5ed7\u5ed8\u5ed9\u5eda\u5edb\u5edc\u5edd\u5ede\u5edf\u5ee0\u5ee1\u5ee2\u5ee3\u5ee4\u5ee5\u5ee6\u5ee7\u5ee8\u5ee9\u5eea\u5eeb\u5eec\u5eed\u5eee\u5eef\u5ef0\u5ef1\u5ef2\u5ef3\u5ef4\u5ef5\u5ef6\u5ef7\u5ef8\u5ef9\u5efa\u5efb\u5efc\u5efd\u5efe\u5eff\u5f00\u5f01\u5f02\u5f03\u5f04\u5f05\u5f06\u5f07\u5f08\u5f09\u5f0a\u5f0b\u5f0c\u5f0d\u5f0e\u5f0f\u5f10\u5f11\u5f12\u5f13\u5f14\u5f15\u5f16\u5f17\u5f18\u5f19\u5f1a\u5f1b\u5f1c\u5f1d\u5f1e\u5f1f\u5f20\u5f21\u5f22\u5f23\u5f24\u5f25\u5f26\u5f27\u5f28\u5f29\u5f2a\u5f2b\u5f2c\u5f2d\u5f2e\u5f2f\u5f30\u5f31\u5f32\u5f33\u5f34\u5f35\u5f36\u5f37\u5f38\u5f39\u5f3a\u5f3b\u5f3c\u5f3d\u5f3e\u5f3f\u5f40\u5f41\u5f42\u5f43\u5f44\u5f45\u5f46\u5f47\u5f48\u5f49\u5f4a\u5f4b\u5f4c\u5f4d\u5f4e\u5f4f\u5f50\u5f51\u5f52\u5f53\u5f54\u5f55\u5f56\u5f57\u5f58\u5f59\u5f5a\u5f5b\u5f5c\u5f5d\u5f5e\u5f5f\u5f60\u5f61\u5f62\u5f63\u5f64\u5f65\u5f66\u5f67\u5f68\u5f69\u5f6a\u5f6b\u5f6c\u5f6d\u5f6e\u5f6f\u5f70\u5f71\u5f72\u5f73\u5f74\u5f75\u5f76\u5f77\u5f78\u5f79\u5f7a\u5f7b\u5f7c\u5f7d\u5f7e\u5f7f\u5f80\u5f81\u5f82\u5f83\u5f84\u5f85\u5f86\u5f87\u5f88\u5f89\u5f8a\u5f8b\u5f8c\u5f8d\u5f8e\u5f8f\u5f90\u5f91\u5f92\u5f93\u5f94\u5f95\u5f96\u5f97\u5f98\u5f99\u5f9a\u5f9b\u5f9c\u5f9d\u5f9e\u5f9f\u5fa0\u5fa1\u5fa2\u5fa3\u5fa4\u5fa5\u5fa6\u5fa7\u5fa8\u5fa9\u5faa\u5fab\u5fac\u5fad\u5fae\u5faf\u5fb0\u5fb1\u5fb2\u5fb3\u5fb4\u5fb5\u5fb6\u5fb7\u5fb8\u5fb9\u5fba\u5fbb\u5fbc\u5fbd\u5fbe\u5fbf\u5fc0\u5fc1\u5fc2\u5fc3\u5fc4\u5fc5\u5fc6\u5fc7\u5fc8\u5fc9\u5fca\u5fcb\u5fcc\u5fcd\u5fce\u5fcf\u5fd0\u5fd1\u5fd2\u5fd3\u5fd4\u5fd5\u5fd6\u5fd7\u5fd8\u5fd9\u5fda\u5fdb\u5fdc\u5fdd\u5fde\u5fdf\u5fe0\u5fe1\u5fe2\u5fe3\u5fe4\u5fe5\u5fe6\u5fe7\u5fe8\u5fe9\u5fea\u5feb\u5fec\u5fed\u5fee\u5fef\u5ff0\u5ff1\u5ff2\u5ff3\u5ff4\u5ff5\u5ff6\u5ff7\u5ff8\u5ff9\u5ffa\u5ffb\u5ffc\u5ffd\u5ffe\u5fff\u6000\u6001\u6002\u6003\u6004\u6005\u6006\u6007\u6008\u6009\u600a\u600b\u600c\u600d\u600e\u600f\u6010\u6011\u6012\u6013\u6014\u6015\u6016\u6017\u6018\u6019\u601a\u601b\u601c\u601d\u601e\u601f\u6020\u6021\u6022\u6023\u6024\u6025\u6026\u6027\u6028\u6029\u602a\u602b\u602c\u602d\u602e\u602f\u6030\u6031\u6032\u6033\u6034\u6035\u6036\u6037\u6038\u6039\u603a\u603b\u603c\u603d\u603e\u603f\u6040\u6041\u6042\u6043\u6044\u6045\u6046\u6047\u6048\u6049\u604a\u604b\u604c\u604d\u604e\u604f\u6050\u6051\u6052\u6053\u6054\u6055\u6056\u6057\u6058\u6059\u605a\u605b\u605c\u605d\u605e\u605f\u6060\u6061\u6062\u6063\u6064\u6065\u6066\u6067\u6068\u6069\u606a\u606b\u606c\u606d\u606e\u606f\u6070\u6071\u6072\u6073\u6074\u6075\u6076\u6077\u6078\u6079\u607a\u607b\u607c\u607d\u607e\u607f\u6080\u6081\u6082\u6083\u6084\u6085\u6086\u6087\u6088\u6089\u608a\u608b\u608c\u608d\u608e\u608f\u6090\u6091\u6092\u6093\u6094\u6095\u6096\u6097\u6098\u6099\u609a\u609b\u609c\u609d\u609e\u609f\u60a0\u60a1\u60a2\u60a3\u60a4\u60a5\u60a6\u60a7\u60a8\u60a9\u60aa\u60ab\u60ac\u60ad\u60ae\u60af\u60b0\u60b1\u60b2\u60b3\u60b4\u60b5\u60b6\u60b7\u60b8\u60b9\u60ba\u60bb\u60bc\u60bd\u60be\u60bf\u60c0\u60c1\u60c2\u60c3\u60c4\u60c5\u60c6\u60c7\u60c8\u60c9\u60ca\u60cb\u60cc\u60cd\u60ce\u60cf\u60d0\u60d1\u60d2\u60d3\u60d4\u60d5\u60d6\u60d7\u60d8\u60d9\u60da\u60db\u60dc\u60dd\u60de\u60df\u60e0\u60e1\u60e2\u60e3\u60e4\u60e5\u60e6\u60e7\u60e8\u60e9\u60ea\u60eb\u60ec\u60ed\u60ee\u60ef\u60f0\u60f1\u60f2\u60f3\u60f4\u60f5\u60f6\u60f7\u60f8\u60f9\u60fa\u60fb\u60fc\u60fd\u60fe\u60ff\u6100\u6101\u6102\u6103\u6104\u6105\u6106\u6107\u6108\u6109\u610a\u610b\u610c\u610d\u610e\u610f\u6110\u6111\u6112\u6113\u6114\u6115\u6116\u6117\u6118\u6119\u611a\u611b\u611c\u611d\u611e\u611f\u6120\u6121\u6122\u6123\u6124\u6125\u6126\u6127\u6128\u6129\u612a\u612b\u612c\u612d\u612e\u612f\u6130\u6131\u6132\u6133\u6134\u6135\u6136\u6137\u6138\u6139\u613a\u613b\u613c\u613d\u613e\u613f\u6140\u6141\u6142\u6143\u6144\u6145\u6146\u6147\u6148\u6149\u614a\u614b\u614c\u614d\u614e\u614f\u6150\u6151\u6152\u6153\u6154\u6155\u6156\u6157\u6158\u6159\u615a\u615b\u615c\u615d\u615e\u615f\u6160\u6161\u6162\u6163\u6164\u6165\u6166\u6167\u6168\u6169\u616a\u616b\u616c\u616d\u616e\u616f\u6170\u6171\u6172\u6173\u6174\u6175\u6176\u6177\u6178\u6179\u617a\u617b\u617c\u617d\u617e\u617f\u6180\u6181\u6182\u6183\u6184\u6185\u6186\u6187\u6188\u6189\u618a\u618b\u618c\u618d\u618e\u618f\u6190\u6191\u6192\u6193\u6194\u6195\u6196\u6197\u6198\u6199\u619a\u619b\u619c\u619d\u619e\u619f\u61a0\u61a1\u61a2\u61a3\u61a4\u61a5\u61a6\u61a7\u61a8\u61a9\u61aa\u61ab\u61ac\u61ad\u61ae\u61af\u61b0\u61b1\u61b2\u61b3\u61b4\u61b5\u61b6\u61b7\u61b8\u61b9\u61ba\u61bb\u61bc\u61bd\u61be\u61bf\u61c0\u61c1\u61c2\u61c3\u61c4\u61c5\u61c6\u61c7\u61c8\u61c9\u61ca\u61cb\u61cc\u61cd\u61ce\u61cf\u61d0\u61d1\u61d2\u61d3\u61d4\u61d5\u61d6\u61d7\u61d8\u61d9\u61da\u61db\u61dc\u61dd\u61de\u61df\u61e0\u61e1\u61e2\u61e3\u61e4\u61e5\u61e6\u61e7\u61e8\u61e9\u61ea\u61eb\u61ec\u61ed\u61ee\u61ef\u61f0\u61f1\u61f2\u61f3\u61f4\u61f5\u61f6\u61f7\u61f8\u61f9\u61fa\u61fb\u61fc\u61fd\u61fe\u61ff\u6200\u6201\u6202\u6203\u6204\u6205\u6206\u6207\u6208\u6209\u620a\u620b\u620c\u620d\u620e\u620f\u6210\u6211\u6212\u6213\u6214\u6215\u6216\u6217\u6218\u6219\u621a\u621b\u621c\u621d\u621e\u621f\u6220\u6221\u6222\u6223\u6224\u6225\u6226\u6227\u6228\u6229\u622a\u622b\u622c\u622d\u622e\u622f\u6230\u6231\u6232\u6233\u6234\u6235\u6236\u6237\u6238\u6239\u623a\u623b\u623c\u623d\u623e\u623f\u6240\u6241\u6242\u6243\u6244\u6245\u6246\u6247\u6248\u6249\u624a\u624b\u624c\u624d\u624e\u624f\u6250\u6251\u6252\u6253\u6254\u6255\u6256\u6257\u6258\u6259\u625a\u625b\u625c\u625d\u625e\u625f\u6260\u6261\u6262\u6263\u6264\u6265\u6266\u6267\u6268\u6269\u626a\u626b\u626c\u626d\u626e\u626f\u6270\u6271\u6272\u6273\u6274\u6275\u6276\u6277\u6278\u6279\u627a\u627b\u627c\u627d\u627e\u627f\u6280\u6281\u6282\u6283\u6284\u6285\u6286\u6287\u6288\u6289\u628a\u628b\u628c\u628d\u628e\u628f\u6290\u6291\u6292\u6293\u6294\u6295\u6296\u6297\u6298\u6299\u629a\u629b\u629c\u629d\u629e\u629f\u62a0\u62a1\u62a2\u62a3\u62a4\u62a5\u62a6\u62a7\u62a8\u62a9\u62aa\u62ab\u62ac\u62ad\u62ae\u62af\u62b0\u62b1\u62b2\u62b3\u62b4\u62b5\u62b6\u62b7\u62b8\u62b9\u62ba\u62bb\u62bc\u62bd\u62be\u62bf\u62c0\u62c1\u62c2\u62c3\u62c4\u62c5\u62c6\u62c7\u62c8\u62c9\u62ca\u62cb\u62cc\u62cd\u62ce\u62cf\u62d0\u62d1\u62d2\u62d3\u62d4\u62d5\u62d6\u62d7\u62d8\u62d9\u62da\u62db\u62dc\u62dd\u62de\u62df\u62e0\u62e1\u62e2\u62e3\u62e4\u62e5\u62e6\u62e7\u62e8\u62e9\u62ea\u62eb\u62ec\u62ed\u62ee\u62ef\u62f0\u62f1\u62f2\u62f3\u62f4\u62f5\u62f6\u62f7\u62f8\u62f9\u62fa\u62fb\u62fc\u62fd\u62fe\u62ff\u6300\u6301\u6302\u6303\u6304\u6305\u6306\u6307\u6308\u6309\u630a\u630b\u630c\u630d\u630e\u630f\u6310\u6311\u6312\u6313\u6314\u6315\u6316\u6317\u6318\u6319\u631a\u631b\u631c\u631d\u631e\u631f\u6320\u6321\u6322\u6323\u6324\u6325\u6326\u6327\u6328\u6329\u632a\u632b\u632c\u632d\u632e\u632f\u6330\u6331\u6332\u6333\u6334\u6335\u6336\u6337\u6338\u6339\u633a\u633b\u633c\u633d\u633e\u633f\u6340\u6341\u6342\u6343\u6344\u6345\u6346\u6347\u6348\u6349\u634a\u634b\u634c\u634d\u634e\u634f\u6350\u6351\u6352\u6353\u6354\u6355\u6356\u6357\u6358\u6359\u635a\u635b\u635c\u635d\u635e\u635f\u6360\u6361\u6362\u6363\u6364\u6365\u6366\u6367\u6368\u6369\u636a\u636b\u636c\u636d\u636e\u636f\u6370\u6371\u6372\u6373\u6374\u6375\u6376\u6377\u6378\u6379\u637a\u637b\u637c\u637d\u637e\u637f\u6380\u6381\u6382\u6383\u6384\u6385\u6386\u6387\u6388\u6389\u638a\u638b\u638c\u638d\u638e\u638f\u6390\u6391\u6392\u6393\u6394\u6395\u6396\u6397\u6398\u6399\u639a\u639b\u639c\u639d\u639e\u639f\u63a0\u63a1\u63a2\u63a3\u63a4\u63a5\u63a6\u63a7\u63a8\u63a9\u63aa\u63ab\u63ac\u63ad\u63ae\u63af\u63b0\u63b1\u63b2\u63b3\u63b4\u63b5\u63b6\u63b7\u63b8\u63b9\u63ba\u63bb\u63bc\u63bd\u63be\u63bf\u63c0\u63c1\u63c2\u63c3\u63c4\u63c5\u63c6\u63c7\u63c8\u63c9\u63ca\u63cb\u63cc\u63cd\u63ce\u63cf\u63d0\u63d1\u63d2\u63d3\u63d4\u63d5\u63d6\u63d7\u63d8\u63d9\u63da\u63db\u63dc\u63dd\u63de\u63df\u63e0\u63e1\u63e2\u63e3\u63e4\u63e5\u63e6\u63e7\u63e8\u63e9\u63ea\u63eb\u63ec\u63ed\u63ee\u63ef\u63f0\u63f1\u63f2\u63f3\u63f4\u63f5\u63f6\u63f7\u63f8\u63f9\u63fa\u63fb\u63fc\u63fd\u63fe\u63ff\u6400\u6401\u6402\u6403\u6404\u6405\u6406\u6407\u6408\u6409\u640a\u640b\u640c\u640d\u640e\u640f\u6410\u6411\u6412\u6413\u6414\u6415\u6416\u6417\u6418\u6419\u641a\u641b\u641c\u641d\u641e\u641f\u6420\u6421\u6422\u6423\u6424\u6425\u6426\u6427\u6428\u6429\u642a\u642b\u642c\u642d\u642e\u642f\u6430\u6431\u6432\u6433\u6434\u6435\u6436\u6437\u6438\u6439\u643a\u643b\u643c\u643d\u643e\u643f\u6440\u6441\u6442\u6443\u6444\u6445\u6446\u6447\u6448\u6449\u644a\u644b\u644c\u644d\u644e\u644f\u6450\u6451\u6452\u6453\u6454\u6455\u6456\u6457\u6458\u6459\u645a\u645b\u645c\u645d\u645e\u645f\u6460\u6461\u6462\u6463\u6464\u6465\u6466\u6467\u6468\u6469\u646a\u646b\u646c\u646d\u646e\u646f\u6470\u6471\u6472\u6473\u6474\u6475\u6476\u6477\u6478\u6479\u647a\u647b\u647c\u647d\u647e\u647f\u6480\u6481\u6482\u6483\u6484\u6485\u6486\u6487\u6488\u6489\u648a\u648b\u648c\u648d\u648e\u648f\u6490\u6491\u6492\u6493\u6494\u6495\u6496\u6497\u6498\u6499\u649a\u649b\u649c\u649d\u649e\u649f\u64a0\u64a1\u64a2\u64a3\u64a4\u64a5\u64a6\u64a7\u64a8\u64a9\u64aa\u64ab\u64ac\u64ad\u64ae\u64af\u64b0\u64b1\u64b2\u64b3\u64b4\u64b5\u64b6\u64b7\u64b8\u64b9\u64ba\u64bb\u64bc\u64bd\u64be\u64bf\u64c0\u64c1\u64c2\u64c3\u64c4\u64c5\u64c6\u64c7\u64c8\u64c9\u64ca\u64cb\u64cc\u64cd\u64ce\u64cf\u64d0\u64d1\u64d2\u64d3\u64d4\u64d5\u64d6\u64d7\u64d8\u64d9\u64da\u64db\u64dc\u64dd\u64de\u64df\u64e0\u64e1\u64e2\u64e3\u64e4\u64e5\u64e6\u64e7\u64e8\u64e9\u64ea\u64eb\u64ec\u64ed\u64ee\u64ef\u64f0\u64f1\u64f2\u64f3\u64f4\u64f5\u64f6\u64f7\u64f8\u64f9\u64fa\u64fb\u64fc\u64fd\u64fe\u64ff\u6500\u6501\u6502\u6503\u6504\u6505\u6506\u6507\u6508\u6509\u650a\u650b\u650c\u650d\u650e\u650f\u6510\u6511\u6512\u6513\u6514\u6515\u6516\u6517\u6518\u6519\u651a\u651b\u651c\u651d\u651e\u651f\u6520\u6521\u6522\u6523\u6524\u6525\u6526\u6527\u6528\u6529\u652a\u652b\u652c\u652d\u652e\u652f\u6530\u6531\u6532\u6533\u6534\u6535\u6536\u6537\u6538\u6539\u653a\u653b\u653c\u653d\u653e\u653f\u6540\u6541\u6542\u6543\u6544\u6545\u6546\u6547\u6548\u6549\u654a\u654b\u654c\u654d\u654e\u654f\u6550\u6551\u6552\u6553\u6554\u6555\u6556\u6557\u6558\u6559\u655a\u655b\u655c\u655d\u655e\u655f\u6560\u6561\u6562\u6563\u6564\u6565\u6566\u6567\u6568\u6569\u656a\u656b\u656c\u656d\u656e\u656f\u6570\u6571\u6572\u6573\u6574\u6575\u6576\u6577\u6578\u6579\u657a\u657b\u657c\u657d\u657e\u657f\u6580\u6581\u6582\u6583\u6584\u6585\u6586\u6587\u6588\u6589\u658a\u658b\u658c\u658d\u658e\u658f\u6590\u6591\u6592\u6593\u6594\u6595\u6596\u6597\u6598\u6599\u659a\u659b\u659c\u659d\u659e\u659f\u65a0\u65a1\u65a2\u65a3\u65a4\u65a5\u65a6\u65a7\u65a8\u65a9\u65aa\u65ab\u65ac\u65ad\u65ae\u65af\u65b0\u65b1\u65b2\u65b3\u65b4\u65b5\u65b6\u65b7\u65b8\u65b9\u65ba\u65bb\u65bc\u65bd\u65be\u65bf\u65c0\u65c1\u65c2\u65c3\u65c4\u65c5\u65c6\u65c7\u65c8\u65c9\u65ca\u65cb\u65cc\u65cd\u65ce\u65cf\u65d0\u65d1\u65d2\u65d3\u65d4\u65d5\u65d6\u65d7\u65d8\u65d9\u65da\u65db\u65dc\u65dd\u65de\u65df\u65e0\u65e1\u65e2\u65e3\u65e4\u65e5\u65e6\u65e7\u65e8\u65e9\u65ea\u65eb\u65ec\u65ed\u65ee\u65ef\u65f0\u65f1\u65f2\u65f3\u65f4\u65f5\u65f6\u65f7\u65f8\u65f9\u65fa\u65fb\u65fc\u65fd\u65fe\u65ff\u6600\u6601\u6602\u6603\u6604\u6605\u6606\u6607\u6608\u6609\u660a\u660b\u660c\u660d\u660e\u660f\u6610\u6611\u6612\u6613\u6614\u6615\u6616\u6617\u6618\u6619\u661a\u661b\u661c\u661d\u661e\u661f\u6620\u6621\u6622\u6623\u6624\u6625\u6626\u6627\u6628\u6629\u662a\u662b\u662c\u662d\u662e\u662f\u6630\u6631\u6632\u6633\u6634\u6635\u6636\u6637\u6638\u6639\u663a\u663b\u663c\u663d\u663e\u663f\u6640\u6641\u6642\u6643\u6644\u6645\u6646\u6647\u6648\u6649\u664a\u664b\u664c\u664d\u664e\u664f\u6650\u6651\u6652\u6653\u6654\u6655\u6656\u6657\u6658\u6659\u665a\u665b\u665c\u665d\u665e\u665f\u6660\u6661\u6662\u6663\u6664\u6665\u6666\u6667\u6668\u6669\u666a\u666b\u666c\u666d\u666e\u666f\u6670\u6671\u6672\u6673\u6674\u6675\u6676\u6677\u6678\u6679\u667a\u667b\u667c\u667d\u667e\u667f\u6680\u6681\u6682\u6683\u6684\u6685\u6686\u6687\u6688\u6689\u668a\u668b\u668c\u668d\u668e\u668f\u6690\u6691\u6692\u6693\u6694\u6695\u6696\u6697\u6698\u6699\u669a\u669b\u669c\u669d\u669e\u669f\u66a0\u66a1\u66a2\u66a3\u66a4\u66a5\u66a6\u66a7\u66a8\u66a9\u66aa\u66ab\u66ac\u66ad\u66ae\u66af\u66b0\u66b1\u66b2\u66b3\u66b4\u66b5\u66b6\u66b7\u66b8\u66b9\u66ba\u66bb\u66bc\u66bd\u66be\u66bf\u66c0\u66c1\u66c2\u66c3\u66c4\u66c5\u66c6\u66c7\u66c8\u66c9\u66ca\u66cb\u66cc\u66cd\u66ce\u66cf\u66d0\u66d1\u66d2\u66d3\u66d4\u66d5\u66d6\u66d7\u66d8\u66d9\u66da\u66db\u66dc\u66dd\u66de\u66df\u66e0\u66e1\u66e2\u66e3\u66e4\u66e5\u66e6\u66e7\u66e8\u66e9\u66ea\u66eb\u66ec\u66ed\u66ee\u66ef\u66f0\u66f1\u66f2\u66f3\u66f4\u66f5\u66f6\u66f7\u66f8\u66f9\u66fa\u66fb\u66fc\u66fd\u66fe\u66ff\u6700\u6701\u6702\u6703\u6704\u6705\u6706\u6707\u6708\u6709\u670a\u670b\u670c\u670d\u670e\u670f\u6710\u6711\u6712\u6713\u6714\u6715\u6716\u6717\u6718\u6719\u671a\u671b\u671c\u671d\u671e\u671f\u6720\u6721\u6722\u6723\u6724\u6725\u6726\u6727\u6728\u6729\u672a\u672b\u672c\u672d\u672e\u672f\u6730\u6731\u6732\u6733\u6734\u6735\u6736\u6737\u6738\u6739\u673a\u673b\u673c\u673d\u673e\u673f\u6740\u6741\u6742\u6743\u6744\u6745\u6746\u6747\u6748\u6749\u674a\u674b\u674c\u674d\u674e\u674f\u6750\u6751\u6752\u6753\u6754\u6755\u6756\u6757\u6758\u6759\u675a\u675b\u675c\u675d\u675e\u675f\u6760\u6761\u6762\u6763\u6764\u6765\u6766\u6767\u6768\u6769\u676a\u676b\u676c\u676d\u676e\u676f\u6770\u6771\u6772\u6773\u6774\u6775\u6776\u6777\u6778\u6779\u677a\u677b\u677c\u677d\u677e\u677f\u6780\u6781\u6782\u6783\u6784\u6785\u6786\u6787\u6788\u6789\u678a\u678b\u678c\u678d\u678e\u678f\u6790\u6791\u6792\u6793\u6794\u6795\u6796\u6797\u6798\u6799\u679a\u679b\u679c\u679d\u679e\u679f\u67a0\u67a1\u67a2\u67a3\u67a4\u67a5\u67a6\u67a7\u67a8\u67a9\u67aa\u67ab\u67ac\u67ad\u67ae\u67af\u67b0\u67b1\u67b2\u67b3\u67b4\u67b5\u67b6\u67b7\u67b8\u67b9\u67ba\u67bb\u67bc\u67bd\u67be\u67bf\u67c0\u67c1\u67c2\u67c3\u67c4\u67c5\u67c6\u67c7\u67c8\u67c9\u67ca\u67cb\u67cc\u67cd\u67ce\u67cf\u67d0\u67d1\u67d2\u67d3\u67d4\u67d5\u67d6\u67d7\u67d8\u67d9\u67da\u67db\u67dc\u67dd\u67de\u67df\u67e0\u67e1\u67e2\u67e3\u67e4\u67e5\u67e6\u67e7\u67e8\u67e9\u67ea\u67eb\u67ec\u67ed\u67ee\u67ef\u67f0\u67f1\u67f2\u67f3\u67f4\u67f5\u67f6\u67f7\u67f8\u67f9\u67fa\u67fb\u67fc\u67fd\u67fe\u67ff\u6800\u6801\u6802\u6803\u6804\u6805\u6806\u6807\u6808\u6809\u680a\u680b\u680c\u680d\u680e\u680f\u6810\u6811\u6812\u6813\u6814\u6815\u6816\u6817\u6818\u6819\u681a\u681b\u681c\u681d\u681e\u681f\u6820\u6821\u6822\u6823\u6824\u6825\u6826\u6827\u6828\u6829\u682a\u682b\u682c\u682d\u682e\u682f\u6830\u6831\u6832\u6833\u6834\u6835\u6836\u6837\u6838\u6839\u683a\u683b\u683c\u683d\u683e\u683f\u6840\u6841\u6842\u6843\u6844\u6845\u6846\u6847\u6848\u6849\u684a\u684b\u684c\u684d\u684e\u684f\u6850\u6851\u6852\u6853\u6854\u6855\u6856\u6857\u6858\u6859\u685a\u685b\u685c\u685d\u685e\u685f\u6860\u6861\u6862\u6863\u6864\u6865\u6866\u6867\u6868\u6869\u686a\u686b\u686c\u686d\u686e\u686f\u6870\u6871\u6872\u6873\u6874\u6875\u6876\u6877\u6878\u6879\u687a\u687b\u687c\u687d\u687e\u687f\u6880\u6881\u6882\u6883\u6884\u6885\u6886\u6887\u6888\u6889\u688a\u688b\u688c\u688d\u688e\u688f\u6890\u6891\u6892\u6893\u6894\u6895\u6896\u6897\u6898\u6899\u689a\u689b\u689c\u689d\u689e\u689f\u68a0\u68a1\u68a2\u68a3\u68a4\u68a5\u68a6\u68a7\u68a8\u68a9\u68aa\u68ab\u68ac\u68ad\u68ae\u68af\u68b0\u68b1\u68b2\u68b3\u68b4\u68b5\u68b6\u68b7\u68b8\u68b9\u68ba\u68bb\u68bc\u68bd\u68be\u68bf\u68c0\u68c1\u68c2\u68c3\u68c4\u68c5\u68c6\u68c7\u68c8\u68c9\u68ca\u68cb\u68cc\u68cd\u68ce\u68cf\u68d0\u68d1\u68d2\u68d3\u68d4\u68d5\u68d6\u68d7\u68d8\u68d9\u68da\u68db\u68dc\u68dd\u68de\u68df\u68e0\u68e1\u68e2\u68e3\u68e4\u68e5\u68e6\u68e7\u68e8\u68e9\u68ea\u68eb\u68ec\u68ed\u68ee\u68ef\u68f0\u68f1\u68f2\u68f3\u68f4\u68f5\u68f6\u68f7\u68f8\u68f9\u68fa\u68fb\u68fc\u68fd\u68fe\u68ff\u6900\u6901\u6902\u6903\u6904\u6905\u6906\u6907\u6908\u6909\u690a\u690b\u690c\u690d\u690e\u690f\u6910\u6911\u6912\u6913\u6914\u6915\u6916\u6917\u6918\u6919\u691a\u691b\u691c\u691d\u691e\u691f\u6920\u6921\u6922\u6923\u6924\u6925\u6926\u6927\u6928\u6929\u692a\u692b\u692c\u692d\u692e\u692f\u6930\u6931\u6932\u6933\u6934\u6935\u6936\u6937\u6938\u6939\u693a\u693b\u693c\u693d\u693e\u693f\u6940\u6941\u6942\u6943\u6944\u6945\u6946\u6947\u6948\u6949\u694a\u694b\u694c\u694d\u694e\u694f\u6950\u6951\u6952\u6953\u6954\u6955\u6956\u6957\u6958\u6959\u695a\u695b\u695c\u695d\u695e\u695f\u6960\u6961\u6962\u6963\u6964\u6965\u6966\u6967\u6968\u6969\u696a\u696b\u696c\u696d\u696e\u696f\u6970\u6971\u6972\u6973\u6974\u6975\u6976\u6977\u6978\u6979\u697a\u697b\u697c\u697d\u697e\u697f\u6980\u6981\u6982\u6983\u6984\u6985\u6986\u6987\u6988\u6989\u698a\u698b\u698c\u698d\u698e\u698f\u6990\u6991\u6992\u6993\u6994\u6995\u6996\u6997\u6998\u6999\u699a\u699b\u699c\u699d\u699e\u699f\u69a0\u69a1\u69a2\u69a3\u69a4\u69a5\u69a6\u69a7\u69a8\u69a9\u69aa\u69ab\u69ac\u69ad\u69ae\u69af\u69b0\u69b1\u69b2\u69b3\u69b4\u69b5\u69b6\u69b7\u69b8\u69b9\u69ba\u69bb\u69bc\u69bd\u69be\u69bf\u69c0\u69c1\u69c2\u69c3\u69c4\u69c5\u69c6\u69c7\u69c8\u69c9\u69ca\u69cb\u69cc\u69cd\u69ce\u69cf\u69d0\u69d1\u69d2\u69d3\u69d4\u69d5\u69d6\u69d7\u69d8\u69d9\u69da\u69db\u69dc\u69dd\u69de\u69df\u69e0\u69e1\u69e2\u69e3\u69e4\u69e5\u69e6\u69e7\u69e8\u69e9\u69ea\u69eb\u69ec\u69ed\u69ee\u69ef\u69f0\u69f1\u69f2\u69f3\u69f4\u69f5\u69f6\u69f7\u69f8\u69f9\u69fa\u69fb\u69fc\u69fd\u69fe\u69ff\u6a00\u6a01\u6a02\u6a03\u6a04\u6a05\u6a06\u6a07\u6a08\u6a09\u6a0a\u6a0b\u6a0c\u6a0d\u6a0e\u6a0f\u6a10\u6a11\u6a12\u6a13\u6a14\u6a15\u6a16\u6a17\u6a18\u6a19\u6a1a\u6a1b\u6a1c\u6a1d\u6a1e\u6a1f\u6a20\u6a21\u6a22\u6a23\u6a24\u6a25\u6a26\u6a27\u6a28\u6a29\u6a2a\u6a2b\u6a2c\u6a2d\u6a2e\u6a2f\u6a30\u6a31\u6a32\u6a33\u6a34\u6a35\u6a36\u6a37\u6a38\u6a39\u6a3a\u6a3b\u6a3c\u6a3d\u6a3e\u6a3f\u6a40\u6a41\u6a42\u6a43\u6a44\u6a45\u6a46\u6a47\u6a48\u6a49\u6a4a\u6a4b\u6a4c\u6a4d\u6a4e\u6a4f\u6a50\u6a51\u6a52\u6a53\u6a54\u6a55\u6a56\u6a57\u6a58\u6a59\u6a5a\u6a5b\u6a5c\u6a5d\u6a5e\u6a5f\u6a60\u6a61\u6a62\u6a63\u6a64\u6a65\u6a66\u6a67\u6a68\u6a69\u6a6a\u6a6b\u6a6c\u6a6d\u6a6e\u6a6f\u6a70\u6a71\u6a72\u6a73\u6a74\u6a75\u6a76\u6a77\u6a78\u6a79\u6a7a\u6a7b\u6a7c\u6a7d\u6a7e\u6a7f\u6a80\u6a81\u6a82\u6a83\u6a84\u6a85\u6a86\u6a87\u6a88\u6a89\u6a8a\u6a8b\u6a8c\u6a8d\u6a8e\u6a8f\u6a90\u6a91\u6a92\u6a93\u6a94\u6a95\u6a96\u6a97\u6a98\u6a99\u6a9a\u6a9b\u6a9c\u6a9d\u6a9e\u6a9f\u6aa0\u6aa1\u6aa2\u6aa3\u6aa4\u6aa5\u6aa6\u6aa7\u6aa8\u6aa9\u6aaa\u6aab\u6aac\u6aad\u6aae\u6aaf\u6ab0\u6ab1\u6ab2\u6ab3\u6ab4\u6ab5\u6ab6\u6ab7\u6ab8\u6ab9\u6aba\u6abb\u6abc\u6abd\u6abe\u6abf\u6ac0\u6ac1\u6ac2\u6ac3\u6ac4\u6ac5\u6ac6\u6ac7\u6ac8\u6ac9\u6aca\u6acb\u6acc\u6acd\u6ace\u6acf\u6ad0\u6ad1\u6ad2\u6ad3\u6ad4\u6ad5\u6ad6\u6ad7\u6ad8\u6ad9\u6ada\u6adb\u6adc\u6add\u6ade\u6adf\u6ae0\u6ae1\u6ae2\u6ae3\u6ae4\u6ae5\u6ae6\u6ae7\u6ae8\u6ae9\u6aea\u6aeb\u6aec\u6aed\u6aee\u6aef\u6af0\u6af1\u6af2\u6af3\u6af4\u6af5\u6af6\u6af7\u6af8\u6af9\u6afa\u6afb\u6afc\u6afd\u6afe\u6aff\u6b00\u6b01\u6b02\u6b03\u6b04\u6b05\u6b06\u6b07\u6b08\u6b09\u6b0a\u6b0b\u6b0c\u6b0d\u6b0e\u6b0f\u6b10\u6b11\u6b12\u6b13\u6b14\u6b15\u6b16\u6b17\u6b18\u6b19\u6b1a\u6b1b\u6b1c\u6b1d\u6b1e\u6b1f\u6b20\u6b21\u6b22\u6b23\u6b24\u6b25\u6b26\u6b27\u6b28\u6b29\u6b2a\u6b2b\u6b2c\u6b2d\u6b2e\u6b2f\u6b30\u6b31\u6b32\u6b33\u6b34\u6b35\u6b36\u6b37\u6b38\u6b39\u6b3a\u6b3b\u6b3c\u6b3d\u6b3e\u6b3f\u6b40\u6b41\u6b42\u6b43\u6b44\u6b45\u6b46\u6b47\u6b48\u6b49\u6b4a\u6b4b\u6b4c\u6b4d\u6b4e\u6b4f\u6b50\u6b51\u6b52\u6b53\u6b54\u6b55\u6b56\u6b57\u6b58\u6b59\u6b5a\u6b5b\u6b5c\u6b5d\u6b5e\u6b5f\u6b60\u6b61\u6b62\u6b63\u6b64\u6b65\u6b66\u6b67\u6b68\u6b69\u6b6a\u6b6b\u6b6c\u6b6d\u6b6e\u6b6f\u6b70\u6b71\u6b72\u6b73\u6b74\u6b75\u6b76\u6b77\u6b78\u6b79\u6b7a\u6b7b\u6b7c\u6b7d\u6b7e\u6b7f\u6b80\u6b81\u6b82\u6b83\u6b84\u6b85\u6b86\u6b87\u6b88\u6b89\u6b8a\u6b8b\u6b8c\u6b8d\u6b8e\u6b8f\u6b90\u6b91\u6b92\u6b93\u6b94\u6b95\u6b96\u6b97\u6b98\u6b99\u6b9a\u6b9b\u6b9c\u6b9d\u6b9e\u6b9f\u6ba0\u6ba1\u6ba2\u6ba3\u6ba4\u6ba5\u6ba6\u6ba7\u6ba8\u6ba9\u6baa\u6bab\u6bac\u6bad\u6bae\u6baf\u6bb0\u6bb1\u6bb2\u6bb3\u6bb4\u6bb5\u6bb6\u6bb7\u6bb8\u6bb9\u6bba\u6bbb\u6bbc\u6bbd\u6bbe\u6bbf\u6bc0\u6bc1\u6bc2\u6bc3\u6bc4\u6bc5\u6bc6\u6bc7\u6bc8\u6bc9\u6bca\u6bcb\u6bcc\u6bcd\u6bce\u6bcf\u6bd0\u6bd1\u6bd2\u6bd3\u6bd4\u6bd5\u6bd6\u6bd7\u6bd8\u6bd9\u6bda\u6bdb\u6bdc\u6bdd\u6bde\u6bdf\u6be0\u6be1\u6be2\u6be3\u6be4\u6be5\u6be6\u6be7\u6be8\u6be9\u6bea\u6beb\u6bec\u6bed\u6bee\u6bef\u6bf0\u6bf1\u6bf2\u6bf3\u6bf4\u6bf5\u6bf6\u6bf7\u6bf8\u6bf9\u6bfa\u6bfb\u6bfc\u6bfd\u6bfe\u6bff\u6c00\u6c01\u6c02\u6c03\u6c04\u6c05\u6c06\u6c07\u6c08\u6c09\u6c0a\u6c0b\u6c0c\u6c0d\u6c0e\u6c0f\u6c10\u6c11\u6c12\u6c13\u6c14\u6c15\u6c16\u6c17\u6c18\u6c19\u6c1a\u6c1b\u6c1c\u6c1d\u6c1e\u6c1f\u6c20\u6c21\u6c22\u6c23\u6c24\u6c25\u6c26\u6c27\u6c28\u6c29\u6c2a\u6c2b\u6c2c\u6c2d\u6c2e\u6c2f\u6c30\u6c31\u6c32\u6c33\u6c34\u6c35\u6c36\u6c37\u6c38\u6c39\u6c3a\u6c3b\u6c3c\u6c3d\u6c3e\u6c3f\u6c40\u6c41\u6c42\u6c43\u6c44\u6c45\u6c46\u6c47\u6c48\u6c49\u6c4a\u6c4b\u6c4c\u6c4d\u6c4e\u6c4f\u6c50\u6c51\u6c52\u6c53\u6c54\u6c55\u6c56\u6c57\u6c58\u6c59\u6c5a\u6c5b\u6c5c\u6c5d\u6c5e\u6c5f\u6c60\u6c61\u6c62\u6c63\u6c64\u6c65\u6c66\u6c67\u6c68\u6c69\u6c6a\u6c6b\u6c6c\u6c6d\u6c6e\u6c6f\u6c70\u6c71\u6c72\u6c73\u6c74\u6c75\u6c76\u6c77\u6c78\u6c79\u6c7a\u6c7b\u6c7c\u6c7d\u6c7e\u6c7f\u6c80\u6c81\u6c82\u6c83\u6c84\u6c85\u6c86\u6c87\u6c88\u6c89\u6c8a\u6c8b\u6c8c\u6c8d\u6c8e\u6c8f\u6c90\u6c91\u6c92\u6c93\u6c94\u6c95\u6c96\u6c97\u6c98\u6c99\u6c9a\u6c9b\u6c9c\u6c9d\u6c9e\u6c9f\u6ca0\u6ca1\u6ca2\u6ca3\u6ca4\u6ca5\u6ca6\u6ca7\u6ca8\u6ca9\u6caa\u6cab\u6cac\u6cad\u6cae\u6caf\u6cb0\u6cb1\u6cb2\u6cb3\u6cb4\u6cb5\u6cb6\u6cb7\u6cb8\u6cb9\u6cba\u6cbb\u6cbc\u6cbd\u6cbe\u6cbf\u6cc0\u6cc1\u6cc2\u6cc3\u6cc4\u6cc5\u6cc6\u6cc7\u6cc8\u6cc9\u6cca\u6ccb\u6ccc\u6ccd\u6cce\u6ccf\u6cd0\u6cd1\u6cd2\u6cd3\u6cd4\u6cd5\u6cd6\u6cd7\u6cd8\u6cd9\u6cda\u6cdb\u6cdc\u6cdd\u6cde\u6cdf\u6ce0\u6ce1\u6ce2\u6ce3\u6ce4\u6ce5\u6ce6\u6ce7\u6ce8\u6ce9\u6cea\u6ceb\u6cec\u6ced\u6cee\u6cef\u6cf0\u6cf1\u6cf2\u6cf3\u6cf4\u6cf5\u6cf6\u6cf7\u6cf8\u6cf9\u6cfa\u6cfb\u6cfc\u6cfd\u6cfe\u6cff\u6d00\u6d01\u6d02\u6d03\u6d04\u6d05\u6d06\u6d07\u6d08\u6d09\u6d0a\u6d0b\u6d0c\u6d0d\u6d0e\u6d0f\u6d10\u6d11\u6d12\u6d13\u6d14\u6d15\u6d16\u6d17\u6d18\u6d19\u6d1a\u6d1b\u6d1c\u6d1d\u6d1e\u6d1f\u6d20\u6d21\u6d22\u6d23\u6d24\u6d25\u6d26\u6d27\u6d28\u6d29\u6d2a\u6d2b\u6d2c\u6d2d\u6d2e\u6d2f\u6d30\u6d31\u6d32\u6d33\u6d34\u6d35\u6d36\u6d37\u6d38\u6d39\u6d3a\u6d3b\u6d3c\u6d3d\u6d3e\u6d3f\u6d40\u6d41\u6d42\u6d43\u6d44\u6d45\u6d46\u6d47\u6d48\u6d49\u6d4a\u6d4b\u6d4c\u6d4d\u6d4e\u6d4f\u6d50\u6d51\u6d52\u6d53\u6d54\u6d55\u6d56\u6d57\u6d58\u6d59\u6d5a\u6d5b\u6d5c\u6d5d\u6d5e\u6d5f\u6d60\u6d61\u6d62\u6d63\u6d64\u6d65\u6d66\u6d67\u6d68\u6d69\u6d6a\u6d6b\u6d6c\u6d6d\u6d6e\u6d6f\u6d70\u6d71\u6d72\u6d73\u6d74\u6d75\u6d76\u6d77\u6d78\u6d79\u6d7a\u6d7b\u6d7c\u6d7d\u6d7e\u6d7f\u6d80\u6d81\u6d82\u6d83\u6d84\u6d85\u6d86\u6d87\u6d88\u6d89\u6d8a\u6d8b\u6d8c\u6d8d\u6d8e\u6d8f\u6d90\u6d91\u6d92\u6d93\u6d94\u6d95\u6d96\u6d97\u6d98\u6d99\u6d9a\u6d9b\u6d9c\u6d9d\u6d9e\u6d9f\u6da0\u6da1\u6da2\u6da3\u6da4\u6da5\u6da6\u6da7\u6da8\u6da9\u6daa\u6dab\u6dac\u6dad\u6dae\u6daf\u6db0\u6db1\u6db2\u6db3\u6db4\u6db5\u6db6\u6db7\u6db8\u6db9\u6dba\u6dbb\u6dbc\u6dbd\u6dbe\u6dbf\u6dc0\u6dc1\u6dc2\u6dc3\u6dc4\u6dc5\u6dc6\u6dc7\u6dc8\u6dc9\u6dca\u6dcb\u6dcc\u6dcd\u6dce\u6dcf\u6dd0\u6dd1\u6dd2\u6dd3\u6dd4\u6dd5\u6dd6\u6dd7\u6dd8\u6dd9\u6dda\u6ddb\u6ddc\u6ddd\u6dde\u6ddf\u6de0\u6de1\u6de2\u6de3\u6de4\u6de5\u6de6\u6de7\u6de8\u6de9\u6dea\u6deb\u6dec\u6ded\u6dee\u6def\u6df0\u6df1\u6df2\u6df3\u6df4\u6df5\u6df6\u6df7\u6df8\u6df9\u6dfa\u6dfb\u6dfc\u6dfd\u6dfe\u6dff\u6e00\u6e01\u6e02\u6e03\u6e04\u6e05\u6e06\u6e07\u6e08\u6e09\u6e0a\u6e0b\u6e0c\u6e0d\u6e0e\u6e0f\u6e10\u6e11\u6e12\u6e13\u6e14\u6e15\u6e16\u6e17\u6e18\u6e19\u6e1a\u6e1b\u6e1c\u6e1d\u6e1e\u6e1f\u6e20\u6e21\u6e22\u6e23\u6e24\u6e25\u6e26\u6e27\u6e28\u6e29\u6e2a\u6e2b\u6e2c\u6e2d\u6e2e\u6e2f\u6e30\u6e31\u6e32\u6e33\u6e34\u6e35\u6e36\u6e37\u6e38\u6e39\u6e3a\u6e3b\u6e3c\u6e3d\u6e3e\u6e3f\u6e40\u6e41\u6e42\u6e43\u6e44\u6e45\u6e46\u6e47\u6e48\u6e49\u6e4a\u6e4b\u6e4c\u6e4d\u6e4e\u6e4f\u6e50\u6e51\u6e52\u6e53\u6e54\u6e55\u6e56\u6e57\u6e58\u6e59\u6e5a\u6e5b\u6e5c\u6e5d\u6e5e\u6e5f\u6e60\u6e61\u6e62\u6e63\u6e64\u6e65\u6e66\u6e67\u6e68\u6e69\u6e6a\u6e6b\u6e6c\u6e6d\u6e6e\u6e6f\u6e70\u6e71\u6e72\u6e73\u6e74\u6e75\u6e76\u6e77\u6e78\u6e79\u6e7a\u6e7b\u6e7c\u6e7d\u6e7e\u6e7f\u6e80\u6e81\u6e82\u6e83\u6e84\u6e85\u6e86\u6e87\u6e88\u6e89\u6e8a\u6e8b\u6e8c\u6e8d\u6e8e\u6e8f\u6e90\u6e91\u6e92\u6e93\u6e94\u6e95\u6e96\u6e97\u6e98\u6e99\u6e9a\u6e9b\u6e9c\u6e9d\u6e9e\u6e9f\u6ea0\u6ea1\u6ea2\u6ea3\u6ea4\u6ea5\u6ea6\u6ea7\u6ea8\u6ea9\u6eaa\u6eab\u6eac\u6ead\u6eae\u6eaf\u6eb0\u6eb1\u6eb2\u6eb3\u6eb4\u6eb5\u6eb6\u6eb7\u6eb8\u6eb9\u6eba\u6ebb\u6ebc\u6ebd\u6ebe\u6ebf\u6ec0\u6ec1\u6ec2\u6ec3\u6ec4\u6ec5\u6ec6\u6ec7\u6ec8\u6ec9\u6eca\u6ecb\u6ecc\u6ecd\u6ece\u6ecf\u6ed0\u6ed1\u6ed2\u6ed3\u6ed4\u6ed5\u6ed6\u6ed7\u6ed8\u6ed9\u6eda\u6edb\u6edc\u6edd\u6ede\u6edf\u6ee0\u6ee1\u6ee2\u6ee3\u6ee4\u6ee5\u6ee6\u6ee7\u6ee8\u6ee9\u6eea\u6eeb\u6eec\u6eed\u6eee\u6eef\u6ef0\u6ef1\u6ef2\u6ef3\u6ef4\u6ef5\u6ef6\u6ef7\u6ef8\u6ef9\u6efa\u6efb\u6efc\u6efd\u6efe\u6eff\u6f00\u6f01\u6f02\u6f03\u6f04\u6f05\u6f06\u6f07\u6f08\u6f09\u6f0a\u6f0b\u6f0c\u6f0d\u6f0e\u6f0f\u6f10\u6f11\u6f12\u6f13\u6f14\u6f15\u6f16\u6f17\u6f18\u6f19\u6f1a\u6f1b\u6f1c\u6f1d\u6f1e\u6f1f\u6f20\u6f21\u6f22\u6f23\u6f24\u6f25\u6f26\u6f27\u6f28\u6f29\u6f2a\u6f2b\u6f2c\u6f2d\u6f2e\u6f2f\u6f30\u6f31\u6f32\u6f33\u6f34\u6f35\u6f36\u6f37\u6f38\u6f39\u6f3a\u6f3b\u6f3c\u6f3d\u6f3e\u6f3f\u6f40\u6f41\u6f42\u6f43\u6f44\u6f45\u6f46\u6f47\u6f48\u6f49\u6f4a\u6f4b\u6f4c\u6f4d\u6f4e\u6f4f\u6f50\u6f51\u6f52\u6f53\u6f54\u6f55\u6f56\u6f57\u6f58\u6f59\u6f5a\u6f5b\u6f5c\u6f5d\u6f5e\u6f5f\u6f60\u6f61\u6f62\u6f63\u6f64\u6f65\u6f66\u6f67\u6f68\u6f69\u6f6a\u6f6b\u6f6c\u6f6d\u6f6e\u6f6f\u6f70\u6f71\u6f72\u6f73\u6f74\u6f75\u6f76\u6f77\u6f78\u6f79\u6f7a\u6f7b\u6f7c\u6f7d\u6f7e\u6f7f\u6f80\u6f81\u6f82\u6f83\u6f84\u6f85\u6f86\u6f87\u6f88\u6f89\u6f8a\u6f8b\u6f8c\u6f8d\u6f8e\u6f8f\u6f90\u6f91\u6f92\u6f93\u6f94\u6f95\u6f96\u6f97\u6f98\u6f99\u6f9a\u6f9b\u6f9c\u6f9d\u6f9e\u6f9f\u6fa0\u6fa1\u6fa2\u6fa3\u6fa4\u6fa5\u6fa6\u6fa7\u6fa8\u6fa9\u6faa\u6fab\u6fac\u6fad\u6fae\u6faf\u6fb0\u6fb1\u6fb2\u6fb3\u6fb4\u6fb5\u6fb6\u6fb7\u6fb8\u6fb9\u6fba\u6fbb\u6fbc\u6fbd\u6fbe\u6fbf\u6fc0\u6fc1\u6fc2\u6fc3\u6fc4\u6fc5\u6fc6\u6fc7\u6fc8\u6fc9\u6fca\u6fcb\u6fcc\u6fcd\u6fce\u6fcf\u6fd0\u6fd1\u6fd2\u6fd3\u6fd4\u6fd5\u6fd6\u6fd7\u6fd8\u6fd9\u6fda\u6fdb\u6fdc\u6fdd\u6fde\u6fdf\u6fe0\u6fe1\u6fe2\u6fe3\u6fe4\u6fe5\u6fe6\u6fe7\u6fe8\u6fe9\u6fea\u6feb\u6fec\u6fed\u6fee\u6fef\u6ff0\u6ff1\u6ff2\u6ff3\u6ff4\u6ff5\u6ff6\u6ff7\u6ff8\u6ff9\u6ffa\u6ffb\u6ffc\u6ffd\u6ffe\u6fff\u7000\u7001\u7002\u7003\u7004\u7005\u7006\u7007\u7008\u7009\u700a\u700b\u700c\u700d\u700e\u700f\u7010\u7011\u7012\u7013\u7014\u7015\u7016\u7017\u7018\u7019\u701a\u701b\u701c\u701d\u701e\u701f\u7020\u7021\u7022\u7023\u7024\u7025\u7026\u7027\u7028\u7029\u702a\u702b\u702c\u702d\u702e\u702f\u7030\u7031\u7032\u7033\u7034\u7035\u7036\u7037\u7038\u7039\u703a\u703b\u703c\u703d\u703e\u703f\u7040\u7041\u7042\u7043\u7044\u7045\u7046\u7047\u7048\u7049\u704a\u704b\u704c\u704d\u704e\u704f\u7050\u7051\u7052\u7053\u7054\u7055\u7056\u7057\u7058\u7059\u705a\u705b\u705c\u705d\u705e\u705f\u7060\u7061\u7062\u7063\u7064\u7065\u7066\u7067\u7068\u7069\u706a\u706b\u706c\u706d\u706e\u706f\u7070\u7071\u7072\u7073\u7074\u7075\u7076\u7077\u7078\u7079\u707a\u707b\u707c\u707d\u707e\u707f\u7080\u7081\u7082\u7083\u7084\u7085\u7086\u7087\u7088\u7089\u708a\u708b\u708c\u708d\u708e\u708f\u7090\u7091\u7092\u7093\u7094\u7095\u7096\u7097\u7098\u7099\u709a\u709b\u709c\u709d\u709e\u709f\u70a0\u70a1\u70a2\u70a3\u70a4\u70a5\u70a6\u70a7\u70a8\u70a9\u70aa\u70ab\u70ac\u70ad\u70ae\u70af\u70b0\u70b1\u70b2\u70b3\u70b4\u70b5\u70b6\u70b7\u70b8\u70b9\u70ba\u70bb\u70bc\u70bd\u70be\u70bf\u70c0\u70c1\u70c2\u70c3\u70c4\u70c5\u70c6\u70c7\u70c8\u70c9\u70ca\u70cb\u70cc\u70cd\u70ce\u70cf\u70d0\u70d1\u70d2\u70d3\u70d4\u70d5\u70d6\u70d7\u70d8\u70d9\u70da\u70db\u70dc\u70dd\u70de\u70df\u70e0\u70e1\u70e2\u70e3\u70e4\u70e5\u70e6\u70e7\u70e8\u70e9\u70ea\u70eb\u70ec\u70ed\u70ee\u70ef\u70f0\u70f1\u70f2\u70f3\u70f4\u70f5\u70f6\u70f7\u70f8\u70f9\u70fa\u70fb\u70fc\u70fd\u70fe\u70ff\u7100\u7101\u7102\u7103\u7104\u7105\u7106\u7107\u7108\u7109\u710a\u710b\u710c\u710d\u710e\u710f\u7110\u7111\u7112\u7113\u7114\u7115\u7116\u7117\u7118\u7119\u711a\u711b\u711c\u711d\u711e\u711f\u7120\u7121\u7122\u7123\u7124\u7125\u7126\u7127\u7128\u7129\u712a\u712b\u712c\u712d\u712e\u712f\u7130\u7131\u7132\u7133\u7134\u7135\u7136\u7137\u7138\u7139\u713a\u713b\u713c\u713d\u713e\u713f\u7140\u7141\u7142\u7143\u7144\u7145\u7146\u7147\u7148\u7149\u714a\u714b\u714c\u714d\u714e\u714f\u7150\u7151\u7152\u7153\u7154\u7155\u7156\u7157\u7158\u7159\u715a\u715b\u715c\u715d\u715e\u715f\u7160\u7161\u7162\u7163\u7164\u7165\u7166\u7167\u7168\u7169\u716a\u716b\u716c\u716d\u716e\u716f\u7170\u7171\u7172\u7173\u7174\u7175\u7176\u7177\u7178\u7179\u717a\u717b\u717c\u717d\u717e\u717f\u7180\u7181\u7182\u7183\u7184\u7185\u7186\u7187\u7188\u7189\u718a\u718b\u718c\u718d\u718e\u718f\u7190\u7191\u7192\u7193\u7194\u7195\u7196\u7197\u7198\u7199\u719a\u719b\u719c\u719d\u719e\u719f\u71a0\u71a1\u71a2\u71a3\u71a4\u71a5\u71a6\u71a7\u71a8\u71a9\u71aa\u71ab\u71ac\u71ad\u71ae\u71af\u71b0\u71b1\u71b2\u71b3\u71b4\u71b5\u71b6\u71b7\u71b8\u71b9\u71ba\u71bb\u71bc\u71bd\u71be\u71bf\u71c0\u71c1\u71c2\u71c3\u71c4\u71c5\u71c6\u71c7\u71c8\u71c9\u71ca\u71cb\u71cc\u71cd\u71ce\u71cf\u71d0\u71d1\u71d2\u71d3\u71d4\u71d5\u71d6\u71d7\u71d8\u71d9\u71da\u71db\u71dc\u71dd\u71de\u71df\u71e0\u71e1\u71e2\u71e3\u71e4\u71e5\u71e6\u71e7\u71e8\u71e9\u71ea\u71eb\u71ec\u71ed\u71ee\u71ef\u71f0\u71f1\u71f2\u71f3\u71f4\u71f5\u71f6\u71f7\u71f8\u71f9\u71fa\u71fb\u71fc\u71fd\u71fe\u71ff\u7200\u7201\u7202\u7203\u7204\u7205\u7206\u7207\u7208\u7209\u720a\u720b\u720c\u720d\u720e\u720f\u7210\u7211\u7212\u7213\u7214\u7215\u7216\u7217\u7218\u7219\u721a\u721b\u721c\u721d\u721e\u721f\u7220\u7221\u7222\u7223\u7224\u7225\u7226\u7227\u7228\u7229\u722a\u722b\u722c\u722d\u722e\u722f\u7230\u7231\u7232\u7233\u7234\u7235\u7236\u7237\u7238\u7239\u723a\u723b\u723c\u723d\u723e\u723f\u7240\u7241\u7242\u7243\u7244\u7245\u7246\u7247\u7248\u7249\u724a\u724b\u724c\u724d\u724e\u724f\u7250\u7251\u7252\u7253\u7254\u7255\u7256\u7257\u7258\u7259\u725a\u725b\u725c\u725d\u725e\u725f\u7260\u7261\u7262\u7263\u7264\u7265\u7266\u7267\u7268\u7269\u726a\u726b\u726c\u726d\u726e\u726f\u7270\u7271\u7272\u7273\u7274\u7275\u7276\u7277\u7278\u7279\u727a\u727b\u727c\u727d\u727e\u727f\u7280\u7281\u7282\u7283\u7284\u7285\u7286\u7287\u7288\u7289\u728a\u728b\u728c\u728d\u728e\u728f\u7290\u7291\u7292\u7293\u7294\u7295\u7296\u7297\u7298\u7299\u729a\u729b\u729c\u729d\u729e\u729f\u72a0\u72a1\u72a2\u72a3\u72a4\u72a5\u72a6\u72a7\u72a8\u72a9\u72aa\u72ab\u72ac\u72ad\u72ae\u72af\u72b0\u72b1\u72b2\u72b3\u72b4\u72b5\u72b6\u72b7\u72b8\u72b9\u72ba\u72bb\u72bc\u72bd\u72be\u72bf\u72c0\u72c1\u72c2\u72c3\u72c4\u72c5\u72c6\u72c7\u72c8\u72c9\u72ca\u72cb\u72cc\u72cd\u72ce\u72cf\u72d0\u72d1\u72d2\u72d3\u72d4\u72d5\u72d6\u72d7\u72d8\u72d9\u72da\u72db\u72dc\u72dd\u72de\u72df\u72e0\u72e1\u72e2\u72e3\u72e4\u72e5\u72e6\u72e7\u72e8\u72e9\u72ea\u72eb\u72ec\u72ed\u72ee\u72ef\u72f0\u72f1\u72f2\u72f3\u72f4\u72f5\u72f6\u72f7\u72f8\u72f9\u72fa\u72fb\u72fc\u72fd\u72fe\u72ff\u7300\u7301\u7302\u7303\u7304\u7305\u7306\u7307\u7308\u7309\u730a\u730b\u730c\u730d\u730e\u730f\u7310\u7311\u7312\u7313\u7314\u7315\u7316\u7317\u7318\u7319\u731a\u731b\u731c\u731d\u731e\u731f\u7320\u7321\u7322\u7323\u7324\u7325\u7326\u7327\u7328\u7329\u732a\u732b\u732c\u732d\u732e\u732f\u7330\u7331\u7332\u7333\u7334\u7335\u7336\u7337\u7338\u7339\u733a\u733b\u733c\u733d\u733e\u733f\u7340\u7341\u7342\u7343\u7344\u7345\u7346\u7347\u7348\u7349\u734a\u734b\u734c\u734d\u734e\u734f\u7350\u7351\u7352\u7353\u7354\u7355\u7356\u7357\u7358\u7359\u735a\u735b\u735c\u735d\u735e\u735f\u7360\u7361\u7362\u7363\u7364\u7365\u7366\u7367\u7368\u7369\u736a\u736b\u736c\u736d\u736e\u736f\u7370\u7371\u7372\u7373\u7374\u7375\u7376\u7377\u7378\u7379\u737a\u737b\u737c\u737d\u737e\u737f\u7380\u7381\u7382\u7383\u7384\u7385\u7386\u7387\u7388\u7389\u738a\u738b\u738c\u738d\u738e\u738f\u7390\u7391\u7392\u7393\u7394\u7395\u7396\u7397\u7398\u7399\u739a\u739b\u739c\u739d\u739e\u739f\u73a0\u73a1\u73a2\u73a3\u73a4\u73a5\u73a6\u73a7\u73a8\u73a9\u73aa\u73ab\u73ac\u73ad\u73ae\u73af\u73b0\u73b1\u73b2\u73b3\u73b4\u73b5\u73b6\u73b7\u73b8\u73b9\u73ba\u73bb\u73bc\u73bd\u73be\u73bf\u73c0\u73c1\u73c2\u73c3\u73c4\u73c5\u73c6\u73c7\u73c8\u73c9\u73ca\u73cb\u73cc\u73cd\u73ce\u73cf\u73d0\u73d1\u73d2\u73d3\u73d4\u73d5\u73d6\u73d7\u73d8\u73d9\u73da\u73db\u73dc\u73dd\u73de\u73df\u73e0\u73e1\u73e2\u73e3\u73e4\u73e5\u73e6\u73e7\u73e8\u73e9\u73ea\u73eb\u73ec\u73ed\u73ee\u73ef\u73f0\u73f1\u73f2\u73f3\u73f4\u73f5\u73f6\u73f7\u73f8\u73f9\u73fa\u73fb\u73fc\u73fd\u73fe\u73ff\u7400\u7401\u7402\u7403\u7404\u7405\u7406\u7407\u7408\u7409\u740a\u740b\u740c\u740d\u740e\u740f\u7410\u7411\u7412\u7413\u7414\u7415\u7416\u7417\u7418\u7419\u741a\u741b\u741c\u741d\u741e\u741f\u7420\u7421\u7422\u7423\u7424\u7425\u7426\u7427\u7428\u7429\u742a\u742b\u742c\u742d\u742e\u742f\u7430\u7431\u7432\u7433\u7434\u7435\u7436\u7437\u7438\u7439\u743a\u743b\u743c\u743d\u743e\u743f\u7440\u7441\u7442\u7443\u7444\u7445\u7446\u7447\u7448\u7449\u744a\u744b\u744c\u744d\u744e\u744f\u7450\u7451\u7452\u7453\u7454\u7455\u7456\u7457\u7458\u7459\u745a\u745b\u745c\u745d\u745e\u745f\u7460\u7461\u7462\u7463\u7464\u7465\u7466\u7467\u7468\u7469\u746a\u746b\u746c\u746d\u746e\u746f\u7470\u7471\u7472\u7473\u7474\u7475\u7476\u7477\u7478\u7479\u747a\u747b\u747c\u747d\u747e\u747f\u7480\u7481\u7482\u7483\u7484\u7485\u7486\u7487\u7488\u7489\u748a\u748b\u748c\u748d\u748e\u748f\u7490\u7491\u7492\u7493\u7494\u7495\u7496\u7497\u7498\u7499\u749a\u749b\u749c\u749d\u749e\u749f\u74a0\u74a1\u74a2\u74a3\u74a4\u74a5\u74a6\u74a7\u74a8\u74a9\u74aa\u74ab\u74ac\u74ad\u74ae\u74af\u74b0\u74b1\u74b2\u74b3\u74b4\u74b5\u74b6\u74b7\u74b8\u74b9\u74ba\u74bb\u74bc\u74bd\u74be\u74bf\u74c0\u74c1\u74c2\u74c3\u74c4\u74c5\u74c6\u74c7\u74c8\u74c9\u74ca\u74cb\u74cc\u74cd\u74ce\u74cf\u74d0\u74d1\u74d2\u74d3\u74d4\u74d5\u74d6\u74d7\u74d8\u74d9\u74da\u74db\u74dc\u74dd\u74de\u74df\u74e0\u74e1\u74e2\u74e3\u74e4\u74e5\u74e6\u74e7\u74e8\u74e9\u74ea\u74eb\u74ec\u74ed\u74ee\u74ef\u74f0\u74f1\u74f2\u74f3\u74f4\u74f5\u74f6\u74f7\u74f8\u74f9\u74fa\u74fb\u74fc\u74fd\u74fe\u74ff\u7500\u7501\u7502\u7503\u7504\u7505\u7506\u7507\u7508\u7509\u750a\u750b\u750c\u750d\u750e\u750f\u7510\u7511\u7512\u7513\u7514\u7515\u7516\u7517\u7518\u7519\u751a\u751b\u751c\u751d\u751e\u751f\u7520\u7521\u7522\u7523\u7524\u7525\u7526\u7527\u7528\u7529\u752a\u752b\u752c\u752d\u752e\u752f\u7530\u7531\u7532\u7533\u7534\u7535\u7536\u7537\u7538\u7539\u753a\u753b\u753c\u753d\u753e\u753f\u7540\u7541\u7542\u7543\u7544\u7545\u7546\u7547\u7548\u7549\u754a\u754b\u754c\u754d\u754e\u754f\u7550\u7551\u7552\u7553\u7554\u7555\u7556\u7557\u7558\u7559\u755a\u755b\u755c\u755d\u755e\u755f\u7560\u7561\u7562\u7563\u7564\u7565\u7566\u7567\u7568\u7569\u756a\u756b\u756c\u756d\u756e\u756f\u7570\u7571\u7572\u7573\u7574\u7575\u7576\u7577\u7578\u7579\u757a\u757b\u757c\u757d\u757e\u757f\u7580\u7581\u7582\u7583\u7584\u7585\u7586\u7587\u7588\u7589\u758a\u758b\u758c\u758d\u758e\u758f\u7590\u7591\u7592\u7593\u7594\u7595\u7596\u7597\u7598\u7599\u759a\u759b\u759c\u759d\u759e\u759f\u75a0\u75a1\u75a2\u75a3\u75a4\u75a5\u75a6\u75a7\u75a8\u75a9\u75aa\u75ab\u75ac\u75ad\u75ae\u75af\u75b0\u75b1\u75b2\u75b3\u75b4\u75b5\u75b6\u75b7\u75b8\u75b9\u75ba\u75bb\u75bc\u75bd\u75be\u75bf\u75c0\u75c1\u75c2\u75c3\u75c4\u75c5\u75c6\u75c7\u75c8\u75c9\u75ca\u75cb\u75cc\u75cd\u75ce\u75cf\u75d0\u75d1\u75d2\u75d3\u75d4\u75d5\u75d6\u75d7\u75d8\u75d9\u75da\u75db\u75dc\u75dd\u75de\u75df\u75e0\u75e1\u75e2\u75e3\u75e4\u75e5\u75e6\u75e7\u75e8\u75e9\u75ea\u75eb\u75ec\u75ed\u75ee\u75ef\u75f0\u75f1\u75f2\u75f3\u75f4\u75f5\u75f6\u75f7\u75f8\u75f9\u75fa\u75fb\u75fc\u75fd\u75fe\u75ff\u7600\u7601\u7602\u7603\u7604\u7605\u7606\u7607\u7608\u7609\u760a\u760b\u760c\u760d\u760e\u760f\u7610\u7611\u7612\u7613\u7614\u7615\u7616\u7617\u7618\u7619\u761a\u761b\u761c\u761d\u761e\u761f\u7620\u7621\u7622\u7623\u7624\u7625\u7626\u7627\u7628\u7629\u762a\u762b\u762c\u762d\u762e\u762f\u7630\u7631\u7632\u7633\u7634\u7635\u7636\u7637\u7638\u7639\u763a\u763b\u763c\u763d\u763e\u763f\u7640\u7641\u7642\u7643\u7644\u7645\u7646\u7647\u7648\u7649\u764a\u764b\u764c\u764d\u764e\u764f\u7650\u7651\u7652\u7653\u7654\u7655\u7656\u7657\u7658\u7659\u765a\u765b\u765c\u765d\u765e\u765f\u7660\u7661\u7662\u7663\u7664\u7665\u7666\u7667\u7668\u7669\u766a\u766b\u766c\u766d\u766e\u766f\u7670\u7671\u7672\u7673\u7674\u7675\u7676\u7677\u7678\u7679\u767a\u767b\u767c\u767d\u767e\u767f\u7680\u7681\u7682\u7683\u7684\u7685\u7686\u7687\u7688\u7689\u768a\u768b\u768c\u768d\u768e\u768f\u7690\u7691\u7692\u7693\u7694\u7695\u7696\u7697\u7698\u7699\u769a\u769b\u769c\u769d\u769e\u769f\u76a0\u76a1\u76a2\u76a3\u76a4\u76a5\u76a6\u76a7\u76a8\u76a9\u76aa\u76ab\u76ac\u76ad\u76ae\u76af\u76b0\u76b1\u76b2\u76b3\u76b4\u76b5\u76b6\u76b7\u76b8\u76b9\u76ba\u76bb\u76bc\u76bd\u76be\u76bf\u76c0\u76c1\u76c2\u76c3\u76c4\u76c5\u76c6\u76c7\u76c8\u76c9\u76ca\u76cb\u76cc\u76cd\u76ce\u76cf\u76d0\u76d1\u76d2\u76d3\u76d4\u76d5\u76d6\u76d7\u76d8\u76d9\u76da\u76db\u76dc\u76dd\u76de\u76df\u76e0\u76e1\u76e2\u76e3\u76e4\u76e5\u76e6\u76e7\u76e8\u76e9\u76ea\u76eb\u76ec\u76ed\u76ee\u76ef\u76f0\u76f1\u76f2\u76f3\u76f4\u76f5\u76f6\u76f7\u76f8\u76f9\u76fa\u76fb\u76fc\u76fd\u76fe\u76ff\u7700\u7701\u7702\u7703\u7704\u7705\u7706\u7707\u7708\u7709\u770a\u770b\u770c\u770d\u770e\u770f\u7710\u7711\u7712\u7713\u7714\u7715\u7716\u7717\u7718\u7719\u771a\u771b\u771c\u771d\u771e\u771f\u7720\u7721\u7722\u7723\u7724\u7725\u7726\u7727\u7728\u7729\u772a\u772b\u772c\u772d\u772e\u772f\u7730\u7731\u7732\u7733\u7734\u7735\u7736\u7737\u7738\u7739\u773a\u773b\u773c\u773d\u773e\u773f\u7740\u7741\u7742\u7743\u7744\u7745\u7746\u7747\u7748\u7749\u774a\u774b\u774c\u774d\u774e\u774f\u7750\u7751\u7752\u7753\u7754\u7755\u7756\u7757\u7758\u7759\u775a\u775b\u775c\u775d\u775e\u775f\u7760\u7761\u7762\u7763\u7764\u7765\u7766\u7767\u7768\u7769\u776a\u776b\u776c\u776d\u776e\u776f\u7770\u7771\u7772\u7773\u7774\u7775\u7776\u7777\u7778\u7779\u777a\u777b\u777c\u777d\u777e\u777f\u7780\u7781\u7782\u7783\u7784\u7785\u7786\u7787\u7788\u7789\u778a\u778b\u778c\u778d\u778e\u778f\u7790\u7791\u7792\u7793\u7794\u7795\u7796\u7797\u7798\u7799\u779a\u779b\u779c\u779d\u779e\u779f\u77a0\u77a1\u77a2\u77a3\u77a4\u77a5\u77a6\u77a7\u77a8\u77a9\u77aa\u77ab\u77ac\u77ad\u77ae\u77af\u77b0\u77b1\u77b2\u77b3\u77b4\u77b5\u77b6\u77b7\u77b8\u77b9\u77ba\u77bb\u77bc\u77bd\u77be\u77bf\u77c0\u77c1\u77c2\u77c3\u77c4\u77c5\u77c6\u77c7\u77c8\u77c9\u77ca\u77cb\u77cc\u77cd\u77ce\u77cf\u77d0\u77d1\u77d2\u77d3\u77d4\u77d5\u77d6\u77d7\u77d8\u77d9\u77da\u77db\u77dc\u77dd\u77de\u77df\u77e0\u77e1\u77e2\u77e3\u77e4\u77e5\u77e6\u77e7\u77e8\u77e9\u77ea\u77eb\u77ec\u77ed\u77ee\u77ef\u77f0\u77f1\u77f2\u77f3\u77f4\u77f5\u77f6\u77f7\u77f8\u77f9\u77fa\u77fb\u77fc\u77fd\u77fe\u77ff\u7800\u7801\u7802\u7803\u7804\u7805\u7806\u7807\u7808\u7809\u780a\u780b\u780c\u780d\u780e\u780f\u7810\u7811\u7812\u7813\u7814\u7815\u7816\u7817\u7818\u7819\u781a\u781b\u781c\u781d\u781e\u781f\u7820\u7821\u7822\u7823\u7824\u7825\u7826\u7827\u7828\u7829\u782a\u782b\u782c\u782d\u782e\u782f\u7830\u7831\u7832\u7833\u7834\u7835\u7836\u7837\u7838\u7839\u783a\u783b\u783c\u783d\u783e\u783f\u7840\u7841\u7842\u7843\u7844\u7845\u7846\u7847\u7848\u7849\u784a\u784b\u784c\u784d\u784e\u784f\u7850\u7851\u7852\u7853\u7854\u7855\u7856\u7857\u7858\u7859\u785a\u785b\u785c\u785d\u785e\u785f\u7860\u7861\u7862\u7863\u7864\u7865\u7866\u7867\u7868\u7869\u786a\u786b\u786c\u786d\u786e\u786f\u7870\u7871\u7872\u7873\u7874\u7875\u7876\u7877\u7878\u7879\u787a\u787b\u787c\u787d\u787e\u787f\u7880\u7881\u7882\u7883\u7884\u7885\u7886\u7887\u7888\u7889\u788a\u788b\u788c\u788d\u788e\u788f\u7890\u7891\u7892\u7893\u7894\u7895\u7896\u7897\u7898\u7899\u789a\u789b\u789c\u789d\u789e\u789f\u78a0\u78a1\u78a2\u78a3\u78a4\u78a5\u78a6\u78a7\u78a8\u78a9\u78aa\u78ab\u78ac\u78ad\u78ae\u78af\u78b0\u78b1\u78b2\u78b3\u78b4\u78b5\u78b6\u78b7\u78b8\u78b9\u78ba\u78bb\u78bc\u78bd\u78be\u78bf\u78c0\u78c1\u78c2\u78c3\u78c4\u78c5\u78c6\u78c7\u78c8\u78c9\u78ca\u78cb\u78cc\u78cd\u78ce\u78cf\u78d0\u78d1\u78d2\u78d3\u78d4\u78d5\u78d6\u78d7\u78d8\u78d9\u78da\u78db\u78dc\u78dd\u78de\u78df\u78e0\u78e1\u78e2\u78e3\u78e4\u78e5\u78e6\u78e7\u78e8\u78e9\u78ea\u78eb\u78ec\u78ed\u78ee\u78ef\u78f0\u78f1\u78f2\u78f3\u78f4\u78f5\u78f6\u78f7\u78f8\u78f9\u78fa\u78fb\u78fc\u78fd\u78fe\u78ff\u7900\u7901\u7902\u7903\u7904\u7905\u7906\u7907\u7908\u7909\u790a\u790b\u790c\u790d\u790e\u790f\u7910\u7911\u7912\u7913\u7914\u7915\u7916\u7917\u7918\u7919\u791a\u791b\u791c\u791d\u791e\u791f\u7920\u7921\u7922\u7923\u7924\u7925\u7926\u7927\u7928\u7929\u792a\u792b\u792c\u792d\u792e\u792f\u7930\u7931\u7932\u7933\u7934\u7935\u7936\u7937\u7938\u7939\u793a\u793b\u793c\u793d\u793e\u793f\u7940\u7941\u7942\u7943\u7944\u7945\u7946\u7947\u7948\u7949\u794a\u794b\u794c\u794d\u794e\u794f\u7950\u7951\u7952\u7953\u7954\u7955\u7956\u7957\u7958\u7959\u795a\u795b\u795c\u795d\u795e\u795f\u7960\u7961\u7962\u7963\u7964\u7965\u7966\u7967\u7968\u7969\u796a\u796b\u796c\u796d\u796e\u796f\u7970\u7971\u7972\u7973\u7974\u7975\u7976\u7977\u7978\u7979\u797a\u797b\u797c\u797d\u797e\u797f\u7980\u7981\u7982\u7983\u7984\u7985\u7986\u7987\u7988\u7989\u798a\u798b\u798c\u798d\u798e\u798f\u7990\u7991\u7992\u7993\u7994\u7995\u7996\u7997\u7998\u7999\u799a\u799b\u799c\u799d\u799e\u799f\u79a0\u79a1\u79a2\u79a3\u79a4\u79a5\u79a6\u79a7\u79a8\u79a9\u79aa\u79ab\u79ac\u79ad\u79ae\u79af\u79b0\u79b1\u79b2\u79b3\u79b4\u79b5\u79b6\u79b7\u79b8\u79b9\u79ba\u79bb\u79bc\u79bd\u79be\u79bf\u79c0\u79c1\u79c2\u79c3\u79c4\u79c5\u79c6\u79c7\u79c8\u79c9\u79ca\u79cb\u79cc\u79cd\u79ce\u79cf\u79d0\u79d1\u79d2\u79d3\u79d4\u79d5\u79d6\u79d7\u79d8\u79d9\u79da\u79db\u79dc\u79dd\u79de\u79df\u79e0\u79e1\u79e2\u79e3\u79e4\u79e5\u79e6\u79e7\u79e8\u79e9\u79ea\u79eb\u79ec\u79ed\u79ee\u79ef\u79f0\u79f1\u79f2\u79f3\u79f4\u79f5\u79f6\u79f7\u79f8\u79f9\u79fa\u79fb\u79fc\u79fd\u79fe\u79ff\u7a00\u7a01\u7a02\u7a03\u7a04\u7a05\u7a06\u7a07\u7a08\u7a09\u7a0a\u7a0b\u7a0c\u7a0d\u7a0e\u7a0f\u7a10\u7a11\u7a12\u7a13\u7a14\u7a15\u7a16\u7a17\u7a18\u7a19\u7a1a\u7a1b\u7a1c\u7a1d\u7a1e\u7a1f\u7a20\u7a21\u7a22\u7a23\u7a24\u7a25\u7a26\u7a27\u7a28\u7a29\u7a2a\u7a2b\u7a2c\u7a2d\u7a2e\u7a2f\u7a30\u7a31\u7a32\u7a33\u7a34\u7a35\u7a36\u7a37\u7a38\u7a39\u7a3a\u7a3b\u7a3c\u7a3d\u7a3e\u7a3f\u7a40\u7a41\u7a42\u7a43\u7a44\u7a45\u7a46\u7a47\u7a48\u7a49\u7a4a\u7a4b\u7a4c\u7a4d\u7a4e\u7a4f\u7a50\u7a51\u7a52\u7a53\u7a54\u7a55\u7a56\u7a57\u7a58\u7a59\u7a5a\u7a5b\u7a5c\u7a5d\u7a5e\u7a5f\u7a60\u7a61\u7a62\u7a63\u7a64\u7a65\u7a66\u7a67\u7a68\u7a69\u7a6a\u7a6b\u7a6c\u7a6d\u7a6e\u7a6f\u7a70\u7a71\u7a72\u7a73\u7a74\u7a75\u7a76\u7a77\u7a78\u7a79\u7a7a\u7a7b\u7a7c\u7a7d\u7a7e\u7a7f\u7a80\u7a81\u7a82\u7a83\u7a84\u7a85\u7a86\u7a87\u7a88\u7a89\u7a8a\u7a8b\u7a8c\u7a8d\u7a8e\u7a8f\u7a90\u7a91\u7a92\u7a93\u7a94\u7a95\u7a96\u7a97\u7a98\u7a99\u7a9a\u7a9b\u7a9c\u7a9d\u7a9e\u7a9f\u7aa0\u7aa1\u7aa2\u7aa3\u7aa4\u7aa5\u7aa6\u7aa7\u7aa8\u7aa9\u7aaa\u7aab\u7aac\u7aad\u7aae\u7aaf\u7ab0\u7ab1\u7ab2\u7ab3\u7ab4\u7ab5\u7ab6\u7ab7\u7ab8\u7ab9\u7aba\u7abb\u7abc\u7abd\u7abe\u7abf\u7ac0\u7ac1\u7ac2\u7ac3\u7ac4\u7ac5\u7ac6\u7ac7\u7ac8\u7ac9\u7aca\u7acb\u7acc\u7acd\u7ace\u7acf\u7ad0\u7ad1\u7ad2\u7ad3\u7ad4\u7ad5\u7ad6\u7ad7\u7ad8\u7ad9\u7ada\u7adb\u7adc\u7add\u7ade\u7adf\u7ae0\u7ae1\u7ae2\u7ae3\u7ae4\u7ae5\u7ae6\u7ae7\u7ae8\u7ae9\u7aea\u7aeb\u7aec\u7aed\u7aee\u7aef\u7af0\u7af1\u7af2\u7af3\u7af4\u7af5\u7af6\u7af7\u7af8\u7af9\u7afa\u7afb\u7afc\u7afd\u7afe\u7aff\u7b00\u7b01\u7b02\u7b03\u7b04\u7b05\u7b06\u7b07\u7b08\u7b09\u7b0a\u7b0b\u7b0c\u7b0d\u7b0e\u7b0f\u7b10\u7b11\u7b12\u7b13\u7b14\u7b15\u7b16\u7b17\u7b18\u7b19\u7b1a\u7b1b\u7b1c\u7b1d\u7b1e\u7b1f\u7b20\u7b21\u7b22\u7b23\u7b24\u7b25\u7b26\u7b27\u7b28\u7b29\u7b2a\u7b2b\u7b2c\u7b2d\u7b2e\u7b2f\u7b30\u7b31\u7b32\u7b33\u7b34\u7b35\u7b36\u7b37\u7b38\u7b39\u7b3a\u7b3b\u7b3c\u7b3d\u7b3e\u7b3f\u7b40\u7b41\u7b42\u7b43\u7b44\u7b45\u7b46\u7b47\u7b48\u7b49\u7b4a\u7b4b\u7b4c\u7b4d\u7b4e\u7b4f\u7b50\u7b51\u7b52\u7b53\u7b54\u7b55\u7b56\u7b57\u7b58\u7b59\u7b5a\u7b5b\u7b5c\u7b5d\u7b5e\u7b5f\u7b60\u7b61\u7b62\u7b63\u7b64\u7b65\u7b66\u7b67\u7b68\u7b69\u7b6a\u7b6b\u7b6c\u7b6d\u7b6e\u7b6f\u7b70\u7b71\u7b72\u7b73\u7b74\u7b75\u7b76\u7b77\u7b78\u7b79\u7b7a\u7b7b\u7b7c\u7b7d\u7b7e\u7b7f\u7b80\u7b81\u7b82\u7b83\u7b84\u7b85\u7b86\u7b87\u7b88\u7b89\u7b8a\u7b8b\u7b8c\u7b8d\u7b8e\u7b8f\u7b90\u7b91\u7b92\u7b93\u7b94\u7b95\u7b96\u7b97\u7b98\u7b99\u7b9a\u7b9b\u7b9c\u7b9d\u7b9e\u7b9f\u7ba0\u7ba1\u7ba2\u7ba3\u7ba4\u7ba5\u7ba6\u7ba7\u7ba8\u7ba9\u7baa\u7bab\u7bac\u7bad\u7bae\u7baf\u7bb0\u7bb1\u7bb2\u7bb3\u7bb4\u7bb5\u7bb6\u7bb7\u7bb8\u7bb9\u7bba\u7bbb\u7bbc\u7bbd\u7bbe\u7bbf\u7bc0\u7bc1\u7bc2\u7bc3\u7bc4\u7bc5\u7bc6\u7bc7\u7bc8\u7bc9\u7bca\u7bcb\u7bcc\u7bcd\u7bce\u7bcf\u7bd0\u7bd1\u7bd2\u7bd3\u7bd4\u7bd5\u7bd6\u7bd7\u7bd8\u7bd9\u7bda\u7bdb\u7bdc\u7bdd\u7bde\u7bdf\u7be0\u7be1\u7be2\u7be3\u7be4\u7be5\u7be6\u7be7\u7be8\u7be9\u7bea\u7beb\u7bec\u7bed\u7bee\u7bef\u7bf0\u7bf1\u7bf2\u7bf3\u7bf4\u7bf5\u7bf6\u7bf7\u7bf8\u7bf9\u7bfa\u7bfb\u7bfc\u7bfd\u7bfe\u7bff\u7c00\u7c01\u7c02\u7c03\u7c04\u7c05\u7c06\u7c07\u7c08\u7c09\u7c0a\u7c0b\u7c0c\u7c0d\u7c0e\u7c0f\u7c10\u7c11\u7c12\u7c13\u7c14\u7c15\u7c16\u7c17\u7c18\u7c19\u7c1a\u7c1b\u7c1c\u7c1d\u7c1e\u7c1f\u7c20\u7c21\u7c22\u7c23\u7c24\u7c25\u7c26\u7c27\u7c28\u7c29\u7c2a\u7c2b\u7c2c\u7c2d\u7c2e\u7c2f\u7c30\u7c31\u7c32\u7c33\u7c34\u7c35\u7c36\u7c37\u7c38\u7c39\u7c3a\u7c3b\u7c3c\u7c3d\u7c3e\u7c3f\u7c40\u7c41\u7c42\u7c43\u7c44\u7c45\u7c46\u7c47\u7c48\u7c49\u7c4a\u7c4b\u7c4c\u7c4d\u7c4e\u7c4f\u7c50\u7c51\u7c52\u7c53\u7c54\u7c55\u7c56\u7c57\u7c58\u7c59\u7c5a\u7c5b\u7c5c\u7c5d\u7c5e\u7c5f\u7c60\u7c61\u7c62\u7c63\u7c64\u7c65\u7c66\u7c67\u7c68\u7c69\u7c6a\u7c6b\u7c6c\u7c6d\u7c6e\u7c6f\u7c70\u7c71\u7c72\u7c73\u7c74\u7c75\u7c76\u7c77\u7c78\u7c79\u7c7a\u7c7b\u7c7c\u7c7d\u7c7e\u7c7f\u7c80\u7c81\u7c82\u7c83\u7c84\u7c85\u7c86\u7c87\u7c88\u7c89\u7c8a\u7c8b\u7c8c\u7c8d\u7c8e\u7c8f\u7c90\u7c91\u7c92\u7c93\u7c94\u7c95\u7c96\u7c97\u7c98\u7c99\u7c9a\u7c9b\u7c9c\u7c9d\u7c9e\u7c9f\u7ca0\u7ca1\u7ca2\u7ca3\u7ca4\u7ca5\u7ca6\u7ca7\u7ca8\u7ca9\u7caa\u7cab\u7cac\u7cad\u7cae\u7caf\u7cb0\u7cb1\u7cb2\u7cb3\u7cb4\u7cb5\u7cb6\u7cb7\u7cb8\u7cb9\u7cba\u7cbb\u7cbc\u7cbd\u7cbe\u7cbf\u7cc0\u7cc1\u7cc2\u7cc3\u7cc4\u7cc5\u7cc6\u7cc7\u7cc8\u7cc9\u7cca\u7ccb\u7ccc\u7ccd\u7cce\u7ccf\u7cd0\u7cd1\u7cd2\u7cd3\u7cd4\u7cd5\u7cd6\u7cd7\u7cd8\u7cd9\u7cda\u7cdb\u7cdc\u7cdd\u7cde\u7cdf\u7ce0\u7ce1\u7ce2\u7ce3\u7ce4\u7ce5\u7ce6\u7ce7\u7ce8\u7ce9\u7cea\u7ceb\u7cec\u7ced\u7cee\u7cef\u7cf0\u7cf1\u7cf2\u7cf3\u7cf4\u7cf5\u7cf6\u7cf7\u7cf8\u7cf9\u7cfa\u7cfb\u7cfc\u7cfd\u7cfe\u7cff\u7d00\u7d01\u7d02\u7d03\u7d04\u7d05\u7d06\u7d07\u7d08\u7d09\u7d0a\u7d0b\u7d0c\u7d0d\u7d0e\u7d0f\u7d10\u7d11\u7d12\u7d13\u7d14\u7d15\u7d16\u7d17\u7d18\u7d19\u7d1a\u7d1b\u7d1c\u7d1d\u7d1e\u7d1f\u7d20\u7d21\u7d22\u7d23\u7d24\u7d25\u7d26\u7d27\u7d28\u7d29\u7d2a\u7d2b\u7d2c\u7d2d\u7d2e\u7d2f\u7d30\u7d31\u7d32\u7d33\u7d34\u7d35\u7d36\u7d37\u7d38\u7d39\u7d3a\u7d3b\u7d3c\u7d3d\u7d3e\u7d3f\u7d40\u7d41\u7d42\u7d43\u7d44\u7d45\u7d46\u7d47\u7d48\u7d49\u7d4a\u7d4b\u7d4c\u7d4d\u7d4e\u7d4f\u7d50\u7d51\u7d52\u7d53\u7d54\u7d55\u7d56\u7d57\u7d58\u7d59\u7d5a\u7d5b\u7d5c\u7d5d\u7d5e\u7d5f\u7d60\u7d61\u7d62\u7d63\u7d64\u7d65\u7d66\u7d67\u7d68\u7d69\u7d6a\u7d6b\u7d6c\u7d6d\u7d6e\u7d6f\u7d70\u7d71\u7d72\u7d73\u7d74\u7d75\u7d76\u7d77\u7d78\u7d79\u7d7a\u7d7b\u7d7c\u7d7d\u7d7e\u7d7f\u7d80\u7d81\u7d82\u7d83\u7d84\u7d85\u7d86\u7d87\u7d88\u7d89\u7d8a\u7d8b\u7d8c\u7d8d\u7d8e\u7d8f\u7d90\u7d91\u7d92\u7d93\u7d94\u7d95\u7d96\u7d97\u7d98\u7d99\u7d9a\u7d9b\u7d9c\u7d9d\u7d9e\u7d9f\u7da0\u7da1\u7da2\u7da3\u7da4\u7da5\u7da6\u7da7\u7da8\u7da9\u7daa\u7dab\u7dac\u7dad\u7dae\u7daf\u7db0\u7db1\u7db2\u7db3\u7db4\u7db5\u7db6\u7db7\u7db8\u7db9\u7dba\u7dbb\u7dbc\u7dbd\u7dbe\u7dbf\u7dc0\u7dc1\u7dc2\u7dc3\u7dc4\u7dc5\u7dc6\u7dc7\u7dc8\u7dc9\u7dca\u7dcb\u7dcc\u7dcd\u7dce\u7dcf\u7dd0\u7dd1\u7dd2\u7dd3\u7dd4\u7dd5\u7dd6\u7dd7\u7dd8\u7dd9\u7dda\u7ddb\u7ddc\u7ddd\u7dde\u7ddf\u7de0\u7de1\u7de2\u7de3\u7de4\u7de5\u7de6\u7de7\u7de8\u7de9\u7dea\u7deb\u7dec\u7ded\u7dee\u7def\u7df0\u7df1\u7df2\u7df3\u7df4\u7df5\u7df6\u7df7\u7df8\u7df9\u7dfa\u7dfb\u7dfc\u7dfd\u7dfe\u7dff\u7e00\u7e01\u7e02\u7e03\u7e04\u7e05\u7e06\u7e07\u7e08\u7e09\u7e0a\u7e0b\u7e0c\u7e0d\u7e0e\u7e0f\u7e10\u7e11\u7e12\u7e13\u7e14\u7e15\u7e16\u7e17\u7e18\u7e19\u7e1a\u7e1b\u7e1c\u7e1d\u7e1e\u7e1f\u7e20\u7e21\u7e22\u7e23\u7e24\u7e25\u7e26\u7e27\u7e28\u7e29\u7e2a\u7e2b\u7e2c\u7e2d\u7e2e\u7e2f\u7e30\u7e31\u7e32\u7e33\u7e34\u7e35\u7e36\u7e37\u7e38\u7e39\u7e3a\u7e3b\u7e3c\u7e3d\u7e3e\u7e3f\u7e40\u7e41\u7e42\u7e43\u7e44\u7e45\u7e46\u7e47\u7e48\u7e49\u7e4a\u7e4b\u7e4c\u7e4d\u7e4e\u7e4f\u7e50\u7e51\u7e52\u7e53\u7e54\u7e55\u7e56\u7e57\u7e58\u7e59\u7e5a\u7e5b\u7e5c\u7e5d\u7e5e\u7e5f\u7e60\u7e61\u7e62\u7e63\u7e64\u7e65\u7e66\u7e67\u7e68\u7e69\u7e6a\u7e6b\u7e6c\u7e6d\u7e6e\u7e6f\u7e70\u7e71\u7e72\u7e73\u7e74\u7e75\u7e76\u7e77\u7e78\u7e79\u7e7a\u7e7b\u7e7c\u7e7d\u7e7e\u7e7f\u7e80\u7e81\u7e82\u7e83\u7e84\u7e85\u7e86\u7e87\u7e88\u7e89\u7e8a\u7e8b\u7e8c\u7e8d\u7e8e\u7e8f\u7e90\u7e91\u7e92\u7e93\u7e94\u7e95\u7e96\u7e97\u7e98\u7e99\u7e9a\u7e9b\u7e9c\u7e9d\u7e9e\u7e9f\u7ea0\u7ea1\u7ea2\u7ea3\u7ea4\u7ea5\u7ea6\u7ea7\u7ea8\u7ea9\u7eaa\u7eab\u7eac\u7ead\u7eae\u7eaf\u7eb0\u7eb1\u7eb2\u7eb3\u7eb4\u7eb5\u7eb6\u7eb7\u7eb8\u7eb9\u7eba\u7ebb\u7ebc\u7ebd\u7ebe\u7ebf\u7ec0\u7ec1\u7ec2\u7ec3\u7ec4\u7ec5\u7ec6\u7ec7\u7ec8\u7ec9\u7eca\u7ecb\u7ecc\u7ecd\u7ece\u7ecf\u7ed0\u7ed1\u7ed2\u7ed3\u7ed4\u7ed5\u7ed6\u7ed7\u7ed8\u7ed9\u7eda\u7edb\u7edc\u7edd\u7ede\u7edf\u7ee0\u7ee1\u7ee2\u7ee3\u7ee4\u7ee5\u7ee6\u7ee7\u7ee8\u7ee9\u7eea\u7eeb\u7eec\u7eed\u7eee\u7eef\u7ef0\u7ef1\u7ef2\u7ef3\u7ef4\u7ef5\u7ef6\u7ef7\u7ef8\u7ef9\u7efa\u7efb\u7efc\u7efd\u7efe\u7eff\u7f00\u7f01\u7f02\u7f03\u7f04\u7f05\u7f06\u7f07\u7f08\u7f09\u7f0a\u7f0b\u7f0c\u7f0d\u7f0e\u7f0f\u7f10\u7f11\u7f12\u7f13\u7f14\u7f15\u7f16\u7f17\u7f18\u7f19\u7f1a\u7f1b\u7f1c\u7f1d\u7f1e\u7f1f\u7f20\u7f21\u7f22\u7f23\u7f24\u7f25\u7f26\u7f27\u7f28\u7f29\u7f2a\u7f2b\u7f2c\u7f2d\u7f2e\u7f2f\u7f30\u7f31\u7f32\u7f33\u7f34\u7f35\u7f36\u7f37\u7f38\u7f39\u7f3a\u7f3b\u7f3c\u7f3d\u7f3e\u7f3f\u7f40\u7f41\u7f42\u7f43\u7f44\u7f45\u7f46\u7f47\u7f48\u7f49\u7f4a\u7f4b\u7f4c\u7f4d\u7f4e\u7f4f\u7f50\u7f51\u7f52\u7f53\u7f54\u7f55\u7f56\u7f57\u7f58\u7f59\u7f5a\u7f5b\u7f5c\u7f5d\u7f5e\u7f5f\u7f60\u7f61\u7f62\u7f63\u7f64\u7f65\u7f66\u7f67\u7f68\u7f69\u7f6a\u7f6b\u7f6c\u7f6d\u7f6e\u7f6f\u7f70\u7f71\u7f72\u7f73\u7f74\u7f75\u7f76\u7f77\u7f78\u7f79\u7f7a\u7f7b\u7f7c\u7f7d\u7f7e\u7f7f\u7f80\u7f81\u7f82\u7f83\u7f84\u7f85\u7f86\u7f87\u7f88\u7f89\u7f8a\u7f8b\u7f8c\u7f8d\u7f8e\u7f8f\u7f90\u7f91\u7f92\u7f93\u7f94\u7f95\u7f96\u7f97\u7f98\u7f99\u7f9a\u7f9b\u7f9c\u7f9d\u7f9e\u7f9f\u7fa0\u7fa1\u7fa2\u7fa3\u7fa4\u7fa5\u7fa6\u7fa7\u7fa8\u7fa9\u7faa\u7fab\u7fac\u7fad\u7fae\u7faf\u7fb0\u7fb1\u7fb2\u7fb3\u7fb4\u7fb5\u7fb6\u7fb7\u7fb8\u7fb9\u7fba\u7fbb\u7fbc\u7fbd\u7fbe\u7fbf\u7fc0\u7fc1\u7fc2\u7fc3\u7fc4\u7fc5\u7fc6\u7fc7\u7fc8\u7fc9\u7fca\u7fcb\u7fcc\u7fcd\u7fce\u7fcf\u7fd0\u7fd1\u7fd2\u7fd3\u7fd4\u7fd5\u7fd6\u7fd7\u7fd8\u7fd9\u7fda\u7fdb\u7fdc\u7fdd\u7fde\u7fdf\u7fe0\u7fe1\u7fe2\u7fe3\u7fe4\u7fe5\u7fe6\u7fe7\u7fe8\u7fe9\u7fea\u7feb\u7fec\u7fed\u7fee\u7fef\u7ff0\u7ff1\u7ff2\u7ff3\u7ff4\u7ff5\u7ff6\u7ff7\u7ff8\u7ff9\u7ffa\u7ffb\u7ffc\u7ffd\u7ffe\u7fff\u8000\u8001\u8002\u8003\u8004\u8005\u8006\u8007\u8008\u8009\u800a\u800b\u800c\u800d\u800e\u800f\u8010\u8011\u8012\u8013\u8014\u8015\u8016\u8017\u8018\u8019\u801a\u801b\u801c\u801d\u801e\u801f\u8020\u8021\u8022\u8023\u8024\u8025\u8026\u8027\u8028\u8029\u802a\u802b\u802c\u802d\u802e\u802f\u8030\u8031\u8032\u8033\u8034\u8035\u8036\u8037\u8038\u8039\u803a\u803b\u803c\u803d\u803e\u803f\u8040\u8041\u8042\u8043\u8044\u8045\u8046\u8047\u8048\u8049\u804a\u804b\u804c\u804d\u804e\u804f\u8050\u8051\u8052\u8053\u8054\u8055\u8056\u8057\u8058\u8059\u805a\u805b\u805c\u805d\u805e\u805f\u8060\u8061\u8062\u8063\u8064\u8065\u8066\u8067\u8068\u8069\u806a\u806b\u806c\u806d\u806e\u806f\u8070\u8071\u8072\u8073\u8074\u8075\u8076\u8077\u8078\u8079\u807a\u807b\u807c\u807d\u807e\u807f\u8080\u8081\u8082\u8083\u8084\u8085\u8086\u8087\u8088\u8089\u808a\u808b\u808c\u808d\u808e\u808f\u8090\u8091\u8092\u8093\u8094\u8095\u8096\u8097\u8098\u8099\u809a\u809b\u809c\u809d\u809e\u809f\u80a0\u80a1\u80a2\u80a3\u80a4\u80a5\u80a6\u80a7\u80a8\u80a9\u80aa\u80ab\u80ac\u80ad\u80ae\u80af\u80b0\u80b1\u80b2\u80b3\u80b4\u80b5\u80b6\u80b7\u80b8\u80b9\u80ba\u80bb\u80bc\u80bd\u80be\u80bf\u80c0\u80c1\u80c2\u80c3\u80c4\u80c5\u80c6\u80c7\u80c8\u80c9\u80ca\u80cb\u80cc\u80cd\u80ce\u80cf\u80d0\u80d1\u80d2\u80d3\u80d4\u80d5\u80d6\u80d7\u80d8\u80d9\u80da\u80db\u80dc\u80dd\u80de\u80df\u80e0\u80e1\u80e2\u80e3\u80e4\u80e5\u80e6\u80e7\u80e8\u80e9\u80ea\u80eb\u80ec\u80ed\u80ee\u80ef\u80f0\u80f1\u80f2\u80f3\u80f4\u80f5\u80f6\u80f7\u80f8\u80f9\u80fa\u80fb\u80fc\u80fd\u80fe\u80ff\u8100\u8101\u8102\u8103\u8104\u8105\u8106\u8107\u8108\u8109\u810a\u810b\u810c\u810d\u810e\u810f\u8110\u8111\u8112\u8113\u8114\u8115\u8116\u8117\u8118\u8119\u811a\u811b\u811c\u811d\u811e\u811f\u8120\u8121\u8122\u8123\u8124\u8125\u8126\u8127\u8128\u8129\u812a\u812b\u812c\u812d\u812e\u812f\u8130\u8131\u8132\u8133\u8134\u8135\u8136\u8137\u8138\u8139\u813a\u813b\u813c\u813d\u813e\u813f\u8140\u8141\u8142\u8143\u8144\u8145\u8146\u8147\u8148\u8149\u814a\u814b\u814c\u814d\u814e\u814f\u8150\u8151\u8152\u8153\u8154\u8155\u8156\u8157\u8158\u8159\u815a\u815b\u815c\u815d\u815e\u815f\u8160\u8161\u8162\u8163\u8164\u8165\u8166\u8167\u8168\u8169\u816a\u816b\u816c\u816d\u816e\u816f\u8170\u8171\u8172\u8173\u8174\u8175\u8176\u8177\u8178\u8179\u817a\u817b\u817c\u817d\u817e\u817f\u8180\u8181\u8182\u8183\u8184\u8185\u8186\u8187\u8188\u8189\u818a\u818b\u818c\u818d\u818e\u818f\u8190\u8191\u8192\u8193\u8194\u8195\u8196\u8197\u8198\u8199\u819a\u819b\u819c\u819d\u819e\u819f\u81a0\u81a1\u81a2\u81a3\u81a4\u81a5\u81a6\u81a7\u81a8\u81a9\u81aa\u81ab\u81ac\u81ad\u81ae\u81af\u81b0\u81b1\u81b2\u81b3\u81b4\u81b5\u81b6\u81b7\u81b8\u81b9\u81ba\u81bb\u81bc\u81bd\u81be\u81bf\u81c0\u81c1\u81c2\u81c3\u81c4\u81c5\u81c6\u81c7\u81c8\u81c9\u81ca\u81cb\u81cc\u81cd\u81ce\u81cf\u81d0\u81d1\u81d2\u81d3\u81d4\u81d5\u81d6\u81d7\u81d8\u81d9\u81da\u81db\u81dc\u81dd\u81de\u81df\u81e0\u81e1\u81e2\u81e3\u81e4\u81e5\u81e6\u81e7\u81e8\u81e9\u81ea\u81eb\u81ec\u81ed\u81ee\u81ef\u81f0\u81f1\u81f2\u81f3\u81f4\u81f5\u81f6\u81f7\u81f8\u81f9\u81fa\u81fb\u81fc\u81fd\u81fe\u81ff\u8200\u8201\u8202\u8203\u8204\u8205\u8206\u8207\u8208\u8209\u820a\u820b\u820c\u820d\u820e\u820f\u8210\u8211\u8212\u8213\u8214\u8215\u8216\u8217\u8218\u8219\u821a\u821b\u821c\u821d\u821e\u821f\u8220\u8221\u8222\u8223\u8224\u8225\u8226\u8227\u8228\u8229\u822a\u822b\u822c\u822d\u822e\u822f\u8230\u8231\u8232\u8233\u8234\u8235\u8236\u8237\u8238\u8239\u823a\u823b\u823c\u823d\u823e\u823f\u8240\u8241\u8242\u8243\u8244\u8245\u8246\u8247\u8248\u8249\u824a\u824b\u824c\u824d\u824e\u824f\u8250\u8251\u8252\u8253\u8254\u8255\u8256\u8257\u8258\u8259\u825a\u825b\u825c\u825d\u825e\u825f\u8260\u8261\u8262\u8263\u8264\u8265\u8266\u8267\u8268\u8269\u826a\u826b\u826c\u826d\u826e\u826f\u8270\u8271\u8272\u8273\u8274\u8275\u8276\u8277\u8278\u8279\u827a\u827b\u827c\u827d\u827e\u827f\u8280\u8281\u8282\u8283\u8284\u8285\u8286\u8287\u8288\u8289\u828a\u828b\u828c\u828d\u828e\u828f\u8290\u8291\u8292\u8293\u8294\u8295\u8296\u8297\u8298\u8299\u829a\u829b\u829c\u829d\u829e\u829f\u82a0\u82a1\u82a2\u82a3\u82a4\u82a5\u82a6\u82a7\u82a8\u82a9\u82aa\u82ab\u82ac\u82ad\u82ae\u82af\u82b0\u82b1\u82b2\u82b3\u82b4\u82b5\u82b6\u82b7\u82b8\u82b9\u82ba\u82bb\u82bc\u82bd\u82be\u82bf\u82c0\u82c1\u82c2\u82c3\u82c4\u82c5\u82c6\u82c7\u82c8\u82c9\u82ca\u82cb\u82cc\u82cd\u82ce\u82cf\u82d0\u82d1\u82d2\u82d3\u82d4\u82d5\u82d6\u82d7\u82d8\u82d9\u82da\u82db\u82dc\u82dd\u82de\u82df\u82e0\u82e1\u82e2\u82e3\u82e4\u82e5\u82e6\u82e7\u82e8\u82e9\u82ea\u82eb\u82ec\u82ed\u82ee\u82ef\u82f0\u82f1\u82f2\u82f3\u82f4\u82f5\u82f6\u82f7\u82f8\u82f9\u82fa\u82fb\u82fc\u82fd\u82fe\u82ff\u8300\u8301\u8302\u8303\u8304\u8305\u8306\u8307\u8308\u8309\u830a\u830b\u830c\u830d\u830e\u830f\u8310\u8311\u8312\u8313\u8314\u8315\u8316\u8317\u8318\u8319\u831a\u831b\u831c\u831d\u831e\u831f\u8320\u8321\u8322\u8323\u8324\u8325\u8326\u8327\u8328\u8329\u832a\u832b\u832c\u832d\u832e\u832f\u8330\u8331\u8332\u8333\u8334\u8335\u8336\u8337\u8338\u8339\u833a\u833b\u833c\u833d\u833e\u833f\u8340\u8341\u8342\u8343\u8344\u8345\u8346\u8347\u8348\u8349\u834a\u834b\u834c\u834d\u834e\u834f\u8350\u8351\u8352\u8353\u8354\u8355\u8356\u8357\u8358\u8359\u835a\u835b\u835c\u835d\u835e\u835f\u8360\u8361\u8362\u8363\u8364\u8365\u8366\u8367\u8368\u8369\u836a\u836b\u836c\u836d\u836e\u836f\u8370\u8371\u8372\u8373\u8374\u8375\u8376\u8377\u8378\u8379\u837a\u837b\u837c\u837d\u837e\u837f\u8380\u8381\u8382\u8383\u8384\u8385\u8386\u8387\u8388\u8389\u838a\u838b\u838c\u838d\u838e\u838f\u8390\u8391\u8392\u8393\u8394\u8395\u8396\u8397\u8398\u8399\u839a\u839b\u839c\u839d\u839e\u839f\u83a0\u83a1\u83a2\u83a3\u83a4\u83a5\u83a6\u83a7\u83a8\u83a9\u83aa\u83ab\u83ac\u83ad\u83ae\u83af\u83b0\u83b1\u83b2\u83b3\u83b4\u83b5\u83b6\u83b7\u83b8\u83b9\u83ba\u83bb\u83bc\u83bd\u83be\u83bf\u83c0\u83c1\u83c2\u83c3\u83c4\u83c5\u83c6\u83c7\u83c8\u83c9\u83ca\u83cb\u83cc\u83cd\u83ce\u83cf\u83d0\u83d1\u83d2\u83d3\u83d4\u83d5\u83d6\u83d7\u83d8\u83d9\u83da\u83db\u83dc\u83dd\u83de\u83df\u83e0\u83e1\u83e2\u83e3\u83e4\u83e5\u83e6\u83e7\u83e8\u83e9\u83ea\u83eb\u83ec\u83ed\u83ee\u83ef\u83f0\u83f1\u83f2\u83f3\u83f4\u83f5\u83f6\u83f7\u83f8\u83f9\u83fa\u83fb\u83fc\u83fd\u83fe\u83ff\u8400\u8401\u8402\u8403\u8404\u8405\u8406\u8407\u8408\u8409\u840a\u840b\u840c\u840d\u840e\u840f\u8410\u8411\u8412\u8413\u8414\u8415\u8416\u8417\u8418\u8419\u841a\u841b\u841c\u841d\u841e\u841f\u8420\u8421\u8422\u8423\u8424\u8425\u8426\u8427\u8428\u8429\u842a\u842b\u842c\u842d\u842e\u842f\u8430\u8431\u8432\u8433\u8434\u8435\u8436\u8437\u8438\u8439\u843a\u843b\u843c\u843d\u843e\u843f\u8440\u8441\u8442\u8443\u8444\u8445\u8446\u8447\u8448\u8449\u844a\u844b\u844c\u844d\u844e\u844f\u8450\u8451\u8452\u8453\u8454\u8455\u8456\u8457\u8458\u8459\u845a\u845b\u845c\u845d\u845e\u845f\u8460\u8461\u8462\u8463\u8464\u8465\u8466\u8467\u8468\u8469\u846a\u846b\u846c\u846d\u846e\u846f\u8470\u8471\u8472\u8473\u8474\u8475\u8476\u8477\u8478\u8479\u847a\u847b\u847c\u847d\u847e\u847f\u8480\u8481\u8482\u8483\u8484\u8485\u8486\u8487\u8488\u8489\u848a\u848b\u848c\u848d\u848e\u848f\u8490\u8491\u8492\u8493\u8494\u8495\u8496\u8497\u8498\u8499\u849a\u849b\u849c\u849d\u849e\u849f\u84a0\u84a1\u84a2\u84a3\u84a4\u84a5\u84a6\u84a7\u84a8\u84a9\u84aa\u84ab\u84ac\u84ad\u84ae\u84af\u84b0\u84b1\u84b2\u84b3\u84b4\u84b5\u84b6\u84b7\u84b8\u84b9\u84ba\u84bb\u84bc\u84bd\u84be\u84bf\u84c0\u84c1\u84c2\u84c3\u84c4\u84c5\u84c6\u84c7\u84c8\u84c9\u84ca\u84cb\u84cc\u84cd\u84ce\u84cf\u84d0\u84d1\u84d2\u84d3\u84d4\u84d5\u84d6\u84d7\u84d8\u84d9\u84da\u84db\u84dc\u84dd\u84de\u84df\u84e0\u84e1\u84e2\u84e3\u84e4\u84e5\u84e6\u84e7\u84e8\u84e9\u84ea\u84eb\u84ec\u84ed\u84ee\u84ef\u84f0\u84f1\u84f2\u84f3\u84f4\u84f5\u84f6\u84f7\u84f8\u84f9\u84fa\u84fb\u84fc\u84fd\u84fe\u84ff\u8500\u8501\u8502\u8503\u8504\u8505\u8506\u8507\u8508\u8509\u850a\u850b\u850c\u850d\u850e\u850f\u8510\u8511\u8512\u8513\u8514\u8515\u8516\u8517\u8518\u8519\u851a\u851b\u851c\u851d\u851e\u851f\u8520\u8521\u8522\u8523\u8524\u8525\u8526\u8527\u8528\u8529\u852a\u852b\u852c\u852d\u852e\u852f\u8530\u8531\u8532\u8533\u8534\u8535\u8536\u8537\u8538\u8539\u853a\u853b\u853c\u853d\u853e\u853f\u8540\u8541\u8542\u8543\u8544\u8545\u8546\u8547\u8548\u8549\u854a\u854b\u854c\u854d\u854e\u854f\u8550\u8551\u8552\u8553\u8554\u8555\u8556\u8557\u8558\u8559\u855a\u855b\u855c\u855d\u855e\u855f\u8560\u8561\u8562\u8563\u8564\u8565\u8566\u8567\u8568\u8569\u856a\u856b\u856c\u856d\u856e\u856f\u8570\u8571\u8572\u8573\u8574\u8575\u8576\u8577\u8578\u8579\u857a\u857b\u857c\u857d\u857e\u857f\u8580\u8581\u8582\u8583\u8584\u8585\u8586\u8587\u8588\u8589\u858a\u858b\u858c\u858d\u858e\u858f\u8590\u8591\u8592\u8593\u8594\u8595\u8596\u8597\u8598\u8599\u859a\u859b\u859c\u859d\u859e\u859f\u85a0\u85a1\u85a2\u85a3\u85a4\u85a5\u85a6\u85a7\u85a8\u85a9\u85aa\u85ab\u85ac\u85ad\u85ae\u85af\u85b0\u85b1\u85b2\u85b3\u85b4\u85b5\u85b6\u85b7\u85b8\u85b9\u85ba\u85bb\u85bc\u85bd\u85be\u85bf\u85c0\u85c1\u85c2\u85c3\u85c4\u85c5\u85c6\u85c7\u85c8\u85c9\u85ca\u85cb\u85cc\u85cd\u85ce\u85cf\u85d0\u85d1\u85d2\u85d3\u85d4\u85d5\u85d6\u85d7\u85d8\u85d9\u85da\u85db\u85dc\u85dd\u85de\u85df\u85e0\u85e1\u85e2\u85e3\u85e4\u85e5\u85e6\u85e7\u85e8\u85e9\u85ea\u85eb\u85ec\u85ed\u85ee\u85ef\u85f0\u85f1\u85f2\u85f3\u85f4\u85f5\u85f6\u85f7\u85f8\u85f9\u85fa\u85fb\u85fc\u85fd\u85fe\u85ff\u8600\u8601\u8602\u8603\u8604\u8605\u8606\u8607\u8608\u8609\u860a\u860b\u860c\u860d\u860e\u860f\u8610\u8611\u8612\u8613\u8614\u8615\u8616\u8617\u8618\u8619\u861a\u861b\u861c\u861d\u861e\u861f\u8620\u8621\u8622\u8623\u8624\u8625\u8626\u8627\u8628\u8629\u862a\u862b\u862c\u862d\u862e\u862f\u8630\u8631\u8632\u8633\u8634\u8635\u8636\u8637\u8638\u8639\u863a\u863b\u863c\u863d\u863e\u863f\u8640\u8641\u8642\u8643\u8644\u8645\u8646\u8647\u8648\u8649\u864a\u864b\u864c\u864d\u864e\u864f\u8650\u8651\u8652\u8653\u8654\u8655\u8656\u8657\u8658\u8659\u865a\u865b\u865c\u865d\u865e\u865f\u8660\u8661\u8662\u8663\u8664\u8665\u8666\u8667\u8668\u8669\u866a\u866b\u866c\u866d\u866e\u866f\u8670\u8671\u8672\u8673\u8674\u8675\u8676\u8677\u8678\u8679\u867a\u867b\u867c\u867d\u867e\u867f\u8680\u8681\u8682\u8683\u8684\u8685\u8686\u8687\u8688\u8689\u868a\u868b\u868c\u868d\u868e\u868f\u8690\u8691\u8692\u8693\u8694\u8695\u8696\u8697\u8698\u8699\u869a\u869b\u869c\u869d\u869e\u869f\u86a0\u86a1\u86a2\u86a3\u86a4\u86a5\u86a6\u86a7\u86a8\u86a9\u86aa\u86ab\u86ac\u86ad\u86ae\u86af\u86b0\u86b1\u86b2\u86b3\u86b4\u86b5\u86b6\u86b7\u86b8\u86b9\u86ba\u86bb\u86bc\u86bd\u86be\u86bf\u86c0\u86c1\u86c2\u86c3\u86c4\u86c5\u86c6\u86c7\u86c8\u86c9\u86ca\u86cb\u86cc\u86cd\u86ce\u86cf\u86d0\u86d1\u86d2\u86d3\u86d4\u86d5\u86d6\u86d7\u86d8\u86d9\u86da\u86db\u86dc\u86dd\u86de\u86df\u86e0\u86e1\u86e2\u86e3\u86e4\u86e5\u86e6\u86e7\u86e8\u86e9\u86ea\u86eb\u86ec\u86ed\u86ee\u86ef\u86f0\u86f1\u86f2\u86f3\u86f4\u86f5\u86f6\u86f7\u86f8\u86f9\u86fa\u86fb\u86fc\u86fd\u86fe\u86ff\u8700\u8701\u8702\u8703\u8704\u8705\u8706\u8707\u8708\u8709\u870a\u870b\u870c\u870d\u870e\u870f\u8710\u8711\u8712\u8713\u8714\u8715\u8716\u8717\u8718\u8719\u871a\u871b\u871c\u871d\u871e\u871f\u8720\u8721\u8722\u8723\u8724\u8725\u8726\u8727\u8728\u8729\u872a\u872b\u872c\u872d\u872e\u872f\u8730\u8731\u8732\u8733\u8734\u8735\u8736\u8737\u8738\u8739\u873a\u873b\u873c\u873d\u873e\u873f\u8740\u8741\u8742\u8743\u8744\u8745\u8746\u8747\u8748\u8749\u874a\u874b\u874c\u874d\u874e\u874f\u8750\u8751\u8752\u8753\u8754\u8755\u8756\u8757\u8758\u8759\u875a\u875b\u875c\u875d\u875e\u875f\u8760\u8761\u8762\u8763\u8764\u8765\u8766\u8767\u8768\u8769\u876a\u876b\u876c\u876d\u876e\u876f\u8770\u8771\u8772\u8773\u8774\u8775\u8776\u8777\u8778\u8779\u877a\u877b\u877c\u877d\u877e\u877f\u8780\u8781\u8782\u8783\u8784\u8785\u8786\u8787\u8788\u8789\u878a\u878b\u878c\u878d\u878e\u878f\u8790\u8791\u8792\u8793\u8794\u8795\u8796\u8797\u8798\u8799\u879a\u879b\u879c\u879d\u879e\u879f\u87a0\u87a1\u87a2\u87a3\u87a4\u87a5\u87a6\u87a7\u87a8\u87a9\u87aa\u87ab\u87ac\u87ad\u87ae\u87af\u87b0\u87b1\u87b2\u87b3\u87b4\u87b5\u87b6\u87b7\u87b8\u87b9\u87ba\u87bb\u87bc\u87bd\u87be\u87bf\u87c0\u87c1\u87c2\u87c3\u87c4\u87c5\u87c6\u87c7\u87c8\u87c9\u87ca\u87cb\u87cc\u87cd\u87ce\u87cf\u87d0\u87d1\u87d2\u87d3\u87d4\u87d5\u87d6\u87d7\u87d8\u87d9\u87da\u87db\u87dc\u87dd\u87de\u87df\u87e0\u87e1\u87e2\u87e3\u87e4\u87e5\u87e6\u87e7\u87e8\u87e9\u87ea\u87eb\u87ec\u87ed\u87ee\u87ef\u87f0\u87f1\u87f2\u87f3\u87f4\u87f5\u87f6\u87f7\u87f8\u87f9\u87fa\u87fb\u87fc\u87fd\u87fe\u87ff\u8800\u8801\u8802\u8803\u8804\u8805\u8806\u8807\u8808\u8809\u880a\u880b\u880c\u880d\u880e\u880f\u8810\u8811\u8812\u8813\u8814\u8815\u8816\u8817\u8818\u8819\u881a\u881b\u881c\u881d\u881e\u881f\u8820\u8821\u8822\u8823\u8824\u8825\u8826\u8827\u8828\u8829\u882a\u882b\u882c\u882d\u882e\u882f\u8830\u8831\u8832\u8833\u8834\u8835\u8836\u8837\u8838\u8839\u883a\u883b\u883c\u883d\u883e\u883f\u8840\u8841\u8842\u8843\u8844\u8845\u8846\u8847\u8848\u8849\u884a\u884b\u884c\u884d\u884e\u884f\u8850\u8851\u8852\u8853\u8854\u8855\u8856\u8857\u8858\u8859\u885a\u885b\u885c\u885d\u885e\u885f\u8860\u8861\u8862\u8863\u8864\u8865\u8866\u8867\u8868\u8869\u886a\u886b\u886c\u886d\u886e\u886f\u8870\u8871\u8872\u8873\u8874\u8875\u8876\u8877\u8878\u8879\u887a\u887b\u887c\u887d\u887e\u887f\u8880\u8881\u8882\u8883\u8884\u8885\u8886\u8887\u8888\u8889\u888a\u888b\u888c\u888d\u888e\u888f\u8890\u8891\u8892\u8893\u8894\u8895\u8896\u8897\u8898\u8899\u889a\u889b\u889c\u889d\u889e\u889f\u88a0\u88a1\u88a2\u88a3\u88a4\u88a5\u88a6\u88a7\u88a8\u88a9\u88aa\u88ab\u88ac\u88ad\u88ae\u88af\u88b0\u88b1\u88b2\u88b3\u88b4\u88b5\u88b6\u88b7\u88b8\u88b9\u88ba\u88bb\u88bc\u88bd\u88be\u88bf\u88c0\u88c1\u88c2\u88c3\u88c4\u88c5\u88c6\u88c7\u88c8\u88c9\u88ca\u88cb\u88cc\u88cd\u88ce\u88cf\u88d0\u88d1\u88d2\u88d3\u88d4\u88d5\u88d6\u88d7\u88d8\u88d9\u88da\u88db\u88dc\u88dd\u88de\u88df\u88e0\u88e1\u88e2\u88e3\u88e4\u88e5\u88e6\u88e7\u88e8\u88e9\u88ea\u88eb\u88ec\u88ed\u88ee\u88ef\u88f0\u88f1\u88f2\u88f3\u88f4\u88f5\u88f6\u88f7\u88f8\u88f9\u88fa\u88fb\u88fc\u88fd\u88fe\u88ff\u8900\u8901\u8902\u8903\u8904\u8905\u8906\u8907\u8908\u8909\u890a\u890b\u890c\u890d\u890e\u890f\u8910\u8911\u8912\u8913\u8914\u8915\u8916\u8917\u8918\u8919\u891a\u891b\u891c\u891d\u891e\u891f\u8920\u8921\u8922\u8923\u8924\u8925\u8926\u8927\u8928\u8929\u892a\u892b\u892c\u892d\u892e\u892f\u8930\u8931\u8932\u8933\u8934\u8935\u8936\u8937\u8938\u8939\u893a\u893b\u893c\u893d\u893e\u893f\u8940\u8941\u8942\u8943\u8944\u8945\u8946\u8947\u8948\u8949\u894a\u894b\u894c\u894d\u894e\u894f\u8950\u8951\u8952\u8953\u8954\u8955\u8956\u8957\u8958\u8959\u895a\u895b\u895c\u895d\u895e\u895f\u8960\u8961\u8962\u8963\u8964\u8965\u8966\u8967\u8968\u8969\u896a\u896b\u896c\u896d\u896e\u896f\u8970\u8971\u8972\u8973\u8974\u8975\u8976\u8977\u8978\u8979\u897a\u897b\u897c\u897d\u897e\u897f\u8980\u8981\u8982\u8983\u8984\u8985\u8986\u8987\u8988\u8989\u898a\u898b\u898c\u898d\u898e\u898f\u8990\u8991\u8992\u8993\u8994\u8995\u8996\u8997\u8998\u8999\u899a\u899b\u899c\u899d\u899e\u899f\u89a0\u89a1\u89a2\u89a3\u89a4\u89a5\u89a6\u89a7\u89a8\u89a9\u89aa\u89ab\u89ac\u89ad\u89ae\u89af\u89b0\u89b1\u89b2\u89b3\u89b4\u89b5\u89b6\u89b7\u89b8\u89b9\u89ba\u89bb\u89bc\u89bd\u89be\u89bf\u89c0\u89c1\u89c2\u89c3\u89c4\u89c5\u89c6\u89c7\u89c8\u89c9\u89ca\u89cb\u89cc\u89cd\u89ce\u89cf\u89d0\u89d1\u89d2\u89d3\u89d4\u89d5\u89d6\u89d7\u89d8\u89d9\u89da\u89db\u89dc\u89dd\u89de\u89df\u89e0\u89e1\u89e2\u89e3\u89e4\u89e5\u89e6\u89e7\u89e8\u89e9\u89ea\u89eb\u89ec\u89ed\u89ee\u89ef\u89f0\u89f1\u89f2\u89f3\u89f4\u89f5\u89f6\u89f7\u89f8\u89f9\u89fa\u89fb\u89fc\u89fd\u89fe\u89ff\u8a00\u8a01\u8a02\u8a03\u8a04\u8a05\u8a06\u8a07\u8a08\u8a09\u8a0a\u8a0b\u8a0c\u8a0d\u8a0e\u8a0f\u8a10\u8a11\u8a12\u8a13\u8a14\u8a15\u8a16\u8a17\u8a18\u8a19\u8a1a\u8a1b\u8a1c\u8a1d\u8a1e\u8a1f\u8a20\u8a21\u8a22\u8a23\u8a24\u8a25\u8a26\u8a27\u8a28\u8a29\u8a2a\u8a2b\u8a2c\u8a2d\u8a2e\u8a2f\u8a30\u8a31\u8a32\u8a33\u8a34\u8a35\u8a36\u8a37\u8a38\u8a39\u8a3a\u8a3b\u8a3c\u8a3d\u8a3e\u8a3f\u8a40\u8a41\u8a42\u8a43\u8a44\u8a45\u8a46\u8a47\u8a48\u8a49\u8a4a\u8a4b\u8a4c\u8a4d\u8a4e\u8a4f\u8a50\u8a51\u8a52\u8a53\u8a54\u8a55\u8a56\u8a57\u8a58\u8a59\u8a5a\u8a5b\u8a5c\u8a5d\u8a5e\u8a5f\u8a60\u8a61\u8a62\u8a63\u8a64\u8a65\u8a66\u8a67\u8a68\u8a69\u8a6a\u8a6b\u8a6c\u8a6d\u8a6e\u8a6f\u8a70\u8a71\u8a72\u8a73\u8a74\u8a75\u8a76\u8a77\u8a78\u8a79\u8a7a\u8a7b\u8a7c\u8a7d\u8a7e\u8a7f\u8a80\u8a81\u8a82\u8a83\u8a84\u8a85\u8a86\u8a87\u8a88\u8a89\u8a8a\u8a8b\u8a8c\u8a8d\u8a8e\u8a8f\u8a90\u8a91\u8a92\u8a93\u8a94\u8a95\u8a96\u8a97\u8a98\u8a99\u8a9a\u8a9b\u8a9c\u8a9d\u8a9e\u8a9f\u8aa0\u8aa1\u8aa2\u8aa3\u8aa4\u8aa5\u8aa6\u8aa7\u8aa8\u8aa9\u8aaa\u8aab\u8aac\u8aad\u8aae\u8aaf\u8ab0\u8ab1\u8ab2\u8ab3\u8ab4\u8ab5\u8ab6\u8ab7\u8ab8\u8ab9\u8aba\u8abb\u8abc\u8abd\u8abe\u8abf\u8ac0\u8ac1\u8ac2\u8ac3\u8ac4\u8ac5\u8ac6\u8ac7\u8ac8\u8ac9\u8aca\u8acb\u8acc\u8acd\u8ace\u8acf\u8ad0\u8ad1\u8ad2\u8ad3\u8ad4\u8ad5\u8ad6\u8ad7\u8ad8\u8ad9\u8ada\u8adb\u8adc\u8add\u8ade\u8adf\u8ae0\u8ae1\u8ae2\u8ae3\u8ae4\u8ae5\u8ae6\u8ae7\u8ae8\u8ae9\u8aea\u8aeb\u8aec\u8aed\u8aee\u8aef\u8af0\u8af1\u8af2\u8af3\u8af4\u8af5\u8af6\u8af7\u8af8\u8af9\u8afa\u8afb\u8afc\u8afd\u8afe\u8aff\u8b00\u8b01\u8b02\u8b03\u8b04\u8b05\u8b06\u8b07\u8b08\u8b09\u8b0a\u8b0b\u8b0c\u8b0d\u8b0e\u8b0f\u8b10\u8b11\u8b12\u8b13\u8b14\u8b15\u8b16\u8b17\u8b18\u8b19\u8b1a\u8b1b\u8b1c\u8b1d\u8b1e\u8b1f\u8b20\u8b21\u8b22\u8b23\u8b24\u8b25\u8b26\u8b27\u8b28\u8b29\u8b2a\u8b2b\u8b2c\u8b2d\u8b2e\u8b2f\u8b30\u8b31\u8b32\u8b33\u8b34\u8b35\u8b36\u8b37\u8b38\u8b39\u8b3a\u8b3b\u8b3c\u8b3d\u8b3e\u8b3f\u8b40\u8b41\u8b42\u8b43\u8b44\u8b45\u8b46\u8b47\u8b48\u8b49\u8b4a\u8b4b\u8b4c\u8b4d\u8b4e\u8b4f\u8b50\u8b51\u8b52\u8b53\u8b54\u8b55\u8b56\u8b57\u8b58\u8b59\u8b5a\u8b5b\u8b5c\u8b5d\u8b5e\u8b5f\u8b60\u8b61\u8b62\u8b63\u8b64\u8b65\u8b66\u8b67\u8b68\u8b69\u8b6a\u8b6b\u8b6c\u8b6d\u8b6e\u8b6f\u8b70\u8b71\u8b72\u8b73\u8b74\u8b75\u8b76\u8b77\u8b78\u8b79\u8b7a\u8b7b\u8b7c\u8b7d\u8b7e\u8b7f\u8b80\u8b81\u8b82\u8b83\u8b84\u8b85\u8b86\u8b87\u8b88\u8b89\u8b8a\u8b8b\u8b8c\u8b8d\u8b8e\u8b8f\u8b90\u8b91\u8b92\u8b93\u8b94\u8b95\u8b96\u8b97\u8b98\u8b99\u8b9a\u8b9b\u8b9c\u8b9d\u8b9e\u8b9f\u8ba0\u8ba1\u8ba2\u8ba3\u8ba4\u8ba5\u8ba6\u8ba7\u8ba8\u8ba9\u8baa\u8bab\u8bac\u8bad\u8bae\u8baf\u8bb0\u8bb1\u8bb2\u8bb3\u8bb4\u8bb5\u8bb6\u8bb7\u8bb8\u8bb9\u8bba\u8bbb\u8bbc\u8bbd\u8bbe\u8bbf\u8bc0\u8bc1\u8bc2\u8bc3\u8bc4\u8bc5\u8bc6\u8bc7\u8bc8\u8bc9\u8bca\u8bcb\u8bcc\u8bcd\u8bce\u8bcf\u8bd0\u8bd1\u8bd2\u8bd3\u8bd4\u8bd5\u8bd6\u8bd7\u8bd8\u8bd9\u8bda\u8bdb\u8bdc\u8bdd\u8bde\u8bdf\u8be0\u8be1\u8be2\u8be3\u8be4\u8be5\u8be6\u8be7\u8be8\u8be9\u8bea\u8beb\u8bec\u8bed\u8bee\u8bef\u8bf0\u8bf1\u8bf2\u8bf3\u8bf4\u8bf5\u8bf6\u8bf7\u8bf8\u8bf9\u8bfa\u8bfb\u8bfc\u8bfd\u8bfe\u8bff\u8c00\u8c01\u8c02\u8c03\u8c04\u8c05\u8c06\u8c07\u8c08\u8c09\u8c0a\u8c0b\u8c0c\u8c0d\u8c0e\u8c0f\u8c10\u8c11\u8c12\u8c13\u8c14\u8c15\u8c16\u8c17\u8c18\u8c19\u8c1a\u8c1b\u8c1c\u8c1d\u8c1e\u8c1f\u8c20\u8c21\u8c22\u8c23\u8c24\u8c25\u8c26\u8c27\u8c28\u8c29\u8c2a\u8c2b\u8c2c\u8c2d\u8c2e\u8c2f\u8c30\u8c31\u8c32\u8c33\u8c34\u8c35\u8c36\u8c37\u8c38\u8c39\u8c3a\u8c3b\u8c3c\u8c3d\u8c3e\u8c3f\u8c40\u8c41\u8c42\u8c43\u8c44\u8c45\u8c46\u8c47\u8c48\u8c49\u8c4a\u8c4b\u8c4c\u8c4d\u8c4e\u8c4f\u8c50\u8c51\u8c52\u8c53\u8c54\u8c55\u8c56\u8c57\u8c58\u8c59\u8c5a\u8c5b\u8c5c\u8c5d\u8c5e\u8c5f\u8c60\u8c61\u8c62\u8c63\u8c64\u8c65\u8c66\u8c67\u8c68\u8c69\u8c6a\u8c6b\u8c6c\u8c6d\u8c6e\u8c6f\u8c70\u8c71\u8c72\u8c73\u8c74\u8c75\u8c76\u8c77\u8c78\u8c79\u8c7a\u8c7b\u8c7c\u8c7d\u8c7e\u8c7f\u8c80\u8c81\u8c82\u8c83\u8c84\u8c85\u8c86\u8c87\u8c88\u8c89\u8c8a\u8c8b\u8c8c\u8c8d\u8c8e\u8c8f\u8c90\u8c91\u8c92\u8c93\u8c94\u8c95\u8c96\u8c97\u8c98\u8c99\u8c9a\u8c9b\u8c9c\u8c9d\u8c9e\u8c9f\u8ca0\u8ca1\u8ca2\u8ca3\u8ca4\u8ca5\u8ca6\u8ca7\u8ca8\u8ca9\u8caa\u8cab\u8cac\u8cad\u8cae\u8caf\u8cb0\u8cb1\u8cb2\u8cb3\u8cb4\u8cb5\u8cb6\u8cb7\u8cb8\u8cb9\u8cba\u8cbb\u8cbc\u8cbd\u8cbe\u8cbf\u8cc0\u8cc1\u8cc2\u8cc3\u8cc4\u8cc5\u8cc6\u8cc7\u8cc8\u8cc9\u8cca\u8ccb\u8ccc\u8ccd\u8cce\u8ccf\u8cd0\u8cd1\u8cd2\u8cd3\u8cd4\u8cd5\u8cd6\u8cd7\u8cd8\u8cd9\u8cda\u8cdb\u8cdc\u8cdd\u8cde\u8cdf\u8ce0\u8ce1\u8ce2\u8ce3\u8ce4\u8ce5\u8ce6\u8ce7\u8ce8\u8ce9\u8cea\u8ceb\u8cec\u8ced\u8cee\u8cef\u8cf0\u8cf1\u8cf2\u8cf3\u8cf4\u8cf5\u8cf6\u8cf7\u8cf8\u8cf9\u8cfa\u8cfb\u8cfc\u8cfd\u8cfe\u8cff\u8d00\u8d01\u8d02\u8d03\u8d04\u8d05\u8d06\u8d07\u8d08\u8d09\u8d0a\u8d0b\u8d0c\u8d0d\u8d0e\u8d0f\u8d10\u8d11\u8d12\u8d13\u8d14\u8d15\u8d16\u8d17\u8d18\u8d19\u8d1a\u8d1b\u8d1c\u8d1d\u8d1e\u8d1f\u8d20\u8d21\u8d22\u8d23\u8d24\u8d25\u8d26\u8d27\u8d28\u8d29\u8d2a\u8d2b\u8d2c\u8d2d\u8d2e\u8d2f\u8d30\u8d31\u8d32\u8d33\u8d34\u8d35\u8d36\u8d37\u8d38\u8d39\u8d3a\u8d3b\u8d3c\u8d3d\u8d3e\u8d3f\u8d40\u8d41\u8d42\u8d43\u8d44\u8d45\u8d46\u8d47\u8d48\u8d49\u8d4a\u8d4b\u8d4c\u8d4d\u8d4e\u8d4f\u8d50\u8d51\u8d52\u8d53\u8d54\u8d55\u8d56\u8d57\u8d58\u8d59\u8d5a\u8d5b\u8d5c\u8d5d\u8d5e\u8d5f\u8d60\u8d61\u8d62\u8d63\u8d64\u8d65\u8d66\u8d67\u8d68\u8d69\u8d6a\u8d6b\u8d6c\u8d6d\u8d6e\u8d6f\u8d70\u8d71\u8d72\u8d73\u8d74\u8d75\u8d76\u8d77\u8d78\u8d79\u8d7a\u8d7b\u8d7c\u8d7d\u8d7e\u8d7f\u8d80\u8d81\u8d82\u8d83\u8d84\u8d85\u8d86\u8d87\u8d88\u8d89\u8d8a\u8d8b\u8d8c\u8d8d\u8d8e\u8d8f\u8d90\u8d91\u8d92\u8d93\u8d94\u8d95\u8d96\u8d97\u8d98\u8d99\u8d9a\u8d9b\u8d9c\u8d9d\u8d9e\u8d9f\u8da0\u8da1\u8da2\u8da3\u8da4\u8da5\u8da6\u8da7\u8da8\u8da9\u8daa\u8dab\u8dac\u8dad\u8dae\u8daf\u8db0\u8db1\u8db2\u8db3\u8db4\u8db5\u8db6\u8db7\u8db8\u8db9\u8dba\u8dbb\u8dbc\u8dbd\u8dbe\u8dbf\u8dc0\u8dc1\u8dc2\u8dc3\u8dc4\u8dc5\u8dc6\u8dc7\u8dc8\u8dc9\u8dca\u8dcb\u8dcc\u8dcd\u8dce\u8dcf\u8dd0\u8dd1\u8dd2\u8dd3\u8dd4\u8dd5\u8dd6\u8dd7\u8dd8\u8dd9\u8dda\u8ddb\u8ddc\u8ddd\u8dde\u8ddf\u8de0\u8de1\u8de2\u8de3\u8de4\u8de5\u8de6\u8de7\u8de8\u8de9\u8dea\u8deb\u8dec\u8ded\u8dee\u8def\u8df0\u8df1\u8df2\u8df3\u8df4\u8df5\u8df6\u8df7\u8df8\u8df9\u8dfa\u8dfb\u8dfc\u8dfd\u8dfe\u8dff\u8e00\u8e01\u8e02\u8e03\u8e04\u8e05\u8e06\u8e07\u8e08\u8e09\u8e0a\u8e0b\u8e0c\u8e0d\u8e0e\u8e0f\u8e10\u8e11\u8e12\u8e13\u8e14\u8e15\u8e16\u8e17\u8e18\u8e19\u8e1a\u8e1b\u8e1c\u8e1d\u8e1e\u8e1f\u8e20\u8e21\u8e22\u8e23\u8e24\u8e25\u8e26\u8e27\u8e28\u8e29\u8e2a\u8e2b\u8e2c\u8e2d\u8e2e\u8e2f\u8e30\u8e31\u8e32\u8e33\u8e34\u8e35\u8e36\u8e37\u8e38\u8e39\u8e3a\u8e3b\u8e3c\u8e3d\u8e3e\u8e3f\u8e40\u8e41\u8e42\u8e43\u8e44\u8e45\u8e46\u8e47\u8e48\u8e49\u8e4a\u8e4b\u8e4c\u8e4d\u8e4e\u8e4f\u8e50\u8e51\u8e52\u8e53\u8e54\u8e55\u8e56\u8e57\u8e58\u8e59\u8e5a\u8e5b\u8e5c\u8e5d\u8e5e\u8e5f\u8e60\u8e61\u8e62\u8e63\u8e64\u8e65\u8e66\u8e67\u8e68\u8e69\u8e6a\u8e6b\u8e6c\u8e6d\u8e6e\u8e6f\u8e70\u8e71\u8e72\u8e73\u8e74\u8e75\u8e76\u8e77\u8e78\u8e79\u8e7a\u8e7b\u8e7c\u8e7d\u8e7e\u8e7f\u8e80\u8e81\u8e82\u8e83\u8e84\u8e85\u8e86\u8e87\u8e88\u8e89\u8e8a\u8e8b\u8e8c\u8e8d\u8e8e\u8e8f\u8e90\u8e91\u8e92\u8e93\u8e94\u8e95\u8e96\u8e97\u8e98\u8e99\u8e9a\u8e9b\u8e9c\u8e9d\u8e9e\u8e9f\u8ea0\u8ea1\u8ea2\u8ea3\u8ea4\u8ea5\u8ea6\u8ea7\u8ea8\u8ea9\u8eaa\u8eab\u8eac\u8ead\u8eae\u8eaf\u8eb0\u8eb1\u8eb2\u8eb3\u8eb4\u8eb5\u8eb6\u8eb7\u8eb8\u8eb9\u8eba\u8ebb\u8ebc\u8ebd\u8ebe\u8ebf\u8ec0\u8ec1\u8ec2\u8ec3\u8ec4\u8ec5\u8ec6\u8ec7\u8ec8\u8ec9\u8eca\u8ecb\u8ecc\u8ecd\u8ece\u8ecf\u8ed0\u8ed1\u8ed2\u8ed3\u8ed4\u8ed5\u8ed6\u8ed7\u8ed8\u8ed9\u8eda\u8edb\u8edc\u8edd\u8ede\u8edf\u8ee0\u8ee1\u8ee2\u8ee3\u8ee4\u8ee5\u8ee6\u8ee7\u8ee8\u8ee9\u8eea\u8eeb\u8eec\u8eed\u8eee\u8eef\u8ef0\u8ef1\u8ef2\u8ef3\u8ef4\u8ef5\u8ef6\u8ef7\u8ef8\u8ef9\u8efa\u8efb\u8efc\u8efd\u8efe\u8eff\u8f00\u8f01\u8f02\u8f03\u8f04\u8f05\u8f06\u8f07\u8f08\u8f09\u8f0a\u8f0b\u8f0c\u8f0d\u8f0e\u8f0f\u8f10\u8f11\u8f12\u8f13\u8f14\u8f15\u8f16\u8f17\u8f18\u8f19\u8f1a\u8f1b\u8f1c\u8f1d\u8f1e\u8f1f\u8f20\u8f21\u8f22\u8f23\u8f24\u8f25\u8f26\u8f27\u8f28\u8f29\u8f2a\u8f2b\u8f2c\u8f2d\u8f2e\u8f2f\u8f30\u8f31\u8f32\u8f33\u8f34\u8f35\u8f36\u8f37\u8f38\u8f39\u8f3a\u8f3b\u8f3c\u8f3d\u8f3e\u8f3f\u8f40\u8f41\u8f42\u8f43\u8f44\u8f45\u8f46\u8f47\u8f48\u8f49\u8f4a\u8f4b\u8f4c\u8f4d\u8f4e\u8f4f\u8f50\u8f51\u8f52\u8f53\u8f54\u8f55\u8f56\u8f57\u8f58\u8f59\u8f5a\u8f5b\u8f5c\u8f5d\u8f5e\u8f5f\u8f60\u8f61\u8f62\u8f63\u8f64\u8f65\u8f66\u8f67\u8f68\u8f69\u8f6a\u8f6b\u8f6c\u8f6d\u8f6e\u8f6f\u8f70\u8f71\u8f72\u8f73\u8f74\u8f75\u8f76\u8f77\u8f78\u8f79\u8f7a\u8f7b\u8f7c\u8f7d\u8f7e\u8f7f\u8f80\u8f81\u8f82\u8f83\u8f84\u8f85\u8f86\u8f87\u8f88\u8f89\u8f8a\u8f8b\u8f8c\u8f8d\u8f8e\u8f8f\u8f90\u8f91\u8f92\u8f93\u8f94\u8f95\u8f96\u8f97\u8f98\u8f99\u8f9a\u8f9b\u8f9c\u8f9d\u8f9e\u8f9f\u8fa0\u8fa1\u8fa2\u8fa3\u8fa4\u8fa5\u8fa6\u8fa7\u8fa8\u8fa9\u8faa\u8fab\u8fac\u8fad\u8fae\u8faf\u8fb0\u8fb1\u8fb2\u8fb3\u8fb4\u8fb5\u8fb6\u8fb7\u8fb8\u8fb9\u8fba\u8fbb\u8fbc\u8fbd\u8fbe\u8fbf\u8fc0\u8fc1\u8fc2\u8fc3\u8fc4\u8fc5\u8fc6\u8fc7\u8fc8\u8fc9\u8fca\u8fcb\u8fcc\u8fcd\u8fce\u8fcf\u8fd0\u8fd1\u8fd2\u8fd3\u8fd4\u8fd5\u8fd6\u8fd7\u8fd8\u8fd9\u8fda\u8fdb\u8fdc\u8fdd\u8fde\u8fdf\u8fe0\u8fe1\u8fe2\u8fe3\u8fe4\u8fe5\u8fe6\u8fe7\u8fe8\u8fe9\u8fea\u8feb\u8fec\u8fed\u8fee\u8fef\u8ff0\u8ff1\u8ff2\u8ff3\u8ff4\u8ff5\u8ff6\u8ff7\u8ff8\u8ff9\u8ffa\u8ffb\u8ffc\u8ffd\u8ffe\u8fff\u9000\u9001\u9002\u9003\u9004\u9005\u9006\u9007\u9008\u9009\u900a\u900b\u900c\u900d\u900e\u900f\u9010\u9011\u9012\u9013\u9014\u9015\u9016\u9017\u9018\u9019\u901a\u901b\u901c\u901d\u901e\u901f\u9020\u9021\u9022\u9023\u9024\u9025\u9026\u9027\u9028\u9029\u902a\u902b\u902c\u902d\u902e\u902f\u9030\u9031\u9032\u9033\u9034\u9035\u9036\u9037\u9038\u9039\u903a\u903b\u903c\u903d\u903e\u903f\u9040\u9041\u9042\u9043\u9044\u9045\u9046\u9047\u9048\u9049\u904a\u904b\u904c\u904d\u904e\u904f\u9050\u9051\u9052\u9053\u9054\u9055\u9056\u9057\u9058\u9059\u905a\u905b\u905c\u905d\u905e\u905f\u9060\u9061\u9062\u9063\u9064\u9065\u9066\u9067\u9068\u9069\u906a\u906b\u906c\u906d\u906e\u906f\u9070\u9071\u9072\u9073\u9074\u9075\u9076\u9077\u9078\u9079\u907a\u907b\u907c\u907d\u907e\u907f\u9080\u9081\u9082\u9083\u9084\u9085\u9086\u9087\u9088\u9089\u908a\u908b\u908c\u908d\u908e\u908f\u9090\u9091\u9092\u9093\u9094\u9095\u9096\u9097\u9098\u9099\u909a\u909b\u909c\u909d\u909e\u909f\u90a0\u90a1\u90a2\u90a3\u90a4\u90a5\u90a6\u90a7\u90a8\u90a9\u90aa\u90ab\u90ac\u90ad\u90ae\u90af\u90b0\u90b1\u90b2\u90b3\u90b4\u90b5\u90b6\u90b7\u90b8\u90b9\u90ba\u90bb\u90bc\u90bd\u90be\u90bf\u90c0\u90c1\u90c2\u90c3\u90c4\u90c5\u90c6\u90c7\u90c8\u90c9\u90ca\u90cb\u90cc\u90cd\u90ce\u90cf\u90d0\u90d1\u90d2\u90d3\u90d4\u90d5\u90d6\u90d7\u90d8\u90d9\u90da\u90db\u90dc\u90dd\u90de\u90df\u90e0\u90e1\u90e2\u90e3\u90e4\u90e5\u90e6\u90e7\u90e8\u90e9\u90ea\u90eb\u90ec\u90ed\u90ee\u90ef\u90f0\u90f1\u90f2\u90f3\u90f4\u90f5\u90f6\u90f7\u90f8\u90f9\u90fa\u90fb\u90fc\u90fd\u90fe\u90ff\u9100\u9101\u9102\u9103\u9104\u9105\u9106\u9107\u9108\u9109\u910a\u910b\u910c\u910d\u910e\u910f\u9110\u9111\u9112\u9113\u9114\u9115\u9116\u9117\u9118\u9119\u911a\u911b\u911c\u911d\u911e\u911f\u9120\u9121\u9122\u9123\u9124\u9125\u9126\u9127\u9128\u9129\u912a\u912b\u912c\u912d\u912e\u912f\u9130\u9131\u9132\u9133\u9134\u9135\u9136\u9137\u9138\u9139\u913a\u913b\u913c\u913d\u913e\u913f\u9140\u9141\u9142\u9143\u9144\u9145\u9146\u9147\u9148\u9149\u914a\u914b\u914c\u914d\u914e\u914f\u9150\u9151\u9152\u9153\u9154\u9155\u9156\u9157\u9158\u9159\u915a\u915b\u915c\u915d\u915e\u915f\u9160\u9161\u9162\u9163\u9164\u9165\u9166\u9167\u9168\u9169\u916a\u916b\u916c\u916d\u916e\u916f\u9170\u9171\u9172\u9173\u9174\u9175\u9176\u9177\u9178\u9179\u917a\u917b\u917c\u917d\u917e\u917f\u9180\u9181\u9182\u9183\u9184\u9185\u9186\u9187\u9188\u9189\u918a\u918b\u918c\u918d\u918e\u918f\u9190\u9191\u9192\u9193\u9194\u9195\u9196\u9197\u9198\u9199\u919a\u919b\u919c\u919d\u919e\u919f\u91a0\u91a1\u91a2\u91a3\u91a4\u91a5\u91a6\u91a7\u91a8\u91a9\u91aa\u91ab\u91ac\u91ad\u91ae\u91af\u91b0\u91b1\u91b2\u91b3\u91b4\u91b5\u91b6\u91b7\u91b8\u91b9\u91ba\u91bb\u91bc\u91bd\u91be\u91bf\u91c0\u91c1\u91c2\u91c3\u91c4\u91c5\u91c6\u91c7\u91c8\u91c9\u91ca\u91cb\u91cc\u91cd\u91ce\u91cf\u91d0\u91d1\u91d2\u91d3\u91d4\u91d5\u91d6\u91d7\u91d8\u91d9\u91da\u91db\u91dc\u91dd\u91de\u91df\u91e0\u91e1\u91e2\u91e3\u91e4\u91e5\u91e6\u91e7\u91e8\u91e9\u91ea\u91eb\u91ec\u91ed\u91ee\u91ef\u91f0\u91f1\u91f2\u91f3\u91f4\u91f5\u91f6\u91f7\u91f8\u91f9\u91fa\u91fb\u91fc\u91fd\u91fe\u91ff\u9200\u9201\u9202\u9203\u9204\u9205\u9206\u9207\u9208\u9209\u920a\u920b\u920c\u920d\u920e\u920f\u9210\u9211\u9212\u9213\u9214\u9215\u9216\u9217\u9218\u9219\u921a\u921b\u921c\u921d\u921e\u921f\u9220\u9221\u9222\u9223\u9224\u9225\u9226\u9227\u9228\u9229\u922a\u922b\u922c\u922d\u922e\u922f\u9230\u9231\u9232\u9233\u9234\u9235\u9236\u9237\u9238\u9239\u923a\u923b\u923c\u923d\u923e\u923f\u9240\u9241\u9242\u9243\u9244\u9245\u9246\u9247\u9248\u9249\u924a\u924b\u924c\u924d\u924e\u924f\u9250\u9251\u9252\u9253\u9254\u9255\u9256\u9257\u9258\u9259\u925a\u925b\u925c\u925d\u925e\u925f\u9260\u9261\u9262\u9263\u9264\u9265\u9266\u9267\u9268\u9269\u926a\u926b\u926c\u926d\u926e\u926f\u9270\u9271\u9272\u9273\u9274\u9275\u9276\u9277\u9278\u9279\u927a\u927b\u927c\u927d\u927e\u927f\u9280\u9281\u9282\u9283\u9284\u9285\u9286\u9287\u9288\u9289\u928a\u928b\u928c\u928d\u928e\u928f\u9290\u9291\u9292\u9293\u9294\u9295\u9296\u9297\u9298\u9299\u929a\u929b\u929c\u929d\u929e\u929f\u92a0\u92a1\u92a2\u92a3\u92a4\u92a5\u92a6\u92a7\u92a8\u92a9\u92aa\u92ab\u92ac\u92ad\u92ae\u92af\u92b0\u92b1\u92b2\u92b3\u92b4\u92b5\u92b6\u92b7\u92b8\u92b9\u92ba\u92bb\u92bc\u92bd\u92be\u92bf\u92c0\u92c1\u92c2\u92c3\u92c4\u92c5\u92c6\u92c7\u92c8\u92c9\u92ca\u92cb\u92cc\u92cd\u92ce\u92cf\u92d0\u92d1\u92d2\u92d3\u92d4\u92d5\u92d6\u92d7\u92d8\u92d9\u92da\u92db\u92dc\u92dd\u92de\u92df\u92e0\u92e1\u92e2\u92e3\u92e4\u92e5\u92e6\u92e7\u92e8\u92e9\u92ea\u92eb\u92ec\u92ed\u92ee\u92ef\u92f0\u92f1\u92f2\u92f3\u92f4\u92f5\u92f6\u92f7\u92f8\u92f9\u92fa\u92fb\u92fc\u92fd\u92fe\u92ff\u9300\u9301\u9302\u9303\u9304\u9305\u9306\u9307\u9308\u9309\u930a\u930b\u930c\u930d\u930e\u930f\u9310\u9311\u9312\u9313\u9314\u9315\u9316\u9317\u9318\u9319\u931a\u931b\u931c\u931d\u931e\u931f\u9320\u9321\u9322\u9323\u9324\u9325\u9326\u9327\u9328\u9329\u932a\u932b\u932c\u932d\u932e\u932f\u9330\u9331\u9332\u9333\u9334\u9335\u9336\u9337\u9338\u9339\u933a\u933b\u933c\u933d\u933e\u933f\u9340\u9341\u9342\u9343\u9344\u9345\u9346\u9347\u9348\u9349\u934a\u934b\u934c\u934d\u934e\u934f\u9350\u9351\u9352\u9353\u9354\u9355\u9356\u9357\u9358\u9359\u935a\u935b\u935c\u935d\u935e\u935f\u9360\u9361\u9362\u9363\u9364\u9365\u9366\u9367\u9368\u9369\u936a\u936b\u936c\u936d\u936e\u936f\u9370\u9371\u9372\u9373\u9374\u9375\u9376\u9377\u9378\u9379\u937a\u937b\u937c\u937d\u937e\u937f\u9380\u9381\u9382\u9383\u9384\u9385\u9386\u9387\u9388\u9389\u938a\u938b\u938c\u938d\u938e\u938f\u9390\u9391\u9392\u9393\u9394\u9395\u9396\u9397\u9398\u9399\u939a\u939b\u939c\u939d\u939e\u939f\u93a0\u93a1\u93a2\u93a3\u93a4\u93a5\u93a6\u93a7\u93a8\u93a9\u93aa\u93ab\u93ac\u93ad\u93ae\u93af\u93b0\u93b1\u93b2\u93b3\u93b4\u93b5\u93b6\u93b7\u93b8\u93b9\u93ba\u93bb\u93bc\u93bd\u93be\u93bf\u93c0\u93c1\u93c2\u93c3\u93c4\u93c5\u93c6\u93c7\u93c8\u93c9\u93ca\u93cb\u93cc\u93cd\u93ce\u93cf\u93d0\u93d1\u93d2\u93d3\u93d4\u93d5\u93d6\u93d7\u93d8\u93d9\u93da\u93db\u93dc\u93dd\u93de\u93df\u93e0\u93e1\u93e2\u93e3\u93e4\u93e5\u93e6\u93e7\u93e8\u93e9\u93ea\u93eb\u93ec\u93ed\u93ee\u93ef\u93f0\u93f1\u93f2\u93f3\u93f4\u93f5\u93f6\u93f7\u93f8\u93f9\u93fa\u93fb\u93fc\u93fd\u93fe\u93ff\u9400\u9401\u9402\u9403\u9404\u9405\u9406\u9407\u9408\u9409\u940a\u940b\u940c\u940d\u940e\u940f\u9410\u9411\u9412\u9413\u9414\u9415\u9416\u9417\u9418\u9419\u941a\u941b\u941c\u941d\u941e\u941f\u9420\u9421\u9422\u9423\u9424\u9425\u9426\u9427\u9428\u9429\u942a\u942b\u942c\u942d\u942e\u942f\u9430\u9431\u9432\u9433\u9434\u9435\u9436\u9437\u9438\u9439\u943a\u943b\u943c\u943d\u943e\u943f\u9440\u9441\u9442\u9443\u9444\u9445\u9446\u9447\u9448\u9449\u944a\u944b\u944c\u944d\u944e\u944f\u9450\u9451\u9452\u9453\u9454\u9455\u9456\u9457\u9458\u9459\u945a\u945b\u945c\u945d\u945e\u945f\u9460\u9461\u9462\u9463\u9464\u9465\u9466\u9467\u9468\u9469\u946a\u946b\u946c\u946d\u946e\u946f\u9470\u9471\u9472\u9473\u9474\u9475\u9476\u9477\u9478\u9479\u947a\u947b\u947c\u947d\u947e\u947f\u9480\u9481\u9482\u9483\u9484\u9485\u9486\u9487\u9488\u9489\u948a\u948b\u948c\u948d\u948e\u948f\u9490\u9491\u9492\u9493\u9494\u9495\u9496\u9497\u9498\u9499\u949a\u949b\u949c\u949d\u949e\u949f\u94a0\u94a1\u94a2\u94a3\u94a4\u94a5\u94a6\u94a7\u94a8\u94a9\u94aa\u94ab\u94ac\u94ad\u94ae\u94af\u94b0\u94b1\u94b2\u94b3\u94b4\u94b5\u94b6\u94b7\u94b8\u94b9\u94ba\u94bb\u94bc\u94bd\u94be\u94bf\u94c0\u94c1\u94c2\u94c3\u94c4\u94c5\u94c6\u94c7\u94c8\u94c9\u94ca\u94cb\u94cc\u94cd\u94ce\u94cf\u94d0\u94d1\u94d2\u94d3\u94d4\u94d5\u94d6\u94d7\u94d8\u94d9\u94da\u94db\u94dc\u94dd\u94de\u94df\u94e0\u94e1\u94e2\u94e3\u94e4\u94e5\u94e6\u94e7\u94e8\u94e9\u94ea\u94eb\u94ec\u94ed\u94ee\u94ef\u94f0\u94f1\u94f2\u94f3\u94f4\u94f5\u94f6\u94f7\u94f8\u94f9\u94fa\u94fb\u94fc\u94fd\u94fe\u94ff\u9500\u9501\u9502\u9503\u9504\u9505\u9506\u9507\u9508\u9509\u950a\u950b\u950c\u950d\u950e\u950f\u9510\u9511\u9512\u9513\u9514\u9515\u9516\u9517\u9518\u9519\u951a\u951b\u951c\u951d\u951e\u951f\u9520\u9521\u9522\u9523\u9524\u9525\u9526\u9527\u9528\u9529\u952a\u952b\u952c\u952d\u952e\u952f\u9530\u9531\u9532\u9533\u9534\u9535\u9536\u9537\u9538\u9539\u953a\u953b\u953c\u953d\u953e\u953f\u9540\u9541\u9542\u9543\u9544\u9545\u9546\u9547\u9548\u9549\u954a\u954b\u954c\u954d\u954e\u954f\u9550\u9551\u9552\u9553\u9554\u9555\u9556\u9557\u9558\u9559\u955a\u955b\u955c\u955d\u955e\u955f\u9560\u9561\u9562\u9563\u9564\u9565\u9566\u9567\u9568\u9569\u956a\u956b\u956c\u956d\u956e\u956f\u9570\u9571\u9572\u9573\u9574\u9575\u9576\u9577\u9578\u9579\u957a\u957b\u957c\u957d\u957e\u957f\u9580\u9581\u9582\u9583\u9584\u9585\u9586\u9587\u9588\u9589\u958a\u958b\u958c\u958d\u958e\u958f\u9590\u9591\u9592\u9593\u9594\u9595\u9596\u9597\u9598\u9599\u959a\u959b\u959c\u959d\u959e\u959f\u95a0\u95a1\u95a2\u95a3\u95a4\u95a5\u95a6\u95a7\u95a8\u95a9\u95aa\u95ab\u95ac\u95ad\u95ae\u95af\u95b0\u95b1\u95b2\u95b3\u95b4\u95b5\u95b6\u95b7\u95b8\u95b9\u95ba\u95bb\u95bc\u95bd\u95be\u95bf\u95c0\u95c1\u95c2\u95c3\u95c4\u95c5\u95c6\u95c7\u95c8\u95c9\u95ca\u95cb\u95cc\u95cd\u95ce\u95cf\u95d0\u95d1\u95d2\u95d3\u95d4\u95d5\u95d6\u95d7\u95d8\u95d9\u95da\u95db\u95dc\u95dd\u95de\u95df\u95e0\u95e1\u95e2\u95e3\u95e4\u95e5\u95e6\u95e7\u95e8\u95e9\u95ea\u95eb\u95ec\u95ed\u95ee\u95ef\u95f0\u95f1\u95f2\u95f3\u95f4\u95f5\u95f6\u95f7\u95f8\u95f9\u95fa\u95fb\u95fc\u95fd\u95fe\u95ff\u9600\u9601\u9602\u9603\u9604\u9605\u9606\u9607\u9608\u9609\u960a\u960b\u960c\u960d\u960e\u960f\u9610\u9611\u9612\u9613\u9614\u9615\u9616\u9617\u9618\u9619\u961a\u961b\u961c\u961d\u961e\u961f\u9620\u9621\u9622\u9623\u9624\u9625\u9626\u9627\u9628\u9629\u962a\u962b\u962c\u962d\u962e\u962f\u9630\u9631\u9632\u9633\u9634\u9635\u9636\u9637\u9638\u9639\u963a\u963b\u963c\u963d\u963e\u963f\u9640\u9641\u9642\u9643\u9644\u9645\u9646\u9647\u9648\u9649\u964a\u964b\u964c\u964d\u964e\u964f\u9650\u9651\u9652\u9653\u9654\u9655\u9656\u9657\u9658\u9659\u965a\u965b\u965c\u965d\u965e\u965f\u9660\u9661\u9662\u9663\u9664\u9665\u9666\u9667\u9668\u9669\u966a\u966b\u966c\u966d\u966e\u966f\u9670\u9671\u9672\u9673\u9674\u9675\u9676\u9677\u9678\u9679\u967a\u967b\u967c\u967d\u967e\u967f\u9680\u9681\u9682\u9683\u9684\u9685\u9686\u9687\u9688\u9689\u968a\u968b\u968c\u968d\u968e\u968f\u9690\u9691\u9692\u9693\u9694\u9695\u9696\u9697\u9698\u9699\u969a\u969b\u969c\u969d\u969e\u969f\u96a0\u96a1\u96a2\u96a3\u96a4\u96a5\u96a6\u96a7\u96a8\u96a9\u96aa\u96ab\u96ac\u96ad\u96ae\u96af\u96b0\u96b1\u96b2\u96b3\u96b4\u96b5\u96b6\u96b7\u96b8\u96b9\u96ba\u96bb\u96bc\u96bd\u96be\u96bf\u96c0\u96c1\u96c2\u96c3\u96c4\u96c5\u96c6\u96c7\u96c8\u96c9\u96ca\u96cb\u96cc\u96cd\u96ce\u96cf\u96d0\u96d1\u96d2\u96d3\u96d4\u96d5\u96d6\u96d7\u96d8\u96d9\u96da\u96db\u96dc\u96dd\u96de\u96df\u96e0\u96e1\u96e2\u96e3\u96e4\u96e5\u96e6\u96e7\u96e8\u96e9\u96ea\u96eb\u96ec\u96ed\u96ee\u96ef\u96f0\u96f1\u96f2\u96f3\u96f4\u96f5\u96f6\u96f7\u96f8\u96f9\u96fa\u96fb\u96fc\u96fd\u96fe\u96ff\u9700\u9701\u9702\u9703\u9704\u9705\u9706\u9707\u9708\u9709\u970a\u970b\u970c\u970d\u970e\u970f\u9710\u9711\u9712\u9713\u9714\u9715\u9716\u9717\u9718\u9719\u971a\u971b\u971c\u971d\u971e\u971f\u9720\u9721\u9722\u9723\u9724\u9725\u9726\u9727\u9728\u9729\u972a\u972b\u972c\u972d\u972e\u972f\u9730\u9731\u9732\u9733\u9734\u9735\u9736\u9737\u9738\u9739\u973a\u973b\u973c\u973d\u973e\u973f\u9740\u9741\u9742\u9743\u9744\u9745\u9746\u9747\u9748\u9749\u974a\u974b\u974c\u974d\u974e\u974f\u9750\u9751\u9752\u9753\u9754\u9755\u9756\u9757\u9758\u9759\u975a\u975b\u975c\u975d\u975e\u975f\u9760\u9761\u9762\u9763\u9764\u9765\u9766\u9767\u9768\u9769\u976a\u976b\u976c\u976d\u976e\u976f\u9770\u9771\u9772\u9773\u9774\u9775\u9776\u9777\u9778\u9779\u977a\u977b\u977c\u977d\u977e\u977f\u9780\u9781\u9782\u9783\u9784\u9785\u9786\u9787\u9788\u9789\u978a\u978b\u978c\u978d\u978e\u978f\u9790\u9791\u9792\u9793\u9794\u9795\u9796\u9797\u9798\u9799\u979a\u979b\u979c\u979d\u979e\u979f\u97a0\u97a1\u97a2\u97a3\u97a4\u97a5\u97a6\u97a7\u97a8\u97a9\u97aa\u97ab\u97ac\u97ad\u97ae\u97af\u97b0\u97b1\u97b2\u97b3\u97b4\u97b5\u97b6\u97b7\u97b8\u97b9\u97ba\u97bb\u97bc\u97bd\u97be\u97bf\u97c0\u97c1\u97c2\u97c3\u97c4\u97c5\u97c6\u97c7\u97c8\u97c9\u97ca\u97cb\u97cc\u97cd\u97ce\u97cf\u97d0\u97d1\u97d2\u97d3\u97d4\u97d5\u97d6\u97d7\u97d8\u97d9\u97da\u97db\u97dc\u97dd\u97de\u97df\u97e0\u97e1\u97e2\u97e3\u97e4\u97e5\u97e6\u97e7\u97e8\u97e9\u97ea\u97eb\u97ec\u97ed\u97ee\u97ef\u97f0\u97f1\u97f2\u97f3\u97f4\u97f5\u97f6\u97f7\u97f8\u97f9\u97fa\u97fb\u97fc\u97fd\u97fe\u97ff\u9800\u9801\u9802\u9803\u9804\u9805\u9806\u9807\u9808\u9809\u980a\u980b\u980c\u980d\u980e\u980f\u9810\u9811\u9812\u9813\u9814\u9815\u9816\u9817\u9818\u9819\u981a\u981b\u981c\u981d\u981e\u981f\u9820\u9821\u9822\u9823\u9824\u9825\u9826\u9827\u9828\u9829\u982a\u982b\u982c\u982d\u982e\u982f\u9830\u9831\u9832\u9833\u9834\u9835\u9836\u9837\u9838\u9839\u983a\u983b\u983c\u983d\u983e\u983f\u9840\u9841\u9842\u9843\u9844\u9845\u9846\u9847\u9848\u9849\u984a\u984b\u984c\u984d\u984e\u984f\u9850\u9851\u9852\u9853\u9854\u9855\u9856\u9857\u9858\u9859\u985a\u985b\u985c\u985d\u985e\u985f\u9860\u9861\u9862\u9863\u9864\u9865\u9866\u9867\u9868\u9869\u986a\u986b\u986c\u986d\u986e\u986f\u9870\u9871\u9872\u9873\u9874\u9875\u9876\u9877\u9878\u9879\u987a\u987b\u987c\u987d\u987e\u987f\u9880\u9881\u9882\u9883\u9884\u9885\u9886\u9887\u9888\u9889\u988a\u988b\u988c\u988d\u988e\u988f\u9890\u9891\u9892\u9893\u9894\u9895\u9896\u9897\u9898\u9899\u989a\u989b\u989c\u989d\u989e\u989f\u98a0\u98a1\u98a2\u98a3\u98a4\u98a5\u98a6\u98a7\u98a8\u98a9\u98aa\u98ab\u98ac\u98ad\u98ae\u98af\u98b0\u98b1\u98b2\u98b3\u98b4\u98b5\u98b6\u98b7\u98b8\u98b9\u98ba\u98bb\u98bc\u98bd\u98be\u98bf\u98c0\u98c1\u98c2\u98c3\u98c4\u98c5\u98c6\u98c7\u98c8\u98c9\u98ca\u98cb\u98cc\u98cd\u98ce\u98cf\u98d0\u98d1\u98d2\u98d3\u98d4\u98d5\u98d6\u98d7\u98d8\u98d9\u98da\u98db\u98dc\u98dd\u98de\u98df\u98e0\u98e1\u98e2\u98e3\u98e4\u98e5\u98e6\u98e7\u98e8\u98e9\u98ea\u98eb\u98ec\u98ed\u98ee\u98ef\u98f0\u98f1\u98f2\u98f3\u98f4\u98f5\u98f6\u98f7\u98f8\u98f9\u98fa\u98fb\u98fc\u98fd\u98fe\u98ff\u9900\u9901\u9902\u9903\u9904\u9905\u9906\u9907\u9908\u9909\u990a\u990b\u990c\u990d\u990e\u990f\u9910\u9911\u9912\u9913\u9914\u9915\u9916\u9917\u9918\u9919\u991a\u991b\u991c\u991d\u991e\u991f\u9920\u9921\u9922\u9923\u9924\u9925\u9926\u9927\u9928\u9929\u992a\u992b\u992c\u992d\u992e\u992f\u9930\u9931\u9932\u9933\u9934\u9935\u9936\u9937\u9938\u9939\u993a\u993b\u993c\u993d\u993e\u993f\u9940\u9941\u9942\u9943\u9944\u9945\u9946\u9947\u9948\u9949\u994a\u994b\u994c\u994d\u994e\u994f\u9950\u9951\u9952\u9953\u9954\u9955\u9956\u9957\u9958\u9959\u995a\u995b\u995c\u995d\u995e\u995f\u9960\u9961\u9962\u9963\u9964\u9965\u9966\u9967\u9968\u9969\u996a\u996b\u996c\u996d\u996e\u996f\u9970\u9971\u9972\u9973\u9974\u9975\u9976\u9977\u9978\u9979\u997a\u997b\u997c\u997d\u997e\u997f\u9980\u9981\u9982\u9983\u9984\u9985\u9986\u9987\u9988\u9989\u998a\u998b\u998c\u998d\u998e\u998f\u9990\u9991\u9992\u9993\u9994\u9995\u9996\u9997\u9998\u9999\u999a\u999b\u999c\u999d\u999e\u999f\u99a0\u99a1\u99a2\u99a3\u99a4\u99a5\u99a6\u99a7\u99a8\u99a9\u99aa\u99ab\u99ac\u99ad\u99ae\u99af\u99b0\u99b1\u99b2\u99b3\u99b4\u99b5\u99b6\u99b7\u99b8\u99b9\u99ba\u99bb\u99bc\u99bd\u99be\u99bf\u99c0\u99c1\u99c2\u99c3\u99c4\u99c5\u99c6\u99c7\u99c8\u99c9\u99ca\u99cb\u99cc\u99cd\u99ce\u99cf\u99d0\u99d1\u99d2\u99d3\u99d4\u99d5\u99d6\u99d7\u99d8\u99d9\u99da\u99db\u99dc\u99dd\u99de\u99df\u99e0\u99e1\u99e2\u99e3\u99e4\u99e5\u99e6\u99e7\u99e8\u99e9\u99ea\u99eb\u99ec\u99ed\u99ee\u99ef\u99f0\u99f1\u99f2\u99f3\u99f4\u99f5\u99f6\u99f7\u99f8\u99f9\u99fa\u99fb\u99fc\u99fd\u99fe\u99ff\u9a00\u9a01\u9a02\u9a03\u9a04\u9a05\u9a06\u9a07\u9a08\u9a09\u9a0a\u9a0b\u9a0c\u9a0d\u9a0e\u9a0f\u9a10\u9a11\u9a12\u9a13\u9a14\u9a15\u9a16\u9a17\u9a18\u9a19\u9a1a\u9a1b\u9a1c\u9a1d\u9a1e\u9a1f\u9a20\u9a21\u9a22\u9a23\u9a24\u9a25\u9a26\u9a27\u9a28\u9a29\u9a2a\u9a2b\u9a2c\u9a2d\u9a2e\u9a2f\u9a30\u9a31\u9a32\u9a33\u9a34\u9a35\u9a36\u9a37\u9a38\u9a39\u9a3a\u9a3b\u9a3c\u9a3d\u9a3e\u9a3f\u9a40\u9a41\u9a42\u9a43\u9a44\u9a45\u9a46\u9a47\u9a48\u9a49\u9a4a\u9a4b\u9a4c\u9a4d\u9a4e\u9a4f\u9a50\u9a51\u9a52\u9a53\u9a54\u9a55\u9a56\u9a57\u9a58\u9a59\u9a5a\u9a5b\u9a5c\u9a5d\u9a5e\u9a5f\u9a60\u9a61\u9a62\u9a63\u9a64\u9a65\u9a66\u9a67\u9a68\u9a69\u9a6a\u9a6b\u9a6c\u9a6d\u9a6e\u9a6f\u9a70\u9a71\u9a72\u9a73\u9a74\u9a75\u9a76\u9a77\u9a78\u9a79\u9a7a\u9a7b\u9a7c\u9a7d\u9a7e\u9a7f\u9a80\u9a81\u9a82\u9a83\u9a84\u9a85\u9a86\u9a87\u9a88\u9a89\u9a8a\u9a8b\u9a8c\u9a8d\u9a8e\u9a8f\u9a90\u9a91\u9a92\u9a93\u9a94\u9a95\u9a96\u9a97\u9a98\u9a99\u9a9a\u9a9b\u9a9c\u9a9d\u9a9e\u9a9f\u9aa0\u9aa1\u9aa2\u9aa3\u9aa4\u9aa5\u9aa6\u9aa7\u9aa8\u9aa9\u9aaa\u9aab\u9aac\u9aad\u9aae\u9aaf\u9ab0\u9ab1\u9ab2\u9ab3\u9ab4\u9ab5\u9ab6\u9ab7\u9ab8\u9ab9\u9aba\u9abb\u9abc\u9abd\u9abe\u9abf\u9ac0\u9ac1\u9ac2\u9ac3\u9ac4\u9ac5\u9ac6\u9ac7\u9ac8\u9ac9\u9aca\u9acb\u9acc\u9acd\u9ace\u9acf\u9ad0\u9ad1\u9ad2\u9ad3\u9ad4\u9ad5\u9ad6\u9ad7\u9ad8\u9ad9\u9ada\u9adb\u9adc\u9add\u9ade\u9adf\u9ae0\u9ae1\u9ae2\u9ae3\u9ae4\u9ae5\u9ae6\u9ae7\u9ae8\u9ae9\u9aea\u9aeb\u9aec\u9aed\u9aee\u9aef\u9af0\u9af1\u9af2\u9af3\u9af4\u9af5\u9af6\u9af7\u9af8\u9af9\u9afa\u9afb\u9afc\u9afd\u9afe\u9aff\u9b00\u9b01\u9b02\u9b03\u9b04\u9b05\u9b06\u9b07\u9b08\u9b09\u9b0a\u9b0b\u9b0c\u9b0d\u9b0e\u9b0f\u9b10\u9b11\u9b12\u9b13\u9b14\u9b15\u9b16\u9b17\u9b18\u9b19\u9b1a\u9b1b\u9b1c\u9b1d\u9b1e\u9b1f\u9b20\u9b21\u9b22\u9b23\u9b24\u9b25\u9b26\u9b27\u9b28\u9b29\u9b2a\u9b2b\u9b2c\u9b2d\u9b2e\u9b2f\u9b30\u9b31\u9b32\u9b33\u9b34\u9b35\u9b36\u9b37\u9b38\u9b39\u9b3a\u9b3b\u9b3c\u9b3d\u9b3e\u9b3f\u9b40\u9b41\u9b42\u9b43\u9b44\u9b45\u9b46\u9b47\u9b48\u9b49\u9b4a\u9b4b\u9b4c\u9b4d\u9b4e\u9b4f\u9b50\u9b51\u9b52\u9b53\u9b54\u9b55\u9b56\u9b57\u9b58\u9b59\u9b5a\u9b5b\u9b5c\u9b5d\u9b5e\u9b5f\u9b60\u9b61\u9b62\u9b63\u9b64\u9b65\u9b66\u9b67\u9b68\u9b69\u9b6a\u9b6b\u9b6c\u9b6d\u9b6e\u9b6f\u9b70\u9b71\u9b72\u9b73\u9b74\u9b75\u9b76\u9b77\u9b78\u9b79\u9b7a\u9b7b\u9b7c\u9b7d\u9b7e\u9b7f\u9b80\u9b81\u9b82\u9b83\u9b84\u9b85\u9b86\u9b87\u9b88\u9b89\u9b8a\u9b8b\u9b8c\u9b8d\u9b8e\u9b8f\u9b90\u9b91\u9b92\u9b93\u9b94\u9b95\u9b96\u9b97\u9b98\u9b99\u9b9a\u9b9b\u9b9c\u9b9d\u9b9e\u9b9f\u9ba0\u9ba1\u9ba2\u9ba3\u9ba4\u9ba5\u9ba6\u9ba7\u9ba8\u9ba9\u9baa\u9bab\u9bac\u9bad\u9bae\u9baf\u9bb0\u9bb1\u9bb2\u9bb3\u9bb4\u9bb5\u9bb6\u9bb7\u9bb8\u9bb9\u9bba\u9bbb\u9bbc\u9bbd\u9bbe\u9bbf\u9bc0\u9bc1\u9bc2\u9bc3\u9bc4\u9bc5\u9bc6\u9bc7\u9bc8\u9bc9\u9bca\u9bcb\u9bcc\u9bcd\u9bce\u9bcf\u9bd0\u9bd1\u9bd2\u9bd3\u9bd4\u9bd5\u9bd6\u9bd7\u9bd8\u9bd9\u9bda\u9bdb\u9bdc\u9bdd\u9bde\u9bdf\u9be0\u9be1\u9be2\u9be3\u9be4\u9be5\u9be6\u9be7\u9be8\u9be9\u9bea\u9beb\u9bec\u9bed\u9bee\u9bef\u9bf0\u9bf1\u9bf2\u9bf3\u9bf4\u9bf5\u9bf6\u9bf7\u9bf8\u9bf9\u9bfa\u9bfb\u9bfc\u9bfd\u9bfe\u9bff\u9c00\u9c01\u9c02\u9c03\u9c04\u9c05\u9c06\u9c07\u9c08\u9c09\u9c0a\u9c0b\u9c0c\u9c0d\u9c0e\u9c0f\u9c10\u9c11\u9c12\u9c13\u9c14\u9c15\u9c16\u9c17\u9c18\u9c19\u9c1a\u9c1b\u9c1c\u9c1d\u9c1e\u9c1f\u9c20\u9c21\u9c22\u9c23\u9c24\u9c25\u9c26\u9c27\u9c28\u9c29\u9c2a\u9c2b\u9c2c\u9c2d\u9c2e\u9c2f\u9c30\u9c31\u9c32\u9c33\u9c34\u9c35\u9c36\u9c37\u9c38\u9c39\u9c3a\u9c3b\u9c3c\u9c3d\u9c3e\u9c3f\u9c40\u9c41\u9c42\u9c43\u9c44\u9c45\u9c46\u9c47\u9c48\u9c49\u9c4a\u9c4b\u9c4c\u9c4d\u9c4e\u9c4f\u9c50\u9c51\u9c52\u9c53\u9c54\u9c55\u9c56\u9c57\u9c58\u9c59\u9c5a\u9c5b\u9c5c\u9c5d\u9c5e\u9c5f\u9c60\u9c61\u9c62\u9c63\u9c64\u9c65\u9c66\u9c67\u9c68\u9c69\u9c6a\u9c6b\u9c6c\u9c6d\u9c6e\u9c6f\u9c70\u9c71\u9c72\u9c73\u9c74\u9c75\u9c76\u9c77\u9c78\u9c79\u9c7a\u9c7b\u9c7c\u9c7d\u9c7e\u9c7f\u9c80\u9c81\u9c82\u9c83\u9c84\u9c85\u9c86\u9c87\u9c88\u9c89\u9c8a\u9c8b\u9c8c\u9c8d\u9c8e\u9c8f\u9c90\u9c91\u9c92\u9c93\u9c94\u9c95\u9c96\u9c97\u9c98\u9c99\u9c9a\u9c9b\u9c9c\u9c9d\u9c9e\u9c9f\u9ca0\u9ca1\u9ca2\u9ca3\u9ca4\u9ca5\u9ca6\u9ca7\u9ca8\u9ca9\u9caa\u9cab\u9cac\u9cad\u9cae\u9caf\u9cb0\u9cb1\u9cb2\u9cb3\u9cb4\u9cb5\u9cb6\u9cb7\u9cb8\u9cb9\u9cba\u9cbb\u9cbc\u9cbd\u9cbe\u9cbf\u9cc0\u9cc1\u9cc2\u9cc3\u9cc4\u9cc5\u9cc6\u9cc7\u9cc8\u9cc9\u9cca\u9ccb\u9ccc\u9ccd\u9cce\u9ccf\u9cd0\u9cd1\u9cd2\u9cd3\u9cd4\u9cd5\u9cd6\u9cd7\u9cd8\u9cd9\u9cda\u9cdb\u9cdc\u9cdd\u9cde\u9cdf\u9ce0\u9ce1\u9ce2\u9ce3\u9ce4\u9ce5\u9ce6\u9ce7\u9ce8\u9ce9\u9cea\u9ceb\u9cec\u9ced\u9cee\u9cef\u9cf0\u9cf1\u9cf2\u9cf3\u9cf4\u9cf5\u9cf6\u9cf7\u9cf8\u9cf9\u9cfa\u9cfb\u9cfc\u9cfd\u9cfe\u9cff\u9d00\u9d01\u9d02\u9d03\u9d04\u9d05\u9d06\u9d07\u9d08\u9d09\u9d0a\u9d0b\u9d0c\u9d0d\u9d0e\u9d0f\u9d10\u9d11\u9d12\u9d13\u9d14\u9d15\u9d16\u9d17\u9d18\u9d19\u9d1a\u9d1b\u9d1c\u9d1d\u9d1e\u9d1f\u9d20\u9d21\u9d22\u9d23\u9d24\u9d25\u9d26\u9d27\u9d28\u9d29\u9d2a\u9d2b\u9d2c\u9d2d\u9d2e\u9d2f\u9d30\u9d31\u9d32\u9d33\u9d34\u9d35\u9d36\u9d37\u9d38\u9d39\u9d3a\u9d3b\u9d3c\u9d3d\u9d3e\u9d3f\u9d40\u9d41\u9d42\u9d43\u9d44\u9d45\u9d46\u9d47\u9d48\u9d49\u9d4a\u9d4b\u9d4c\u9d4d\u9d4e\u9d4f\u9d50\u9d51\u9d52\u9d53\u9d54\u9d55\u9d56\u9d57\u9d58\u9d59\u9d5a\u9d5b\u9d5c\u9d5d\u9d5e\u9d5f\u9d60\u9d61\u9d62\u9d63\u9d64\u9d65\u9d66\u9d67\u9d68\u9d69\u9d6a\u9d6b\u9d6c\u9d6d\u9d6e\u9d6f\u9d70\u9d71\u9d72\u9d73\u9d74\u9d75\u9d76\u9d77\u9d78\u9d79\u9d7a\u9d7b\u9d7c\u9d7d\u9d7e\u9d7f\u9d80\u9d81\u9d82\u9d83\u9d84\u9d85\u9d86\u9d87\u9d88\u9d89\u9d8a\u9d8b\u9d8c\u9d8d\u9d8e\u9d8f\u9d90\u9d91\u9d92\u9d93\u9d94\u9d95\u9d96\u9d97\u9d98\u9d99\u9d9a\u9d9b\u9d9c\u9d9d\u9d9e\u9d9f\u9da0\u9da1\u9da2\u9da3\u9da4\u9da5\u9da6\u9da7\u9da8\u9da9\u9daa\u9dab\u9dac\u9dad\u9dae\u9daf\u9db0\u9db1\u9db2\u9db3\u9db4\u9db5\u9db6\u9db7\u9db8\u9db9\u9dba\u9dbb\u9dbc\u9dbd\u9dbe\u9dbf\u9dc0\u9dc1\u9dc2\u9dc3\u9dc4\u9dc5\u9dc6\u9dc7\u9dc8\u9dc9\u9dca\u9dcb\u9dcc\u9dcd\u9dce\u9dcf\u9dd0\u9dd1\u9dd2\u9dd3\u9dd4\u9dd5\u9dd6\u9dd7\u9dd8\u9dd9\u9dda\u9ddb\u9ddc\u9ddd\u9dde\u9ddf\u9de0\u9de1\u9de2\u9de3\u9de4\u9de5\u9de6\u9de7\u9de8\u9de9\u9dea\u9deb\u9dec\u9ded\u9dee\u9def\u9df0\u9df1\u9df2\u9df3\u9df4\u9df5\u9df6\u9df7\u9df8\u9df9\u9dfa\u9dfb\u9dfc\u9dfd\u9dfe\u9dff\u9e00\u9e01\u9e02\u9e03\u9e04\u9e05\u9e06\u9e07\u9e08\u9e09\u9e0a\u9e0b\u9e0c\u9e0d\u9e0e\u9e0f\u9e10\u9e11\u9e12\u9e13\u9e14\u9e15\u9e16\u9e17\u9e18\u9e19\u9e1a\u9e1b\u9e1c\u9e1d\u9e1e\u9e1f\u9e20\u9e21\u9e22\u9e23\u9e24\u9e25\u9e26\u9e27\u9e28\u9e29\u9e2a\u9e2b\u9e2c\u9e2d\u9e2e\u9e2f\u9e30\u9e31\u9e32\u9e33\u9e34\u9e35\u9e36\u9e37\u9e38\u9e39\u9e3a\u9e3b\u9e3c\u9e3d\u9e3e\u9e3f\u9e40\u9e41\u9e42\u9e43\u9e44\u9e45\u9e46\u9e47\u9e48\u9e49\u9e4a\u9e4b\u9e4c\u9e4d\u9e4e\u9e4f\u9e50\u9e51\u9e52\u9e53\u9e54\u9e55\u9e56\u9e57\u9e58\u9e59\u9e5a\u9e5b\u9e5c\u9e5d\u9e5e\u9e5f\u9e60\u9e61\u9e62\u9e63\u9e64\u9e65\u9e66\u9e67\u9e68\u9e69\u9e6a\u9e6b\u9e6c\u9e6d\u9e6e\u9e6f\u9e70\u9e71\u9e72\u9e73\u9e74\u9e75\u9e76\u9e77\u9e78\u9e79\u9e7a\u9e7b\u9e7c\u9e7d\u9e7e\u9e7f\u9e80\u9e81\u9e82\u9e83\u9e84\u9e85\u9e86\u9e87\u9e88\u9e89\u9e8a\u9e8b\u9e8c\u9e8d\u9e8e\u9e8f\u9e90\u9e91\u9e92\u9e93\u9e94\u9e95\u9e96\u9e97\u9e98\u9e99\u9e9a\u9e9b\u9e9c\u9e9d\u9e9e\u9e9f\u9ea0\u9ea1\u9ea2\u9ea3\u9ea4\u9ea5\u9ea6\u9ea7\u9ea8\u9ea9\u9eaa\u9eab\u9eac\u9ead\u9eae\u9eaf\u9eb0\u9eb1\u9eb2\u9eb3\u9eb4\u9eb5\u9eb6\u9eb7\u9eb8\u9eb9\u9eba\u9ebb\u9ebc\u9ebd\u9ebe\u9ebf\u9ec0\u9ec1\u9ec2\u9ec3\u9ec4\u9ec5\u9ec6\u9ec7\u9ec8\u9ec9\u9eca\u9ecb\u9ecc\u9ecd\u9ece\u9ecf\u9ed0\u9ed1\u9ed2\u9ed3\u9ed4\u9ed5\u9ed6\u9ed7\u9ed8\u9ed9\u9eda\u9edb\u9edc\u9edd\u9ede\u9edf\u9ee0\u9ee1\u9ee2\u9ee3\u9ee4\u9ee5\u9ee6\u9ee7\u9ee8\u9ee9\u9eea\u9eeb\u9eec\u9eed\u9eee\u9eef\u9ef0\u9ef1\u9ef2\u9ef3\u9ef4\u9ef5\u9ef6\u9ef7\u9ef8\u9ef9\u9efa\u9efb\u9efc\u9efd\u9efe\u9eff\u9f00\u9f01\u9f02\u9f03\u9f04\u9f05\u9f06\u9f07\u9f08\u9f09\u9f0a\u9f0b\u9f0c\u9f0d\u9f0e\u9f0f\u9f10\u9f11\u9f12\u9f13\u9f14\u9f15\u9f16\u9f17\u9f18\u9f19\u9f1a\u9f1b\u9f1c\u9f1d\u9f1e\u9f1f\u9f20\u9f21\u9f22\u9f23\u9f24\u9f25\u9f26\u9f27\u9f28\u9f29\u9f2a\u9f2b\u9f2c\u9f2d\u9f2e\u9f2f\u9f30\u9f31\u9f32\u9f33\u9f34\u9f35\u9f36\u9f37\u9f38\u9f39\u9f3a\u9f3b\u9f3c\u9f3d\u9f3e\u9f3f\u9f40\u9f41\u9f42\u9f43\u9f44\u9f45\u9f46\u9f47\u9f48\u9f49\u9f4a\u9f4b\u9f4c\u9f4d\u9f4e\u9f4f\u9f50\u9f51\u9f52\u9f53\u9f54\u9f55\u9f56\u9f57\u9f58\u9f59\u9f5a\u9f5b\u9f5c\u9f5d\u9f5e\u9f5f\u9f60\u9f61\u9f62\u9f63\u9f64\u9f65\u9f66\u9f67\u9f68\u9f69\u9f6a\u9f6b\u9f6c\u9f6d\u9f6e\u9f6f\u9f70\u9f71\u9f72\u9f73\u9f74\u9f75\u9f76\u9f77\u9f78\u9f79\u9f7a\u9f7b\u9f7c\u9f7d\u9f7e\u9f7f\u9f80\u9f81\u9f82\u9f83\u9f84\u9f85\u9f86\u9f87\u9f88\u9f89\u9f8a\u9f8b\u9f8c\u9f8d\u9f8e\u9f8f\u9f90\u9f91\u9f92\u9f93\u9f94\u9f95\u9f96\u9f97\u9f98\u9f99\u9f9a\u9f9b\u9f9c\u9f9d\u9f9e\u9f9f\u9fa0\u9fa1\u9fa2\u9fa3\u9fa4\u9fa5\u9fa6\u9fa7\u9fa8\u9fa9\u9faa\u9fab\u9fac\u9fad\u9fae\u9faf\u9fb0\u9fb1\u9fb2\u9fb3\u9fb4\u9fb5\u9fb6\u9fb7\u9fb8\u9fb9\u9fba\u9fbb\u9fbc\u9fbd\u9fbe\u9fbf\u9fc0\u9fc1\u9fc2\u9fc3\u9fc4\u9fc5\u9fc6\u9fc7\u9fc8\u9fc9\u9fca\u9fcb\u9fcc\u9fcd\u9fce\u9fcf\u9fd0\u9fd1\u9fd2\u9fd3\u9fd4\u9fd5\ua000\ua001\ua002\ua003\ua004\ua005\ua006\ua007\ua008\ua009\ua00a\ua00b\ua00c\ua00d\ua00e\ua00f\ua010\ua011\ua012\ua013\ua014\ua015\ua016\ua017\ua018\ua019\ua01a\ua01b\ua01c\ua01d\ua01e\ua01f\ua020\ua021\ua022\ua023\ua024\ua025\ua026\ua027\ua028\ua029\ua02a\ua02b\ua02c\ua02d\ua02e\ua02f\ua030\ua031\ua032\ua033\ua034\ua035\ua036\ua037\ua038\ua039\ua03a\ua03b\ua03c\ua03d\ua03e\ua03f\ua040\ua041\ua042\ua043\ua044\ua045\ua046\ua047\ua048\ua049\ua04a\ua04b\ua04c\ua04d\ua04e\ua04f\ua050\ua051\ua052\ua053\ua054\ua055\ua056\ua057\ua058\ua059\ua05a\ua05b\ua05c\ua05d\ua05e\ua05f\ua060\ua061\ua062\ua063\ua064\ua065\ua066\ua067\ua068\ua069\ua06a\ua06b\ua06c\ua06d\ua06e\ua06f\ua070\ua071\ua072\ua073\ua074\ua075\ua076\ua077\ua078\ua079\ua07a\ua07b\ua07c\ua07d\ua07e\ua07f\ua080\ua081\ua082\ua083\ua084\ua085\ua086\ua087\ua088\ua089\ua08a\ua08b\ua08c\ua08d\ua08e\ua08f\ua090\ua091\ua092\ua093\ua094\ua095\ua096\ua097\ua098\ua099\ua09a\ua09b\ua09c\ua09d\ua09e\ua09f\ua0a0\ua0a1\ua0a2\ua0a3\ua0a4\ua0a5\ua0a6\ua0a7\ua0a8\ua0a9\ua0aa\ua0ab\ua0ac\ua0ad\ua0ae\ua0af\ua0b0\ua0b1\ua0b2\ua0b3\ua0b4\ua0b5\ua0b6\ua0b7\ua0b8\ua0b9\ua0ba\ua0bb\ua0bc\ua0bd\ua0be\ua0bf\ua0c0\ua0c1\ua0c2\ua0c3\ua0c4\ua0c5\ua0c6\ua0c7\ua0c8\ua0c9\ua0ca\ua0cb\ua0cc\ua0cd\ua0ce\ua0cf\ua0d0\ua0d1\ua0d2\ua0d3\ua0d4\ua0d5\ua0d6\ua0d7\ua0d8\ua0d9\ua0da\ua0db\ua0dc\ua0dd\ua0de\ua0df\ua0e0\ua0e1\ua0e2\ua0e3\ua0e4\ua0e5\ua0e6\ua0e7\ua0e8\ua0e9\ua0ea\ua0eb\ua0ec\ua0ed\ua0ee\ua0ef\ua0f0\ua0f1\ua0f2\ua0f3\ua0f4\ua0f5\ua0f6\ua0f7\ua0f8\ua0f9\ua0fa\ua0fb\ua0fc\ua0fd\ua0fe\ua0ff\ua100\ua101\ua102\ua103\ua104\ua105\ua106\ua107\ua108\ua109\ua10a\ua10b\ua10c\ua10d\ua10e\ua10f\ua110\ua111\ua112\ua113\ua114\ua115\ua116\ua117\ua118\ua119\ua11a\ua11b\ua11c\ua11d\ua11e\ua11f\ua120\ua121\ua122\ua123\ua124\ua125\ua126\ua127\ua128\ua129\ua12a\ua12b\ua12c\ua12d\ua12e\ua12f\ua130\ua131\ua132\ua133\ua134\ua135\ua136\ua137\ua138\ua139\ua13a\ua13b\ua13c\ua13d\ua13e\ua13f\ua140\ua141\ua142\ua143\ua144\ua145\ua146\ua147\ua148\ua149\ua14a\ua14b\ua14c\ua14d\ua14e\ua14f\ua150\ua151\ua152\ua153\ua154\ua155\ua156\ua157\ua158\ua159\ua15a\ua15b\ua15c\ua15d\ua15e\ua15f\ua160\ua161\ua162\ua163\ua164\ua165\ua166\ua167\ua168\ua169\ua16a\ua16b\ua16c\ua16d\ua16e\ua16f\ua170\ua171\ua172\ua173\ua174\ua175\ua176\ua177\ua178\ua179\ua17a\ua17b\ua17c\ua17d\ua17e\ua17f\ua180\ua181\ua182\ua183\ua184\ua185\ua186\ua187\ua188\ua189\ua18a\ua18b\ua18c\ua18d\ua18e\ua18f\ua190\ua191\ua192\ua193\ua194\ua195\ua196\ua197\ua198\ua199\ua19a\ua19b\ua19c\ua19d\ua19e\ua19f\ua1a0\ua1a1\ua1a2\ua1a3\ua1a4\ua1a5\ua1a6\ua1a7\ua1a8\ua1a9\ua1aa\ua1ab\ua1ac\ua1ad\ua1ae\ua1af\ua1b0\ua1b1\ua1b2\ua1b3\ua1b4\ua1b5\ua1b6\ua1b7\ua1b8\ua1b9\ua1ba\ua1bb\ua1bc\ua1bd\ua1be\ua1bf\ua1c0\ua1c1\ua1c2\ua1c3\ua1c4\ua1c5\ua1c6\ua1c7\ua1c8\ua1c9\ua1ca\ua1cb\ua1cc\ua1cd\ua1ce\ua1cf\ua1d0\ua1d1\ua1d2\ua1d3\ua1d4\ua1d5\ua1d6\ua1d7\ua1d8\ua1d9\ua1da\ua1db\ua1dc\ua1dd\ua1de\ua1df\ua1e0\ua1e1\ua1e2\ua1e3\ua1e4\ua1e5\ua1e6\ua1e7\ua1e8\ua1e9\ua1ea\ua1eb\ua1ec\ua1ed\ua1ee\ua1ef\ua1f0\ua1f1\ua1f2\ua1f3\ua1f4\ua1f5\ua1f6\ua1f7\ua1f8\ua1f9\ua1fa\ua1fb\ua1fc\ua1fd\ua1fe\ua1ff\ua200\ua201\ua202\ua203\ua204\ua205\ua206\ua207\ua208\ua209\ua20a\ua20b\ua20c\ua20d\ua20e\ua20f\ua210\ua211\ua212\ua213\ua214\ua215\ua216\ua217\ua218\ua219\ua21a\ua21b\ua21c\ua21d\ua21e\ua21f\ua220\ua221\ua222\ua223\ua224\ua225\ua226\ua227\ua228\ua229\ua22a\ua22b\ua22c\ua22d\ua22e\ua22f\ua230\ua231\ua232\ua233\ua234\ua235\ua236\ua237\ua238\ua239\ua23a\ua23b\ua23c\ua23d\ua23e\ua23f\ua240\ua241\ua242\ua243\ua244\ua245\ua246\ua247\ua248\ua249\ua24a\ua24b\ua24c\ua24d\ua24e\ua24f\ua250\ua251\ua252\ua253\ua254\ua255\ua256\ua257\ua258\ua259\ua25a\ua25b\ua25c\ua25d\ua25e\ua25f\ua260\ua261\ua262\ua263\ua264\ua265\ua266\ua267\ua268\ua269\ua26a\ua26b\ua26c\ua26d\ua26e\ua26f\ua270\ua271\ua272\ua273\ua274\ua275\ua276\ua277\ua278\ua279\ua27a\ua27b\ua27c\ua27d\ua27e\ua27f\ua280\ua281\ua282\ua283\ua284\ua285\ua286\ua287\ua288\ua289\ua28a\ua28b\ua28c\ua28d\ua28e\ua28f\ua290\ua291\ua292\ua293\ua294\ua295\ua296\ua297\ua298\ua299\ua29a\ua29b\ua29c\ua29d\ua29e\ua29f\ua2a0\ua2a1\ua2a2\ua2a3\ua2a4\ua2a5\ua2a6\ua2a7\ua2a8\ua2a9\ua2aa\ua2ab\ua2ac\ua2ad\ua2ae\ua2af\ua2b0\ua2b1\ua2b2\ua2b3\ua2b4\ua2b5\ua2b6\ua2b7\ua2b8\ua2b9\ua2ba\ua2bb\ua2bc\ua2bd\ua2be\ua2bf\ua2c0\ua2c1\ua2c2\ua2c3\ua2c4\ua2c5\ua2c6\ua2c7\ua2c8\ua2c9\ua2ca\ua2cb\ua2cc\ua2cd\ua2ce\ua2cf\ua2d0\ua2d1\ua2d2\ua2d3\ua2d4\ua2d5\ua2d6\ua2d7\ua2d8\ua2d9\ua2da\ua2db\ua2dc\ua2dd\ua2de\ua2df\ua2e0\ua2e1\ua2e2\ua2e3\ua2e4\ua2e5\ua2e6\ua2e7\ua2e8\ua2e9\ua2ea\ua2eb\ua2ec\ua2ed\ua2ee\ua2ef\ua2f0\ua2f1\ua2f2\ua2f3\ua2f4\ua2f5\ua2f6\ua2f7\ua2f8\ua2f9\ua2fa\ua2fb\ua2fc\ua2fd\ua2fe\ua2ff\ua300\ua301\ua302\ua303\ua304\ua305\ua306\ua307\ua308\ua309\ua30a\ua30b\ua30c\ua30d\ua30e\ua30f\ua310\ua311\ua312\ua313\ua314\ua315\ua316\ua317\ua318\ua319\ua31a\ua31b\ua31c\ua31d\ua31e\ua31f\ua320\ua321\ua322\ua323\ua324\ua325\ua326\ua327\ua328\ua329\ua32a\ua32b\ua32c\ua32d\ua32e\ua32f\ua330\ua331\ua332\ua333\ua334\ua335\ua336\ua337\ua338\ua339\ua33a\ua33b\ua33c\ua33d\ua33e\ua33f\ua340\ua341\ua342\ua343\ua344\ua345\ua346\ua347\ua348\ua349\ua34a\ua34b\ua34c\ua34d\ua34e\ua34f\ua350\ua351\ua352\ua353\ua354\ua355\ua356\ua357\ua358\ua359\ua35a\ua35b\ua35c\ua35d\ua35e\ua35f\ua360\ua361\ua362\ua363\ua364\ua365\ua366\ua367\ua368\ua369\ua36a\ua36b\ua36c\ua36d\ua36e\ua36f\ua370\ua371\ua372\ua373\ua374\ua375\ua376\ua377\ua378\ua379\ua37a\ua37b\ua37c\ua37d\ua37e\ua37f\ua380\ua381\ua382\ua383\ua384\ua385\ua386\ua387\ua388\ua389\ua38a\ua38b\ua38c\ua38d\ua38e\ua38f\ua390\ua391\ua392\ua393\ua394\ua395\ua396\ua397\ua398\ua399\ua39a\ua39b\ua39c\ua39d\ua39e\ua39f\ua3a0\ua3a1\ua3a2\ua3a3\ua3a4\ua3a5\ua3a6\ua3a7\ua3a8\ua3a9\ua3aa\ua3ab\ua3ac\ua3ad\ua3ae\ua3af\ua3b0\ua3b1\ua3b2\ua3b3\ua3b4\ua3b5\ua3b6\ua3b7\ua3b8\ua3b9\ua3ba\ua3bb\ua3bc\ua3bd\ua3be\ua3bf\ua3c0\ua3c1\ua3c2\ua3c3\ua3c4\ua3c5\ua3c6\ua3c7\ua3c8\ua3c9\ua3ca\ua3cb\ua3cc\ua3cd\ua3ce\ua3cf\ua3d0\ua3d1\ua3d2\ua3d3\ua3d4\ua3d5\ua3d6\ua3d7\ua3d8\ua3d9\ua3da\ua3db\ua3dc\ua3dd\ua3de\ua3df\ua3e0\ua3e1\ua3e2\ua3e3\ua3e4\ua3e5\ua3e6\ua3e7\ua3e8\ua3e9\ua3ea\ua3eb\ua3ec\ua3ed\ua3ee\ua3ef\ua3f0\ua3f1\ua3f2\ua3f3\ua3f4\ua3f5\ua3f6\ua3f7\ua3f8\ua3f9\ua3fa\ua3fb\ua3fc\ua3fd\ua3fe\ua3ff\ua400\ua401\ua402\ua403\ua404\ua405\ua406\ua407\ua408\ua409\ua40a\ua40b\ua40c\ua40d\ua40e\ua40f\ua410\ua411\ua412\ua413\ua414\ua415\ua416\ua417\ua418\ua419\ua41a\ua41b\ua41c\ua41d\ua41e\ua41f\ua420\ua421\ua422\ua423\ua424\ua425\ua426\ua427\ua428\ua429\ua42a\ua42b\ua42c\ua42d\ua42e\ua42f\ua430\ua431\ua432\ua433\ua434\ua435\ua436\ua437\ua438\ua439\ua43a\ua43b\ua43c\ua43d\ua43e\ua43f\ua440\ua441\ua442\ua443\ua444\ua445\ua446\ua447\ua448\ua449\ua44a\ua44b\ua44c\ua44d\ua44e\ua44f\ua450\ua451\ua452\ua453\ua454\ua455\ua456\ua457\ua458\ua459\ua45a\ua45b\ua45c\ua45d\ua45e\ua45f\ua460\ua461\ua462\ua463\ua464\ua465\ua466\ua467\ua468\ua469\ua46a\ua46b\ua46c\ua46d\ua46e\ua46f\ua470\ua471\ua472\ua473\ua474\ua475\ua476\ua477\ua478\ua479\ua47a\ua47b\ua47c\ua47d\ua47e\ua47f\ua480\ua481\ua482\ua483\ua484\ua485\ua486\ua487\ua488\ua489\ua48a\ua48b\ua48c\ua4d0\ua4d1\ua4d2\ua4d3\ua4d4\ua4d5\ua4d6\ua4d7\ua4d8\ua4d9\ua4da\ua4db\ua4dc\ua4dd\ua4de\ua4df\ua4e0\ua4e1\ua4e2\ua4e3\ua4e4\ua4e5\ua4e6\ua4e7\ua4e8\ua4e9\ua4ea\ua4eb\ua4ec\ua4ed\ua4ee\ua4ef\ua4f0\ua4f1\ua4f2\ua4f3\ua4f4\ua4f5\ua4f6\ua4f7\ua4f8\ua4f9\ua4fa\ua4fb\ua4fc\ua4fd\ua500\ua501\ua502\ua503\ua504\ua505\ua506\ua507\ua508\ua509\ua50a\ua50b\ua50c\ua50d\ua50e\ua50f\ua510\ua511\ua512\ua513\ua514\ua515\ua516\ua517\ua518\ua519\ua51a\ua51b\ua51c\ua51d\ua51e\ua51f\ua520\ua521\ua522\ua523\ua524\ua525\ua526\ua527\ua528\ua529\ua52a\ua52b\ua52c\ua52d\ua52e\ua52f\ua530\ua531\ua532\ua533\ua534\ua535\ua536\ua537\ua538\ua539\ua53a\ua53b\ua53c\ua53d\ua53e\ua53f\ua540\ua541\ua542\ua543\ua544\ua545\ua546\ua547\ua548\ua549\ua54a\ua54b\ua54c\ua54d\ua54e\ua54f\ua550\ua551\ua552\ua553\ua554\ua555\ua556\ua557\ua558\ua559\ua55a\ua55b\ua55c\ua55d\ua55e\ua55f\ua560\ua561\ua562\ua563\ua564\ua565\ua566\ua567\ua568\ua569\ua56a\ua56b\ua56c\ua56d\ua56e\ua56f\ua570\ua571\ua572\ua573\ua574\ua575\ua576\ua577\ua578\ua579\ua57a\ua57b\ua57c\ua57d\ua57e\ua57f\ua580\ua581\ua582\ua583\ua584\ua585\ua586\ua587\ua588\ua589\ua58a\ua58b\ua58c\ua58d\ua58e\ua58f\ua590\ua591\ua592\ua593\ua594\ua595\ua596\ua597\ua598\ua599\ua59a\ua59b\ua59c\ua59d\ua59e\ua59f\ua5a0\ua5a1\ua5a2\ua5a3\ua5a4\ua5a5\ua5a6\ua5a7\ua5a8\ua5a9\ua5aa\ua5ab\ua5ac\ua5ad\ua5ae\ua5af\ua5b0\ua5b1\ua5b2\ua5b3\ua5b4\ua5b5\ua5b6\ua5b7\ua5b8\ua5b9\ua5ba\ua5bb\ua5bc\ua5bd\ua5be\ua5bf\ua5c0\ua5c1\ua5c2\ua5c3\ua5c4\ua5c5\ua5c6\ua5c7\ua5c8\ua5c9\ua5ca\ua5cb\ua5cc\ua5cd\ua5ce\ua5cf\ua5d0\ua5d1\ua5d2\ua5d3\ua5d4\ua5d5\ua5d6\ua5d7\ua5d8\ua5d9\ua5da\ua5db\ua5dc\ua5dd\ua5de\ua5df\ua5e0\ua5e1\ua5e2\ua5e3\ua5e4\ua5e5\ua5e6\ua5e7\ua5e8\ua5e9\ua5ea\ua5eb\ua5ec\ua5ed\ua5ee\ua5ef\ua5f0\ua5f1\ua5f2\ua5f3\ua5f4\ua5f5\ua5f6\ua5f7\ua5f8\ua5f9\ua5fa\ua5fb\ua5fc\ua5fd\ua5fe\ua5ff\ua600\ua601\ua602\ua603\ua604\ua605\ua606\ua607\ua608\ua609\ua60a\ua60b\ua60c\ua610\ua611\ua612\ua613\ua614\ua615\ua616\ua617\ua618\ua619\ua61a\ua61b\ua61c\ua61d\ua61e\ua61f\ua62a\ua62b\ua640\ua641\ua642\ua643\ua644\ua645\ua646\ua647\ua648\ua649\ua64a\ua64b\ua64c\ua64d\ua64e\ua64f\ua650\ua651\ua652\ua653\ua654\ua655\ua656\ua657\ua658\ua659\ua65a\ua65b\ua65c\ua65d\ua65e\ua65f\ua660\ua661\ua662\ua663\ua664\ua665\ua666\ua667\ua668\ua669\ua66a\ua66b\ua66c\ua66d\ua66e\ua67f\ua680\ua681\ua682\ua683\ua684\ua685\ua686\ua687\ua688\ua689\ua68a\ua68b\ua68c\ua68d\ua68e\ua68f\ua690\ua691\ua692\ua693\ua694\ua695\ua696\ua697\ua698\ua699\ua69a\ua69b\ua69c\ua69d\ua6a0\ua6a1\ua6a2\ua6a3\ua6a4\ua6a5\ua6a6\ua6a7\ua6a8\ua6a9\ua6aa\ua6ab\ua6ac\ua6ad\ua6ae\ua6af\ua6b0\ua6b1\ua6b2\ua6b3\ua6b4\ua6b5\ua6b6\ua6b7\ua6b8\ua6b9\ua6ba\ua6bb\ua6bc\ua6bd\ua6be\ua6bf\ua6c0\ua6c1\ua6c2\ua6c3\ua6c4\ua6c5\ua6c6\ua6c7\ua6c8\ua6c9\ua6ca\ua6cb\ua6cc\ua6cd\ua6ce\ua6cf\ua6d0\ua6d1\ua6d2\ua6d3\ua6d4\ua6d5\ua6d6\ua6d7\ua6d8\ua6d9\ua6da\ua6db\ua6dc\ua6dd\ua6de\ua6df\ua6e0\ua6e1\ua6e2\ua6e3\ua6e4\ua6e5\ua6e6\ua6e7\ua6e8\ua6e9\ua6ea\ua6eb\ua6ec\ua6ed\ua6ee\ua6ef\ua717\ua718\ua719\ua71a\ua71b\ua71c\ua71d\ua71e\ua71f\ua722\ua723\ua724\ua725\ua726\ua727\ua728\ua729\ua72a\ua72b\ua72c\ua72d\ua72e\ua72f\ua730\ua731\ua732\ua733\ua734\ua735\ua736\ua737\ua738\ua739\ua73a\ua73b\ua73c\ua73d\ua73e\ua73f\ua740\ua741\ua742\ua743\ua744\ua745\ua746\ua747\ua748\ua749\ua74a\ua74b\ua74c\ua74d\ua74e\ua74f\ua750\ua751\ua752\ua753\ua754\ua755\ua756\ua757\ua758\ua759\ua75a\ua75b\ua75c\ua75d\ua75e\ua75f\ua760\ua761\ua762\ua763\ua764\ua765\ua766\ua767\ua768\ua769\ua76a\ua76b\ua76c\ua76d\ua76e\ua76f\ua770\ua771\ua772\ua773\ua774\ua775\ua776\ua777\ua778\ua779\ua77a\ua77b\ua77c\ua77d\ua77e\ua77f\ua780\ua781\ua782\ua783\ua784\ua785\ua786\ua787\ua788\ua78b\ua78c\ua78d\ua78e\ua78f\ua790\ua791\ua792\ua793\ua794\ua795\ua796\ua797\ua798\ua799\ua79a\ua79b\ua79c\ua79d\ua79e\ua79f\ua7a0\ua7a1\ua7a2\ua7a3\ua7a4\ua7a5\ua7a6\ua7a7\ua7a8\ua7a9\ua7aa\ua7ab\ua7ac\ua7ad\ua7ae\ua7b0\ua7b1\ua7b2\ua7b3\ua7b4\ua7b5\ua7b6\ua7b7\ua7f7\ua7f8\ua7f9\ua7fa\ua7fb\ua7fc\ua7fd\ua7fe\ua7ff\ua800\ua801\ua803\ua804\ua805\ua807\ua808\ua809\ua80a\ua80c\ua80d\ua80e\ua80f\ua810\ua811\ua812\ua813\ua814\ua815\ua816\ua817\ua818\ua819\ua81a\ua81b\ua81c\ua81d\ua81e\ua81f\ua820\ua821\ua822\ua840\ua841\ua842\ua843\ua844\ua845\ua846\ua847\ua848\ua849\ua84a\ua84b\ua84c\ua84d\ua84e\ua84f\ua850\ua851\ua852\ua853\ua854\ua855\ua856\ua857\ua858\ua859\ua85a\ua85b\ua85c\ua85d\ua85e\ua85f\ua860\ua861\ua862\ua863\ua864\ua865\ua866\ua867\ua868\ua869\ua86a\ua86b\ua86c\ua86d\ua86e\ua86f\ua870\ua871\ua872\ua873\ua882\ua883\ua884\ua885\ua886\ua887\ua888\ua889\ua88a\ua88b\ua88c\ua88d\ua88e\ua88f\ua890\ua891\ua892\ua893\ua894\ua895\ua896\ua897\ua898\ua899\ua89a\ua89b\ua89c\ua89d\ua89e\ua89f\ua8a0\ua8a1\ua8a2\ua8a3\ua8a4\ua8a5\ua8a6\ua8a7\ua8a8\ua8a9\ua8aa\ua8ab\ua8ac\ua8ad\ua8ae\ua8af\ua8b0\ua8b1\ua8b2\ua8b3\ua8f2\ua8f3\ua8f4\ua8f5\ua8f6\ua8f7\ua8fb\ua8fd\ua90a\ua90b\ua90c\ua90d\ua90e\ua90f\ua910\ua911\ua912\ua913\ua914\ua915\ua916\ua917\ua918\ua919\ua91a\ua91b\ua91c\ua91d\ua91e\ua91f\ua920\ua921\ua922\ua923\ua924\ua925\ua930\ua931\ua932\ua933\ua934\ua935\ua936\ua937\ua938\ua939\ua93a\ua93b\ua93c\ua93d\ua93e\ua93f\ua940\ua941\ua942\ua943\ua944\ua945\ua946\ua960\ua961\ua962\ua963\ua964\ua965\ua966\ua967\ua968\ua969\ua96a\ua96b\ua96c\ua96d\ua96e\ua96f\ua970\ua971\ua972\ua973\ua974\ua975\ua976\ua977\ua978\ua979\ua97a\ua97b\ua97c\ua984\ua985\ua986\ua987\ua988\ua989\ua98a\ua98b\ua98c\ua98d\ua98e\ua98f\ua990\ua991\ua992\ua993\ua994\ua995\ua996\ua997\ua998\ua999\ua99a\ua99b\ua99c\ua99d\ua99e\ua99f\ua9a0\ua9a1\ua9a2\ua9a3\ua9a4\ua9a5\ua9a6\ua9a7\ua9a8\ua9a9\ua9aa\ua9ab\ua9ac\ua9ad\ua9ae\ua9af\ua9b0\ua9b1\ua9b2\ua9cf\ua9e0\ua9e1\ua9e2\ua9e3\ua9e4\ua9e6\ua9e7\ua9e8\ua9e9\ua9ea\ua9eb\ua9ec\ua9ed\ua9ee\ua9ef\ua9fa\ua9fb\ua9fc\ua9fd\ua9fe\uaa00\uaa01\uaa02\uaa03\uaa04\uaa05\uaa06\uaa07\uaa08\uaa09\uaa0a\uaa0b\uaa0c\uaa0d\uaa0e\uaa0f\uaa10\uaa11\uaa12\uaa13\uaa14\uaa15\uaa16\uaa17\uaa18\uaa19\uaa1a\uaa1b\uaa1c\uaa1d\uaa1e\uaa1f\uaa20\uaa21\uaa22\uaa23\uaa24\uaa25\uaa26\uaa27\uaa28\uaa40\uaa41\uaa42\uaa44\uaa45\uaa46\uaa47\uaa48\uaa49\uaa4a\uaa4b\uaa60\uaa61\uaa62\uaa63\uaa64\uaa65\uaa66\uaa67\uaa68\uaa69\uaa6a\uaa6b\uaa6c\uaa6d\uaa6e\uaa6f\uaa70\uaa71\uaa72\uaa73\uaa74\uaa75\uaa76\uaa7a\uaa7e\uaa7f\uaa80\uaa81\uaa82\uaa83\uaa84\uaa85\uaa86\uaa87\uaa88\uaa89\uaa8a\uaa8b\uaa8c\uaa8d\uaa8e\uaa8f\uaa90\uaa91\uaa92\uaa93\uaa94\uaa95\uaa96\uaa97\uaa98\uaa99\uaa9a\uaa9b\uaa9c\uaa9d\uaa9e\uaa9f\uaaa0\uaaa1\uaaa2\uaaa3\uaaa4\uaaa5\uaaa6\uaaa7\uaaa8\uaaa9\uaaaa\uaaab\uaaac\uaaad\uaaae\uaaaf\uaab1\uaab5\uaab6\uaab9\uaaba\uaabb\uaabc\uaabd\uaac0\uaac2\uaadb\uaadc\uaadd\uaae0\uaae1\uaae2\uaae3\uaae4\uaae5\uaae6\uaae7\uaae8\uaae9\uaaea\uaaf2\uaaf3\uaaf4\uab01\uab02\uab03\uab04\uab05\uab06\uab09\uab0a\uab0b\uab0c\uab0d\uab0e\uab11\uab12\uab13\uab14\uab15\uab16\uab20\uab21\uab22\uab23\uab24\uab25\uab26\uab28\uab29\uab2a\uab2b\uab2c\uab2d\uab2e\uab30\uab31\uab32\uab33\uab34\uab35\uab36\uab37\uab38\uab39\uab3a\uab3b\uab3c\uab3d\uab3e\uab3f\uab40\uab41\uab42\uab43\uab44\uab45\uab46\uab47\uab48\uab49\uab4a\uab4b\uab4c\uab4d\uab4e\uab4f\uab50\uab51\uab52\uab53\uab54\uab55\uab56\uab57\uab58\uab59\uab5a\uab5c\uab5d\uab5e\uab5f\uab60\uab61\uab62\uab63\uab64\uab65\uab70\uab71\uab72\uab73\uab74\uab75\uab76\uab77\uab78\uab79\uab7a\uab7b\uab7c\uab7d\uab7e\uab7f\uab80\uab81\uab82\uab83\uab84\uab85\uab86\uab87\uab88\uab89\uab8a\uab8b\uab8c\uab8d\uab8e\uab8f\uab90\uab91\uab92\uab93\uab94\uab95\uab96\uab97\uab98\uab99\uab9a\uab9b\uab9c\uab9d\uab9e\uab9f\uaba0\uaba1\uaba2\uaba3\uaba4\uaba5\uaba6\uaba7\uaba8\uaba9\uabaa\uabab\uabac\uabad\uabae\uabaf\uabb0\uabb1\uabb2\uabb3\uabb4\uabb5\uabb6\uabb7\uabb8\uabb9\uabba\uabbb\uabbc\uabbd\uabbe\uabbf\uabc0\uabc1\uabc2\uabc3\uabc4\uabc5\uabc6\uabc7\uabc8\uabc9\uabca\uabcb\uabcc\uabcd\uabce\uabcf\uabd0\uabd1\uabd2\uabd3\uabd4\uabd5\uabd6\uabd7\uabd8\uabd9\uabda\uabdb\uabdc\uabdd\uabde\uabdf\uabe0\uabe1\uabe2\uac00\uac01\uac02\uac03\uac04\uac05\uac06\uac07\uac08\uac09\uac0a\uac0b\uac0c\uac0d\uac0e\uac0f\uac10\uac11\uac12\uac13\uac14\uac15\uac16\uac17\uac18\uac19\uac1a\uac1b\uac1c\uac1d\uac1e\uac1f\uac20\uac21\uac22\uac23\uac24\uac25\uac26\uac27\uac28\uac29\uac2a\uac2b\uac2c\uac2d\uac2e\uac2f\uac30\uac31\uac32\uac33\uac34\uac35\uac36\uac37\uac38\uac39\uac3a\uac3b\uac3c\uac3d\uac3e\uac3f\uac40\uac41\uac42\uac43\uac44\uac45\uac46\uac47\uac48\uac49\uac4a\uac4b\uac4c\uac4d\uac4e\uac4f\uac50\uac51\uac52\uac53\uac54\uac55\uac56\uac57\uac58\uac59\uac5a\uac5b\uac5c\uac5d\uac5e\uac5f\uac60\uac61\uac62\uac63\uac64\uac65\uac66\uac67\uac68\uac69\uac6a\uac6b\uac6c\uac6d\uac6e\uac6f\uac70\uac71\uac72\uac73\uac74\uac75\uac76\uac77\uac78\uac79\uac7a\uac7b\uac7c\uac7d\uac7e\uac7f\uac80\uac81\uac82\uac83\uac84\uac85\uac86\uac87\uac88\uac89\uac8a\uac8b\uac8c\uac8d\uac8e\uac8f\uac90\uac91\uac92\uac93\uac94\uac95\uac96\uac97\uac98\uac99\uac9a\uac9b\uac9c\uac9d\uac9e\uac9f\uaca0\uaca1\uaca2\uaca3\uaca4\uaca5\uaca6\uaca7\uaca8\uaca9\uacaa\uacab\uacac\uacad\uacae\uacaf\uacb0\uacb1\uacb2\uacb3\uacb4\uacb5\uacb6\uacb7\uacb8\uacb9\uacba\uacbb\uacbc\uacbd\uacbe\uacbf\uacc0\uacc1\uacc2\uacc3\uacc4\uacc5\uacc6\uacc7\uacc8\uacc9\uacca\uaccb\uaccc\uaccd\uacce\uaccf\uacd0\uacd1\uacd2\uacd3\uacd4\uacd5\uacd6\uacd7\uacd8\uacd9\uacda\uacdb\uacdc\uacdd\uacde\uacdf\uace0\uace1\uace2\uace3\uace4\uace5\uace6\uace7\uace8\uace9\uacea\uaceb\uacec\uaced\uacee\uacef\uacf0\uacf1\uacf2\uacf3\uacf4\uacf5\uacf6\uacf7\uacf8\uacf9\uacfa\uacfb\uacfc\uacfd\uacfe\uacff\uad00\uad01\uad02\uad03\uad04\uad05\uad06\uad07\uad08\uad09\uad0a\uad0b\uad0c\uad0d\uad0e\uad0f\uad10\uad11\uad12\uad13\uad14\uad15\uad16\uad17\uad18\uad19\uad1a\uad1b\uad1c\uad1d\uad1e\uad1f\uad20\uad21\uad22\uad23\uad24\uad25\uad26\uad27\uad28\uad29\uad2a\uad2b\uad2c\uad2d\uad2e\uad2f\uad30\uad31\uad32\uad33\uad34\uad35\uad36\uad37\uad38\uad39\uad3a\uad3b\uad3c\uad3d\uad3e\uad3f\uad40\uad41\uad42\uad43\uad44\uad45\uad46\uad47\uad48\uad49\uad4a\uad4b\uad4c\uad4d\uad4e\uad4f\uad50\uad51\uad52\uad53\uad54\uad55\uad56\uad57\uad58\uad59\uad5a\uad5b\uad5c\uad5d\uad5e\uad5f\uad60\uad61\uad62\uad63\uad64\uad65\uad66\uad67\uad68\uad69\uad6a\uad6b\uad6c\uad6d\uad6e\uad6f\uad70\uad71\uad72\uad73\uad74\uad75\uad76\uad77\uad78\uad79\uad7a\uad7b\uad7c\uad7d\uad7e\uad7f\uad80\uad81\uad82\uad83\uad84\uad85\uad86\uad87\uad88\uad89\uad8a\uad8b\uad8c\uad8d\uad8e\uad8f\uad90\uad91\uad92\uad93\uad94\uad95\uad96\uad97\uad98\uad99\uad9a\uad9b\uad9c\uad9d\uad9e\uad9f\uada0\uada1\uada2\uada3\uada4\uada5\uada6\uada7\uada8\uada9\uadaa\uadab\uadac\uadad\uadae\uadaf\uadb0\uadb1\uadb2\uadb3\uadb4\uadb5\uadb6\uadb7\uadb8\uadb9\uadba\uadbb\uadbc\uadbd\uadbe\uadbf\uadc0\uadc1\uadc2\uadc3\uadc4\uadc5\uadc6\uadc7\uadc8\uadc9\uadca\uadcb\uadcc\uadcd\uadce\uadcf\uadd0\uadd1\uadd2\uadd3\uadd4\uadd5\uadd6\uadd7\uadd8\uadd9\uadda\uaddb\uaddc\uaddd\uadde\uaddf\uade0\uade1\uade2\uade3\uade4\uade5\uade6\uade7\uade8\uade9\uadea\uadeb\uadec\uaded\uadee\uadef\uadf0\uadf1\uadf2\uadf3\uadf4\uadf5\uadf6\uadf7\uadf8\uadf9\uadfa\uadfb\uadfc\uadfd\uadfe\uadff\uae00\uae01\uae02\uae03\uae04\uae05\uae06\uae07\uae08\uae09\uae0a\uae0b\uae0c\uae0d\uae0e\uae0f\uae10\uae11\uae12\uae13\uae14\uae15\uae16\uae17\uae18\uae19\uae1a\uae1b\uae1c\uae1d\uae1e\uae1f\uae20\uae21\uae22\uae23\uae24\uae25\uae26\uae27\uae28\uae29\uae2a\uae2b\uae2c\uae2d\uae2e\uae2f\uae30\uae31\uae32\uae33\uae34\uae35\uae36\uae37\uae38\uae39\uae3a\uae3b\uae3c\uae3d\uae3e\uae3f\uae40\uae41\uae42\uae43\uae44\uae45\uae46\uae47\uae48\uae49\uae4a\uae4b\uae4c\uae4d\uae4e\uae4f\uae50\uae51\uae52\uae53\uae54\uae55\uae56\uae57\uae58\uae59\uae5a\uae5b\uae5c\uae5d\uae5e\uae5f\uae60\uae61\uae62\uae63\uae64\uae65\uae66\uae67\uae68\uae69\uae6a\uae6b\uae6c\uae6d\uae6e\uae6f\uae70\uae71\uae72\uae73\uae74\uae75\uae76\uae77\uae78\uae79\uae7a\uae7b\uae7c\uae7d\uae7e\uae7f\uae80\uae81\uae82\uae83\uae84\uae85\uae86\uae87\uae88\uae89\uae8a\uae8b\uae8c\uae8d\uae8e\uae8f\uae90\uae91\uae92\uae93\uae94\uae95\uae96\uae97\uae98\uae99\uae9a\uae9b\uae9c\uae9d\uae9e\uae9f\uaea0\uaea1\uaea2\uaea3\uaea4\uaea5\uaea6\uaea7\uaea8\uaea9\uaeaa\uaeab\uaeac\uaead\uaeae\uaeaf\uaeb0\uaeb1\uaeb2\uaeb3\uaeb4\uaeb5\uaeb6\uaeb7\uaeb8\uaeb9\uaeba\uaebb\uaebc\uaebd\uaebe\uaebf\uaec0\uaec1\uaec2\uaec3\uaec4\uaec5\uaec6\uaec7\uaec8\uaec9\uaeca\uaecb\uaecc\uaecd\uaece\uaecf\uaed0\uaed1\uaed2\uaed3\uaed4\uaed5\uaed6\uaed7\uaed8\uaed9\uaeda\uaedb\uaedc\uaedd\uaede\uaedf\uaee0\uaee1\uaee2\uaee3\uaee4\uaee5\uaee6\uaee7\uaee8\uaee9\uaeea\uaeeb\uaeec\uaeed\uaeee\uaeef\uaef0\uaef1\uaef2\uaef3\uaef4\uaef5\uaef6\uaef7\uaef8\uaef9\uaefa\uaefb\uaefc\uaefd\uaefe\uaeff\uaf00\uaf01\uaf02\uaf03\uaf04\uaf05\uaf06\uaf07\uaf08\uaf09\uaf0a\uaf0b\uaf0c\uaf0d\uaf0e\uaf0f\uaf10\uaf11\uaf12\uaf13\uaf14\uaf15\uaf16\uaf17\uaf18\uaf19\uaf1a\uaf1b\uaf1c\uaf1d\uaf1e\uaf1f\uaf20\uaf21\uaf22\uaf23\uaf24\uaf25\uaf26\uaf27\uaf28\uaf29\uaf2a\uaf2b\uaf2c\uaf2d\uaf2e\uaf2f\uaf30\uaf31\uaf32\uaf33\uaf34\uaf35\uaf36\uaf37\uaf38\uaf39\uaf3a\uaf3b\uaf3c\uaf3d\uaf3e\uaf3f\uaf40\uaf41\uaf42\uaf43\uaf44\uaf45\uaf46\uaf47\uaf48\uaf49\uaf4a\uaf4b\uaf4c\uaf4d\uaf4e\uaf4f\uaf50\uaf51\uaf52\uaf53\uaf54\uaf55\uaf56\uaf57\uaf58\uaf59\uaf5a\uaf5b\uaf5c\uaf5d\uaf5e\uaf5f\uaf60\uaf61\uaf62\uaf63\uaf64\uaf65\uaf66\uaf67\uaf68\uaf69\uaf6a\uaf6b\uaf6c\uaf6d\uaf6e\uaf6f\uaf70\uaf71\uaf72\uaf73\uaf74\uaf75\uaf76\uaf77\uaf78\uaf79\uaf7a\uaf7b\uaf7c\uaf7d\uaf7e\uaf7f\uaf80\uaf81\uaf82\uaf83\uaf84\uaf85\uaf86\uaf87\uaf88\uaf89\uaf8a\uaf8b\uaf8c\uaf8d\uaf8e\uaf8f\uaf90\uaf91\uaf92\uaf93\uaf94\uaf95\uaf96\uaf97\uaf98\uaf99\uaf9a\uaf9b\uaf9c\uaf9d\uaf9e\uaf9f\uafa0\uafa1\uafa2\uafa3\uafa4\uafa5\uafa6\uafa7\uafa8\uafa9\uafaa\uafab\uafac\uafad\uafae\uafaf\uafb0\uafb1\uafb2\uafb3\uafb4\uafb5\uafb6\uafb7\uafb8\uafb9\uafba\uafbb\uafbc\uafbd\uafbe\uafbf\uafc0\uafc1\uafc2\uafc3\uafc4\uafc5\uafc6\uafc7\uafc8\uafc9\uafca\uafcb\uafcc\uafcd\uafce\uafcf\uafd0\uafd1\uafd2\uafd3\uafd4\uafd5\uafd6\uafd7\uafd8\uafd9\uafda\uafdb\uafdc\uafdd\uafde\uafdf\uafe0\uafe1\uafe2\uafe3\uafe4\uafe5\uafe6\uafe7\uafe8\uafe9\uafea\uafeb\uafec\uafed\uafee\uafef\uaff0\uaff1\uaff2\uaff3\uaff4\uaff5\uaff6\uaff7\uaff8\uaff9\uaffa\uaffb\uaffc\uaffd\uaffe\uafff\ub000\ub001\ub002\ub003\ub004\ub005\ub006\ub007\ub008\ub009\ub00a\ub00b\ub00c\ub00d\ub00e\ub00f\ub010\ub011\ub012\ub013\ub014\ub015\ub016\ub017\ub018\ub019\ub01a\ub01b\ub01c\ub01d\ub01e\ub01f\ub020\ub021\ub022\ub023\ub024\ub025\ub026\ub027\ub028\ub029\ub02a\ub02b\ub02c\ub02d\ub02e\ub02f\ub030\ub031\ub032\ub033\ub034\ub035\ub036\ub037\ub038\ub039\ub03a\ub03b\ub03c\ub03d\ub03e\ub03f\ub040\ub041\ub042\ub043\ub044\ub045\ub046\ub047\ub048\ub049\ub04a\ub04b\ub04c\ub04d\ub04e\ub04f\ub050\ub051\ub052\ub053\ub054\ub055\ub056\ub057\ub058\ub059\ub05a\ub05b\ub05c\ub05d\ub05e\ub05f\ub060\ub061\ub062\ub063\ub064\ub065\ub066\ub067\ub068\ub069\ub06a\ub06b\ub06c\ub06d\ub06e\ub06f\ub070\ub071\ub072\ub073\ub074\ub075\ub076\ub077\ub078\ub079\ub07a\ub07b\ub07c\ub07d\ub07e\ub07f\ub080\ub081\ub082\ub083\ub084\ub085\ub086\ub087\ub088\ub089\ub08a\ub08b\ub08c\ub08d\ub08e\ub08f\ub090\ub091\ub092\ub093\ub094\ub095\ub096\ub097\ub098\ub099\ub09a\ub09b\ub09c\ub09d\ub09e\ub09f\ub0a0\ub0a1\ub0a2\ub0a3\ub0a4\ub0a5\ub0a6\ub0a7\ub0a8\ub0a9\ub0aa\ub0ab\ub0ac\ub0ad\ub0ae\ub0af\ub0b0\ub0b1\ub0b2\ub0b3\ub0b4\ub0b5\ub0b6\ub0b7\ub0b8\ub0b9\ub0ba\ub0bb\ub0bc\ub0bd\ub0be\ub0bf\ub0c0\ub0c1\ub0c2\ub0c3\ub0c4\ub0c5\ub0c6\ub0c7\ub0c8\ub0c9\ub0ca\ub0cb\ub0cc\ub0cd\ub0ce\ub0cf\ub0d0\ub0d1\ub0d2\ub0d3\ub0d4\ub0d5\ub0d6\ub0d7\ub0d8\ub0d9\ub0da\ub0db\ub0dc\ub0dd\ub0de\ub0df\ub0e0\ub0e1\ub0e2\ub0e3\ub0e4\ub0e5\ub0e6\ub0e7\ub0e8\ub0e9\ub0ea\ub0eb\ub0ec\ub0ed\ub0ee\ub0ef\ub0f0\ub0f1\ub0f2\ub0f3\ub0f4\ub0f5\ub0f6\ub0f7\ub0f8\ub0f9\ub0fa\ub0fb\ub0fc\ub0fd\ub0fe\ub0ff\ub100\ub101\ub102\ub103\ub104\ub105\ub106\ub107\ub108\ub109\ub10a\ub10b\ub10c\ub10d\ub10e\ub10f\ub110\ub111\ub112\ub113\ub114\ub115\ub116\ub117\ub118\ub119\ub11a\ub11b\ub11c\ub11d\ub11e\ub11f\ub120\ub121\ub122\ub123\ub124\ub125\ub126\ub127\ub128\ub129\ub12a\ub12b\ub12c\ub12d\ub12e\ub12f\ub130\ub131\ub132\ub133\ub134\ub135\ub136\ub137\ub138\ub139\ub13a\ub13b\ub13c\ub13d\ub13e\ub13f\ub140\ub141\ub142\ub143\ub144\ub145\ub146\ub147\ub148\ub149\ub14a\ub14b\ub14c\ub14d\ub14e\ub14f\ub150\ub151\ub152\ub153\ub154\ub155\ub156\ub157\ub158\ub159\ub15a\ub15b\ub15c\ub15d\ub15e\ub15f\ub160\ub161\ub162\ub163\ub164\ub165\ub166\ub167\ub168\ub169\ub16a\ub16b\ub16c\ub16d\ub16e\ub16f\ub170\ub171\ub172\ub173\ub174\ub175\ub176\ub177\ub178\ub179\ub17a\ub17b\ub17c\ub17d\ub17e\ub17f\ub180\ub181\ub182\ub183\ub184\ub185\ub186\ub187\ub188\ub189\ub18a\ub18b\ub18c\ub18d\ub18e\ub18f\ub190\ub191\ub192\ub193\ub194\ub195\ub196\ub197\ub198\ub199\ub19a\ub19b\ub19c\ub19d\ub19e\ub19f\ub1a0\ub1a1\ub1a2\ub1a3\ub1a4\ub1a5\ub1a6\ub1a7\ub1a8\ub1a9\ub1aa\ub1ab\ub1ac\ub1ad\ub1ae\ub1af\ub1b0\ub1b1\ub1b2\ub1b3\ub1b4\ub1b5\ub1b6\ub1b7\ub1b8\ub1b9\ub1ba\ub1bb\ub1bc\ub1bd\ub1be\ub1bf\ub1c0\ub1c1\ub1c2\ub1c3\ub1c4\ub1c5\ub1c6\ub1c7\ub1c8\ub1c9\ub1ca\ub1cb\ub1cc\ub1cd\ub1ce\ub1cf\ub1d0\ub1d1\ub1d2\ub1d3\ub1d4\ub1d5\ub1d6\ub1d7\ub1d8\ub1d9\ub1da\ub1db\ub1dc\ub1dd\ub1de\ub1df\ub1e0\ub1e1\ub1e2\ub1e3\ub1e4\ub1e5\ub1e6\ub1e7\ub1e8\ub1e9\ub1ea\ub1eb\ub1ec\ub1ed\ub1ee\ub1ef\ub1f0\ub1f1\ub1f2\ub1f3\ub1f4\ub1f5\ub1f6\ub1f7\ub1f8\ub1f9\ub1fa\ub1fb\ub1fc\ub1fd\ub1fe\ub1ff\ub200\ub201\ub202\ub203\ub204\ub205\ub206\ub207\ub208\ub209\ub20a\ub20b\ub20c\ub20d\ub20e\ub20f\ub210\ub211\ub212\ub213\ub214\ub215\ub216\ub217\ub218\ub219\ub21a\ub21b\ub21c\ub21d\ub21e\ub21f\ub220\ub221\ub222\ub223\ub224\ub225\ub226\ub227\ub228\ub229\ub22a\ub22b\ub22c\ub22d\ub22e\ub22f\ub230\ub231\ub232\ub233\ub234\ub235\ub236\ub237\ub238\ub239\ub23a\ub23b\ub23c\ub23d\ub23e\ub23f\ub240\ub241\ub242\ub243\ub244\ub245\ub246\ub247\ub248\ub249\ub24a\ub24b\ub24c\ub24d\ub24e\ub24f\ub250\ub251\ub252\ub253\ub254\ub255\ub256\ub257\ub258\ub259\ub25a\ub25b\ub25c\ub25d\ub25e\ub25f\ub260\ub261\ub262\ub263\ub264\ub265\ub266\ub267\ub268\ub269\ub26a\ub26b\ub26c\ub26d\ub26e\ub26f\ub270\ub271\ub272\ub273\ub274\ub275\ub276\ub277\ub278\ub279\ub27a\ub27b\ub27c\ub27d\ub27e\ub27f\ub280\ub281\ub282\ub283\ub284\ub285\ub286\ub287\ub288\ub289\ub28a\ub28b\ub28c\ub28d\ub28e\ub28f\ub290\ub291\ub292\ub293\ub294\ub295\ub296\ub297\ub298\ub299\ub29a\ub29b\ub29c\ub29d\ub29e\ub29f\ub2a0\ub2a1\ub2a2\ub2a3\ub2a4\ub2a5\ub2a6\ub2a7\ub2a8\ub2a9\ub2aa\ub2ab\ub2ac\ub2ad\ub2ae\ub2af\ub2b0\ub2b1\ub2b2\ub2b3\ub2b4\ub2b5\ub2b6\ub2b7\ub2b8\ub2b9\ub2ba\ub2bb\ub2bc\ub2bd\ub2be\ub2bf\ub2c0\ub2c1\ub2c2\ub2c3\ub2c4\ub2c5\ub2c6\ub2c7\ub2c8\ub2c9\ub2ca\ub2cb\ub2cc\ub2cd\ub2ce\ub2cf\ub2d0\ub2d1\ub2d2\ub2d3\ub2d4\ub2d5\ub2d6\ub2d7\ub2d8\ub2d9\ub2da\ub2db\ub2dc\ub2dd\ub2de\ub2df\ub2e0\ub2e1\ub2e2\ub2e3\ub2e4\ub2e5\ub2e6\ub2e7\ub2e8\ub2e9\ub2ea\ub2eb\ub2ec\ub2ed\ub2ee\ub2ef\ub2f0\ub2f1\ub2f2\ub2f3\ub2f4\ub2f5\ub2f6\ub2f7\ub2f8\ub2f9\ub2fa\ub2fb\ub2fc\ub2fd\ub2fe\ub2ff\ub300\ub301\ub302\ub303\ub304\ub305\ub306\ub307\ub308\ub309\ub30a\ub30b\ub30c\ub30d\ub30e\ub30f\ub310\ub311\ub312\ub313\ub314\ub315\ub316\ub317\ub318\ub319\ub31a\ub31b\ub31c\ub31d\ub31e\ub31f\ub320\ub321\ub322\ub323\ub324\ub325\ub326\ub327\ub328\ub329\ub32a\ub32b\ub32c\ub32d\ub32e\ub32f\ub330\ub331\ub332\ub333\ub334\ub335\ub336\ub337\ub338\ub339\ub33a\ub33b\ub33c\ub33d\ub33e\ub33f\ub340\ub341\ub342\ub343\ub344\ub345\ub346\ub347\ub348\ub349\ub34a\ub34b\ub34c\ub34d\ub34e\ub34f\ub350\ub351\ub352\ub353\ub354\ub355\ub356\ub357\ub358\ub359\ub35a\ub35b\ub35c\ub35d\ub35e\ub35f\ub360\ub361\ub362\ub363\ub364\ub365\ub366\ub367\ub368\ub369\ub36a\ub36b\ub36c\ub36d\ub36e\ub36f\ub370\ub371\ub372\ub373\ub374\ub375\ub376\ub377\ub378\ub379\ub37a\ub37b\ub37c\ub37d\ub37e\ub37f\ub380\ub381\ub382\ub383\ub384\ub385\ub386\ub387\ub388\ub389\ub38a\ub38b\ub38c\ub38d\ub38e\ub38f\ub390\ub391\ub392\ub393\ub394\ub395\ub396\ub397\ub398\ub399\ub39a\ub39b\ub39c\ub39d\ub39e\ub39f\ub3a0\ub3a1\ub3a2\ub3a3\ub3a4\ub3a5\ub3a6\ub3a7\ub3a8\ub3a9\ub3aa\ub3ab\ub3ac\ub3ad\ub3ae\ub3af\ub3b0\ub3b1\ub3b2\ub3b3\ub3b4\ub3b5\ub3b6\ub3b7\ub3b8\ub3b9\ub3ba\ub3bb\ub3bc\ub3bd\ub3be\ub3bf\ub3c0\ub3c1\ub3c2\ub3c3\ub3c4\ub3c5\ub3c6\ub3c7\ub3c8\ub3c9\ub3ca\ub3cb\ub3cc\ub3cd\ub3ce\ub3cf\ub3d0\ub3d1\ub3d2\ub3d3\ub3d4\ub3d5\ub3d6\ub3d7\ub3d8\ub3d9\ub3da\ub3db\ub3dc\ub3dd\ub3de\ub3df\ub3e0\ub3e1\ub3e2\ub3e3\ub3e4\ub3e5\ub3e6\ub3e7\ub3e8\ub3e9\ub3ea\ub3eb\ub3ec\ub3ed\ub3ee\ub3ef\ub3f0\ub3f1\ub3f2\ub3f3\ub3f4\ub3f5\ub3f6\ub3f7\ub3f8\ub3f9\ub3fa\ub3fb\ub3fc\ub3fd\ub3fe\ub3ff\ub400\ub401\ub402\ub403\ub404\ub405\ub406\ub407\ub408\ub409\ub40a\ub40b\ub40c\ub40d\ub40e\ub40f\ub410\ub411\ub412\ub413\ub414\ub415\ub416\ub417\ub418\ub419\ub41a\ub41b\ub41c\ub41d\ub41e\ub41f\ub420\ub421\ub422\ub423\ub424\ub425\ub426\ub427\ub428\ub429\ub42a\ub42b\ub42c\ub42d\ub42e\ub42f\ub430\ub431\ub432\ub433\ub434\ub435\ub436\ub437\ub438\ub439\ub43a\ub43b\ub43c\ub43d\ub43e\ub43f\ub440\ub441\ub442\ub443\ub444\ub445\ub446\ub447\ub448\ub449\ub44a\ub44b\ub44c\ub44d\ub44e\ub44f\ub450\ub451\ub452\ub453\ub454\ub455\ub456\ub457\ub458\ub459\ub45a\ub45b\ub45c\ub45d\ub45e\ub45f\ub460\ub461\ub462\ub463\ub464\ub465\ub466\ub467\ub468\ub469\ub46a\ub46b\ub46c\ub46d\ub46e\ub46f\ub470\ub471\ub472\ub473\ub474\ub475\ub476\ub477\ub478\ub479\ub47a\ub47b\ub47c\ub47d\ub47e\ub47f\ub480\ub481\ub482\ub483\ub484\ub485\ub486\ub487\ub488\ub489\ub48a\ub48b\ub48c\ub48d\ub48e\ub48f\ub490\ub491\ub492\ub493\ub494\ub495\ub496\ub497\ub498\ub499\ub49a\ub49b\ub49c\ub49d\ub49e\ub49f\ub4a0\ub4a1\ub4a2\ub4a3\ub4a4\ub4a5\ub4a6\ub4a7\ub4a8\ub4a9\ub4aa\ub4ab\ub4ac\ub4ad\ub4ae\ub4af\ub4b0\ub4b1\ub4b2\ub4b3\ub4b4\ub4b5\ub4b6\ub4b7\ub4b8\ub4b9\ub4ba\ub4bb\ub4bc\ub4bd\ub4be\ub4bf\ub4c0\ub4c1\ub4c2\ub4c3\ub4c4\ub4c5\ub4c6\ub4c7\ub4c8\ub4c9\ub4ca\ub4cb\ub4cc\ub4cd\ub4ce\ub4cf\ub4d0\ub4d1\ub4d2\ub4d3\ub4d4\ub4d5\ub4d6\ub4d7\ub4d8\ub4d9\ub4da\ub4db\ub4dc\ub4dd\ub4de\ub4df\ub4e0\ub4e1\ub4e2\ub4e3\ub4e4\ub4e5\ub4e6\ub4e7\ub4e8\ub4e9\ub4ea\ub4eb\ub4ec\ub4ed\ub4ee\ub4ef\ub4f0\ub4f1\ub4f2\ub4f3\ub4f4\ub4f5\ub4f6\ub4f7\ub4f8\ub4f9\ub4fa\ub4fb\ub4fc\ub4fd\ub4fe\ub4ff\ub500\ub501\ub502\ub503\ub504\ub505\ub506\ub507\ub508\ub509\ub50a\ub50b\ub50c\ub50d\ub50e\ub50f\ub510\ub511\ub512\ub513\ub514\ub515\ub516\ub517\ub518\ub519\ub51a\ub51b\ub51c\ub51d\ub51e\ub51f\ub520\ub521\ub522\ub523\ub524\ub525\ub526\ub527\ub528\ub529\ub52a\ub52b\ub52c\ub52d\ub52e\ub52f\ub530\ub531\ub532\ub533\ub534\ub535\ub536\ub537\ub538\ub539\ub53a\ub53b\ub53c\ub53d\ub53e\ub53f\ub540\ub541\ub542\ub543\ub544\ub545\ub546\ub547\ub548\ub549\ub54a\ub54b\ub54c\ub54d\ub54e\ub54f\ub550\ub551\ub552\ub553\ub554\ub555\ub556\ub557\ub558\ub559\ub55a\ub55b\ub55c\ub55d\ub55e\ub55f\ub560\ub561\ub562\ub563\ub564\ub565\ub566\ub567\ub568\ub569\ub56a\ub56b\ub56c\ub56d\ub56e\ub56f\ub570\ub571\ub572\ub573\ub574\ub575\ub576\ub577\ub578\ub579\ub57a\ub57b\ub57c\ub57d\ub57e\ub57f\ub580\ub581\ub582\ub583\ub584\ub585\ub586\ub587\ub588\ub589\ub58a\ub58b\ub58c\ub58d\ub58e\ub58f\ub590\ub591\ub592\ub593\ub594\ub595\ub596\ub597\ub598\ub599\ub59a\ub59b\ub59c\ub59d\ub59e\ub59f\ub5a0\ub5a1\ub5a2\ub5a3\ub5a4\ub5a5\ub5a6\ub5a7\ub5a8\ub5a9\ub5aa\ub5ab\ub5ac\ub5ad\ub5ae\ub5af\ub5b0\ub5b1\ub5b2\ub5b3\ub5b4\ub5b5\ub5b6\ub5b7\ub5b8\ub5b9\ub5ba\ub5bb\ub5bc\ub5bd\ub5be\ub5bf\ub5c0\ub5c1\ub5c2\ub5c3\ub5c4\ub5c5\ub5c6\ub5c7\ub5c8\ub5c9\ub5ca\ub5cb\ub5cc\ub5cd\ub5ce\ub5cf\ub5d0\ub5d1\ub5d2\ub5d3\ub5d4\ub5d5\ub5d6\ub5d7\ub5d8\ub5d9\ub5da\ub5db\ub5dc\ub5dd\ub5de\ub5df\ub5e0\ub5e1\ub5e2\ub5e3\ub5e4\ub5e5\ub5e6\ub5e7\ub5e8\ub5e9\ub5ea\ub5eb\ub5ec\ub5ed\ub5ee\ub5ef\ub5f0\ub5f1\ub5f2\ub5f3\ub5f4\ub5f5\ub5f6\ub5f7\ub5f8\ub5f9\ub5fa\ub5fb\ub5fc\ub5fd\ub5fe\ub5ff\ub600\ub601\ub602\ub603\ub604\ub605\ub606\ub607\ub608\ub609\ub60a\ub60b\ub60c\ub60d\ub60e\ub60f\ub610\ub611\ub612\ub613\ub614\ub615\ub616\ub617\ub618\ub619\ub61a\ub61b\ub61c\ub61d\ub61e\ub61f\ub620\ub621\ub622\ub623\ub624\ub625\ub626\ub627\ub628\ub629\ub62a\ub62b\ub62c\ub62d\ub62e\ub62f\ub630\ub631\ub632\ub633\ub634\ub635\ub636\ub637\ub638\ub639\ub63a\ub63b\ub63c\ub63d\ub63e\ub63f\ub640\ub641\ub642\ub643\ub644\ub645\ub646\ub647\ub648\ub649\ub64a\ub64b\ub64c\ub64d\ub64e\ub64f\ub650\ub651\ub652\ub653\ub654\ub655\ub656\ub657\ub658\ub659\ub65a\ub65b\ub65c\ub65d\ub65e\ub65f\ub660\ub661\ub662\ub663\ub664\ub665\ub666\ub667\ub668\ub669\ub66a\ub66b\ub66c\ub66d\ub66e\ub66f\ub670\ub671\ub672\ub673\ub674\ub675\ub676\ub677\ub678\ub679\ub67a\ub67b\ub67c\ub67d\ub67e\ub67f\ub680\ub681\ub682\ub683\ub684\ub685\ub686\ub687\ub688\ub689\ub68a\ub68b\ub68c\ub68d\ub68e\ub68f\ub690\ub691\ub692\ub693\ub694\ub695\ub696\ub697\ub698\ub699\ub69a\ub69b\ub69c\ub69d\ub69e\ub69f\ub6a0\ub6a1\ub6a2\ub6a3\ub6a4\ub6a5\ub6a6\ub6a7\ub6a8\ub6a9\ub6aa\ub6ab\ub6ac\ub6ad\ub6ae\ub6af\ub6b0\ub6b1\ub6b2\ub6b3\ub6b4\ub6b5\ub6b6\ub6b7\ub6b8\ub6b9\ub6ba\ub6bb\ub6bc\ub6bd\ub6be\ub6bf\ub6c0\ub6c1\ub6c2\ub6c3\ub6c4\ub6c5\ub6c6\ub6c7\ub6c8\ub6c9\ub6ca\ub6cb\ub6cc\ub6cd\ub6ce\ub6cf\ub6d0\ub6d1\ub6d2\ub6d3\ub6d4\ub6d5\ub6d6\ub6d7\ub6d8\ub6d9\ub6da\ub6db\ub6dc\ub6dd\ub6de\ub6df\ub6e0\ub6e1\ub6e2\ub6e3\ub6e4\ub6e5\ub6e6\ub6e7\ub6e8\ub6e9\ub6ea\ub6eb\ub6ec\ub6ed\ub6ee\ub6ef\ub6f0\ub6f1\ub6f2\ub6f3\ub6f4\ub6f5\ub6f6\ub6f7\ub6f8\ub6f9\ub6fa\ub6fb\ub6fc\ub6fd\ub6fe\ub6ff\ub700\ub701\ub702\ub703\ub704\ub705\ub706\ub707\ub708\ub709\ub70a\ub70b\ub70c\ub70d\ub70e\ub70f\ub710\ub711\ub712\ub713\ub714\ub715\ub716\ub717\ub718\ub719\ub71a\ub71b\ub71c\ub71d\ub71e\ub71f\ub720\ub721\ub722\ub723\ub724\ub725\ub726\ub727\ub728\ub729\ub72a\ub72b\ub72c\ub72d\ub72e\ub72f\ub730\ub731\ub732\ub733\ub734\ub735\ub736\ub737\ub738\ub739\ub73a\ub73b\ub73c\ub73d\ub73e\ub73f\ub740\ub741\ub742\ub743\ub744\ub745\ub746\ub747\ub748\ub749\ub74a\ub74b\ub74c\ub74d\ub74e\ub74f\ub750\ub751\ub752\ub753\ub754\ub755\ub756\ub757\ub758\ub759\ub75a\ub75b\ub75c\ub75d\ub75e\ub75f\ub760\ub761\ub762\ub763\ub764\ub765\ub766\ub767\ub768\ub769\ub76a\ub76b\ub76c\ub76d\ub76e\ub76f\ub770\ub771\ub772\ub773\ub774\ub775\ub776\ub777\ub778\ub779\ub77a\ub77b\ub77c\ub77d\ub77e\ub77f\ub780\ub781\ub782\ub783\ub784\ub785\ub786\ub787\ub788\ub789\ub78a\ub78b\ub78c\ub78d\ub78e\ub78f\ub790\ub791\ub792\ub793\ub794\ub795\ub796\ub797\ub798\ub799\ub79a\ub79b\ub79c\ub79d\ub79e\ub79f\ub7a0\ub7a1\ub7a2\ub7a3\ub7a4\ub7a5\ub7a6\ub7a7\ub7a8\ub7a9\ub7aa\ub7ab\ub7ac\ub7ad\ub7ae\ub7af\ub7b0\ub7b1\ub7b2\ub7b3\ub7b4\ub7b5\ub7b6\ub7b7\ub7b8\ub7b9\ub7ba\ub7bb\ub7bc\ub7bd\ub7be\ub7bf\ub7c0\ub7c1\ub7c2\ub7c3\ub7c4\ub7c5\ub7c6\ub7c7\ub7c8\ub7c9\ub7ca\ub7cb\ub7cc\ub7cd\ub7ce\ub7cf\ub7d0\ub7d1\ub7d2\ub7d3\ub7d4\ub7d5\ub7d6\ub7d7\ub7d8\ub7d9\ub7da\ub7db\ub7dc\ub7dd\ub7de\ub7df\ub7e0\ub7e1\ub7e2\ub7e3\ub7e4\ub7e5\ub7e6\ub7e7\ub7e8\ub7e9\ub7ea\ub7eb\ub7ec\ub7ed\ub7ee\ub7ef\ub7f0\ub7f1\ub7f2\ub7f3\ub7f4\ub7f5\ub7f6\ub7f7\ub7f8\ub7f9\ub7fa\ub7fb\ub7fc\ub7fd\ub7fe\ub7ff\ub800\ub801\ub802\ub803\ub804\ub805\ub806\ub807\ub808\ub809\ub80a\ub80b\ub80c\ub80d\ub80e\ub80f\ub810\ub811\ub812\ub813\ub814\ub815\ub816\ub817\ub818\ub819\ub81a\ub81b\ub81c\ub81d\ub81e\ub81f\ub820\ub821\ub822\ub823\ub824\ub825\ub826\ub827\ub828\ub829\ub82a\ub82b\ub82c\ub82d\ub82e\ub82f\ub830\ub831\ub832\ub833\ub834\ub835\ub836\ub837\ub838\ub839\ub83a\ub83b\ub83c\ub83d\ub83e\ub83f\ub840\ub841\ub842\ub843\ub844\ub845\ub846\ub847\ub848\ub849\ub84a\ub84b\ub84c\ub84d\ub84e\ub84f\ub850\ub851\ub852\ub853\ub854\ub855\ub856\ub857\ub858\ub859\ub85a\ub85b\ub85c\ub85d\ub85e\ub85f\ub860\ub861\ub862\ub863\ub864\ub865\ub866\ub867\ub868\ub869\ub86a\ub86b\ub86c\ub86d\ub86e\ub86f\ub870\ub871\ub872\ub873\ub874\ub875\ub876\ub877\ub878\ub879\ub87a\ub87b\ub87c\ub87d\ub87e\ub87f\ub880\ub881\ub882\ub883\ub884\ub885\ub886\ub887\ub888\ub889\ub88a\ub88b\ub88c\ub88d\ub88e\ub88f\ub890\ub891\ub892\ub893\ub894\ub895\ub896\ub897\ub898\ub899\ub89a\ub89b\ub89c\ub89d\ub89e\ub89f\ub8a0\ub8a1\ub8a2\ub8a3\ub8a4\ub8a5\ub8a6\ub8a7\ub8a8\ub8a9\ub8aa\ub8ab\ub8ac\ub8ad\ub8ae\ub8af\ub8b0\ub8b1\ub8b2\ub8b3\ub8b4\ub8b5\ub8b6\ub8b7\ub8b8\ub8b9\ub8ba\ub8bb\ub8bc\ub8bd\ub8be\ub8bf\ub8c0\ub8c1\ub8c2\ub8c3\ub8c4\ub8c5\ub8c6\ub8c7\ub8c8\ub8c9\ub8ca\ub8cb\ub8cc\ub8cd\ub8ce\ub8cf\ub8d0\ub8d1\ub8d2\ub8d3\ub8d4\ub8d5\ub8d6\ub8d7\ub8d8\ub8d9\ub8da\ub8db\ub8dc\ub8dd\ub8de\ub8df\ub8e0\ub8e1\ub8e2\ub8e3\ub8e4\ub8e5\ub8e6\ub8e7\ub8e8\ub8e9\ub8ea\ub8eb\ub8ec\ub8ed\ub8ee\ub8ef\ub8f0\ub8f1\ub8f2\ub8f3\ub8f4\ub8f5\ub8f6\ub8f7\ub8f8\ub8f9\ub8fa\ub8fb\ub8fc\ub8fd\ub8fe\ub8ff\ub900\ub901\ub902\ub903\ub904\ub905\ub906\ub907\ub908\ub909\ub90a\ub90b\ub90c\ub90d\ub90e\ub90f\ub910\ub911\ub912\ub913\ub914\ub915\ub916\ub917\ub918\ub919\ub91a\ub91b\ub91c\ub91d\ub91e\ub91f\ub920\ub921\ub922\ub923\ub924\ub925\ub926\ub927\ub928\ub929\ub92a\ub92b\ub92c\ub92d\ub92e\ub92f\ub930\ub931\ub932\ub933\ub934\ub935\ub936\ub937\ub938\ub939\ub93a\ub93b\ub93c\ub93d\ub93e\ub93f\ub940\ub941\ub942\ub943\ub944\ub945\ub946\ub947\ub948\ub949\ub94a\ub94b\ub94c\ub94d\ub94e\ub94f\ub950\ub951\ub952\ub953\ub954\ub955\ub956\ub957\ub958\ub959\ub95a\ub95b\ub95c\ub95d\ub95e\ub95f\ub960\ub961\ub962\ub963\ub964\ub965\ub966\ub967\ub968\ub969\ub96a\ub96b\ub96c\ub96d\ub96e\ub96f\ub970\ub971\ub972\ub973\ub974\ub975\ub976\ub977\ub978\ub979\ub97a\ub97b\ub97c\ub97d\ub97e\ub97f\ub980\ub981\ub982\ub983\ub984\ub985\ub986\ub987\ub988\ub989\ub98a\ub98b\ub98c\ub98d\ub98e\ub98f\ub990\ub991\ub992\ub993\ub994\ub995\ub996\ub997\ub998\ub999\ub99a\ub99b\ub99c\ub99d\ub99e\ub99f\ub9a0\ub9a1\ub9a2\ub9a3\ub9a4\ub9a5\ub9a6\ub9a7\ub9a8\ub9a9\ub9aa\ub9ab\ub9ac\ub9ad\ub9ae\ub9af\ub9b0\ub9b1\ub9b2\ub9b3\ub9b4\ub9b5\ub9b6\ub9b7\ub9b8\ub9b9\ub9ba\ub9bb\ub9bc\ub9bd\ub9be\ub9bf\ub9c0\ub9c1\ub9c2\ub9c3\ub9c4\ub9c5\ub9c6\ub9c7\ub9c8\ub9c9\ub9ca\ub9cb\ub9cc\ub9cd\ub9ce\ub9cf\ub9d0\ub9d1\ub9d2\ub9d3\ub9d4\ub9d5\ub9d6\ub9d7\ub9d8\ub9d9\ub9da\ub9db\ub9dc\ub9dd\ub9de\ub9df\ub9e0\ub9e1\ub9e2\ub9e3\ub9e4\ub9e5\ub9e6\ub9e7\ub9e8\ub9e9\ub9ea\ub9eb\ub9ec\ub9ed\ub9ee\ub9ef\ub9f0\ub9f1\ub9f2\ub9f3\ub9f4\ub9f5\ub9f6\ub9f7\ub9f8\ub9f9\ub9fa\ub9fb\ub9fc\ub9fd\ub9fe\ub9ff\uba00\uba01\uba02\uba03\uba04\uba05\uba06\uba07\uba08\uba09\uba0a\uba0b\uba0c\uba0d\uba0e\uba0f\uba10\uba11\uba12\uba13\uba14\uba15\uba16\uba17\uba18\uba19\uba1a\uba1b\uba1c\uba1d\uba1e\uba1f\uba20\uba21\uba22\uba23\uba24\uba25\uba26\uba27\uba28\uba29\uba2a\uba2b\uba2c\uba2d\uba2e\uba2f\uba30\uba31\uba32\uba33\uba34\uba35\uba36\uba37\uba38\uba39\uba3a\uba3b\uba3c\uba3d\uba3e\uba3f\uba40\uba41\uba42\uba43\uba44\uba45\uba46\uba47\uba48\uba49\uba4a\uba4b\uba4c\uba4d\uba4e\uba4f\uba50\uba51\uba52\uba53\uba54\uba55\uba56\uba57\uba58\uba59\uba5a\uba5b\uba5c\uba5d\uba5e\uba5f\uba60\uba61\uba62\uba63\uba64\uba65\uba66\uba67\uba68\uba69\uba6a\uba6b\uba6c\uba6d\uba6e\uba6f\uba70\uba71\uba72\uba73\uba74\uba75\uba76\uba77\uba78\uba79\uba7a\uba7b\uba7c\uba7d\uba7e\uba7f\uba80\uba81\uba82\uba83\uba84\uba85\uba86\uba87\uba88\uba89\uba8a\uba8b\uba8c\uba8d\uba8e\uba8f\uba90\uba91\uba92\uba93\uba94\uba95\uba96\uba97\uba98\uba99\uba9a\uba9b\uba9c\uba9d\uba9e\uba9f\ubaa0\ubaa1\ubaa2\ubaa3\ubaa4\ubaa5\ubaa6\ubaa7\ubaa8\ubaa9\ubaaa\ubaab\ubaac\ubaad\ubaae\ubaaf\ubab0\ubab1\ubab2\ubab3\ubab4\ubab5\ubab6\ubab7\ubab8\ubab9\ubaba\ubabb\ubabc\ubabd\ubabe\ubabf\ubac0\ubac1\ubac2\ubac3\ubac4\ubac5\ubac6\ubac7\ubac8\ubac9\ubaca\ubacb\ubacc\ubacd\ubace\ubacf\ubad0\ubad1\ubad2\ubad3\ubad4\ubad5\ubad6\ubad7\ubad8\ubad9\ubada\ubadb\ubadc\ubadd\ubade\ubadf\ubae0\ubae1\ubae2\ubae3\ubae4\ubae5\ubae6\ubae7\ubae8\ubae9\ubaea\ubaeb\ubaec\ubaed\ubaee\ubaef\ubaf0\ubaf1\ubaf2\ubaf3\ubaf4\ubaf5\ubaf6\ubaf7\ubaf8\ubaf9\ubafa\ubafb\ubafc\ubafd\ubafe\ubaff\ubb00\ubb01\ubb02\ubb03\ubb04\ubb05\ubb06\ubb07\ubb08\ubb09\ubb0a\ubb0b\ubb0c\ubb0d\ubb0e\ubb0f\ubb10\ubb11\ubb12\ubb13\ubb14\ubb15\ubb16\ubb17\ubb18\ubb19\ubb1a\ubb1b\ubb1c\ubb1d\ubb1e\ubb1f\ubb20\ubb21\ubb22\ubb23\ubb24\ubb25\ubb26\ubb27\ubb28\ubb29\ubb2a\ubb2b\ubb2c\ubb2d\ubb2e\ubb2f\ubb30\ubb31\ubb32\ubb33\ubb34\ubb35\ubb36\ubb37\ubb38\ubb39\ubb3a\ubb3b\ubb3c\ubb3d\ubb3e\ubb3f\ubb40\ubb41\ubb42\ubb43\ubb44\ubb45\ubb46\ubb47\ubb48\ubb49\ubb4a\ubb4b\ubb4c\ubb4d\ubb4e\ubb4f\ubb50\ubb51\ubb52\ubb53\ubb54\ubb55\ubb56\ubb57\ubb58\ubb59\ubb5a\ubb5b\ubb5c\ubb5d\ubb5e\ubb5f\ubb60\ubb61\ubb62\ubb63\ubb64\ubb65\ubb66\ubb67\ubb68\ubb69\ubb6a\ubb6b\ubb6c\ubb6d\ubb6e\ubb6f\ubb70\ubb71\ubb72\ubb73\ubb74\ubb75\ubb76\ubb77\ubb78\ubb79\ubb7a\ubb7b\ubb7c\ubb7d\ubb7e\ubb7f\ubb80\ubb81\ubb82\ubb83\ubb84\ubb85\ubb86\ubb87\ubb88\ubb89\ubb8a\ubb8b\ubb8c\ubb8d\ubb8e\ubb8f\ubb90\ubb91\ubb92\ubb93\ubb94\ubb95\ubb96\ubb97\ubb98\ubb99\ubb9a\ubb9b\ubb9c\ubb9d\ubb9e\ubb9f\ubba0\ubba1\ubba2\ubba3\ubba4\ubba5\ubba6\ubba7\ubba8\ubba9\ubbaa\ubbab\ubbac\ubbad\ubbae\ubbaf\ubbb0\ubbb1\ubbb2\ubbb3\ubbb4\ubbb5\ubbb6\ubbb7\ubbb8\ubbb9\ubbba\ubbbb\ubbbc\ubbbd\ubbbe\ubbbf\ubbc0\ubbc1\ubbc2\ubbc3\ubbc4\ubbc5\ubbc6\ubbc7\ubbc8\ubbc9\ubbca\ubbcb\ubbcc\ubbcd\ubbce\ubbcf\ubbd0\ubbd1\ubbd2\ubbd3\ubbd4\ubbd5\ubbd6\ubbd7\ubbd8\ubbd9\ubbda\ubbdb\ubbdc\ubbdd\ubbde\ubbdf\ubbe0\ubbe1\ubbe2\ubbe3\ubbe4\ubbe5\ubbe6\ubbe7\ubbe8\ubbe9\ubbea\ubbeb\ubbec\ubbed\ubbee\ubbef\ubbf0\ubbf1\ubbf2\ubbf3\ubbf4\ubbf5\ubbf6\ubbf7\ubbf8\ubbf9\ubbfa\ubbfb\ubbfc\ubbfd\ubbfe\ubbff\ubc00\ubc01\ubc02\ubc03\ubc04\ubc05\ubc06\ubc07\ubc08\ubc09\ubc0a\ubc0b\ubc0c\ubc0d\ubc0e\ubc0f\ubc10\ubc11\ubc12\ubc13\ubc14\ubc15\ubc16\ubc17\ubc18\ubc19\ubc1a\ubc1b\ubc1c\ubc1d\ubc1e\ubc1f\ubc20\ubc21\ubc22\ubc23\ubc24\ubc25\ubc26\ubc27\ubc28\ubc29\ubc2a\ubc2b\ubc2c\ubc2d\ubc2e\ubc2f\ubc30\ubc31\ubc32\ubc33\ubc34\ubc35\ubc36\ubc37\ubc38\ubc39\ubc3a\ubc3b\ubc3c\ubc3d\ubc3e\ubc3f\ubc40\ubc41\ubc42\ubc43\ubc44\ubc45\ubc46\ubc47\ubc48\ubc49\ubc4a\ubc4b\ubc4c\ubc4d\ubc4e\ubc4f\ubc50\ubc51\ubc52\ubc53\ubc54\ubc55\ubc56\ubc57\ubc58\ubc59\ubc5a\ubc5b\ubc5c\ubc5d\ubc5e\ubc5f\ubc60\ubc61\ubc62\ubc63\ubc64\ubc65\ubc66\ubc67\ubc68\ubc69\ubc6a\ubc6b\ubc6c\ubc6d\ubc6e\ubc6f\ubc70\ubc71\ubc72\ubc73\ubc74\ubc75\ubc76\ubc77\ubc78\ubc79\ubc7a\ubc7b\ubc7c\ubc7d\ubc7e\ubc7f\ubc80\ubc81\ubc82\ubc83\ubc84\ubc85\ubc86\ubc87\ubc88\ubc89\ubc8a\ubc8b\ubc8c\ubc8d\ubc8e\ubc8f\ubc90\ubc91\ubc92\ubc93\ubc94\ubc95\ubc96\ubc97\ubc98\ubc99\ubc9a\ubc9b\ubc9c\ubc9d\ubc9e\ubc9f\ubca0\ubca1\ubca2\ubca3\ubca4\ubca5\ubca6\ubca7\ubca8\ubca9\ubcaa\ubcab\ubcac\ubcad\ubcae\ubcaf\ubcb0\ubcb1\ubcb2\ubcb3\ubcb4\ubcb5\ubcb6\ubcb7\ubcb8\ubcb9\ubcba\ubcbb\ubcbc\ubcbd\ubcbe\ubcbf\ubcc0\ubcc1\ubcc2\ubcc3\ubcc4\ubcc5\ubcc6\ubcc7\ubcc8\ubcc9\ubcca\ubccb\ubccc\ubccd\ubcce\ubccf\ubcd0\ubcd1\ubcd2\ubcd3\ubcd4\ubcd5\ubcd6\ubcd7\ubcd8\ubcd9\ubcda\ubcdb\ubcdc\ubcdd\ubcde\ubcdf\ubce0\ubce1\ubce2\ubce3\ubce4\ubce5\ubce6\ubce7\ubce8\ubce9\ubcea\ubceb\ubcec\ubced\ubcee\ubcef\ubcf0\ubcf1\ubcf2\ubcf3\ubcf4\ubcf5\ubcf6\ubcf7\ubcf8\ubcf9\ubcfa\ubcfb\ubcfc\ubcfd\ubcfe\ubcff\ubd00\ubd01\ubd02\ubd03\ubd04\ubd05\ubd06\ubd07\ubd08\ubd09\ubd0a\ubd0b\ubd0c\ubd0d\ubd0e\ubd0f\ubd10\ubd11\ubd12\ubd13\ubd14\ubd15\ubd16\ubd17\ubd18\ubd19\ubd1a\ubd1b\ubd1c\ubd1d\ubd1e\ubd1f\ubd20\ubd21\ubd22\ubd23\ubd24\ubd25\ubd26\ubd27\ubd28\ubd29\ubd2a\ubd2b\ubd2c\ubd2d\ubd2e\ubd2f\ubd30\ubd31\ubd32\ubd33\ubd34\ubd35\ubd36\ubd37\ubd38\ubd39\ubd3a\ubd3b\ubd3c\ubd3d\ubd3e\ubd3f\ubd40\ubd41\ubd42\ubd43\ubd44\ubd45\ubd46\ubd47\ubd48\ubd49\ubd4a\ubd4b\ubd4c\ubd4d\ubd4e\ubd4f\ubd50\ubd51\ubd52\ubd53\ubd54\ubd55\ubd56\ubd57\ubd58\ubd59\ubd5a\ubd5b\ubd5c\ubd5d\ubd5e\ubd5f\ubd60\ubd61\ubd62\ubd63\ubd64\ubd65\ubd66\ubd67\ubd68\ubd69\ubd6a\ubd6b\ubd6c\ubd6d\ubd6e\ubd6f\ubd70\ubd71\ubd72\ubd73\ubd74\ubd75\ubd76\ubd77\ubd78\ubd79\ubd7a\ubd7b\ubd7c\ubd7d\ubd7e\ubd7f\ubd80\ubd81\ubd82\ubd83\ubd84\ubd85\ubd86\ubd87\ubd88\ubd89\ubd8a\ubd8b\ubd8c\ubd8d\ubd8e\ubd8f\ubd90\ubd91\ubd92\ubd93\ubd94\ubd95\ubd96\ubd97\ubd98\ubd99\ubd9a\ubd9b\ubd9c\ubd9d\ubd9e\ubd9f\ubda0\ubda1\ubda2\ubda3\ubda4\ubda5\ubda6\ubda7\ubda8\ubda9\ubdaa\ubdab\ubdac\ubdad\ubdae\ubdaf\ubdb0\ubdb1\ubdb2\ubdb3\ubdb4\ubdb5\ubdb6\ubdb7\ubdb8\ubdb9\ubdba\ubdbb\ubdbc\ubdbd\ubdbe\ubdbf\ubdc0\ubdc1\ubdc2\ubdc3\ubdc4\ubdc5\ubdc6\ubdc7\ubdc8\ubdc9\ubdca\ubdcb\ubdcc\ubdcd\ubdce\ubdcf\ubdd0\ubdd1\ubdd2\ubdd3\ubdd4\ubdd5\ubdd6\ubdd7\ubdd8\ubdd9\ubdda\ubddb\ubddc\ubddd\ubdde\ubddf\ubde0\ubde1\ubde2\ubde3\ubde4\ubde5\ubde6\ubde7\ubde8\ubde9\ubdea\ubdeb\ubdec\ubded\ubdee\ubdef\ubdf0\ubdf1\ubdf2\ubdf3\ubdf4\ubdf5\ubdf6\ubdf7\ubdf8\ubdf9\ubdfa\ubdfb\ubdfc\ubdfd\ubdfe\ubdff\ube00\ube01\ube02\ube03\ube04\ube05\ube06\ube07\ube08\ube09\ube0a\ube0b\ube0c\ube0d\ube0e\ube0f\ube10\ube11\ube12\ube13\ube14\ube15\ube16\ube17\ube18\ube19\ube1a\ube1b\ube1c\ube1d\ube1e\ube1f\ube20\ube21\ube22\ube23\ube24\ube25\ube26\ube27\ube28\ube29\ube2a\ube2b\ube2c\ube2d\ube2e\ube2f\ube30\ube31\ube32\ube33\ube34\ube35\ube36\ube37\ube38\ube39\ube3a\ube3b\ube3c\ube3d\ube3e\ube3f\ube40\ube41\ube42\ube43\ube44\ube45\ube46\ube47\ube48\ube49\ube4a\ube4b\ube4c\ube4d\ube4e\ube4f\ube50\ube51\ube52\ube53\ube54\ube55\ube56\ube57\ube58\ube59\ube5a\ube5b\ube5c\ube5d\ube5e\ube5f\ube60\ube61\ube62\ube63\ube64\ube65\ube66\ube67\ube68\ube69\ube6a\ube6b\ube6c\ube6d\ube6e\ube6f\ube70\ube71\ube72\ube73\ube74\ube75\ube76\ube77\ube78\ube79\ube7a\ube7b\ube7c\ube7d\ube7e\ube7f\ube80\ube81\ube82\ube83\ube84\ube85\ube86\ube87\ube88\ube89\ube8a\ube8b\ube8c\ube8d\ube8e\ube8f\ube90\ube91\ube92\ube93\ube94\ube95\ube96\ube97\ube98\ube99\ube9a\ube9b\ube9c\ube9d\ube9e\ube9f\ubea0\ubea1\ubea2\ubea3\ubea4\ubea5\ubea6\ubea7\ubea8\ubea9\ubeaa\ubeab\ubeac\ubead\ubeae\ubeaf\ubeb0\ubeb1\ubeb2\ubeb3\ubeb4\ubeb5\ubeb6\ubeb7\ubeb8\ubeb9\ubeba\ubebb\ubebc\ubebd\ubebe\ubebf\ubec0\ubec1\ubec2\ubec3\ubec4\ubec5\ubec6\ubec7\ubec8\ubec9\ubeca\ubecb\ubecc\ubecd\ubece\ubecf\ubed0\ubed1\ubed2\ubed3\ubed4\ubed5\ubed6\ubed7\ubed8\ubed9\ubeda\ubedb\ubedc\ubedd\ubede\ubedf\ubee0\ubee1\ubee2\ubee3\ubee4\ubee5\ubee6\ubee7\ubee8\ubee9\ubeea\ubeeb\ubeec\ubeed\ubeee\ubeef\ubef0\ubef1\ubef2\ubef3\ubef4\ubef5\ubef6\ubef7\ubef8\ubef9\ubefa\ubefb\ubefc\ubefd\ubefe\ubeff\ubf00\ubf01\ubf02\ubf03\ubf04\ubf05\ubf06\ubf07\ubf08\ubf09\ubf0a\ubf0b\ubf0c\ubf0d\ubf0e\ubf0f\ubf10\ubf11\ubf12\ubf13\ubf14\ubf15\ubf16\ubf17\ubf18\ubf19\ubf1a\ubf1b\ubf1c\ubf1d\ubf1e\ubf1f\ubf20\ubf21\ubf22\ubf23\ubf24\ubf25\ubf26\ubf27\ubf28\ubf29\ubf2a\ubf2b\ubf2c\ubf2d\ubf2e\ubf2f\ubf30\ubf31\ubf32\ubf33\ubf34\ubf35\ubf36\ubf37\ubf38\ubf39\ubf3a\ubf3b\ubf3c\ubf3d\ubf3e\ubf3f\ubf40\ubf41\ubf42\ubf43\ubf44\ubf45\ubf46\ubf47\ubf48\ubf49\ubf4a\ubf4b\ubf4c\ubf4d\ubf4e\ubf4f\ubf50\ubf51\ubf52\ubf53\ubf54\ubf55\ubf56\ubf57\ubf58\ubf59\ubf5a\ubf5b\ubf5c\ubf5d\ubf5e\ubf5f\ubf60\ubf61\ubf62\ubf63\ubf64\ubf65\ubf66\ubf67\ubf68\ubf69\ubf6a\ubf6b\ubf6c\ubf6d\ubf6e\ubf6f\ubf70\ubf71\ubf72\ubf73\ubf74\ubf75\ubf76\ubf77\ubf78\ubf79\ubf7a\ubf7b\ubf7c\ubf7d\ubf7e\ubf7f\ubf80\ubf81\ubf82\ubf83\ubf84\ubf85\ubf86\ubf87\ubf88\ubf89\ubf8a\ubf8b\ubf8c\ubf8d\ubf8e\ubf8f\ubf90\ubf91\ubf92\ubf93\ubf94\ubf95\ubf96\ubf97\ubf98\ubf99\ubf9a\ubf9b\ubf9c\ubf9d\ubf9e\ubf9f\ubfa0\ubfa1\ubfa2\ubfa3\ubfa4\ubfa5\ubfa6\ubfa7\ubfa8\ubfa9\ubfaa\ubfab\ubfac\ubfad\ubfae\ubfaf\ubfb0\ubfb1\ubfb2\ubfb3\ubfb4\ubfb5\ubfb6\ubfb7\ubfb8\ubfb9\ubfba\ubfbb\ubfbc\ubfbd\ubfbe\ubfbf\ubfc0\ubfc1\ubfc2\ubfc3\ubfc4\ubfc5\ubfc6\ubfc7\ubfc8\ubfc9\ubfca\ubfcb\ubfcc\ubfcd\ubfce\ubfcf\ubfd0\ubfd1\ubfd2\ubfd3\ubfd4\ubfd5\ubfd6\ubfd7\ubfd8\ubfd9\ubfda\ubfdb\ubfdc\ubfdd\ubfde\ubfdf\ubfe0\ubfe1\ubfe2\ubfe3\ubfe4\ubfe5\ubfe6\ubfe7\ubfe8\ubfe9\ubfea\ubfeb\ubfec\ubfed\ubfee\ubfef\ubff0\ubff1\ubff2\ubff3\ubff4\ubff5\ubff6\ubff7\ubff8\ubff9\ubffa\ubffb\ubffc\ubffd\ubffe\ubfff\uc000\uc001\uc002\uc003\uc004\uc005\uc006\uc007\uc008\uc009\uc00a\uc00b\uc00c\uc00d\uc00e\uc00f\uc010\uc011\uc012\uc013\uc014\uc015\uc016\uc017\uc018\uc019\uc01a\uc01b\uc01c\uc01d\uc01e\uc01f\uc020\uc021\uc022\uc023\uc024\uc025\uc026\uc027\uc028\uc029\uc02a\uc02b\uc02c\uc02d\uc02e\uc02f\uc030\uc031\uc032\uc033\uc034\uc035\uc036\uc037\uc038\uc039\uc03a\uc03b\uc03c\uc03d\uc03e\uc03f\uc040\uc041\uc042\uc043\uc044\uc045\uc046\uc047\uc048\uc049\uc04a\uc04b\uc04c\uc04d\uc04e\uc04f\uc050\uc051\uc052\uc053\uc054\uc055\uc056\uc057\uc058\uc059\uc05a\uc05b\uc05c\uc05d\uc05e\uc05f\uc060\uc061\uc062\uc063\uc064\uc065\uc066\uc067\uc068\uc069\uc06a\uc06b\uc06c\uc06d\uc06e\uc06f\uc070\uc071\uc072\uc073\uc074\uc075\uc076\uc077\uc078\uc079\uc07a\uc07b\uc07c\uc07d\uc07e\uc07f\uc080\uc081\uc082\uc083\uc084\uc085\uc086\uc087\uc088\uc089\uc08a\uc08b\uc08c\uc08d\uc08e\uc08f\uc090\uc091\uc092\uc093\uc094\uc095\uc096\uc097\uc098\uc099\uc09a\uc09b\uc09c\uc09d\uc09e\uc09f\uc0a0\uc0a1\uc0a2\uc0a3\uc0a4\uc0a5\uc0a6\uc0a7\uc0a8\uc0a9\uc0aa\uc0ab\uc0ac\uc0ad\uc0ae\uc0af\uc0b0\uc0b1\uc0b2\uc0b3\uc0b4\uc0b5\uc0b6\uc0b7\uc0b8\uc0b9\uc0ba\uc0bb\uc0bc\uc0bd\uc0be\uc0bf\uc0c0\uc0c1\uc0c2\uc0c3\uc0c4\uc0c5\uc0c6\uc0c7\uc0c8\uc0c9\uc0ca\uc0cb\uc0cc\uc0cd\uc0ce\uc0cf\uc0d0\uc0d1\uc0d2\uc0d3\uc0d4\uc0d5\uc0d6\uc0d7\uc0d8\uc0d9\uc0da\uc0db\uc0dc\uc0dd\uc0de\uc0df\uc0e0\uc0e1\uc0e2\uc0e3\uc0e4\uc0e5\uc0e6\uc0e7\uc0e8\uc0e9\uc0ea\uc0eb\uc0ec\uc0ed\uc0ee\uc0ef\uc0f0\uc0f1\uc0f2\uc0f3\uc0f4\uc0f5\uc0f6\uc0f7\uc0f8\uc0f9\uc0fa\uc0fb\uc0fc\uc0fd\uc0fe\uc0ff\uc100\uc101\uc102\uc103\uc104\uc105\uc106\uc107\uc108\uc109\uc10a\uc10b\uc10c\uc10d\uc10e\uc10f\uc110\uc111\uc112\uc113\uc114\uc115\uc116\uc117\uc118\uc119\uc11a\uc11b\uc11c\uc11d\uc11e\uc11f\uc120\uc121\uc122\uc123\uc124\uc125\uc126\uc127\uc128\uc129\uc12a\uc12b\uc12c\uc12d\uc12e\uc12f\uc130\uc131\uc132\uc133\uc134\uc135\uc136\uc137\uc138\uc139\uc13a\uc13b\uc13c\uc13d\uc13e\uc13f\uc140\uc141\uc142\uc143\uc144\uc145\uc146\uc147\uc148\uc149\uc14a\uc14b\uc14c\uc14d\uc14e\uc14f\uc150\uc151\uc152\uc153\uc154\uc155\uc156\uc157\uc158\uc159\uc15a\uc15b\uc15c\uc15d\uc15e\uc15f\uc160\uc161\uc162\uc163\uc164\uc165\uc166\uc167\uc168\uc169\uc16a\uc16b\uc16c\uc16d\uc16e\uc16f\uc170\uc171\uc172\uc173\uc174\uc175\uc176\uc177\uc178\uc179\uc17a\uc17b\uc17c\uc17d\uc17e\uc17f\uc180\uc181\uc182\uc183\uc184\uc185\uc186\uc187\uc188\uc189\uc18a\uc18b\uc18c\uc18d\uc18e\uc18f\uc190\uc191\uc192\uc193\uc194\uc195\uc196\uc197\uc198\uc199\uc19a\uc19b\uc19c\uc19d\uc19e\uc19f\uc1a0\uc1a1\uc1a2\uc1a3\uc1a4\uc1a5\uc1a6\uc1a7\uc1a8\uc1a9\uc1aa\uc1ab\uc1ac\uc1ad\uc1ae\uc1af\uc1b0\uc1b1\uc1b2\uc1b3\uc1b4\uc1b5\uc1b6\uc1b7\uc1b8\uc1b9\uc1ba\uc1bb\uc1bc\uc1bd\uc1be\uc1bf\uc1c0\uc1c1\uc1c2\uc1c3\uc1c4\uc1c5\uc1c6\uc1c7\uc1c8\uc1c9\uc1ca\uc1cb\uc1cc\uc1cd\uc1ce\uc1cf\uc1d0\uc1d1\uc1d2\uc1d3\uc1d4\uc1d5\uc1d6\uc1d7\uc1d8\uc1d9\uc1da\uc1db\uc1dc\uc1dd\uc1de\uc1df\uc1e0\uc1e1\uc1e2\uc1e3\uc1e4\uc1e5\uc1e6\uc1e7\uc1e8\uc1e9\uc1ea\uc1eb\uc1ec\uc1ed\uc1ee\uc1ef\uc1f0\uc1f1\uc1f2\uc1f3\uc1f4\uc1f5\uc1f6\uc1f7\uc1f8\uc1f9\uc1fa\uc1fb\uc1fc\uc1fd\uc1fe\uc1ff\uc200\uc201\uc202\uc203\uc204\uc205\uc206\uc207\uc208\uc209\uc20a\uc20b\uc20c\uc20d\uc20e\uc20f\uc210\uc211\uc212\uc213\uc214\uc215\uc216\uc217\uc218\uc219\uc21a\uc21b\uc21c\uc21d\uc21e\uc21f\uc220\uc221\uc222\uc223\uc224\uc225\uc226\uc227\uc228\uc229\uc22a\uc22b\uc22c\uc22d\uc22e\uc22f\uc230\uc231\uc232\uc233\uc234\uc235\uc236\uc237\uc238\uc239\uc23a\uc23b\uc23c\uc23d\uc23e\uc23f\uc240\uc241\uc242\uc243\uc244\uc245\uc246\uc247\uc248\uc249\uc24a\uc24b\uc24c\uc24d\uc24e\uc24f\uc250\uc251\uc252\uc253\uc254\uc255\uc256\uc257\uc258\uc259\uc25a\uc25b\uc25c\uc25d\uc25e\uc25f\uc260\uc261\uc262\uc263\uc264\uc265\uc266\uc267\uc268\uc269\uc26a\uc26b\uc26c\uc26d\uc26e\uc26f\uc270\uc271\uc272\uc273\uc274\uc275\uc276\uc277\uc278\uc279\uc27a\uc27b\uc27c\uc27d\uc27e\uc27f\uc280\uc281\uc282\uc283\uc284\uc285\uc286\uc287\uc288\uc289\uc28a\uc28b\uc28c\uc28d\uc28e\uc28f\uc290\uc291\uc292\uc293\uc294\uc295\uc296\uc297\uc298\uc299\uc29a\uc29b\uc29c\uc29d\uc29e\uc29f\uc2a0\uc2a1\uc2a2\uc2a3\uc2a4\uc2a5\uc2a6\uc2a7\uc2a8\uc2a9\uc2aa\uc2ab\uc2ac\uc2ad\uc2ae\uc2af\uc2b0\uc2b1\uc2b2\uc2b3\uc2b4\uc2b5\uc2b6\uc2b7\uc2b8\uc2b9\uc2ba\uc2bb\uc2bc\uc2bd\uc2be\uc2bf\uc2c0\uc2c1\uc2c2\uc2c3\uc2c4\uc2c5\uc2c6\uc2c7\uc2c8\uc2c9\uc2ca\uc2cb\uc2cc\uc2cd\uc2ce\uc2cf\uc2d0\uc2d1\uc2d2\uc2d3\uc2d4\uc2d5\uc2d6\uc2d7\uc2d8\uc2d9\uc2da\uc2db\uc2dc\uc2dd\uc2de\uc2df\uc2e0\uc2e1\uc2e2\uc2e3\uc2e4\uc2e5\uc2e6\uc2e7\uc2e8\uc2e9\uc2ea\uc2eb\uc2ec\uc2ed\uc2ee\uc2ef\uc2f0\uc2f1\uc2f2\uc2f3\uc2f4\uc2f5\uc2f6\uc2f7\uc2f8\uc2f9\uc2fa\uc2fb\uc2fc\uc2fd\uc2fe\uc2ff\uc300\uc301\uc302\uc303\uc304\uc305\uc306\uc307\uc308\uc309\uc30a\uc30b\uc30c\uc30d\uc30e\uc30f\uc310\uc311\uc312\uc313\uc314\uc315\uc316\uc317\uc318\uc319\uc31a\uc31b\uc31c\uc31d\uc31e\uc31f\uc320\uc321\uc322\uc323\uc324\uc325\uc326\uc327\uc328\uc329\uc32a\uc32b\uc32c\uc32d\uc32e\uc32f\uc330\uc331\uc332\uc333\uc334\uc335\uc336\uc337\uc338\uc339\uc33a\uc33b\uc33c\uc33d\uc33e\uc33f\uc340\uc341\uc342\uc343\uc344\uc345\uc346\uc347\uc348\uc349\uc34a\uc34b\uc34c\uc34d\uc34e\uc34f\uc350\uc351\uc352\uc353\uc354\uc355\uc356\uc357\uc358\uc359\uc35a\uc35b\uc35c\uc35d\uc35e\uc35f\uc360\uc361\uc362\uc363\uc364\uc365\uc366\uc367\uc368\uc369\uc36a\uc36b\uc36c\uc36d\uc36e\uc36f\uc370\uc371\uc372\uc373\uc374\uc375\uc376\uc377\uc378\uc379\uc37a\uc37b\uc37c\uc37d\uc37e\uc37f\uc380\uc381\uc382\uc383\uc384\uc385\uc386\uc387\uc388\uc389\uc38a\uc38b\uc38c\uc38d\uc38e\uc38f\uc390\uc391\uc392\uc393\uc394\uc395\uc396\uc397\uc398\uc399\uc39a\uc39b\uc39c\uc39d\uc39e\uc39f\uc3a0\uc3a1\uc3a2\uc3a3\uc3a4\uc3a5\uc3a6\uc3a7\uc3a8\uc3a9\uc3aa\uc3ab\uc3ac\uc3ad\uc3ae\uc3af\uc3b0\uc3b1\uc3b2\uc3b3\uc3b4\uc3b5\uc3b6\uc3b7\uc3b8\uc3b9\uc3ba\uc3bb\uc3bc\uc3bd\uc3be\uc3bf\uc3c0\uc3c1\uc3c2\uc3c3\uc3c4\uc3c5\uc3c6\uc3c7\uc3c8\uc3c9\uc3ca\uc3cb\uc3cc\uc3cd\uc3ce\uc3cf\uc3d0\uc3d1\uc3d2\uc3d3\uc3d4\uc3d5\uc3d6\uc3d7\uc3d8\uc3d9\uc3da\uc3db\uc3dc\uc3dd\uc3de\uc3df\uc3e0\uc3e1\uc3e2\uc3e3\uc3e4\uc3e5\uc3e6\uc3e7\uc3e8\uc3e9\uc3ea\uc3eb\uc3ec\uc3ed\uc3ee\uc3ef\uc3f0\uc3f1\uc3f2\uc3f3\uc3f4\uc3f5\uc3f6\uc3f7\uc3f8\uc3f9\uc3fa\uc3fb\uc3fc\uc3fd\uc3fe\uc3ff\uc400\uc401\uc402\uc403\uc404\uc405\uc406\uc407\uc408\uc409\uc40a\uc40b\uc40c\uc40d\uc40e\uc40f\uc410\uc411\uc412\uc413\uc414\uc415\uc416\uc417\uc418\uc419\uc41a\uc41b\uc41c\uc41d\uc41e\uc41f\uc420\uc421\uc422\uc423\uc424\uc425\uc426\uc427\uc428\uc429\uc42a\uc42b\uc42c\uc42d\uc42e\uc42f\uc430\uc431\uc432\uc433\uc434\uc435\uc436\uc437\uc438\uc439\uc43a\uc43b\uc43c\uc43d\uc43e\uc43f\uc440\uc441\uc442\uc443\uc444\uc445\uc446\uc447\uc448\uc449\uc44a\uc44b\uc44c\uc44d\uc44e\uc44f\uc450\uc451\uc452\uc453\uc454\uc455\uc456\uc457\uc458\uc459\uc45a\uc45b\uc45c\uc45d\uc45e\uc45f\uc460\uc461\uc462\uc463\uc464\uc465\uc466\uc467\uc468\uc469\uc46a\uc46b\uc46c\uc46d\uc46e\uc46f\uc470\uc471\uc472\uc473\uc474\uc475\uc476\uc477\uc478\uc479\uc47a\uc47b\uc47c\uc47d\uc47e\uc47f\uc480\uc481\uc482\uc483\uc484\uc485\uc486\uc487\uc488\uc489\uc48a\uc48b\uc48c\uc48d\uc48e\uc48f\uc490\uc491\uc492\uc493\uc494\uc495\uc496\uc497\uc498\uc499\uc49a\uc49b\uc49c\uc49d\uc49e\uc49f\uc4a0\uc4a1\uc4a2\uc4a3\uc4a4\uc4a5\uc4a6\uc4a7\uc4a8\uc4a9\uc4aa\uc4ab\uc4ac\uc4ad\uc4ae\uc4af\uc4b0\uc4b1\uc4b2\uc4b3\uc4b4\uc4b5\uc4b6\uc4b7\uc4b8\uc4b9\uc4ba\uc4bb\uc4bc\uc4bd\uc4be\uc4bf\uc4c0\uc4c1\uc4c2\uc4c3\uc4c4\uc4c5\uc4c6\uc4c7\uc4c8\uc4c9\uc4ca\uc4cb\uc4cc\uc4cd\uc4ce\uc4cf\uc4d0\uc4d1\uc4d2\uc4d3\uc4d4\uc4d5\uc4d6\uc4d7\uc4d8\uc4d9\uc4da\uc4db\uc4dc\uc4dd\uc4de\uc4df\uc4e0\uc4e1\uc4e2\uc4e3\uc4e4\uc4e5\uc4e6\uc4e7\uc4e8\uc4e9\uc4ea\uc4eb\uc4ec\uc4ed\uc4ee\uc4ef\uc4f0\uc4f1\uc4f2\uc4f3\uc4f4\uc4f5\uc4f6\uc4f7\uc4f8\uc4f9\uc4fa\uc4fb\uc4fc\uc4fd\uc4fe\uc4ff\uc500\uc501\uc502\uc503\uc504\uc505\uc506\uc507\uc508\uc509\uc50a\uc50b\uc50c\uc50d\uc50e\uc50f\uc510\uc511\uc512\uc513\uc514\uc515\uc516\uc517\uc518\uc519\uc51a\uc51b\uc51c\uc51d\uc51e\uc51f\uc520\uc521\uc522\uc523\uc524\uc525\uc526\uc527\uc528\uc529\uc52a\uc52b\uc52c\uc52d\uc52e\uc52f\uc530\uc531\uc532\uc533\uc534\uc535\uc536\uc537\uc538\uc539\uc53a\uc53b\uc53c\uc53d\uc53e\uc53f\uc540\uc541\uc542\uc543\uc544\uc545\uc546\uc547\uc548\uc549\uc54a\uc54b\uc54c\uc54d\uc54e\uc54f\uc550\uc551\uc552\uc553\uc554\uc555\uc556\uc557\uc558\uc559\uc55a\uc55b\uc55c\uc55d\uc55e\uc55f\uc560\uc561\uc562\uc563\uc564\uc565\uc566\uc567\uc568\uc569\uc56a\uc56b\uc56c\uc56d\uc56e\uc56f\uc570\uc571\uc572\uc573\uc574\uc575\uc576\uc577\uc578\uc579\uc57a\uc57b\uc57c\uc57d\uc57e\uc57f\uc580\uc581\uc582\uc583\uc584\uc585\uc586\uc587\uc588\uc589\uc58a\uc58b\uc58c\uc58d\uc58e\uc58f\uc590\uc591\uc592\uc593\uc594\uc595\uc596\uc597\uc598\uc599\uc59a\uc59b\uc59c\uc59d\uc59e\uc59f\uc5a0\uc5a1\uc5a2\uc5a3\uc5a4\uc5a5\uc5a6\uc5a7\uc5a8\uc5a9\uc5aa\uc5ab\uc5ac\uc5ad\uc5ae\uc5af\uc5b0\uc5b1\uc5b2\uc5b3\uc5b4\uc5b5\uc5b6\uc5b7\uc5b8\uc5b9\uc5ba\uc5bb\uc5bc\uc5bd\uc5be\uc5bf\uc5c0\uc5c1\uc5c2\uc5c3\uc5c4\uc5c5\uc5c6\uc5c7\uc5c8\uc5c9\uc5ca\uc5cb\uc5cc\uc5cd\uc5ce\uc5cf\uc5d0\uc5d1\uc5d2\uc5d3\uc5d4\uc5d5\uc5d6\uc5d7\uc5d8\uc5d9\uc5da\uc5db\uc5dc\uc5dd\uc5de\uc5df\uc5e0\uc5e1\uc5e2\uc5e3\uc5e4\uc5e5\uc5e6\uc5e7\uc5e8\uc5e9\uc5ea\uc5eb\uc5ec\uc5ed\uc5ee\uc5ef\uc5f0\uc5f1\uc5f2\uc5f3\uc5f4\uc5f5\uc5f6\uc5f7\uc5f8\uc5f9\uc5fa\uc5fb\uc5fc\uc5fd\uc5fe\uc5ff\uc600\uc601\uc602\uc603\uc604\uc605\uc606\uc607\uc608\uc609\uc60a\uc60b\uc60c\uc60d\uc60e\uc60f\uc610\uc611\uc612\uc613\uc614\uc615\uc616\uc617\uc618\uc619\uc61a\uc61b\uc61c\uc61d\uc61e\uc61f\uc620\uc621\uc622\uc623\uc624\uc625\uc626\uc627\uc628\uc629\uc62a\uc62b\uc62c\uc62d\uc62e\uc62f\uc630\uc631\uc632\uc633\uc634\uc635\uc636\uc637\uc638\uc639\uc63a\uc63b\uc63c\uc63d\uc63e\uc63f\uc640\uc641\uc642\uc643\uc644\uc645\uc646\uc647\uc648\uc649\uc64a\uc64b\uc64c\uc64d\uc64e\uc64f\uc650\uc651\uc652\uc653\uc654\uc655\uc656\uc657\uc658\uc659\uc65a\uc65b\uc65c\uc65d\uc65e\uc65f\uc660\uc661\uc662\uc663\uc664\uc665\uc666\uc667\uc668\uc669\uc66a\uc66b\uc66c\uc66d\uc66e\uc66f\uc670\uc671\uc672\uc673\uc674\uc675\uc676\uc677\uc678\uc679\uc67a\uc67b\uc67c\uc67d\uc67e\uc67f\uc680\uc681\uc682\uc683\uc684\uc685\uc686\uc687\uc688\uc689\uc68a\uc68b\uc68c\uc68d\uc68e\uc68f\uc690\uc691\uc692\uc693\uc694\uc695\uc696\uc697\uc698\uc699\uc69a\uc69b\uc69c\uc69d\uc69e\uc69f\uc6a0\uc6a1\uc6a2\uc6a3\uc6a4\uc6a5\uc6a6\uc6a7\uc6a8\uc6a9\uc6aa\uc6ab\uc6ac\uc6ad\uc6ae\uc6af\uc6b0\uc6b1\uc6b2\uc6b3\uc6b4\uc6b5\uc6b6\uc6b7\uc6b8\uc6b9\uc6ba\uc6bb\uc6bc\uc6bd\uc6be\uc6bf\uc6c0\uc6c1\uc6c2\uc6c3\uc6c4\uc6c5\uc6c6\uc6c7\uc6c8\uc6c9\uc6ca\uc6cb\uc6cc\uc6cd\uc6ce\uc6cf\uc6d0\uc6d1\uc6d2\uc6d3\uc6d4\uc6d5\uc6d6\uc6d7\uc6d8\uc6d9\uc6da\uc6db\uc6dc\uc6dd\uc6de\uc6df\uc6e0\uc6e1\uc6e2\uc6e3\uc6e4\uc6e5\uc6e6\uc6e7\uc6e8\uc6e9\uc6ea\uc6eb\uc6ec\uc6ed\uc6ee\uc6ef\uc6f0\uc6f1\uc6f2\uc6f3\uc6f4\uc6f5\uc6f6\uc6f7\uc6f8\uc6f9\uc6fa\uc6fb\uc6fc\uc6fd\uc6fe\uc6ff\uc700\uc701\uc702\uc703\uc704\uc705\uc706\uc707\uc708\uc709\uc70a\uc70b\uc70c\uc70d\uc70e\uc70f\uc710\uc711\uc712\uc713\uc714\uc715\uc716\uc717\uc718\uc719\uc71a\uc71b\uc71c\uc71d\uc71e\uc71f\uc720\uc721\uc722\uc723\uc724\uc725\uc726\uc727\uc728\uc729\uc72a\uc72b\uc72c\uc72d\uc72e\uc72f\uc730\uc731\uc732\uc733\uc734\uc735\uc736\uc737\uc738\uc739\uc73a\uc73b\uc73c\uc73d\uc73e\uc73f\uc740\uc741\uc742\uc743\uc744\uc745\uc746\uc747\uc748\uc749\uc74a\uc74b\uc74c\uc74d\uc74e\uc74f\uc750\uc751\uc752\uc753\uc754\uc755\uc756\uc757\uc758\uc759\uc75a\uc75b\uc75c\uc75d\uc75e\uc75f\uc760\uc761\uc762\uc763\uc764\uc765\uc766\uc767\uc768\uc769\uc76a\uc76b\uc76c\uc76d\uc76e\uc76f\uc770\uc771\uc772\uc773\uc774\uc775\uc776\uc777\uc778\uc779\uc77a\uc77b\uc77c\uc77d\uc77e\uc77f\uc780\uc781\uc782\uc783\uc784\uc785\uc786\uc787\uc788\uc789\uc78a\uc78b\uc78c\uc78d\uc78e\uc78f\uc790\uc791\uc792\uc793\uc794\uc795\uc796\uc797\uc798\uc799\uc79a\uc79b\uc79c\uc79d\uc79e\uc79f\uc7a0\uc7a1\uc7a2\uc7a3\uc7a4\uc7a5\uc7a6\uc7a7\uc7a8\uc7a9\uc7aa\uc7ab\uc7ac\uc7ad\uc7ae\uc7af\uc7b0\uc7b1\uc7b2\uc7b3\uc7b4\uc7b5\uc7b6\uc7b7\uc7b8\uc7b9\uc7ba\uc7bb\uc7bc\uc7bd\uc7be\uc7bf\uc7c0\uc7c1\uc7c2\uc7c3\uc7c4\uc7c5\uc7c6\uc7c7\uc7c8\uc7c9\uc7ca\uc7cb\uc7cc\uc7cd\uc7ce\uc7cf\uc7d0\uc7d1\uc7d2\uc7d3\uc7d4\uc7d5\uc7d6\uc7d7\uc7d8\uc7d9\uc7da\uc7db\uc7dc\uc7dd\uc7de\uc7df\uc7e0\uc7e1\uc7e2\uc7e3\uc7e4\uc7e5\uc7e6\uc7e7\uc7e8\uc7e9\uc7ea\uc7eb\uc7ec\uc7ed\uc7ee\uc7ef\uc7f0\uc7f1\uc7f2\uc7f3\uc7f4\uc7f5\uc7f6\uc7f7\uc7f8\uc7f9\uc7fa\uc7fb\uc7fc\uc7fd\uc7fe\uc7ff\uc800\uc801\uc802\uc803\uc804\uc805\uc806\uc807\uc808\uc809\uc80a\uc80b\uc80c\uc80d\uc80e\uc80f\uc810\uc811\uc812\uc813\uc814\uc815\uc816\uc817\uc818\uc819\uc81a\uc81b\uc81c\uc81d\uc81e\uc81f\uc820\uc821\uc822\uc823\uc824\uc825\uc826\uc827\uc828\uc829\uc82a\uc82b\uc82c\uc82d\uc82e\uc82f\uc830\uc831\uc832\uc833\uc834\uc835\uc836\uc837\uc838\uc839\uc83a\uc83b\uc83c\uc83d\uc83e\uc83f\uc840\uc841\uc842\uc843\uc844\uc845\uc846\uc847\uc848\uc849\uc84a\uc84b\uc84c\uc84d\uc84e\uc84f\uc850\uc851\uc852\uc853\uc854\uc855\uc856\uc857\uc858\uc859\uc85a\uc85b\uc85c\uc85d\uc85e\uc85f\uc860\uc861\uc862\uc863\uc864\uc865\uc866\uc867\uc868\uc869\uc86a\uc86b\uc86c\uc86d\uc86e\uc86f\uc870\uc871\uc872\uc873\uc874\uc875\uc876\uc877\uc878\uc879\uc87a\uc87b\uc87c\uc87d\uc87e\uc87f\uc880\uc881\uc882\uc883\uc884\uc885\uc886\uc887\uc888\uc889\uc88a\uc88b\uc88c\uc88d\uc88e\uc88f\uc890\uc891\uc892\uc893\uc894\uc895\uc896\uc897\uc898\uc899\uc89a\uc89b\uc89c\uc89d\uc89e\uc89f\uc8a0\uc8a1\uc8a2\uc8a3\uc8a4\uc8a5\uc8a6\uc8a7\uc8a8\uc8a9\uc8aa\uc8ab\uc8ac\uc8ad\uc8ae\uc8af\uc8b0\uc8b1\uc8b2\uc8b3\uc8b4\uc8b5\uc8b6\uc8b7\uc8b8\uc8b9\uc8ba\uc8bb\uc8bc\uc8bd\uc8be\uc8bf\uc8c0\uc8c1\uc8c2\uc8c3\uc8c4\uc8c5\uc8c6\uc8c7\uc8c8\uc8c9\uc8ca\uc8cb\uc8cc\uc8cd\uc8ce\uc8cf\uc8d0\uc8d1\uc8d2\uc8d3\uc8d4\uc8d5\uc8d6\uc8d7\uc8d8\uc8d9\uc8da\uc8db\uc8dc\uc8dd\uc8de\uc8df\uc8e0\uc8e1\uc8e2\uc8e3\uc8e4\uc8e5\uc8e6\uc8e7\uc8e8\uc8e9\uc8ea\uc8eb\uc8ec\uc8ed\uc8ee\uc8ef\uc8f0\uc8f1\uc8f2\uc8f3\uc8f4\uc8f5\uc8f6\uc8f7\uc8f8\uc8f9\uc8fa\uc8fb\uc8fc\uc8fd\uc8fe\uc8ff\uc900\uc901\uc902\uc903\uc904\uc905\uc906\uc907\uc908\uc909\uc90a\uc90b\uc90c\uc90d\uc90e\uc90f\uc910\uc911\uc912\uc913\uc914\uc915\uc916\uc917\uc918\uc919\uc91a\uc91b\uc91c\uc91d\uc91e\uc91f\uc920\uc921\uc922\uc923\uc924\uc925\uc926\uc927\uc928\uc929\uc92a\uc92b\uc92c\uc92d\uc92e\uc92f\uc930\uc931\uc932\uc933\uc934\uc935\uc936\uc937\uc938\uc939\uc93a\uc93b\uc93c\uc93d\uc93e\uc93f\uc940\uc941\uc942\uc943\uc944\uc945\uc946\uc947\uc948\uc949\uc94a\uc94b\uc94c\uc94d\uc94e\uc94f\uc950\uc951\uc952\uc953\uc954\uc955\uc956\uc957\uc958\uc959\uc95a\uc95b\uc95c\uc95d\uc95e\uc95f\uc960\uc961\uc962\uc963\uc964\uc965\uc966\uc967\uc968\uc969\uc96a\uc96b\uc96c\uc96d\uc96e\uc96f\uc970\uc971\uc972\uc973\uc974\uc975\uc976\uc977\uc978\uc979\uc97a\uc97b\uc97c\uc97d\uc97e\uc97f\uc980\uc981\uc982\uc983\uc984\uc985\uc986\uc987\uc988\uc989\uc98a\uc98b\uc98c\uc98d\uc98e\uc98f\uc990\uc991\uc992\uc993\uc994\uc995\uc996\uc997\uc998\uc999\uc99a\uc99b\uc99c\uc99d\uc99e\uc99f\uc9a0\uc9a1\uc9a2\uc9a3\uc9a4\uc9a5\uc9a6\uc9a7\uc9a8\uc9a9\uc9aa\uc9ab\uc9ac\uc9ad\uc9ae\uc9af\uc9b0\uc9b1\uc9b2\uc9b3\uc9b4\uc9b5\uc9b6\uc9b7\uc9b8\uc9b9\uc9ba\uc9bb\uc9bc\uc9bd\uc9be\uc9bf\uc9c0\uc9c1\uc9c2\uc9c3\uc9c4\uc9c5\uc9c6\uc9c7\uc9c8\uc9c9\uc9ca\uc9cb\uc9cc\uc9cd\uc9ce\uc9cf\uc9d0\uc9d1\uc9d2\uc9d3\uc9d4\uc9d5\uc9d6\uc9d7\uc9d8\uc9d9\uc9da\uc9db\uc9dc\uc9dd\uc9de\uc9df\uc9e0\uc9e1\uc9e2\uc9e3\uc9e4\uc9e5\uc9e6\uc9e7\uc9e8\uc9e9\uc9ea\uc9eb\uc9ec\uc9ed\uc9ee\uc9ef\uc9f0\uc9f1\uc9f2\uc9f3\uc9f4\uc9f5\uc9f6\uc9f7\uc9f8\uc9f9\uc9fa\uc9fb\uc9fc\uc9fd\uc9fe\uc9ff\uca00\uca01\uca02\uca03\uca04\uca05\uca06\uca07\uca08\uca09\uca0a\uca0b\uca0c\uca0d\uca0e\uca0f\uca10\uca11\uca12\uca13\uca14\uca15\uca16\uca17\uca18\uca19\uca1a\uca1b\uca1c\uca1d\uca1e\uca1f\uca20\uca21\uca22\uca23\uca24\uca25\uca26\uca27\uca28\uca29\uca2a\uca2b\uca2c\uca2d\uca2e\uca2f\uca30\uca31\uca32\uca33\uca34\uca35\uca36\uca37\uca38\uca39\uca3a\uca3b\uca3c\uca3d\uca3e\uca3f\uca40\uca41\uca42\uca43\uca44\uca45\uca46\uca47\uca48\uca49\uca4a\uca4b\uca4c\uca4d\uca4e\uca4f\uca50\uca51\uca52\uca53\uca54\uca55\uca56\uca57\uca58\uca59\uca5a\uca5b\uca5c\uca5d\uca5e\uca5f\uca60\uca61\uca62\uca63\uca64\uca65\uca66\uca67\uca68\uca69\uca6a\uca6b\uca6c\uca6d\uca6e\uca6f\uca70\uca71\uca72\uca73\uca74\uca75\uca76\uca77\uca78\uca79\uca7a\uca7b\uca7c\uca7d\uca7e\uca7f\uca80\uca81\uca82\uca83\uca84\uca85\uca86\uca87\uca88\uca89\uca8a\uca8b\uca8c\uca8d\uca8e\uca8f\uca90\uca91\uca92\uca93\uca94\uca95\uca96\uca97\uca98\uca99\uca9a\uca9b\uca9c\uca9d\uca9e\uca9f\ucaa0\ucaa1\ucaa2\ucaa3\ucaa4\ucaa5\ucaa6\ucaa7\ucaa8\ucaa9\ucaaa\ucaab\ucaac\ucaad\ucaae\ucaaf\ucab0\ucab1\ucab2\ucab3\ucab4\ucab5\ucab6\ucab7\ucab8\ucab9\ucaba\ucabb\ucabc\ucabd\ucabe\ucabf\ucac0\ucac1\ucac2\ucac3\ucac4\ucac5\ucac6\ucac7\ucac8\ucac9\ucaca\ucacb\ucacc\ucacd\ucace\ucacf\ucad0\ucad1\ucad2\ucad3\ucad4\ucad5\ucad6\ucad7\ucad8\ucad9\ucada\ucadb\ucadc\ucadd\ucade\ucadf\ucae0\ucae1\ucae2\ucae3\ucae4\ucae5\ucae6\ucae7\ucae8\ucae9\ucaea\ucaeb\ucaec\ucaed\ucaee\ucaef\ucaf0\ucaf1\ucaf2\ucaf3\ucaf4\ucaf5\ucaf6\ucaf7\ucaf8\ucaf9\ucafa\ucafb\ucafc\ucafd\ucafe\ucaff\ucb00\ucb01\ucb02\ucb03\ucb04\ucb05\ucb06\ucb07\ucb08\ucb09\ucb0a\ucb0b\ucb0c\ucb0d\ucb0e\ucb0f\ucb10\ucb11\ucb12\ucb13\ucb14\ucb15\ucb16\ucb17\ucb18\ucb19\ucb1a\ucb1b\ucb1c\ucb1d\ucb1e\ucb1f\ucb20\ucb21\ucb22\ucb23\ucb24\ucb25\ucb26\ucb27\ucb28\ucb29\ucb2a\ucb2b\ucb2c\ucb2d\ucb2e\ucb2f\ucb30\ucb31\ucb32\ucb33\ucb34\ucb35\ucb36\ucb37\ucb38\ucb39\ucb3a\ucb3b\ucb3c\ucb3d\ucb3e\ucb3f\ucb40\ucb41\ucb42\ucb43\ucb44\ucb45\ucb46\ucb47\ucb48\ucb49\ucb4a\ucb4b\ucb4c\ucb4d\ucb4e\ucb4f\ucb50\ucb51\ucb52\ucb53\ucb54\ucb55\ucb56\ucb57\ucb58\ucb59\ucb5a\ucb5b\ucb5c\ucb5d\ucb5e\ucb5f\ucb60\ucb61\ucb62\ucb63\ucb64\ucb65\ucb66\ucb67\ucb68\ucb69\ucb6a\ucb6b\ucb6c\ucb6d\ucb6e\ucb6f\ucb70\ucb71\ucb72\ucb73\ucb74\ucb75\ucb76\ucb77\ucb78\ucb79\ucb7a\ucb7b\ucb7c\ucb7d\ucb7e\ucb7f\ucb80\ucb81\ucb82\ucb83\ucb84\ucb85\ucb86\ucb87\ucb88\ucb89\ucb8a\ucb8b\ucb8c\ucb8d\ucb8e\ucb8f\ucb90\ucb91\ucb92\ucb93\ucb94\ucb95\ucb96\ucb97\ucb98\ucb99\ucb9a\ucb9b\ucb9c\ucb9d\ucb9e\ucb9f\ucba0\ucba1\ucba2\ucba3\ucba4\ucba5\ucba6\ucba7\ucba8\ucba9\ucbaa\ucbab\ucbac\ucbad\ucbae\ucbaf\ucbb0\ucbb1\ucbb2\ucbb3\ucbb4\ucbb5\ucbb6\ucbb7\ucbb8\ucbb9\ucbba\ucbbb\ucbbc\ucbbd\ucbbe\ucbbf\ucbc0\ucbc1\ucbc2\ucbc3\ucbc4\ucbc5\ucbc6\ucbc7\ucbc8\ucbc9\ucbca\ucbcb\ucbcc\ucbcd\ucbce\ucbcf\ucbd0\ucbd1\ucbd2\ucbd3\ucbd4\ucbd5\ucbd6\ucbd7\ucbd8\ucbd9\ucbda\ucbdb\ucbdc\ucbdd\ucbde\ucbdf\ucbe0\ucbe1\ucbe2\ucbe3\ucbe4\ucbe5\ucbe6\ucbe7\ucbe8\ucbe9\ucbea\ucbeb\ucbec\ucbed\ucbee\ucbef\ucbf0\ucbf1\ucbf2\ucbf3\ucbf4\ucbf5\ucbf6\ucbf7\ucbf8\ucbf9\ucbfa\ucbfb\ucbfc\ucbfd\ucbfe\ucbff\ucc00\ucc01\ucc02\ucc03\ucc04\ucc05\ucc06\ucc07\ucc08\ucc09\ucc0a\ucc0b\ucc0c\ucc0d\ucc0e\ucc0f\ucc10\ucc11\ucc12\ucc13\ucc14\ucc15\ucc16\ucc17\ucc18\ucc19\ucc1a\ucc1b\ucc1c\ucc1d\ucc1e\ucc1f\ucc20\ucc21\ucc22\ucc23\ucc24\ucc25\ucc26\ucc27\ucc28\ucc29\ucc2a\ucc2b\ucc2c\ucc2d\ucc2e\ucc2f\ucc30\ucc31\ucc32\ucc33\ucc34\ucc35\ucc36\ucc37\ucc38\ucc39\ucc3a\ucc3b\ucc3c\ucc3d\ucc3e\ucc3f\ucc40\ucc41\ucc42\ucc43\ucc44\ucc45\ucc46\ucc47\ucc48\ucc49\ucc4a\ucc4b\ucc4c\ucc4d\ucc4e\ucc4f\ucc50\ucc51\ucc52\ucc53\ucc54\ucc55\ucc56\ucc57\ucc58\ucc59\ucc5a\ucc5b\ucc5c\ucc5d\ucc5e\ucc5f\ucc60\ucc61\ucc62\ucc63\ucc64\ucc65\ucc66\ucc67\ucc68\ucc69\ucc6a\ucc6b\ucc6c\ucc6d\ucc6e\ucc6f\ucc70\ucc71\ucc72\ucc73\ucc74\ucc75\ucc76\ucc77\ucc78\ucc79\ucc7a\ucc7b\ucc7c\ucc7d\ucc7e\ucc7f\ucc80\ucc81\ucc82\ucc83\ucc84\ucc85\ucc86\ucc87\ucc88\ucc89\ucc8a\ucc8b\ucc8c\ucc8d\ucc8e\ucc8f\ucc90\ucc91\ucc92\ucc93\ucc94\ucc95\ucc96\ucc97\ucc98\ucc99\ucc9a\ucc9b\ucc9c\ucc9d\ucc9e\ucc9f\ucca0\ucca1\ucca2\ucca3\ucca4\ucca5\ucca6\ucca7\ucca8\ucca9\uccaa\uccab\uccac\uccad\uccae\uccaf\uccb0\uccb1\uccb2\uccb3\uccb4\uccb5\uccb6\uccb7\uccb8\uccb9\uccba\uccbb\uccbc\uccbd\uccbe\uccbf\uccc0\uccc1\uccc2\uccc3\uccc4\uccc5\uccc6\uccc7\uccc8\uccc9\uccca\ucccb\ucccc\ucccd\uccce\ucccf\uccd0\uccd1\uccd2\uccd3\uccd4\uccd5\uccd6\uccd7\uccd8\uccd9\uccda\uccdb\uccdc\uccdd\uccde\uccdf\ucce0\ucce1\ucce2\ucce3\ucce4\ucce5\ucce6\ucce7\ucce8\ucce9\uccea\ucceb\uccec\ucced\uccee\uccef\uccf0\uccf1\uccf2\uccf3\uccf4\uccf5\uccf6\uccf7\uccf8\uccf9\uccfa\uccfb\uccfc\uccfd\uccfe\uccff\ucd00\ucd01\ucd02\ucd03\ucd04\ucd05\ucd06\ucd07\ucd08\ucd09\ucd0a\ucd0b\ucd0c\ucd0d\ucd0e\ucd0f\ucd10\ucd11\ucd12\ucd13\ucd14\ucd15\ucd16\ucd17\ucd18\ucd19\ucd1a\ucd1b\ucd1c\ucd1d\ucd1e\ucd1f\ucd20\ucd21\ucd22\ucd23\ucd24\ucd25\ucd26\ucd27\ucd28\ucd29\ucd2a\ucd2b\ucd2c\ucd2d\ucd2e\ucd2f\ucd30\ucd31\ucd32\ucd33\ucd34\ucd35\ucd36\ucd37\ucd38\ucd39\ucd3a\ucd3b\ucd3c\ucd3d\ucd3e\ucd3f\ucd40\ucd41\ucd42\ucd43\ucd44\ucd45\ucd46\ucd47\ucd48\ucd49\ucd4a\ucd4b\ucd4c\ucd4d\ucd4e\ucd4f\ucd50\ucd51\ucd52\ucd53\ucd54\ucd55\ucd56\ucd57\ucd58\ucd59\ucd5a\ucd5b\ucd5c\ucd5d\ucd5e\ucd5f\ucd60\ucd61\ucd62\ucd63\ucd64\ucd65\ucd66\ucd67\ucd68\ucd69\ucd6a\ucd6b\ucd6c\ucd6d\ucd6e\ucd6f\ucd70\ucd71\ucd72\ucd73\ucd74\ucd75\ucd76\ucd77\ucd78\ucd79\ucd7a\ucd7b\ucd7c\ucd7d\ucd7e\ucd7f\ucd80\ucd81\ucd82\ucd83\ucd84\ucd85\ucd86\ucd87\ucd88\ucd89\ucd8a\ucd8b\ucd8c\ucd8d\ucd8e\ucd8f\ucd90\ucd91\ucd92\ucd93\ucd94\ucd95\ucd96\ucd97\ucd98\ucd99\ucd9a\ucd9b\ucd9c\ucd9d\ucd9e\ucd9f\ucda0\ucda1\ucda2\ucda3\ucda4\ucda5\ucda6\ucda7\ucda8\ucda9\ucdaa\ucdab\ucdac\ucdad\ucdae\ucdaf\ucdb0\ucdb1\ucdb2\ucdb3\ucdb4\ucdb5\ucdb6\ucdb7\ucdb8\ucdb9\ucdba\ucdbb\ucdbc\ucdbd\ucdbe\ucdbf\ucdc0\ucdc1\ucdc2\ucdc3\ucdc4\ucdc5\ucdc6\ucdc7\ucdc8\ucdc9\ucdca\ucdcb\ucdcc\ucdcd\ucdce\ucdcf\ucdd0\ucdd1\ucdd2\ucdd3\ucdd4\ucdd5\ucdd6\ucdd7\ucdd8\ucdd9\ucdda\ucddb\ucddc\ucddd\ucdde\ucddf\ucde0\ucde1\ucde2\ucde3\ucde4\ucde5\ucde6\ucde7\ucde8\ucde9\ucdea\ucdeb\ucdec\ucded\ucdee\ucdef\ucdf0\ucdf1\ucdf2\ucdf3\ucdf4\ucdf5\ucdf6\ucdf7\ucdf8\ucdf9\ucdfa\ucdfb\ucdfc\ucdfd\ucdfe\ucdff\uce00\uce01\uce02\uce03\uce04\uce05\uce06\uce07\uce08\uce09\uce0a\uce0b\uce0c\uce0d\uce0e\uce0f\uce10\uce11\uce12\uce13\uce14\uce15\uce16\uce17\uce18\uce19\uce1a\uce1b\uce1c\uce1d\uce1e\uce1f\uce20\uce21\uce22\uce23\uce24\uce25\uce26\uce27\uce28\uce29\uce2a\uce2b\uce2c\uce2d\uce2e\uce2f\uce30\uce31\uce32\uce33\uce34\uce35\uce36\uce37\uce38\uce39\uce3a\uce3b\uce3c\uce3d\uce3e\uce3f\uce40\uce41\uce42\uce43\uce44\uce45\uce46\uce47\uce48\uce49\uce4a\uce4b\uce4c\uce4d\uce4e\uce4f\uce50\uce51\uce52\uce53\uce54\uce55\uce56\uce57\uce58\uce59\uce5a\uce5b\uce5c\uce5d\uce5e\uce5f\uce60\uce61\uce62\uce63\uce64\uce65\uce66\uce67\uce68\uce69\uce6a\uce6b\uce6c\uce6d\uce6e\uce6f\uce70\uce71\uce72\uce73\uce74\uce75\uce76\uce77\uce78\uce79\uce7a\uce7b\uce7c\uce7d\uce7e\uce7f\uce80\uce81\uce82\uce83\uce84\uce85\uce86\uce87\uce88\uce89\uce8a\uce8b\uce8c\uce8d\uce8e\uce8f\uce90\uce91\uce92\uce93\uce94\uce95\uce96\uce97\uce98\uce99\uce9a\uce9b\uce9c\uce9d\uce9e\uce9f\ucea0\ucea1\ucea2\ucea3\ucea4\ucea5\ucea6\ucea7\ucea8\ucea9\uceaa\uceab\uceac\ucead\uceae\uceaf\uceb0\uceb1\uceb2\uceb3\uceb4\uceb5\uceb6\uceb7\uceb8\uceb9\uceba\ucebb\ucebc\ucebd\ucebe\ucebf\ucec0\ucec1\ucec2\ucec3\ucec4\ucec5\ucec6\ucec7\ucec8\ucec9\uceca\ucecb\ucecc\ucecd\ucece\ucecf\uced0\uced1\uced2\uced3\uced4\uced5\uced6\uced7\uced8\uced9\uceda\ucedb\ucedc\ucedd\ucede\ucedf\ucee0\ucee1\ucee2\ucee3\ucee4\ucee5\ucee6\ucee7\ucee8\ucee9\uceea\uceeb\uceec\uceed\uceee\uceef\ucef0\ucef1\ucef2\ucef3\ucef4\ucef5\ucef6\ucef7\ucef8\ucef9\ucefa\ucefb\ucefc\ucefd\ucefe\uceff\ucf00\ucf01\ucf02\ucf03\ucf04\ucf05\ucf06\ucf07\ucf08\ucf09\ucf0a\ucf0b\ucf0c\ucf0d\ucf0e\ucf0f\ucf10\ucf11\ucf12\ucf13\ucf14\ucf15\ucf16\ucf17\ucf18\ucf19\ucf1a\ucf1b\ucf1c\ucf1d\ucf1e\ucf1f\ucf20\ucf21\ucf22\ucf23\ucf24\ucf25\ucf26\ucf27\ucf28\ucf29\ucf2a\ucf2b\ucf2c\ucf2d\ucf2e\ucf2f\ucf30\ucf31\ucf32\ucf33\ucf34\ucf35\ucf36\ucf37\ucf38\ucf39\ucf3a\ucf3b\ucf3c\ucf3d\ucf3e\ucf3f\ucf40\ucf41\ucf42\ucf43\ucf44\ucf45\ucf46\ucf47\ucf48\ucf49\ucf4a\ucf4b\ucf4c\ucf4d\ucf4e\ucf4f\ucf50\ucf51\ucf52\ucf53\ucf54\ucf55\ucf56\ucf57\ucf58\ucf59\ucf5a\ucf5b\ucf5c\ucf5d\ucf5e\ucf5f\ucf60\ucf61\ucf62\ucf63\ucf64\ucf65\ucf66\ucf67\ucf68\ucf69\ucf6a\ucf6b\ucf6c\ucf6d\ucf6e\ucf6f\ucf70\ucf71\ucf72\ucf73\ucf74\ucf75\ucf76\ucf77\ucf78\ucf79\ucf7a\ucf7b\ucf7c\ucf7d\ucf7e\ucf7f\ucf80\ucf81\ucf82\ucf83\ucf84\ucf85\ucf86\ucf87\ucf88\ucf89\ucf8a\ucf8b\ucf8c\ucf8d\ucf8e\ucf8f\ucf90\ucf91\ucf92\ucf93\ucf94\ucf95\ucf96\ucf97\ucf98\ucf99\ucf9a\ucf9b\ucf9c\ucf9d\ucf9e\ucf9f\ucfa0\ucfa1\ucfa2\ucfa3\ucfa4\ucfa5\ucfa6\ucfa7\ucfa8\ucfa9\ucfaa\ucfab\ucfac\ucfad\ucfae\ucfaf\ucfb0\ucfb1\ucfb2\ucfb3\ucfb4\ucfb5\ucfb6\ucfb7\ucfb8\ucfb9\ucfba\ucfbb\ucfbc\ucfbd\ucfbe\ucfbf\ucfc0\ucfc1\ucfc2\ucfc3\ucfc4\ucfc5\ucfc6\ucfc7\ucfc8\ucfc9\ucfca\ucfcb\ucfcc\ucfcd\ucfce\ucfcf\ucfd0\ucfd1\ucfd2\ucfd3\ucfd4\ucfd5\ucfd6\ucfd7\ucfd8\ucfd9\ucfda\ucfdb\ucfdc\ucfdd\ucfde\ucfdf\ucfe0\ucfe1\ucfe2\ucfe3\ucfe4\ucfe5\ucfe6\ucfe7\ucfe8\ucfe9\ucfea\ucfeb\ucfec\ucfed\ucfee\ucfef\ucff0\ucff1\ucff2\ucff3\ucff4\ucff5\ucff6\ucff7\ucff8\ucff9\ucffa\ucffb\ucffc\ucffd\ucffe\ucfff\ud000\ud001\ud002\ud003\ud004\ud005\ud006\ud007\ud008\ud009\ud00a\ud00b\ud00c\ud00d\ud00e\ud00f\ud010\ud011\ud012\ud013\ud014\ud015\ud016\ud017\ud018\ud019\ud01a\ud01b\ud01c\ud01d\ud01e\ud01f\ud020\ud021\ud022\ud023\ud024\ud025\ud026\ud027\ud028\ud029\ud02a\ud02b\ud02c\ud02d\ud02e\ud02f\ud030\ud031\ud032\ud033\ud034\ud035\ud036\ud037\ud038\ud039\ud03a\ud03b\ud03c\ud03d\ud03e\ud03f\ud040\ud041\ud042\ud043\ud044\ud045\ud046\ud047\ud048\ud049\ud04a\ud04b\ud04c\ud04d\ud04e\ud04f\ud050\ud051\ud052\ud053\ud054\ud055\ud056\ud057\ud058\ud059\ud05a\ud05b\ud05c\ud05d\ud05e\ud05f\ud060\ud061\ud062\ud063\ud064\ud065\ud066\ud067\ud068\ud069\ud06a\ud06b\ud06c\ud06d\ud06e\ud06f\ud070\ud071\ud072\ud073\ud074\ud075\ud076\ud077\ud078\ud079\ud07a\ud07b\ud07c\ud07d\ud07e\ud07f\ud080\ud081\ud082\ud083\ud084\ud085\ud086\ud087\ud088\ud089\ud08a\ud08b\ud08c\ud08d\ud08e\ud08f\ud090\ud091\ud092\ud093\ud094\ud095\ud096\ud097\ud098\ud099\ud09a\ud09b\ud09c\ud09d\ud09e\ud09f\ud0a0\ud0a1\ud0a2\ud0a3\ud0a4\ud0a5\ud0a6\ud0a7\ud0a8\ud0a9\ud0aa\ud0ab\ud0ac\ud0ad\ud0ae\ud0af\ud0b0\ud0b1\ud0b2\ud0b3\ud0b4\ud0b5\ud0b6\ud0b7\ud0b8\ud0b9\ud0ba\ud0bb\ud0bc\ud0bd\ud0be\ud0bf\ud0c0\ud0c1\ud0c2\ud0c3\ud0c4\ud0c5\ud0c6\ud0c7\ud0c8\ud0c9\ud0ca\ud0cb\ud0cc\ud0cd\ud0ce\ud0cf\ud0d0\ud0d1\ud0d2\ud0d3\ud0d4\ud0d5\ud0d6\ud0d7\ud0d8\ud0d9\ud0da\ud0db\ud0dc\ud0dd\ud0de\ud0df\ud0e0\ud0e1\ud0e2\ud0e3\ud0e4\ud0e5\ud0e6\ud0e7\ud0e8\ud0e9\ud0ea\ud0eb\ud0ec\ud0ed\ud0ee\ud0ef\ud0f0\ud0f1\ud0f2\ud0f3\ud0f4\ud0f5\ud0f6\ud0f7\ud0f8\ud0f9\ud0fa\ud0fb\ud0fc\ud0fd\ud0fe\ud0ff\ud100\ud101\ud102\ud103\ud104\ud105\ud106\ud107\ud108\ud109\ud10a\ud10b\ud10c\ud10d\ud10e\ud10f\ud110\ud111\ud112\ud113\ud114\ud115\ud116\ud117\ud118\ud119\ud11a\ud11b\ud11c\ud11d\ud11e\ud11f\ud120\ud121\ud122\ud123\ud124\ud125\ud126\ud127\ud128\ud129\ud12a\ud12b\ud12c\ud12d\ud12e\ud12f\ud130\ud131\ud132\ud133\ud134\ud135\ud136\ud137\ud138\ud139\ud13a\ud13b\ud13c\ud13d\ud13e\ud13f\ud140\ud141\ud142\ud143\ud144\ud145\ud146\ud147\ud148\ud149\ud14a\ud14b\ud14c\ud14d\ud14e\ud14f\ud150\ud151\ud152\ud153\ud154\ud155\ud156\ud157\ud158\ud159\ud15a\ud15b\ud15c\ud15d\ud15e\ud15f\ud160\ud161\ud162\ud163\ud164\ud165\ud166\ud167\ud168\ud169\ud16a\ud16b\ud16c\ud16d\ud16e\ud16f\ud170\ud171\ud172\ud173\ud174\ud175\ud176\ud177\ud178\ud179\ud17a\ud17b\ud17c\ud17d\ud17e\ud17f\ud180\ud181\ud182\ud183\ud184\ud185\ud186\ud187\ud188\ud189\ud18a\ud18b\ud18c\ud18d\ud18e\ud18f\ud190\ud191\ud192\ud193\ud194\ud195\ud196\ud197\ud198\ud199\ud19a\ud19b\ud19c\ud19d\ud19e\ud19f\ud1a0\ud1a1\ud1a2\ud1a3\ud1a4\ud1a5\ud1a6\ud1a7\ud1a8\ud1a9\ud1aa\ud1ab\ud1ac\ud1ad\ud1ae\ud1af\ud1b0\ud1b1\ud1b2\ud1b3\ud1b4\ud1b5\ud1b6\ud1b7\ud1b8\ud1b9\ud1ba\ud1bb\ud1bc\ud1bd\ud1be\ud1bf\ud1c0\ud1c1\ud1c2\ud1c3\ud1c4\ud1c5\ud1c6\ud1c7\ud1c8\ud1c9\ud1ca\ud1cb\ud1cc\ud1cd\ud1ce\ud1cf\ud1d0\ud1d1\ud1d2\ud1d3\ud1d4\ud1d5\ud1d6\ud1d7\ud1d8\ud1d9\ud1da\ud1db\ud1dc\ud1dd\ud1de\ud1df\ud1e0\ud1e1\ud1e2\ud1e3\ud1e4\ud1e5\ud1e6\ud1e7\ud1e8\ud1e9\ud1ea\ud1eb\ud1ec\ud1ed\ud1ee\ud1ef\ud1f0\ud1f1\ud1f2\ud1f3\ud1f4\ud1f5\ud1f6\ud1f7\ud1f8\ud1f9\ud1fa\ud1fb\ud1fc\ud1fd\ud1fe\ud1ff\ud200\ud201\ud202\ud203\ud204\ud205\ud206\ud207\ud208\ud209\ud20a\ud20b\ud20c\ud20d\ud20e\ud20f\ud210\ud211\ud212\ud213\ud214\ud215\ud216\ud217\ud218\ud219\ud21a\ud21b\ud21c\ud21d\ud21e\ud21f\ud220\ud221\ud222\ud223\ud224\ud225\ud226\ud227\ud228\ud229\ud22a\ud22b\ud22c\ud22d\ud22e\ud22f\ud230\ud231\ud232\ud233\ud234\ud235\ud236\ud237\ud238\ud239\ud23a\ud23b\ud23c\ud23d\ud23e\ud23f\ud240\ud241\ud242\ud243\ud244\ud245\ud246\ud247\ud248\ud249\ud24a\ud24b\ud24c\ud24d\ud24e\ud24f\ud250\ud251\ud252\ud253\ud254\ud255\ud256\ud257\ud258\ud259\ud25a\ud25b\ud25c\ud25d\ud25e\ud25f\ud260\ud261\ud262\ud263\ud264\ud265\ud266\ud267\ud268\ud269\ud26a\ud26b\ud26c\ud26d\ud26e\ud26f\ud270\ud271\ud272\ud273\ud274\ud275\ud276\ud277\ud278\ud279\ud27a\ud27b\ud27c\ud27d\ud27e\ud27f\ud280\ud281\ud282\ud283\ud284\ud285\ud286\ud287\ud288\ud289\ud28a\ud28b\ud28c\ud28d\ud28e\ud28f\ud290\ud291\ud292\ud293\ud294\ud295\ud296\ud297\ud298\ud299\ud29a\ud29b\ud29c\ud29d\ud29e\ud29f\ud2a0\ud2a1\ud2a2\ud2a3\ud2a4\ud2a5\ud2a6\ud2a7\ud2a8\ud2a9\ud2aa\ud2ab\ud2ac\ud2ad\ud2ae\ud2af\ud2b0\ud2b1\ud2b2\ud2b3\ud2b4\ud2b5\ud2b6\ud2b7\ud2b8\ud2b9\ud2ba\ud2bb\ud2bc\ud2bd\ud2be\ud2bf\ud2c0\ud2c1\ud2c2\ud2c3\ud2c4\ud2c5\ud2c6\ud2c7\ud2c8\ud2c9\ud2ca\ud2cb\ud2cc\ud2cd\ud2ce\ud2cf\ud2d0\ud2d1\ud2d2\ud2d3\ud2d4\ud2d5\ud2d6\ud2d7\ud2d8\ud2d9\ud2da\ud2db\ud2dc\ud2dd\ud2de\ud2df\ud2e0\ud2e1\ud2e2\ud2e3\ud2e4\ud2e5\ud2e6\ud2e7\ud2e8\ud2e9\ud2ea\ud2eb\ud2ec\ud2ed\ud2ee\ud2ef\ud2f0\ud2f1\ud2f2\ud2f3\ud2f4\ud2f5\ud2f6\ud2f7\ud2f8\ud2f9\ud2fa\ud2fb\ud2fc\ud2fd\ud2fe\ud2ff\ud300\ud301\ud302\ud303\ud304\ud305\ud306\ud307\ud308\ud309\ud30a\ud30b\ud30c\ud30d\ud30e\ud30f\ud310\ud311\ud312\ud313\ud314\ud315\ud316\ud317\ud318\ud319\ud31a\ud31b\ud31c\ud31d\ud31e\ud31f\ud320\ud321\ud322\ud323\ud324\ud325\ud326\ud327\ud328\ud329\ud32a\ud32b\ud32c\ud32d\ud32e\ud32f\ud330\ud331\ud332\ud333\ud334\ud335\ud336\ud337\ud338\ud339\ud33a\ud33b\ud33c\ud33d\ud33e\ud33f\ud340\ud341\ud342\ud343\ud344\ud345\ud346\ud347\ud348\ud349\ud34a\ud34b\ud34c\ud34d\ud34e\ud34f\ud350\ud351\ud352\ud353\ud354\ud355\ud356\ud357\ud358\ud359\ud35a\ud35b\ud35c\ud35d\ud35e\ud35f\ud360\ud361\ud362\ud363\ud364\ud365\ud366\ud367\ud368\ud369\ud36a\ud36b\ud36c\ud36d\ud36e\ud36f\ud370\ud371\ud372\ud373\ud374\ud375\ud376\ud377\ud378\ud379\ud37a\ud37b\ud37c\ud37d\ud37e\ud37f\ud380\ud381\ud382\ud383\ud384\ud385\ud386\ud387\ud388\ud389\ud38a\ud38b\ud38c\ud38d\ud38e\ud38f\ud390\ud391\ud392\ud393\ud394\ud395\ud396\ud397\ud398\ud399\ud39a\ud39b\ud39c\ud39d\ud39e\ud39f\ud3a0\ud3a1\ud3a2\ud3a3\ud3a4\ud3a5\ud3a6\ud3a7\ud3a8\ud3a9\ud3aa\ud3ab\ud3ac\ud3ad\ud3ae\ud3af\ud3b0\ud3b1\ud3b2\ud3b3\ud3b4\ud3b5\ud3b6\ud3b7\ud3b8\ud3b9\ud3ba\ud3bb\ud3bc\ud3bd\ud3be\ud3bf\ud3c0\ud3c1\ud3c2\ud3c3\ud3c4\ud3c5\ud3c6\ud3c7\ud3c8\ud3c9\ud3ca\ud3cb\ud3cc\ud3cd\ud3ce\ud3cf\ud3d0\ud3d1\ud3d2\ud3d3\ud3d4\ud3d5\ud3d6\ud3d7\ud3d8\ud3d9\ud3da\ud3db\ud3dc\ud3dd\ud3de\ud3df\ud3e0\ud3e1\ud3e2\ud3e3\ud3e4\ud3e5\ud3e6\ud3e7\ud3e8\ud3e9\ud3ea\ud3eb\ud3ec\ud3ed\ud3ee\ud3ef\ud3f0\ud3f1\ud3f2\ud3f3\ud3f4\ud3f5\ud3f6\ud3f7\ud3f8\ud3f9\ud3fa\ud3fb\ud3fc\ud3fd\ud3fe\ud3ff\ud400\ud401\ud402\ud403\ud404\ud405\ud406\ud407\ud408\ud409\ud40a\ud40b\ud40c\ud40d\ud40e\ud40f\ud410\ud411\ud412\ud413\ud414\ud415\ud416\ud417\ud418\ud419\ud41a\ud41b\ud41c\ud41d\ud41e\ud41f\ud420\ud421\ud422\ud423\ud424\ud425\ud426\ud427\ud428\ud429\ud42a\ud42b\ud42c\ud42d\ud42e\ud42f\ud430\ud431\ud432\ud433\ud434\ud435\ud436\ud437\ud438\ud439\ud43a\ud43b\ud43c\ud43d\ud43e\ud43f\ud440\ud441\ud442\ud443\ud444\ud445\ud446\ud447\ud448\ud449\ud44a\ud44b\ud44c\ud44d\ud44e\ud44f\ud450\ud451\ud452\ud453\ud454\ud455\ud456\ud457\ud458\ud459\ud45a\ud45b\ud45c\ud45d\ud45e\ud45f\ud460\ud461\ud462\ud463\ud464\ud465\ud466\ud467\ud468\ud469\ud46a\ud46b\ud46c\ud46d\ud46e\ud46f\ud470\ud471\ud472\ud473\ud474\ud475\ud476\ud477\ud478\ud479\ud47a\ud47b\ud47c\ud47d\ud47e\ud47f\ud480\ud481\ud482\ud483\ud484\ud485\ud486\ud487\ud488\ud489\ud48a\ud48b\ud48c\ud48d\ud48e\ud48f\ud490\ud491\ud492\ud493\ud494\ud495\ud496\ud497\ud498\ud499\ud49a\ud49b\ud49c\ud49d\ud49e\ud49f\ud4a0\ud4a1\ud4a2\ud4a3\ud4a4\ud4a5\ud4a6\ud4a7\ud4a8\ud4a9\ud4aa\ud4ab\ud4ac\ud4ad\ud4ae\ud4af\ud4b0\ud4b1\ud4b2\ud4b3\ud4b4\ud4b5\ud4b6\ud4b7\ud4b8\ud4b9\ud4ba\ud4bb\ud4bc\ud4bd\ud4be\ud4bf\ud4c0\ud4c1\ud4c2\ud4c3\ud4c4\ud4c5\ud4c6\ud4c7\ud4c8\ud4c9\ud4ca\ud4cb\ud4cc\ud4cd\ud4ce\ud4cf\ud4d0\ud4d1\ud4d2\ud4d3\ud4d4\ud4d5\ud4d6\ud4d7\ud4d8\ud4d9\ud4da\ud4db\ud4dc\ud4dd\ud4de\ud4df\ud4e0\ud4e1\ud4e2\ud4e3\ud4e4\ud4e5\ud4e6\ud4e7\ud4e8\ud4e9\ud4ea\ud4eb\ud4ec\ud4ed\ud4ee\ud4ef\ud4f0\ud4f1\ud4f2\ud4f3\ud4f4\ud4f5\ud4f6\ud4f7\ud4f8\ud4f9\ud4fa\ud4fb\ud4fc\ud4fd\ud4fe\ud4ff\ud500\ud501\ud502\ud503\ud504\ud505\ud506\ud507\ud508\ud509\ud50a\ud50b\ud50c\ud50d\ud50e\ud50f\ud510\ud511\ud512\ud513\ud514\ud515\ud516\ud517\ud518\ud519\ud51a\ud51b\ud51c\ud51d\ud51e\ud51f\ud520\ud521\ud522\ud523\ud524\ud525\ud526\ud527\ud528\ud529\ud52a\ud52b\ud52c\ud52d\ud52e\ud52f\ud530\ud531\ud532\ud533\ud534\ud535\ud536\ud537\ud538\ud539\ud53a\ud53b\ud53c\ud53d\ud53e\ud53f\ud540\ud541\ud542\ud543\ud544\ud545\ud546\ud547\ud548\ud549\ud54a\ud54b\ud54c\ud54d\ud54e\ud54f\ud550\ud551\ud552\ud553\ud554\ud555\ud556\ud557\ud558\ud559\ud55a\ud55b\ud55c\ud55d\ud55e\ud55f\ud560\ud561\ud562\ud563\ud564\ud565\ud566\ud567\ud568\ud569\ud56a\ud56b\ud56c\ud56d\ud56e\ud56f\ud570\ud571\ud572\ud573\ud574\ud575\ud576\ud577\ud578\ud579\ud57a\ud57b\ud57c\ud57d\ud57e\ud57f\ud580\ud581\ud582\ud583\ud584\ud585\ud586\ud587\ud588\ud589\ud58a\ud58b\ud58c\ud58d\ud58e\ud58f\ud590\ud591\ud592\ud593\ud594\ud595\ud596\ud597\ud598\ud599\ud59a\ud59b\ud59c\ud59d\ud59e\ud59f\ud5a0\ud5a1\ud5a2\ud5a3\ud5a4\ud5a5\ud5a6\ud5a7\ud5a8\ud5a9\ud5aa\ud5ab\ud5ac\ud5ad\ud5ae\ud5af\ud5b0\ud5b1\ud5b2\ud5b3\ud5b4\ud5b5\ud5b6\ud5b7\ud5b8\ud5b9\ud5ba\ud5bb\ud5bc\ud5bd\ud5be\ud5bf\ud5c0\ud5c1\ud5c2\ud5c3\ud5c4\ud5c5\ud5c6\ud5c7\ud5c8\ud5c9\ud5ca\ud5cb\ud5cc\ud5cd\ud5ce\ud5cf\ud5d0\ud5d1\ud5d2\ud5d3\ud5d4\ud5d5\ud5d6\ud5d7\ud5d8\ud5d9\ud5da\ud5db\ud5dc\ud5dd\ud5de\ud5df\ud5e0\ud5e1\ud5e2\ud5e3\ud5e4\ud5e5\ud5e6\ud5e7\ud5e8\ud5e9\ud5ea\ud5eb\ud5ec\ud5ed\ud5ee\ud5ef\ud5f0\ud5f1\ud5f2\ud5f3\ud5f4\ud5f5\ud5f6\ud5f7\ud5f8\ud5f9\ud5fa\ud5fb\ud5fc\ud5fd\ud5fe\ud5ff\ud600\ud601\ud602\ud603\ud604\ud605\ud606\ud607\ud608\ud609\ud60a\ud60b\ud60c\ud60d\ud60e\ud60f\ud610\ud611\ud612\ud613\ud614\ud615\ud616\ud617\ud618\ud619\ud61a\ud61b\ud61c\ud61d\ud61e\ud61f\ud620\ud621\ud622\ud623\ud624\ud625\ud626\ud627\ud628\ud629\ud62a\ud62b\ud62c\ud62d\ud62e\ud62f\ud630\ud631\ud632\ud633\ud634\ud635\ud636\ud637\ud638\ud639\ud63a\ud63b\ud63c\ud63d\ud63e\ud63f\ud640\ud641\ud642\ud643\ud644\ud645\ud646\ud647\ud648\ud649\ud64a\ud64b\ud64c\ud64d\ud64e\ud64f\ud650\ud651\ud652\ud653\ud654\ud655\ud656\ud657\ud658\ud659\ud65a\ud65b\ud65c\ud65d\ud65e\ud65f\ud660\ud661\ud662\ud663\ud664\ud665\ud666\ud667\ud668\ud669\ud66a\ud66b\ud66c\ud66d\ud66e\ud66f\ud670\ud671\ud672\ud673\ud674\ud675\ud676\ud677\ud678\ud679\ud67a\ud67b\ud67c\ud67d\ud67e\ud67f\ud680\ud681\ud682\ud683\ud684\ud685\ud686\ud687\ud688\ud689\ud68a\ud68b\ud68c\ud68d\ud68e\ud68f\ud690\ud691\ud692\ud693\ud694\ud695\ud696\ud697\ud698\ud699\ud69a\ud69b\ud69c\ud69d\ud69e\ud69f\ud6a0\ud6a1\ud6a2\ud6a3\ud6a4\ud6a5\ud6a6\ud6a7\ud6a8\ud6a9\ud6aa\ud6ab\ud6ac\ud6ad\ud6ae\ud6af\ud6b0\ud6b1\ud6b2\ud6b3\ud6b4\ud6b5\ud6b6\ud6b7\ud6b8\ud6b9\ud6ba\ud6bb\ud6bc\ud6bd\ud6be\ud6bf\ud6c0\ud6c1\ud6c2\ud6c3\ud6c4\ud6c5\ud6c6\ud6c7\ud6c8\ud6c9\ud6ca\ud6cb\ud6cc\ud6cd\ud6ce\ud6cf\ud6d0\ud6d1\ud6d2\ud6d3\ud6d4\ud6d5\ud6d6\ud6d7\ud6d8\ud6d9\ud6da\ud6db\ud6dc\ud6dd\ud6de\ud6df\ud6e0\ud6e1\ud6e2\ud6e3\ud6e4\ud6e5\ud6e6\ud6e7\ud6e8\ud6e9\ud6ea\ud6eb\ud6ec\ud6ed\ud6ee\ud6ef\ud6f0\ud6f1\ud6f2\ud6f3\ud6f4\ud6f5\ud6f6\ud6f7\ud6f8\ud6f9\ud6fa\ud6fb\ud6fc\ud6fd\ud6fe\ud6ff\ud700\ud701\ud702\ud703\ud704\ud705\ud706\ud707\ud708\ud709\ud70a\ud70b\ud70c\ud70d\ud70e\ud70f\ud710\ud711\ud712\ud713\ud714\ud715\ud716\ud717\ud718\ud719\ud71a\ud71b\ud71c\ud71d\ud71e\ud71f\ud720\ud721\ud722\ud723\ud724\ud725\ud726\ud727\ud728\ud729\ud72a\ud72b\ud72c\ud72d\ud72e\ud72f\ud730\ud731\ud732\ud733\ud734\ud735\ud736\ud737\ud738\ud739\ud73a\ud73b\ud73c\ud73d\ud73e\ud73f\ud740\ud741\ud742\ud743\ud744\ud745\ud746\ud747\ud748\ud749\ud74a\ud74b\ud74c\ud74d\ud74e\ud74f\ud750\ud751\ud752\ud753\ud754\ud755\ud756\ud757\ud758\ud759\ud75a\ud75b\ud75c\ud75d\ud75e\ud75f\ud760\ud761\ud762\ud763\ud764\ud765\ud766\ud767\ud768\ud769\ud76a\ud76b\ud76c\ud76d\ud76e\ud76f\ud770\ud771\ud772\ud773\ud774\ud775\ud776\ud777\ud778\ud779\ud77a\ud77b\ud77c\ud77d\ud77e\ud77f\ud780\ud781\ud782\ud783\ud784\ud785\ud786\ud787\ud788\ud789\ud78a\ud78b\ud78c\ud78d\ud78e\ud78f\ud790\ud791\ud792\ud793\ud794\ud795\ud796\ud797\ud798\ud799\ud79a\ud79b\ud79c\ud79d\ud79e\ud79f\ud7a0\ud7a1\ud7a2\ud7a3\ud7b0\ud7b1\ud7b2\ud7b3\ud7b4\ud7b5\ud7b6\ud7b7\ud7b8\ud7b9\ud7ba\ud7bb\ud7bc\ud7bd\ud7be\ud7bf\ud7c0\ud7c1\ud7c2\ud7c3\ud7c4\ud7c5\ud7c6\ud7cb\ud7cc\ud7cd\ud7ce\ud7cf\ud7d0\ud7d1\ud7d2\ud7d3\ud7d4\ud7d5\ud7d6\ud7d7\ud7d8\ud7d9\ud7da\ud7db\ud7dc\ud7dd\ud7de\ud7df\ud7e0\ud7e1\ud7e2\ud7e3\ud7e4\ud7e5\ud7e6\ud7e7\ud7e8\ud7e9\ud7ea\ud7eb\ud7ec\ud7ed\ud7ee\ud7ef\ud7f0\ud7f1\ud7f2\ud7f3\ud7f4\ud7f5\ud7f6\ud7f7\ud7f8\ud7f9\ud7fa\ud7fb\uf900\uf901\uf902\uf903\uf904\uf905\uf906\uf907\uf908\uf909\uf90a\uf90b\uf90c\uf90d\uf90e\uf90f\uf910\uf911\uf912\uf913\uf914\uf915\uf916\uf917\uf918\uf919\uf91a\uf91b\uf91c\uf91d\uf91e\uf91f\uf920\uf921\uf922\uf923\uf924\uf925\uf926\uf927\uf928\uf929\uf92a\uf92b\uf92c\uf92d\uf92e\uf92f\uf930\uf931\uf932\uf933\uf934\uf935\uf936\uf937\uf938\uf939\uf93a\uf93b\uf93c\uf93d\uf93e\uf93f\uf940\uf941\uf942\uf943\uf944\uf945\uf946\uf947\uf948\uf949\uf94a\uf94b\uf94c\uf94d\uf94e\uf94f\uf950\uf951\uf952\uf953\uf954\uf955\uf956\uf957\uf958\uf959\uf95a\uf95b\uf95c\uf95d\uf95e\uf95f\uf960\uf961\uf962\uf963\uf964\uf965\uf966\uf967\uf968\uf969\uf96a\uf96b\uf96c\uf96d\uf96e\uf96f\uf970\uf971\uf972\uf973\uf974\uf975\uf976\uf977\uf978\uf979\uf97a\uf97b\uf97c\uf97d\uf97e\uf97f\uf980\uf981\uf982\uf983\uf984\uf985\uf986\uf987\uf988\uf989\uf98a\uf98b\uf98c\uf98d\uf98e\uf98f\uf990\uf991\uf992\uf993\uf994\uf995\uf996\uf997\uf998\uf999\uf99a\uf99b\uf99c\uf99d\uf99e\uf99f\uf9a0\uf9a1\uf9a2\uf9a3\uf9a4\uf9a5\uf9a6\uf9a7\uf9a8\uf9a9\uf9aa\uf9ab\uf9ac\uf9ad\uf9ae\uf9af\uf9b0\uf9b1\uf9b2\uf9b3\uf9b4\uf9b5\uf9b6\uf9b7\uf9b8\uf9b9\uf9ba\uf9bb\uf9bc\uf9bd\uf9be\uf9bf\uf9c0\uf9c1\uf9c2\uf9c3\uf9c4\uf9c5\uf9c6\uf9c7\uf9c8\uf9c9\uf9ca\uf9cb\uf9cc\uf9cd\uf9ce\uf9cf\uf9d0\uf9d1\uf9d2\uf9d3\uf9d4\uf9d5\uf9d6\uf9d7\uf9d8\uf9d9\uf9da\uf9db\uf9dc\uf9dd\uf9de\uf9df\uf9e0\uf9e1\uf9e2\uf9e3\uf9e4\uf9e5\uf9e6\uf9e7\uf9e8\uf9e9\uf9ea\uf9eb\uf9ec\uf9ed\uf9ee\uf9ef\uf9f0\uf9f1\uf9f2\uf9f3\uf9f4\uf9f5\uf9f6\uf9f7\uf9f8\uf9f9\uf9fa\uf9fb\uf9fc\uf9fd\uf9fe\uf9ff\ufa00\ufa01\ufa02\ufa03\ufa04\ufa05\ufa06\ufa07\ufa08\ufa09\ufa0a\ufa0b\ufa0c\ufa0d\ufa0e\ufa0f\ufa10\ufa11\ufa12\ufa13\ufa14\ufa15\ufa16\ufa17\ufa18\ufa19\ufa1a\ufa1b\ufa1c\ufa1d\ufa1e\ufa1f\ufa20\ufa21\ufa22\ufa23\ufa24\ufa25\ufa26\ufa27\ufa28\ufa29\ufa2a\ufa2b\ufa2c\ufa2d\ufa2e\ufa2f\ufa30\ufa31\ufa32\ufa33\ufa34\ufa35\ufa36\ufa37\ufa38\ufa39\ufa3a\ufa3b\ufa3c\ufa3d\ufa3e\ufa3f\ufa40\ufa41\ufa42\ufa43\ufa44\ufa45\ufa46\ufa47\ufa48\ufa49\ufa4a\ufa4b\ufa4c\ufa4d\ufa4e\ufa4f\ufa50\ufa51\ufa52\ufa53\ufa54\ufa55\ufa56\ufa57\ufa58\ufa59\ufa5a\ufa5b\ufa5c\ufa5d\ufa5e\ufa5f\ufa60\ufa61\ufa62\ufa63\ufa64\ufa65\ufa66\ufa67\ufa68\ufa69\ufa6a\ufa6b\ufa6d\ufa70\ufa71\ufa72\ufa73\ufa74\ufa75\ufa76\ufa77\ufa78\ufa79\ufa7a\ufa7b\ufa7c\ufa7d\ufa7e\ufa7f\ufa80\ufa81\ufa82\ufa83\ufa84\ufa85\ufa86\ufa87\ufa88\ufa89\ufa8a\ufa8b\ufa8c\ufa8d\ufa8e\ufa8f\ufa90\ufa91\ufa92\ufa93\ufa94\ufa95\ufa96\ufa97\ufa98\ufa99\ufa9a\ufa9b\ufa9c\ufa9d\ufa9e\ufa9f\ufaa0\ufaa1\ufaa2\ufaa3\ufaa4\ufaa5\ufaa6\ufaa7\ufaa8\ufaa9\ufaaa\ufaab\ufaac\ufaad\ufaae\ufaaf\ufab0\ufab1\ufab2\ufab3\ufab4\ufab5\ufab6\ufab7\ufab8\ufab9\ufaba\ufabb\ufabc\ufabd\ufabe\ufabf\ufac0\ufac1\ufac2\ufac3\ufac4\ufac5\ufac6\ufac7\ufac8\ufac9\ufaca\ufacb\ufacc\ufacd\uface\ufad2\ufad3\ufad4\ufad8\ufad9\ufb20\ufb21\ufb22\ufb23\ufb24\ufb25\ufb26\ufb27\ufb28\ufb50\ufb51\ufb52\ufb53\ufb54\ufb55\ufb56\ufb57\ufb58\ufb59\ufb5a\ufb5b\ufb5c\ufb5d\ufb5e\ufb5f\ufb60\ufb61\ufb62\ufb63\ufb64\ufb65\ufb66\ufb67\ufb68\ufb69\ufb6a\ufb6b\ufb6c\ufb6d\ufb6e\ufb6f\ufb70\ufb71\ufb72\ufb73\ufb74\ufb75\ufb76\ufb77\ufb78\ufb79\ufb7a\ufb7b\ufb7c\ufb7d\ufb7e\ufb7f\ufb80\ufb81\ufb82\ufb83\ufb84\ufb85\ufb86\ufb87\ufb88\ufb89\ufb8a\ufb8b\ufb8c\ufb8d\ufb8e\ufb8f\ufb90\ufb91\ufb92\ufb93\ufb94\ufb95\ufb96\ufb97\ufb98\ufb99\ufb9a\ufb9b\ufb9c\ufb9d\ufb9e\ufb9f\ufba0\ufba1\ufba2\ufba3\ufba4\ufba5\ufba6\ufba7\ufba8\ufba9\ufbaa\ufbab\ufbac\ufbad\ufbae\ufbaf\ufbb0\ufbb1\ufbd3\ufbd4\ufbd5\ufbd6\ufbd7\ufbd8\ufbd9\ufbda\ufbdb\ufbdc\ufbde\ufbdf\ufbe0\ufbe1\ufbe2\ufbe3\ufbe4\ufbe5\ufbe6\ufbe7\ufbe8\ufbe9\ufbfc\ufbfd\ufbfe\ufbff\ufe33\ufe34\ufe4d\ufe4e\ufe4f\ufe73\ufe80\ufe81\ufe82\ufe83\ufe84\ufe85\ufe86\ufe87\ufe88\ufe89\ufe8a\ufe8b\ufe8c\ufe8d\ufe8e\ufe8f\ufe90\ufe91\ufe92\ufe93\ufe94\ufe95\ufe96\ufe97\ufe98\ufe99\ufe9a\ufe9b\ufe9c\ufe9d\ufe9e\ufe9f\ufea0\ufea1\ufea2\ufea3\ufea4\ufea5\ufea6\ufea7\ufea8\ufea9\ufeaa\ufeab\ufeac\ufead\ufeae\ufeaf\ufeb0\ufeb1\ufeb2\ufeb3\ufeb4\ufeb5\ufeb6\ufeb7\ufeb8\ufeb9\ufeba\ufebb\ufebc\ufebd\ufebe\ufebf\ufec0\ufec1\ufec2\ufec3\ufec4\ufec5\ufec6\ufec7\ufec8\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed2\ufed3\ufed4\ufed5\ufed6\ufed7\ufed8\ufed9\ufeda\ufedb\ufedc\ufedd\ufede\ufedf\ufee0\ufee1\ufee2\ufee3\ufee4\ufee5\ufee6\ufee7\ufee8\ufee9\ufeea\ufeeb\ufeec\ufeed\ufeee\ufeef\ufef0\ufef1\ufef2\ufef3\ufef4\uff21\uff22\uff23\uff24\uff25\uff26\uff27\uff28\uff29\uff2a\uff2b\uff2c\uff2d\uff2e\uff2f\uff30\uff31\uff32\uff33\uff34\uff35\uff36\uff37\uff38\uff39\uff3a\uff3f\uff41\uff42\uff43\uff44\uff45\uff46\uff47\uff48\uff49\uff4a\uff4b\uff4c\uff4d\uff4e\uff4f\uff50\uff51\uff52\uff53\uff54\uff55\uff56\uff57\uff58\uff59\uff5a\uff66\uff67\uff68\uff69\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff7a\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82\uff83\uff84\uff85\uff86\uff87\uff88\uff89\uff8a\uff8b\uff8c\uff8d\uff8e\uff8f\uff90\uff91\uff92\uff93\uff94\uff95\uff96\uff97\uff98\uff99\uff9a\uff9b\uff9c\uff9d\uffa0\uffa1\uffa2\uffa3\uffa4\uffa5\uffa6\uffa7\uffa8\uffa9\uffaa\uffab\uffac\uffad\uffae\uffaf\uffb0\uffb1\uffb2\uffb3\uffb4\uffb5\uffb6\uffb7\uffb8\uffb9\uffba\uffbb\uffbc\uffbd\uffbe\uffc2\uffc3\uffc4\uffc5\uffc6\uffc7\uffca\uffcb\uffcc\uffcd\uffce\uffcf\uffd2\uffd3\uffd4\uffd5\uffd6\uffd7\uffda\uffdb\uffdc'
-xid_continue = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz\xaa\xb5\xb7\xba\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\u0100\u0101\u0102\u0103\u0104\u0105\u0106\u0107\u0108\u0109\u010a\u010b\u010c\u010d\u010e\u010f\u0110\u0111\u0112\u0113\u0114\u0115\u0116\u0117\u0118\u0119\u011a\u011b\u011c\u011d\u011e\u011f\u0120\u0121\u0122\u0123\u0124\u0125\u0126\u0127\u0128\u0129\u012a\u012b\u012c\u012d\u012e\u012f\u0130\u0131\u0134\u0135\u0136\u0137\u0138\u0139\u013a\u013b\u013c\u013d\u013e\u0141\u0142\u0143\u0144\u0145\u0146\u0147\u0148\u014a\u014b\u014c\u014d\u014e\u014f\u0150\u0151\u0152\u0153\u0154\u0155\u0156\u0157\u0158\u0159\u015a\u015b\u015c\u015d\u015e\u015f\u0160\u0161\u0162\u0163\u0164\u0165\u0166\u0167\u0168\u0169\u016a\u016b\u016c\u016d\u016e\u016f\u0170\u0171\u0172\u0173\u0174\u0175\u0176\u0177\u0178\u0179\u017a\u017b\u017c\u017d\u017e\u017f\u0180\u0181\u0182\u0183\u0184\u0185\u0186\u0187\u0188\u0189\u018a\u018b\u018c\u018d\u018e\u018f\u0190\u0191\u0192\u0193\u0194\u0195\u0196\u0197\u0198\u0199\u019a\u019b\u019c\u019d\u019e\u019f\u01a0\u01a1\u01a2\u01a3\u01a4\u01a5\u01a6\u01a7\u01a8\u01a9\u01aa\u01ab\u01ac\u01ad\u01ae\u01af\u01b0\u01b1\u01b2\u01b3\u01b4\u01b5\u01b6\u01b7\u01b8\u01b9\u01ba\u01bb\u01bc\u01bd\u01be\u01bf\u01c0\u01c1\u01c2\u01c3\u01cd\u01ce\u01cf\u01d0\u01d1\u01d2\u01d3\u01d4\u01d5\u01d6\u01d7\u01d8\u01d9\u01da\u01db\u01dc\u01dd\u01de\u01df\u01e0\u01e1\u01e2\u01e3\u01e4\u01e5\u01e6\u01e7\u01e8\u01e9\u01ea\u01eb\u01ec\u01ed\u01ee\u01ef\u01f0\u01f4\u01f5\u01f6\u01f7\u01f8\u01f9\u01fa\u01fb\u01fc\u01fd\u01fe\u01ff\u0200\u0201\u0202\u0203\u0204\u0205\u0206\u0207\u0208\u0209\u020a\u020b\u020c\u020d\u020e\u020f\u0210\u0211\u0212\u0213\u0214\u0215\u0216\u0217\u0218\u0219\u021a\u021b\u021c\u021d\u021e\u021f\u0220\u0221\u0222\u0223\u0224\u0225\u0226\u0227\u0228\u0229\u022a\u022b\u022c\u022d\u022e\u022f\u0230\u0231\u0232\u0233\u0234\u0235\u0236\u0237\u0238\u0239\u023a\u023b\u023c\u023d\u023e\u023f\u0240\u0241\u0242\u0243\u0244\u0245\u0246\u0247\u0248\u0249\u024a\u024b\u024c\u024d\u024e\u024f\u0250\u0251\u0252\u0253\u0254\u0255\u0256\u0257\u0258\u0259\u025a\u025b\u025c\u025d\u025e\u025f\u0260\u0261\u0262\u0263\u0264\u0265\u0266\u0267\u0268\u0269\u026a\u026b\u026c\u026d\u026e\u026f\u0270\u0271\u0272\u0273\u0274\u0275\u0276\u0277\u0278\u0279\u027a\u027b\u027c\u027d\u027e\u027f\u0280\u0281\u0282\u0283\u0284\u0285\u0286\u0287\u0288\u0289\u028a\u028b\u028c\u028d\u028e\u028f\u0290\u0291\u0292\u0293\u0294\u0295\u0296\u0297\u0298\u0299\u029a\u029b\u029c\u029d\u029e\u029f\u02a0\u02a1\u02a2\u02a3\u02a4\u02a5\u02a6\u02a7\u02a8\u02a9\u02aa\u02ab\u02ac\u02ad\u02ae\u02af\u02b0\u02b1\u02b2\u02b3\u02b4\u02b5\u02b6\u02b7\u02b8\u02b9\u02ba\u02bb\u02bc\u02bd\u02be\u02bf\u02c0\u02c1\u02c6\u02c7\u02c8\u02c9\u02ca\u02cb\u02cc\u02cd\u02ce\u02cf\u02d0\u02d1\u02e0\u02e1\u02e2\u02e3\u02e4\u02ec\u02ee\u0300\u0301\u0302\u0303\u0304\u0305\u0306\u0307\u0308\u0309\u030a\u030b\u030c\u030d\u030e\u030f\u0310\u0311\u0312\u0313\u0314\u0315\u0316\u0317\u0318\u0319\u031a\u031b\u031c\u031d\u031e\u031f\u0320\u0321\u0322\u0323\u0324\u0325\u0326\u0327\u0328\u0329\u032a\u032b\u032c\u032d\u032e\u032f\u0330\u0331\u0332\u0333\u0334\u0335\u0336\u0337\u0338\u0339\u033a\u033b\u033c\u033d\u033e\u033f\u0340\u0341\u0342\u0343\u0345\u0346\u0347\u0348\u0349\u034a\u034b\u034c\u034d\u034e\u034f\u0350\u0351\u0352\u0353\u0354\u0355\u0356\u0357\u0358\u0359\u035a\u035b\u035c\u035d\u035e\u035f\u0360\u0361\u0362\u0363\u0364\u0365\u0366\u0367\u0368\u0369\u036a\u036b\u036c\u036d\u036e\u036f\u0370\u0371\u0372\u0373\u0374\u0376\u0377\u037b\u037c\u037d\u037f\u0386\u0387\u0388\u0389\u038a\u038c\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\u03cf\u03d0\u03d1\u03d2\u03d3\u03d4\u03d5\u03d6\u03d7\u03d8\u03d9\u03da\u03db\u03dc\u03dd\u03de\u03df\u03e0\u03e1\u03e2\u03e3\u03e4\u03e5\u03e6\u03e7\u03e8\u03e9\u03ea\u03eb\u03ec\u03ed\u03ee\u03ef\u03f0\u03f1\u03f2\u03f3\u03f4\u03f5\u03f7\u03f8\u03f9\u03fa\u03fb\u03fc\u03fd\u03fe\u03ff\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u040d\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0450\u0451\u0452\u0453\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u045d\u045e\u045f\u0460\u0461\u0462\u0463\u0464\u0465\u0466\u0467\u0468\u0469\u046a\u046b\u046c\u046d\u046e\u046f\u0470\u0471\u0472\u0473\u0474\u0475\u0476\u0477\u0478\u0479\u047a\u047b\u047c\u047d\u047e\u047f\u0480\u0481\u0483\u0484\u0485\u0486\u0487\u048a\u048b\u048c\u048d\u048e\u048f\u0490\u0491\u0492\u0493\u0494\u0495\u0496\u0497\u0498\u0499\u049a\u049b\u049c\u049d\u049e\u049f\u04a0\u04a1\u04a2\u04a3\u04a4\u04a5\u04a6\u04a7\u04a8\u04a9\u04aa\u04ab\u04ac\u04ad\u04ae\u04af\u04b0\u04b1\u04b2\u04b3\u04b4\u04b5\u04b6\u04b7\u04b8\u04b9\u04ba\u04bb\u04bc\u04bd\u04be\u04bf\u04c0\u04c1\u04c2\u04c3\u04c4\u04c5\u04c6\u04c7\u04c8\u04c9\u04ca\u04cb\u04cc\u04cd\u04ce\u04cf\u04d0\u04d1\u04d2\u04d3\u04d4\u04d5\u04d6\u04d7\u04d8\u04d9\u04da\u04db\u04dc\u04dd\u04de\u04df\u04e0\u04e1\u04e2\u04e3\u04e4\u04e5\u04e6\u04e7\u04e8\u04e9\u04ea\u04eb\u04ec\u04ed\u04ee\u04ef\u04f0\u04f1\u04f2\u04f3\u04f4\u04f5\u04f6\u04f7\u04f8\u04f9\u04fa\u04fb\u04fc\u04fd\u04fe\u04ff\u0500\u0501\u0502\u0503\u0504\u0505\u0506\u0507\u0508\u0509\u050a\u050b\u050c\u050d\u050e\u050f\u0510\u0511\u0512\u0513\u0514\u0515\u0516\u0517\u0518\u0519\u051a\u051b\u051c\u051d\u051e\u051f\u0520\u0521\u0522\u0523\u0524\u0525\u0526\u0527\u0528\u0529\u052a\u052b\u052c\u052d\u052e\u052f\u0531\u0532\u0533\u0534\u0535\u0536\u0537\u0538\u0539\u053a\u053b\u053c\u053d\u053e\u053f\u0540\u0541\u0542\u0543\u0544\u0545\u0546\u0547\u0548\u0549\u054a\u054b\u054c\u054d\u054e\u054f\u0550\u0551\u0552\u0553\u0554\u0555\u0556\u0559\u0561\u0562\u0563\u0564\u0565\u0566\u0567\u0568\u0569\u056a\u056b\u056c\u056d\u056e\u056f\u0570\u0571\u0572\u0573\u0574\u0575\u0576\u0577\u0578\u0579\u057a\u057b\u057c\u057d\u057e\u057f\u0580\u0581\u0582\u0583\u0584\u0585\u0586\u0591\u0592\u0593\u0594\u0595\u0596\u0597\u0598\u0599\u059a\u059b\u059c\u059d\u059e\u059f\u05a0\u05a1\u05a2\u05a3\u05a4\u05a5\u05a6\u05a7\u05a8\u05a9\u05aa\u05ab\u05ac\u05ad\u05ae\u05af\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\u05ba\u05bb\u05bc\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u05f0\u05f1\u05f2\u0610\u0611\u0612\u0613\u0614\u0615\u0616\u0617\u0618\u0619\u061a\u0620\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\u063b\u063c\u063d\u063e\u063f\u0640\u0641\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u064b\u064c\u064d\u064e\u064f\u0650\u0651\u0652\u0653\u0654\u0655\u0656\u0657\u0658\u0659\u065a\u065b\u065c\u065d\u065e\u065f\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u066e\u066f\u0670\u0671\u0672\u0673\u0674\u0679\u067a\u067b\u067c\u067d\u067e\u067f\u0680\u0681\u0682\u0683\u0684\u0685\u0686\u0687\u0688\u0689\u068a\u068b\u068c\u068d\u068e\u068f\u0690\u0691\u0692\u0693\u0694\u0695\u0696\u0697\u0698\u0699\u069a\u069b\u069c\u069d\u069e\u069f\u06a0\u06a1\u06a2\u06a3\u06a4\u06a5\u06a6\u06a7\u06a8\u06a9\u06aa\u06ab\u06ac\u06ad\u06ae\u06af\u06b0\u06b1\u06b2\u06b3\u06b4\u06b5\u06b6\u06b7\u06b8\u06b9\u06ba\u06bb\u06bc\u06bd\u06be\u06bf\u06c0\u06c1\u06c2\u06c3\u06c4\u06c5\u06c6\u06c7\u06c8\u06c9\u06ca\u06cb\u06cc\u06cd\u06ce\u06cf\u06d0\u06d1\u06d2\u06d3\u06d5\u06d6\u06d7\u06d8\u06d9\u06da\u06db\u06dc\u06df\u06e0\u06e1\u06e2\u06e3\u06e4\u06e5\u06e6\u06e7\u06e8\u06ea\u06eb\u06ec\u06ed\u06ee\u06ef\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u06fa\u06fb\u06fc\u06ff\u0710\u0711\u0712\u0713\u0714\u0715\u0716\u0717\u0718\u0719\u071a\u071b\u071c\u071d\u071e\u071f\u0720\u0721\u0722\u0723\u0724\u0725\u0726\u0727\u0728\u0729\u072a\u072b\u072c\u072d\u072e\u072f\u0730\u0731\u0732\u0733\u0734\u0735\u0736\u0737\u0738\u0739\u073a\u073b\u073c\u073d\u073e\u073f\u0740\u0741\u0742\u0743\u0744\u0745\u0746\u0747\u0748\u0749\u074a\u074d\u074e\u074f\u0750\u0751\u0752\u0753\u0754\u0755\u0756\u0757\u0758\u0759\u075a\u075b\u075c\u075d\u075e\u075f\u0760\u0761\u0762\u0763\u0764\u0765\u0766\u0767\u0768\u0769\u076a\u076b\u076c\u076d\u076e\u076f\u0770\u0771\u0772\u0773\u0774\u0775\u0776\u0777\u0778\u0779\u077a\u077b\u077c\u077d\u077e\u077f\u0780\u0781\u0782\u0783\u0784\u0785\u0786\u0787\u0788\u0789\u078a\u078b\u078c\u078d\u078e\u078f\u0790\u0791\u0792\u0793\u0794\u0795\u0796\u0797\u0798\u0799\u079a\u079b\u079c\u079d\u079e\u079f\u07a0\u07a1\u07a2\u07a3\u07a4\u07a5\u07a6\u07a7\u07a8\u07a9\u07aa\u07ab\u07ac\u07ad\u07ae\u07af\u07b0\u07b1\u07c0\u07c1\u07c2\u07c3\u07c4\u07c5\u07c6\u07c7\u07c8\u07c9\u07ca\u07cb\u07cc\u07cd\u07ce\u07cf\u07d0\u07d1\u07d2\u07d3\u07d4\u07d5\u07d6\u07d7\u07d8\u07d9\u07da\u07db\u07dc\u07dd\u07de\u07df\u07e0\u07e1\u07e2\u07e3\u07e4\u07e5\u07e6\u07e7\u07e8\u07e9\u07ea\u07eb\u07ec\u07ed\u07ee\u07ef\u07f0\u07f1\u07f2\u07f3\u07f4\u07f5\u07fa\u0800\u0801\u0802\u0803\u0804\u0805\u0806\u0807\u0808\u0809\u080a\u080b\u080c\u080d\u080e\u080f\u0810\u0811\u0812\u0813\u0814\u0815\u0816\u0817\u0818\u0819\u081a\u081b\u081c\u081d\u081e\u081f\u0820\u0821\u0822\u0823\u0824\u0825\u0826\u0827\u0828\u0829\u082a\u082b\u082c\u082d\u0840\u0841\u0842\u0843\u0844\u0845\u0846\u0847\u0848\u0849\u084a\u084b\u084c\u084d\u084e\u084f\u0850\u0851\u0852\u0853\u0854\u0855\u0856\u0857\u0858\u0859\u085a\u085b\u08a0\u08a1\u08a2\u08a3\u08a4\u08a5\u08a6\u08a7\u08a8\u08a9\u08aa\u08ab\u08ac\u08ad\u08ae\u08af\u08b0\u08b1\u08b2\u08b3\u08b4\u08b6\u08b7\u08b8\u08b9\u08ba\u08bb\u08bc\u08bd\u08d4\u08d5\u08d6\u08d7\u08d8\u08d9\u08da\u08db\u08dc\u08dd\u08de\u08df\u08e0\u08e1\u08e3\u08e4\u08e5\u08e6\u08e7\u08e8\u08e9\u08ea\u08eb\u08ec\u08ed\u08ee\u08ef\u08f0\u08f1\u08f2\u08f3\u08f4\u08f5\u08f6\u08f7\u08f8\u08f9\u08fa\u08fb\u08fc\u08fd\u08fe\u08ff\u0900\u0901\u0902\u0903\u0904\u0905\u0906\u0907\u0908\u0909\u090a\u090b\u090c\u090d\u090e\u090f\u0910\u0911\u0912\u0913\u0914\u0915\u0916\u0917\u0918\u0919\u091a\u091b\u091c\u091d\u091e\u091f\u0920\u0921\u0922\u0923\u0924\u0925\u0926\u0927\u0928\u0929\u092a\u092b\u092c\u092d\u092e\u092f\u0930\u0931\u0932\u0933\u0934\u0935\u0936\u0937\u0938\u0939\u093a\u093b\u093c\u093d\u093e\u093f\u0940\u0941\u0942\u0943\u0944\u0945\u0946\u0947\u0948\u0949\u094a\u094b\u094c\u094d\u094e\u094f\u0950\u0951\u0952\u0953\u0954\u0955\u0956\u0957\u0960\u0961\u0962\u0963\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u0971\u0972\u0973\u0974\u0975\u0976\u0977\u0978\u0979\u097a\u097b\u097c\u097d\u097e\u097f\u0980\u0981\u0982\u0983\u0985\u0986\u0987\u0988\u0989\u098a\u098b\u098c\u098f\u0990\u0993\u0994\u0995\u0996\u0997\u0998\u0999\u099a\u099b\u099c\u099d\u099e\u099f\u09a0\u09a1\u09a2\u09a3\u09a4\u09a5\u09a6\u09a7\u09a8\u09aa\u09ab\u09ac\u09ad\u09ae\u09af\u09b0\u09b2\u09b6\u09b7\u09b8\u09b9\u09bc\u09bd\u09be\u09bf\u09c0\u09c1\u09c2\u09c3\u09c4\u09c7\u09c8\u09cb\u09cc\u09cd\u09ce\u09d7\u09e0\u09e1\u09e2\u09e3\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u09f0\u09f1\u0a01\u0a02\u0a03\u0a05\u0a06\u0a07\u0a08\u0a09\u0a0a\u0a0f\u0a10\u0a13\u0a14\u0a15\u0a16\u0a17\u0a18\u0a19\u0a1a\u0a1b\u0a1c\u0a1d\u0a1e\u0a1f\u0a20\u0a21\u0a22\u0a23\u0a24\u0a25\u0a26\u0a27\u0a28\u0a2a\u0a2b\u0a2c\u0a2d\u0a2e\u0a2f\u0a30\u0a32\u0a35\u0a38\u0a39\u0a3c\u0a3e\u0a3f\u0a40\u0a41\u0a42\u0a47\u0a48\u0a4b\u0a4c\u0a4d\u0a51\u0a5c\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0a70\u0a71\u0a72\u0a73\u0a74\u0a75\u0a81\u0a82\u0a83\u0a85\u0a86\u0a87\u0a88\u0a89\u0a8a\u0a8b\u0a8c\u0a8d\u0a8f\u0a90\u0a91\u0a93\u0a94\u0a95\u0a96\u0a97\u0a98\u0a99\u0a9a\u0a9b\u0a9c\u0a9d\u0a9e\u0a9f\u0aa0\u0aa1\u0aa2\u0aa3\u0aa4\u0aa5\u0aa6\u0aa7\u0aa8\u0aaa\u0aab\u0aac\u0aad\u0aae\u0aaf\u0ab0\u0ab2\u0ab3\u0ab5\u0ab6\u0ab7\u0ab8\u0ab9\u0abc\u0abd\u0abe\u0abf\u0ac0\u0ac1\u0ac2\u0ac3\u0ac4\u0ac5\u0ac7\u0ac8\u0ac9\u0acb\u0acc\u0acd\u0ad0\u0ae0\u0ae1\u0ae2\u0ae3\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0af9\u0b01\u0b02\u0b03\u0b05\u0b06\u0b07\u0b08\u0b09\u0b0a\u0b0b\u0b0c\u0b0f\u0b10\u0b13\u0b14\u0b15\u0b16\u0b17\u0b18\u0b19\u0b1a\u0b1b\u0b1c\u0b1d\u0b1e\u0b1f\u0b20\u0b21\u0b22\u0b23\u0b24\u0b25\u0b26\u0b27\u0b28\u0b2a\u0b2b\u0b2c\u0b2d\u0b2e\u0b2f\u0b30\u0b32\u0b33\u0b35\u0b36\u0b37\u0b38\u0b39\u0b3c\u0b3d\u0b3e\u0b3f\u0b40\u0b41\u0b42\u0b43\u0b44\u0b47\u0b48\u0b4b\u0b4c\u0b4d\u0b56\u0b57\u0b5f\u0b60\u0b61\u0b62\u0b63\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0b71\u0b82\u0b83\u0b85\u0b86\u0b87\u0b88\u0b89\u0b8a\u0b8e\u0b8f\u0b90\u0b92\u0b93\u0b94\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8\u0ba9\u0baa\u0bae\u0baf\u0bb0\u0bb1\u0bb2\u0bb3\u0bb4\u0bb5\u0bb6\u0bb7\u0bb8\u0bb9\u0bbe\u0bbf\u0bc0\u0bc1\u0bc2\u0bc6\u0bc7\u0bc8\u0bca\u0bcb\u0bcc\u0bcd\u0bd0\u0bd7\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0c00\u0c01\u0c02\u0c03\u0c05\u0c06\u0c07\u0c08\u0c09\u0c0a\u0c0b\u0c0c\u0c0e\u0c0f\u0c10\u0c12\u0c13\u0c14\u0c15\u0c16\u0c17\u0c18\u0c19\u0c1a\u0c1b\u0c1c\u0c1d\u0c1e\u0c1f\u0c20\u0c21\u0c22\u0c23\u0c24\u0c25\u0c26\u0c27\u0c28\u0c2a\u0c2b\u0c2c\u0c2d\u0c2e\u0c2f\u0c30\u0c31\u0c32\u0c33\u0c34\u0c35\u0c36\u0c37\u0c38\u0c39\u0c3d\u0c3e\u0c3f\u0c40\u0c41\u0c42\u0c43\u0c44\u0c46\u0c47\u0c48\u0c4a\u0c4b\u0c4c\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c5a\u0c60\u0c61\u0c62\u0c63\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0c80\u0c81\u0c82\u0c83\u0c85\u0c86\u0c87\u0c88\u0c89\u0c8a\u0c8b\u0c8c\u0c8e\u0c8f\u0c90\u0c92\u0c93\u0c94\u0c95\u0c96\u0c97\u0c98\u0c99\u0c9a\u0c9b\u0c9c\u0c9d\u0c9e\u0c9f\u0ca0\u0ca1\u0ca2\u0ca3\u0ca4\u0ca5\u0ca6\u0ca7\u0ca8\u0caa\u0cab\u0cac\u0cad\u0cae\u0caf\u0cb0\u0cb1\u0cb2\u0cb3\u0cb5\u0cb6\u0cb7\u0cb8\u0cb9\u0cbc\u0cbd\u0cbe\u0cbf\u0cc0\u0cc1\u0cc2\u0cc3\u0cc4\u0cc6\u0cc7\u0cc8\u0cca\u0ccb\u0ccc\u0ccd\u0cd5\u0cd6\u0cde\u0ce0\u0ce1\u0ce2\u0ce3\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0cf1\u0cf2\u0d01\u0d02\u0d03\u0d05\u0d06\u0d07\u0d08\u0d09\u0d0a\u0d0b\u0d0c\u0d0e\u0d0f\u0d10\u0d12\u0d13\u0d14\u0d15\u0d16\u0d17\u0d18\u0d19\u0d1a\u0d1b\u0d1c\u0d1d\u0d1e\u0d1f\u0d20\u0d21\u0d22\u0d23\u0d24\u0d25\u0d26\u0d27\u0d28\u0d29\u0d2a\u0d2b\u0d2c\u0d2d\u0d2e\u0d2f\u0d30\u0d31\u0d32\u0d33\u0d34\u0d35\u0d36\u0d37\u0d38\u0d39\u0d3a\u0d3d\u0d3e\u0d3f\u0d40\u0d41\u0d42\u0d43\u0d44\u0d46\u0d47\u0d48\u0d4a\u0d4b\u0d4c\u0d4d\u0d4e\u0d54\u0d55\u0d56\u0d57\u0d5f\u0d60\u0d61\u0d62\u0d63\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0d7a\u0d7b\u0d7c\u0d7d\u0d7e\u0d7f\u0d82\u0d83\u0d85\u0d86\u0d87\u0d88\u0d89\u0d8a\u0d8b\u0d8c\u0d8d\u0d8e\u0d8f\u0d90\u0d91\u0d92\u0d93\u0d94\u0d95\u0d96\u0d9a\u0d9b\u0d9c\u0d9d\u0d9e\u0d9f\u0da0\u0da1\u0da2\u0da3\u0da4\u0da5\u0da6\u0da7\u0da8\u0da9\u0daa\u0dab\u0dac\u0dad\u0dae\u0daf\u0db0\u0db1\u0db3\u0db4\u0db5\u0db6\u0db7\u0db8\u0db9\u0dba\u0dbb\u0dbd\u0dc0\u0dc1\u0dc2\u0dc3\u0dc4\u0dc5\u0dc6\u0dca\u0dcf\u0dd0\u0dd1\u0dd2\u0dd3\u0dd4\u0dd6\u0dd8\u0dd9\u0dda\u0ddb\u0ddc\u0ddd\u0dde\u0ddf\u0de6\u0de7\u0de8\u0de9\u0dea\u0deb\u0dec\u0ded\u0dee\u0def\u0df2\u0df3\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e31\u0e32\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e46\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94\u0e95\u0e96\u0e97\u0e99\u0e9a\u0e9b\u0e9c\u0e9d\u0e9e\u0e9f\u0ea1\u0ea2\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead\u0eae\u0eaf\u0eb0\u0eb1\u0eb2\u0eb4\u0eb5\u0eb6\u0eb7\u0eb8\u0eb9\u0ebb\u0ebc\u0ebd\u0ec0\u0ec1\u0ec2\u0ec3\u0ec4\u0ec6\u0ec8\u0ec9\u0eca\u0ecb\u0ecc\u0ecd\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0ede\u0edf\u0f00\u0f18\u0f19\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f40\u0f41\u0f42\u0f44\u0f45\u0f46\u0f47\u0f49\u0f4a\u0f4b\u0f4c\u0f4e\u0f4f\u0f50\u0f51\u0f53\u0f54\u0f55\u0f56\u0f58\u0f59\u0f5a\u0f5b\u0f5d\u0f5e\u0f5f\u0f60\u0f61\u0f62\u0f63\u0f64\u0f65\u0f66\u0f67\u0f68\u0f6a\u0f6b\u0f6c\u0f71\u0f72\u0f74\u0f7a\u0f7b\u0f7c\u0f7d\u0f7e\u0f7f\u0f80\u0f82\u0f83\u0f84\u0f86\u0f87\u0f88\u0f89\u0f8a\u0f8b\u0f8c\u0f8d\u0f8e\u0f8f\u0f90\u0f91\u0f92\u0f94\u0f95\u0f96\u0f97\u0f99\u0f9a\u0f9b\u0f9c\u0f9e\u0f9f\u0fa0\u0fa1\u0fa3\u0fa4\u0fa5\u0fa6\u0fa8\u0fa9\u0faa\u0fab\u0fad\u0fae\u0faf\u0fb0\u0fb1\u0fb2\u0fb3\u0fb4\u0fb5\u0fb6\u0fb7\u0fb8\u0fba\u0fbb\u0fbc\u0fc6\u1000\u1001\u1002\u1003\u1004\u1005\u1006\u1007\u1008\u1009\u100a\u100b\u100c\u100d\u100e\u100f\u1010\u1011\u1012\u1013\u1014\u1015\u1016\u1017\u1018\u1019\u101a\u101b\u101c\u101d\u101e\u101f\u1020\u1021\u1022\u1023\u1024\u1025\u1026\u1027\u1028\u1029\u102a\u102b\u102c\u102d\u102e\u102f\u1030\u1031\u1032\u1033\u1034\u1035\u1036\u1037\u1038\u1039\u103a\u103b\u103c\u103d\u103e\u103f\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049\u1050\u1051\u1052\u1053\u1054\u1055\u1056\u1057\u1058\u1059\u105a\u105b\u105c\u105d\u105e\u105f\u1060\u1061\u1062\u1063\u1064\u1065\u1066\u1067\u1068\u1069\u106a\u106b\u106c\u106d\u106e\u106f\u1070\u1071\u1072\u1073\u1074\u1075\u1076\u1077\u1078\u1079\u107a\u107b\u107c\u107d\u107e\u107f\u1080\u1081\u1082\u1083\u1084\u1085\u1086\u1087\u1088\u1089\u108a\u108b\u108c\u108d\u108e\u108f\u1090\u1091\u1092\u1093\u1094\u1095\u1096\u1097\u1098\u1099\u109a\u109b\u109c\u109d\u10a0\u10a1\u10a2\u10a3\u10a4\u10a5\u10a6\u10a7\u10a8\u10a9\u10aa\u10ab\u10ac\u10ad\u10ae\u10af\u10b0\u10b1\u10b2\u10b3\u10b4\u10b5\u10b6\u10b7\u10b8\u10b9\u10ba\u10bb\u10bc\u10bd\u10be\u10bf\u10c0\u10c1\u10c2\u10c3\u10c4\u10c5\u10c7\u10cd\u10d0\u10d1\u10d2\u10d3\u10d4\u10d5\u10d6\u10d7\u10d8\u10d9\u10da\u10db\u10dc\u10dd\u10de\u10df\u10e0\u10e1\u10e2\u10e3\u10e4\u10e5\u10e6\u10e7\u10e8\u10e9\u10ea\u10eb\u10ec\u10ed\u10ee\u10ef\u10f0\u10f1\u10f2\u10f3\u10f4\u10f5\u10f6\u10f7\u10f8\u10f9\u10fa\u10fc\u10fd\u10fe\u10ff\u1100\u1101\u1102\u1103\u1104\u1105\u1106\u1107\u1108\u1109\u110a\u110b\u110c\u110d\u110e\u110f\u1110\u1111\u1112\u1113\u1114\u1115\u1116\u1117\u1118\u1119\u111a\u111b\u111c\u111d\u111e\u111f\u1120\u1121\u1122\u1123\u1124\u1125\u1126\u1127\u1128\u1129\u112a\u112b\u112c\u112d\u112e\u112f\u1130\u1131\u1132\u1133\u1134\u1135\u1136\u1137\u1138\u1139\u113a\u113b\u113c\u113d\u113e\u113f\u1140\u1141\u1142\u1143\u1144\u1145\u1146\u1147\u1148\u1149\u114a\u114b\u114c\u114d\u114e\u114f\u1150\u1151\u1152\u1153\u1154\u1155\u1156\u1157\u1158\u1159\u115a\u115b\u115c\u115d\u115e\u115f\u1160\u1161\u1162\u1163\u1164\u1165\u1166\u1167\u1168\u1169\u116a\u116b\u116c\u116d\u116e\u116f\u1170\u1171\u1172\u1173\u1174\u1175\u1176\u1177\u1178\u1179\u117a\u117b\u117c\u117d\u117e\u117f\u1180\u1181\u1182\u1183\u1184\u1185\u1186\u1187\u1188\u1189\u118a\u118b\u118c\u118d\u118e\u118f\u1190\u1191\u1192\u1193\u1194\u1195\u1196\u1197\u1198\u1199\u119a\u119b\u119c\u119d\u119e\u119f\u11a0\u11a1\u11a2\u11a3\u11a4\u11a5\u11a6\u11a7\u11a8\u11a9\u11aa\u11ab\u11ac\u11ad\u11ae\u11af\u11b0\u11b1\u11b2\u11b3\u11b4\u11b5\u11b6\u11b7\u11b8\u11b9\u11ba\u11bb\u11bc\u11bd\u11be\u11bf\u11c0\u11c1\u11c2\u11c3\u11c4\u11c5\u11c6\u11c7\u11c8\u11c9\u11ca\u11cb\u11cc\u11cd\u11ce\u11cf\u11d0\u11d1\u11d2\u11d3\u11d4\u11d5\u11d6\u11d7\u11d8\u11d9\u11da\u11db\u11dc\u11dd\u11de\u11df\u11e0\u11e1\u11e2\u11e3\u11e4\u11e5\u11e6\u11e7\u11e8\u11e9\u11ea\u11eb\u11ec\u11ed\u11ee\u11ef\u11f0\u11f1\u11f2\u11f3\u11f4\u11f5\u11f6\u11f7\u11f8\u11f9\u11fa\u11fb\u11fc\u11fd\u11fe\u11ff\u1200\u1201\u1202\u1203\u1204\u1205\u1206\u1207\u1208\u1209\u120a\u120b\u120c\u120d\u120e\u120f\u1210\u1211\u1212\u1213\u1214\u1215\u1216\u1217\u1218\u1219\u121a\u121b\u121c\u121d\u121e\u121f\u1220\u1221\u1222\u1223\u1224\u1225\u1226\u1227\u1228\u1229\u122a\u122b\u122c\u122d\u122e\u122f\u1230\u1231\u1232\u1233\u1234\u1235\u1236\u1237\u1238\u1239\u123a\u123b\u123c\u123d\u123e\u123f\u1240\u1241\u1242\u1243\u1244\u1245\u1246\u1247\u1248\u124a\u124b\u124c\u124d\u1250\u1251\u1252\u1253\u1254\u1255\u1256\u1258\u125a\u125b\u125c\u125d\u1260\u1261\u1262\u1263\u1264\u1265\u1266\u1267\u1268\u1269\u126a\u126b\u126c\u126d\u126e\u126f\u1270\u1271\u1272\u1273\u1274\u1275\u1276\u1277\u1278\u1279\u127a\u127b\u127c\u127d\u127e\u127f\u1280\u1281\u1282\u1283\u1284\u1285\u1286\u1287\u1288\u128a\u128b\u128c\u128d\u1290\u1291\u1292\u1293\u1294\u1295\u1296\u1297\u1298\u1299\u129a\u129b\u129c\u129d\u129e\u129f\u12a0\u12a1\u12a2\u12a3\u12a4\u12a5\u12a6\u12a7\u12a8\u12a9\u12aa\u12ab\u12ac\u12ad\u12ae\u12af\u12b0\u12b2\u12b3\u12b4\u12b5\u12b8\u12b9\u12ba\u12bb\u12bc\u12bd\u12be\u12c0\u12c2\u12c3\u12c4\u12c5\u12c8\u12c9\u12ca\u12cb\u12cc\u12cd\u12ce\u12cf\u12d0\u12d1\u12d2\u12d3\u12d4\u12d5\u12d6\u12d8\u12d9\u12da\u12db\u12dc\u12dd\u12de\u12df\u12e0\u12e1\u12e2\u12e3\u12e4\u12e5\u12e6\u12e7\u12e8\u12e9\u12ea\u12eb\u12ec\u12ed\u12ee\u12ef\u12f0\u12f1\u12f2\u12f3\u12f4\u12f5\u12f6\u12f7\u12f8\u12f9\u12fa\u12fb\u12fc\u12fd\u12fe\u12ff\u1300\u1301\u1302\u1303\u1304\u1305\u1306\u1307\u1308\u1309\u130a\u130b\u130c\u130d\u130e\u130f\u1310\u1312\u1313\u1314\u1315\u1318\u1319\u131a\u131b\u131c\u131d\u131e\u131f\u1320\u1321\u1322\u1323\u1324\u1325\u1326\u1327\u1328\u1329\u132a\u132b\u132c\u132d\u132e\u132f\u1330\u1331\u1332\u1333\u1334\u1335\u1336\u1337\u1338\u1339\u133a\u133b\u133c\u133d\u133e\u133f\u1340\u1341\u1342\u1343\u1344\u1345\u1346\u1347\u1348\u1349\u134a\u134b\u134c\u134d\u134e\u134f\u1350\u1351\u1352\u1353\u1354\u1355\u1356\u1357\u1358\u1359\u135a\u135d\u135e\u135f\u1369\u1370\u1371\u1380\u1381\u1382\u1383\u1384\u1385\u1386\u1387\u1388\u1389\u138a\u138b\u138c\u138d\u138e\u138f\u13a0\u13a1\u13a2\u13a3\u13a4\u13a5\u13a6\u13a7\u13a8\u13a9\u13aa\u13ab\u13ac\u13ad\u13ae\u13af\u13b0\u13b1\u13b2\u13b3\u13b4\u13b5\u13b6\u13b7\u13b8\u13b9\u13ba\u13bb\u13bc\u13bd\u13be\u13bf\u13c0\u13c1\u13c2\u13c3\u13c4\u13c5\u13c6\u13c7\u13c8\u13c9\u13ca\u13cb\u13cc\u13cd\u13ce\u13cf\u13d0\u13d1\u13d2\u13d3\u13d4\u13d5\u13d6\u13d7\u13d8\u13d9\u13da\u13db\u13dc\u13dd\u13de\u13df\u13e0\u13e1\u13e2\u13e3\u13e4\u13e5\u13e6\u13e7\u13e8\u13e9\u13ea\u13eb\u13ec\u13ed\u13ee\u13ef\u13f0\u13f1\u13f2\u13f3\u13f4\u13f5\u13f8\u13f9\u13fa\u13fb\u13fc\u13fd\u1401\u1402\u1403\u1404\u1405\u1406\u1407\u1408\u1409\u140a\u140b\u140c\u140d\u140e\u140f\u1410\u1411\u1412\u1413\u1414\u1415\u1416\u1417\u1418\u1419\u141a\u141b\u141c\u141d\u141e\u141f\u1420\u1421\u1422\u1423\u1424\u1425\u1426\u1427\u1428\u1429\u142a\u142b\u142c\u142d\u142e\u142f\u1430\u1431\u1432\u1433\u1434\u1435\u1436\u1437\u1438\u1439\u143a\u143b\u143c\u143d\u143e\u143f\u1440\u1441\u1442\u1443\u1444\u1445\u1446\u1447\u1448\u1449\u144a\u144b\u144c\u144d\u144e\u144f\u1450\u1451\u1452\u1453\u1454\u1455\u1456\u1457\u1458\u1459\u145a\u145b\u145c\u145d\u145e\u145f\u1460\u1461\u1462\u1463\u1464\u1465\u1466\u1467\u1468\u1469\u146a\u146b\u146c\u146d\u146e\u146f\u1470\u1471\u1472\u1473\u1474\u1475\u1476\u1477\u1478\u1479\u147a\u147b\u147c\u147d\u147e\u147f\u1480\u1481\u1482\u1483\u1484\u1485\u1486\u1487\u1488\u1489\u148a\u148b\u148c\u148d\u148e\u148f\u1490\u1491\u1492\u1493\u1494\u1495\u1496\u1497\u1498\u1499\u149a\u149b\u149c\u149d\u149e\u149f\u14a0\u14a1\u14a2\u14a3\u14a4\u14a5\u14a6\u14a7\u14a8\u14a9\u14aa\u14ab\u14ac\u14ad\u14ae\u14af\u14b0\u14b1\u14b2\u14b3\u14b4\u14b5\u14b6\u14b7\u14b8\u14b9\u14ba\u14bb\u14bc\u14bd\u14be\u14bf\u14c0\u14c1\u14c2\u14c3\u14c4\u14c5\u14c6\u14c7\u14c8\u14c9\u14ca\u14cb\u14cc\u14cd\u14ce\u14cf\u14d0\u14d1\u14d2\u14d3\u14d4\u14d5\u14d6\u14d7\u14d8\u14d9\u14da\u14db\u14dc\u14dd\u14de\u14df\u14e0\u14e1\u14e2\u14e3\u14e4\u14e5\u14e6\u14e7\u14e8\u14e9\u14ea\u14eb\u14ec\u14ed\u14ee\u14ef\u14f0\u14f1\u14f2\u14f3\u14f4\u14f5\u14f6\u14f7\u14f8\u14f9\u14fa\u14fb\u14fc\u14fd\u14fe\u14ff\u1500\u1501\u1502\u1503\u1504\u1505\u1506\u1507\u1508\u1509\u150a\u150b\u150c\u150d\u150e\u150f\u1510\u1511\u1512\u1513\u1514\u1515\u1516\u1517\u1518\u1519\u151a\u151b\u151c\u151d\u151e\u151f\u1520\u1521\u1522\u1523\u1524\u1525\u1526\u1527\u1528\u1529\u152a\u152b\u152c\u152d\u152e\u152f\u1530\u1531\u1532\u1533\u1534\u1535\u1536\u1537\u1538\u1539\u153a\u153b\u153c\u153d\u153e\u153f\u1540\u1541\u1542\u1543\u1544\u1545\u1546\u1547\u1548\u1549\u154a\u154b\u154c\u154d\u154e\u154f\u1550\u1551\u1552\u1553\u1554\u1555\u1556\u1557\u1558\u1559\u155a\u155b\u155c\u155d\u155e\u155f\u1560\u1561\u1562\u1563\u1564\u1565\u1566\u1567\u1568\u1569\u156a\u156b\u156c\u156d\u156e\u156f\u1570\u1571\u1572\u1573\u1574\u1575\u1576\u1577\u1578\u1579\u157a\u157b\u157c\u157d\u157e\u157f\u1580\u1581\u1582\u1583\u1584\u1585\u1586\u1587\u1588\u1589\u158a\u158b\u158c\u158d\u158e\u158f\u1590\u1591\u1592\u1593\u1594\u1595\u1596\u1597\u1598\u1599\u159a\u159b\u159c\u159d\u159e\u159f\u15a0\u15a1\u15a2\u15a3\u15a4\u15a5\u15a6\u15a7\u15a8\u15a9\u15aa\u15ab\u15ac\u15ad\u15ae\u15af\u15b0\u15b1\u15b2\u15b3\u15b4\u15b5\u15b6\u15b7\u15b8\u15b9\u15ba\u15bb\u15bc\u15bd\u15be\u15bf\u15c0\u15c1\u15c2\u15c3\u15c4\u15c5\u15c6\u15c7\u15c8\u15c9\u15ca\u15cb\u15cc\u15cd\u15ce\u15cf\u15d0\u15d1\u15d2\u15d3\u15d4\u15d5\u15d6\u15d7\u15d8\u15d9\u15da\u15db\u15dc\u15dd\u15de\u15df\u15e0\u15e1\u15e2\u15e3\u15e4\u15e5\u15e6\u15e7\u15e8\u15e9\u15ea\u15eb\u15ec\u15ed\u15ee\u15ef\u15f0\u15f1\u15f2\u15f3\u15f4\u15f5\u15f6\u15f7\u15f8\u15f9\u15fa\u15fb\u15fc\u15fd\u15fe\u15ff\u1600\u1601\u1602\u1603\u1604\u1605\u1606\u1607\u1608\u1609\u160a\u160b\u160c\u160d\u160e\u160f\u1610\u1611\u1612\u1613\u1614\u1615\u1616\u1617\u1618\u1619\u161a\u161b\u161c\u161d\u161e\u161f\u1620\u1621\u1622\u1623\u1624\u1625\u1626\u1627\u1628\u1629\u162a\u162b\u162c\u162d\u162e\u162f\u1630\u1631\u1632\u1633\u1634\u1635\u1636\u1637\u1638\u1639\u163a\u163b\u163c\u163d\u163e\u163f\u1640\u1641\u1642\u1643\u1644\u1645\u1646\u1647\u1648\u1649\u164a\u164b\u164c\u164d\u164e\u164f\u1650\u1651\u1652\u1653\u1654\u1655\u1656\u1657\u1658\u1659\u165a\u165b\u165c\u165d\u165e\u165f\u1660\u1661\u1662\u1663\u1664\u1665\u1666\u1667\u1668\u1669\u166a\u166b\u166c\u166f\u1670\u1671\u1672\u1673\u1674\u1675\u1676\u1677\u1678\u1679\u167a\u167b\u167c\u167d\u167e\u167f\u1681\u1682\u1683\u1684\u1685\u1686\u1687\u1688\u1689\u168a\u168b\u168c\u168d\u168e\u168f\u1690\u1691\u1692\u1693\u1694\u1695\u1696\u1697\u1698\u1699\u169a\u16a0\u16a1\u16a2\u16a3\u16a4\u16a5\u16a6\u16a7\u16a8\u16a9\u16aa\u16ab\u16ac\u16ad\u16ae\u16af\u16b0\u16b1\u16b2\u16b3\u16b4\u16b5\u16b6\u16b7\u16b8\u16b9\u16ba\u16bb\u16bc\u16bd\u16be\u16bf\u16c0\u16c1\u16c2\u16c3\u16c4\u16c5\u16c6\u16c7\u16c8\u16c9\u16ca\u16cb\u16cc\u16cd\u16ce\u16cf\u16d0\u16d1\u16d2\u16d3\u16d4\u16d5\u16d6\u16d7\u16d8\u16d9\u16da\u16db\u16dc\u16dd\u16de\u16df\u16e0\u16e1\u16e2\u16e3\u16e4\u16e5\u16e6\u16e7\u16e8\u16e9\u16ea\u16ee\u16ef\u16f0\u16f1\u16f2\u16f3\u16f4\u16f5\u16f6\u16f7\u16f8\u1700\u1701\u1702\u1703\u1704\u1705\u1706\u1707\u1708\u1709\u170a\u170b\u170c\u170e\u170f\u1710\u1711\u1712\u1713\u1714\u1720\u1721\u1722\u1723\u1724\u1725\u1726\u1727\u1728\u1729\u172a\u172b\u172c\u172d\u172e\u172f\u1730\u1731\u1732\u1733\u1734\u1740\u1741\u1742\u1743\u1744\u1745\u1746\u1747\u1748\u1749\u174a\u174b\u174c\u174d\u174e\u174f\u1750\u1751\u1752\u1753\u1760\u1761\u1762\u1763\u1764\u1765\u1766\u1767\u1768\u1769\u176a\u176b\u176c\u176e\u176f\u1770\u1772\u1773\u1780\u1781\u1782\u1783\u1784\u1785\u1786\u1787\u1788\u1789\u178a\u178b\u178c\u178d\u178e\u178f\u1790\u1791\u1792\u1793\u1794\u1795\u1796\u1797\u1798\u1799\u179a\u179b\u179c\u179d\u179e\u179f\u17a0\u17a1\u17a2\u17a3\u17a4\u17a5\u17a6\u17a7\u17a8\u17a9\u17aa\u17ab\u17ac\u17ad\u17ae\u17af\u17b0\u17b1\u17b2\u17b3\u17b4\u17b5\u17b6\u17b7\u17b8\u17b9\u17ba\u17bb\u17bc\u17bd\u17be\u17bf\u17c0\u17c1\u17c2\u17c3\u17c4\u17c5\u17c6\u17c7\u17c8\u17c9\u17ca\u17cb\u17cc\u17cd\u17ce\u17cf\u17d0\u17d1\u17d2\u17d3\u17d7\u17dc\u17dd\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u180b\u180c\u180d\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819\u1820\u1821\u1822\u1823\u1824\u1825\u1826\u1827\u1828\u1829\u182a\u182b\u182c\u182d\u182e\u182f\u1830\u1831\u1832\u1833\u1834\u1835\u1836\u1837\u1838\u1839\u183a\u183b\u183c\u183d\u183e\u183f\u1840\u1841\u1842\u1843\u1844\u1845\u1846\u1847\u1848\u1849\u184a\u184b\u184c\u184d\u184e\u184f\u1850\u1851\u1852\u1853\u1854\u1855\u1856\u1857\u1858\u1859\u185a\u185b\u185c\u185d\u185e\u185f\u1860\u1861\u1862\u1863\u1864\u1865\u1866\u1867\u1868\u1869\u186a\u186b\u186c\u186d\u186e\u186f\u1870\u1871\u1872\u1873\u1874\u1875\u1876\u1877\u1880\u1881\u1882\u1883\u1884\u1885\u1886\u1887\u1888\u1889\u188a\u188b\u188c\u188d\u188e\u188f\u1890\u1891\u1892\u1893\u1894\u1895\u1896\u1897\u1898\u1899\u189a\u189b\u189c\u189d\u189e\u189f\u18a0\u18a1\u18a2\u18a3\u18a4\u18a5\u18a6\u18a7\u18a8\u18a9\u18aa\u18b0\u18b1\u18b2\u18b3\u18b4\u18b5\u18b6\u18b7\u18b8\u18b9\u18ba\u18bb\u18bc\u18bd\u18be\u18bf\u18c0\u18c1\u18c2\u18c3\u18c4\u18c5\u18c6\u18c7\u18c8\u18c9\u18ca\u18cb\u18cc\u18cd\u18ce\u18cf\u18d0\u18d1\u18d2\u18d3\u18d4\u18d5\u18d6\u18d7\u18d8\u18d9\u18da\u18db\u18dc\u18dd\u18de\u18df\u18e0\u18e1\u18e2\u18e3\u18e4\u18e5\u18e6\u18e7\u18e8\u18e9\u18ea\u18eb\u18ec\u18ed\u18ee\u18ef\u18f0\u18f1\u18f2\u18f3\u18f4\u18f5\u1900\u1901\u1902\u1903\u1904\u1905\u1906\u1907\u1908\u1909\u190a\u190b\u190c\u190d\u190e\u190f\u1910\u1911\u1912\u1913\u1914\u1915\u1916\u1917\u1918\u1919\u191a\u191b\u191c\u191d\u191e\u1920\u1921\u1922\u1923\u1924\u1925\u1926\u1927\u1928\u1929\u192a\u192b\u1930\u1931\u1932\u1933\u1934\u1935\u1936\u1937\u1938\u1939\u193a\u193b\u1946\u1947\u1948\u1949\u194a\u194b\u194c\u194d\u194e\u194f\u1950\u1951\u1952\u1953\u1954\u1955\u1956\u1957\u1958\u1959\u195a\u195b\u195c\u195d\u195e\u195f\u1960\u1961\u1962\u1963\u1964\u1965\u1966\u1967\u1968\u1969\u196a\u196b\u196c\u196d\u1970\u1971\u1972\u1973\u1974\u1980\u1981\u1982\u1983\u1984\u1985\u1986\u1987\u1988\u1989\u198a\u198b\u198c\u198d\u198e\u198f\u1990\u1991\u1992\u1993\u1994\u1995\u1996\u1997\u1998\u1999\u199a\u199b\u199c\u199d\u199e\u199f\u19a0\u19a1\u19a2\u19a3\u19a4\u19a5\u19a6\u19a7\u19a8\u19a9\u19aa\u19ab\u19b0\u19b1\u19b2\u19b3\u19b4\u19b5\u19b6\u19b7\u19b8\u19b9\u19ba\u19bb\u19bc\u19bd\u19be\u19bf\u19c0\u19c1\u19c2\u19c3\u19c4\u19c5\u19c6\u19c7\u19c8\u19c9\u19d0\u19d1\u19d2\u19d3\u19d4\u19d5\u19d6\u19d7\u19d8\u19d9\u19da\u1a00\u1a01\u1a02\u1a03\u1a04\u1a05\u1a06\u1a07\u1a08\u1a09\u1a0a\u1a0b\u1a0c\u1a0d\u1a0e\u1a0f\u1a10\u1a11\u1a12\u1a13\u1a14\u1a15\u1a16\u1a17\u1a18\u1a19\u1a1a\u1a1b\u1a20\u1a21\u1a22\u1a23\u1a24\u1a25\u1a26\u1a27\u1a28\u1a29\u1a2a\u1a2b\u1a2c\u1a2d\u1a2e\u1a2f\u1a30\u1a31\u1a32\u1a33\u1a34\u1a35\u1a36\u1a37\u1a38\u1a39\u1a3a\u1a3b\u1a3c\u1a3d\u1a3e\u1a3f\u1a40\u1a41\u1a42\u1a43\u1a44\u1a45\u1a46\u1a47\u1a48\u1a49\u1a4a\u1a4b\u1a4c\u1a4d\u1a4e\u1a4f\u1a50\u1a51\u1a52\u1a53\u1a54\u1a55\u1a56\u1a57\u1a58\u1a59\u1a5a\u1a5b\u1a5c\u1a5d\u1a5e\u1a60\u1a61\u1a62\u1a63\u1a64\u1a65\u1a66\u1a67\u1a68\u1a69\u1a6a\u1a6b\u1a6c\u1a6d\u1a6e\u1a6f\u1a70\u1a71\u1a72\u1a73\u1a74\u1a75\u1a76\u1a77\u1a78\u1a79\u1a7a\u1a7b\u1a7c\u1a7f\u1a80\u1a81\u1a82\u1a83\u1a84\u1a85\u1a86\u1a87\u1a88\u1a89\u1a90\u1a91\u1a92\u1a93\u1a94\u1a95\u1a96\u1a97\u1a98\u1a99\u1aa7\u1ab0\u1ab1\u1ab2\u1ab3\u1ab4\u1ab5\u1ab6\u1ab7\u1ab8\u1ab9\u1aba\u1abb\u1abc\u1abd\u1b00\u1b01\u1b02\u1b03\u1b04\u1b05\u1b06\u1b07\u1b08\u1b09\u1b0a\u1b0b\u1b0c\u1b0d\u1b0e\u1b0f\u1b10\u1b11\u1b12\u1b13\u1b14\u1b15\u1b16\u1b17\u1b18\u1b19\u1b1a\u1b1b\u1b1c\u1b1d\u1b1e\u1b1f\u1b20\u1b21\u1b22\u1b23\u1b24\u1b25\u1b26\u1b27\u1b28\u1b29\u1b2a\u1b2b\u1b2c\u1b2d\u1b2e\u1b2f\u1b30\u1b31\u1b32\u1b33\u1b34\u1b35\u1b36\u1b37\u1b38\u1b39\u1b3a\u1b3b\u1b3c\u1b3d\u1b3e\u1b3f\u1b40\u1b41\u1b42\u1b43\u1b44\u1b45\u1b46\u1b47\u1b48\u1b49\u1b4a\u1b4b\u1b50\u1b51\u1b52\u1b53\u1b54\u1b55\u1b56\u1b57\u1b58\u1b59\u1b6b\u1b6c\u1b6d\u1b6e\u1b6f\u1b70\u1b71\u1b72\u1b73\u1b80\u1b81\u1b82\u1b83\u1b84\u1b85\u1b86\u1b87\u1b88\u1b89\u1b8a\u1b8b\u1b8c\u1b8d\u1b8e\u1b8f\u1b90\u1b91\u1b92\u1b93\u1b94\u1b95\u1b96\u1b97\u1b98\u1b99\u1b9a\u1b9b\u1b9c\u1b9d\u1b9e\u1b9f\u1ba0\u1ba1\u1ba2\u1ba3\u1ba4\u1ba5\u1ba6\u1ba7\u1ba8\u1ba9\u1baa\u1bab\u1bac\u1bad\u1bae\u1baf\u1bb0\u1bb1\u1bb2\u1bb3\u1bb4\u1bb5\u1bb6\u1bb7\u1bb8\u1bb9\u1bba\u1bbb\u1bbc\u1bbd\u1bbe\u1bbf\u1bc0\u1bc1\u1bc2\u1bc3\u1bc4\u1bc5\u1bc6\u1bc7\u1bc8\u1bc9\u1bca\u1bcb\u1bcc\u1bcd\u1bce\u1bcf\u1bd0\u1bd1\u1bd2\u1bd3\u1bd4\u1bd5\u1bd6\u1bd7\u1bd8\u1bd9\u1bda\u1bdb\u1bdc\u1bdd\u1bde\u1bdf\u1be0\u1be1\u1be2\u1be3\u1be4\u1be5\u1be6\u1be7\u1be8\u1be9\u1bea\u1beb\u1bec\u1bed\u1bee\u1bef\u1bf0\u1bf1\u1bf2\u1bf3\u1c00\u1c01\u1c02\u1c03\u1c04\u1c05\u1c06\u1c07\u1c08\u1c09\u1c0a\u1c0b\u1c0c\u1c0d\u1c0e\u1c0f\u1c10\u1c11\u1c12\u1c13\u1c14\u1c15\u1c16\u1c17\u1c18\u1c19\u1c1a\u1c1b\u1c1c\u1c1d\u1c1e\u1c1f\u1c20\u1c21\u1c22\u1c23\u1c24\u1c25\u1c26\u1c27\u1c28\u1c29\u1c2a\u1c2b\u1c2c\u1c2d\u1c2e\u1c2f\u1c30\u1c31\u1c32\u1c33\u1c34\u1c35\u1c36\u1c37\u1c40\u1c41\u1c42\u1c43\u1c44\u1c45\u1c46\u1c47\u1c48\u1c49\u1c4d\u1c4e\u1c4f\u1c50\u1c51\u1c52\u1c53\u1c54\u1c55\u1c56\u1c57\u1c58\u1c59\u1c5a\u1c5b\u1c5c\u1c5d\u1c5e\u1c5f\u1c60\u1c61\u1c62\u1c63\u1c64\u1c65\u1c66\u1c67\u1c68\u1c69\u1c6a\u1c6b\u1c6c\u1c6d\u1c6e\u1c6f\u1c70\u1c71\u1c72\u1c73\u1c74\u1c75\u1c76\u1c77\u1c78\u1c79\u1c7a\u1c7b\u1c7c\u1c7d\u1c80\u1c81\u1c82\u1c83\u1c84\u1c85\u1c86\u1c87\u1c88\u1cd0\u1cd1\u1cd2\u1cd4\u1cd5\u1cd6\u1cd7\u1cd8\u1cd9\u1cda\u1cdb\u1cdc\u1cdd\u1cde\u1cdf\u1ce0\u1ce1\u1ce2\u1ce3\u1ce4\u1ce5\u1ce6\u1ce7\u1ce8\u1ce9\u1cea\u1ceb\u1cec\u1ced\u1cee\u1cef\u1cf0\u1cf1\u1cf2\u1cf3\u1cf4\u1cf5\u1cf6\u1cf8\u1cf9\u1d00\u1d01\u1d02\u1d03\u1d04\u1d05\u1d06\u1d07\u1d08\u1d09\u1d0a\u1d0b\u1d0c\u1d0d\u1d0e\u1d0f\u1d10\u1d11\u1d12\u1d13\u1d14\u1d15\u1d16\u1d17\u1d18\u1d19\u1d1a\u1d1b\u1d1c\u1d1d\u1d1e\u1d1f\u1d20\u1d21\u1d22\u1d23\u1d24\u1d25\u1d26\u1d27\u1d28\u1d29\u1d2a\u1d2b\u1d2c\u1d2d\u1d2e\u1d2f\u1d30\u1d31\u1d32\u1d33\u1d34\u1d35\u1d36\u1d37\u1d38\u1d39\u1d3a\u1d3b\u1d3c\u1d3d\u1d3e\u1d3f\u1d40\u1d41\u1d42\u1d43\u1d44\u1d45\u1d46\u1d47\u1d48\u1d49\u1d4a\u1d4b\u1d4c\u1d4d\u1d4e\u1d4f\u1d50\u1d51\u1d52\u1d53\u1d54\u1d55\u1d56\u1d57\u1d58\u1d59\u1d5a\u1d5b\u1d5c\u1d5d\u1d5e\u1d5f\u1d60\u1d61\u1d62\u1d63\u1d64\u1d65\u1d66\u1d67\u1d68\u1d69\u1d6a\u1d6b\u1d6c\u1d6d\u1d6e\u1d6f\u1d70\u1d71\u1d72\u1d73\u1d74\u1d75\u1d76\u1d77\u1d78\u1d79\u1d7a\u1d7b\u1d7c\u1d7d\u1d7e\u1d7f\u1d80\u1d81\u1d82\u1d83\u1d84\u1d85\u1d86\u1d87\u1d88\u1d89\u1d8a\u1d8b\u1d8c\u1d8d\u1d8e\u1d8f\u1d90\u1d91\u1d92\u1d93\u1d94\u1d95\u1d96\u1d97\u1d98\u1d99\u1d9a\u1d9b\u1d9c\u1d9d\u1d9e\u1d9f\u1da0\u1da1\u1da2\u1da3\u1da4\u1da5\u1da6\u1da7\u1da8\u1da9\u1daa\u1dab\u1dac\u1dad\u1dae\u1daf\u1db0\u1db1\u1db2\u1db3\u1db4\u1db5\u1db6\u1db7\u1db8\u1db9\u1dba\u1dbb\u1dbc\u1dbd\u1dbe\u1dbf\u1dc0\u1dc1\u1dc2\u1dc3\u1dc4\u1dc5\u1dc6\u1dc7\u1dc8\u1dc9\u1dca\u1dcb\u1dcc\u1dcd\u1dce\u1dcf\u1dd0\u1dd1\u1dd2\u1dd3\u1dd4\u1dd5\u1dd6\u1dd7\u1dd8\u1dd9\u1dda\u1ddb\u1ddc\u1ddd\u1dde\u1ddf\u1de0\u1de1\u1de2\u1de3\u1de4\u1de5\u1de6\u1de7\u1de8\u1de9\u1dea\u1deb\u1dec\u1ded\u1dee\u1def\u1df0\u1df1\u1df2\u1df3\u1df4\u1df5\u1dfb\u1dfc\u1dfd\u1dfe\u1dff\u1e00\u1e01\u1e02\u1e03\u1e04\u1e05\u1e06\u1e07\u1e08\u1e09\u1e0a\u1e0b\u1e0c\u1e0d\u1e0e\u1e0f\u1e10\u1e11\u1e12\u1e13\u1e14\u1e15\u1e16\u1e17\u1e18\u1e19\u1e1a\u1e1b\u1e1c\u1e1d\u1e1e\u1e1f\u1e20\u1e21\u1e22\u1e23\u1e24\u1e25\u1e26\u1e27\u1e28\u1e29\u1e2a\u1e2b\u1e2c\u1e2d\u1e2e\u1e2f\u1e30\u1e31\u1e32\u1e33\u1e34\u1e35\u1e36\u1e37\u1e38\u1e39\u1e3a\u1e3b\u1e3c\u1e3d\u1e3e\u1e3f\u1e40\u1e41\u1e42\u1e43\u1e44\u1e45\u1e46\u1e47\u1e48\u1e49\u1e4a\u1e4b\u1e4c\u1e4d\u1e4e\u1e4f\u1e50\u1e51\u1e52\u1e53\u1e54\u1e55\u1e56\u1e57\u1e58\u1e59\u1e5a\u1e5b\u1e5c\u1e5d\u1e5e\u1e5f\u1e60\u1e61\u1e62\u1e63\u1e64\u1e65\u1e66\u1e67\u1e68\u1e69\u1e6a\u1e6b\u1e6c\u1e6d\u1e6e\u1e6f\u1e70\u1e71\u1e72\u1e73\u1e74\u1e75\u1e76\u1e77\u1e78\u1e79\u1e7a\u1e7b\u1e7c\u1e7d\u1e7e\u1e7f\u1e80\u1e81\u1e82\u1e83\u1e84\u1e85\u1e86\u1e87\u1e88\u1e89\u1e8a\u1e8b\u1e8c\u1e8d\u1e8e\u1e8f\u1e90\u1e91\u1e92\u1e93\u1e94\u1e95\u1e96\u1e97\u1e98\u1e99\u1e9b\u1e9c\u1e9d\u1e9e\u1e9f\u1ea0\u1ea1\u1ea2\u1ea3\u1ea4\u1ea5\u1ea6\u1ea7\u1ea8\u1ea9\u1eaa\u1eab\u1eac\u1ead\u1eae\u1eaf\u1eb0\u1eb1\u1eb2\u1eb3\u1eb4\u1eb5\u1eb6\u1eb7\u1eb8\u1eb9\u1eba\u1ebb\u1ebc\u1ebd\u1ebe\u1ebf\u1ec0\u1ec1\u1ec2\u1ec3\u1ec4\u1ec5\u1ec6\u1ec7\u1ec8\u1ec9\u1eca\u1ecb\u1ecc\u1ecd\u1ece\u1ecf\u1ed0\u1ed1\u1ed2\u1ed3\u1ed4\u1ed5\u1ed6\u1ed7\u1ed8\u1ed9\u1eda\u1edb\u1edc\u1edd\u1ede\u1edf\u1ee0\u1ee1\u1ee2\u1ee3\u1ee4\u1ee5\u1ee6\u1ee7\u1ee8\u1ee9\u1eea\u1eeb\u1eec\u1eed\u1eee\u1eef\u1ef0\u1ef1\u1ef2\u1ef3\u1ef4\u1ef5\u1ef6\u1ef7\u1ef8\u1ef9\u1efa\u1efb\u1efc\u1efd\u1efe\u1eff\u1f00\u1f01\u1f02\u1f03\u1f04\u1f05\u1f06\u1f07\u1f08\u1f09\u1f0a\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1f10\u1f11\u1f12\u1f13\u1f14\u1f15\u1f18\u1f19\u1f1a\u1f1b\u1f1c\u1f1d\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u1f27\u1f28\u1f29\u1f2a\u1f2b\u1f2c\u1f2d\u1f2e\u1f2f\u1f30\u1f31\u1f32\u1f33\u1f34\u1f35\u1f36\u1f37\u1f38\u1f39\u1f3a\u1f3b\u1f3c\u1f3d\u1f3e\u1f3f\u1f40\u1f41\u1f42\u1f43\u1f44\u1f45\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f50\u1f51\u1f52\u1f53\u1f54\u1f55\u1f56\u1f57\u1f59\u1f5b\u1f5d\u1f5f\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u1f66\u1f67\u1f68\u1f69\u1f6a\u1f6b\u1f6c\u1f6d\u1f6e\u1f6f\u1f70\u1f71\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u1f7b\u1f7c\u1f7d\u1f80\u1f81\u1f82\u1f83\u1f84\u1f85\u1f86\u1f87\u1f88\u1f89\u1f8a\u1f8b\u1f8c\u1f8d\u1f8e\u1f8f\u1f90\u1f91\u1f92\u1f93\u1f94\u1f95\u1f96\u1f97\u1f98\u1f99\u1f9a\u1f9b\u1f9c\u1f9d\u1f9e\u1f9f\u1fa0\u1fa1\u1fa2\u1fa3\u1fa4\u1fa5\u1fa6\u1fa7\u1fa8\u1fa9\u1faa\u1fab\u1fac\u1fad\u1fae\u1faf\u1fb0\u1fb1\u1fb2\u1fb3\u1fb4\u1fb6\u1fb7\u1fb8\u1fb9\u1fba\u1fbb\u1fbc\u1fbe\u1fc2\u1fc3\u1fc4\u1fc6\u1fc7\u1fc8\u1fc9\u1fca\u1fcb\u1fcc\u1fd0\u1fd1\u1fd2\u1fd3\u1fd6\u1fd7\u1fd8\u1fd9\u1fda\u1fdb\u1fe0\u1fe1\u1fe2\u1fe3\u1fe4\u1fe5\u1fe6\u1fe7\u1fe8\u1fe9\u1fea\u1feb\u1fec\u1ff2\u1ff3\u1ff4\u1ff6\u1ff7\u1ff8\u1ff9\u1ffa\u1ffb\u1ffc\u203f\u2040\u2054\u2071\u207f\u2090\u2091\u2092\u2093\u2094\u2095\u2096\u2097\u2098\u2099\u209a\u209b\u209c\u20d0\u20d1\u20d2\u20d3\u20d4\u20d5\u20d6\u20d7\u20d8\u20d9\u20da\u20db\u20dc\u20e1\u20e5\u20e6\u20e7\u20e8\u20e9\u20ea\u20eb\u20ec\u20ed\u20ee\u20ef\u20f0\u2102\u2107\u210a\u210b\u210c\u210d\u210e\u210f\u2110\u2111\u2112\u2113\u2115\u2118\u2119\u211a\u211b\u211c\u211d\u2124\u2126\u2128\u212a\u212b\u212c\u212d\u212e\u212f\u2130\u2131\u2132\u2133\u2134\u2135\u2136\u2137\u2138\u2139\u213c\u213d\u213e\u213f\u2145\u2146\u2147\u2148\u2149\u214e\u2160\u2164\u2169\u216c\u216d\u216e\u216f\u2170\u2174\u2179\u217c\u217d\u217e\u217f\u2180\u2181\u2182\u2183\u2184\u2185\u2186\u2187\u2188\u2c00\u2c01\u2c02\u2c03\u2c04\u2c05\u2c06\u2c07\u2c08\u2c09\u2c0a\u2c0b\u2c0c\u2c0d\u2c0e\u2c0f\u2c10\u2c11\u2c12\u2c13\u2c14\u2c15\u2c16\u2c17\u2c18\u2c19\u2c1a\u2c1b\u2c1c\u2c1d\u2c1e\u2c1f\u2c20\u2c21\u2c22\u2c23\u2c24\u2c25\u2c26\u2c27\u2c28\u2c29\u2c2a\u2c2b\u2c2c\u2c2d\u2c2e\u2c30\u2c31\u2c32\u2c33\u2c34\u2c35\u2c36\u2c37\u2c38\u2c39\u2c3a\u2c3b\u2c3c\u2c3d\u2c3e\u2c3f\u2c40\u2c41\u2c42\u2c43\u2c44\u2c45\u2c46\u2c47\u2c48\u2c49\u2c4a\u2c4b\u2c4c\u2c4d\u2c4e\u2c4f\u2c50\u2c51\u2c52\u2c53\u2c54\u2c55\u2c56\u2c57\u2c58\u2c59\u2c5a\u2c5b\u2c5c\u2c5d\u2c5e\u2c60\u2c61\u2c62\u2c63\u2c64\u2c65\u2c66\u2c67\u2c68\u2c69\u2c6a\u2c6b\u2c6c\u2c6d\u2c6e\u2c6f\u2c70\u2c71\u2c72\u2c73\u2c74\u2c75\u2c76\u2c77\u2c78\u2c79\u2c7a\u2c7b\u2c7c\u2c7d\u2c7e\u2c7f\u2c80\u2c81\u2c82\u2c83\u2c84\u2c85\u2c86\u2c87\u2c88\u2c89\u2c8a\u2c8b\u2c8c\u2c8d\u2c8e\u2c8f\u2c90\u2c91\u2c92\u2c93\u2c94\u2c95\u2c96\u2c97\u2c98\u2c99\u2c9a\u2c9b\u2c9c\u2c9d\u2c9e\u2c9f\u2ca0\u2ca1\u2ca2\u2ca3\u2ca4\u2ca5\u2ca6\u2ca7\u2ca8\u2ca9\u2caa\u2cab\u2cac\u2cad\u2cae\u2caf\u2cb0\u2cb1\u2cb2\u2cb3\u2cb4\u2cb5\u2cb6\u2cb7\u2cb8\u2cb9\u2cba\u2cbb\u2cbc\u2cbd\u2cbe\u2cbf\u2cc0\u2cc1\u2cc2\u2cc3\u2cc4\u2cc5\u2cc6\u2cc7\u2cc8\u2cc9\u2cca\u2ccb\u2ccc\u2ccd\u2cce\u2ccf\u2cd0\u2cd1\u2cd2\u2cd3\u2cd4\u2cd5\u2cd6\u2cd7\u2cd8\u2cd9\u2cda\u2cdb\u2cdc\u2cdd\u2cde\u2cdf\u2ce0\u2ce1\u2ce2\u2ce3\u2ce4\u2ceb\u2cec\u2ced\u2cee\u2cef\u2cf0\u2cf1\u2cf2\u2cf3\u2d00\u2d01\u2d02\u2d03\u2d04\u2d05\u2d06\u2d07\u2d08\u2d09\u2d0a\u2d0b\u2d0c\u2d0d\u2d0e\u2d0f\u2d10\u2d11\u2d12\u2d13\u2d14\u2d15\u2d16\u2d17\u2d18\u2d19\u2d1a\u2d1b\u2d1c\u2d1d\u2d1e\u2d1f\u2d20\u2d21\u2d22\u2d23\u2d24\u2d25\u2d27\u2d2d\u2d30\u2d31\u2d32\u2d33\u2d34\u2d35\u2d36\u2d37\u2d38\u2d39\u2d3a\u2d3b\u2d3c\u2d3d\u2d3e\u2d3f\u2d40\u2d41\u2d42\u2d43\u2d44\u2d45\u2d46\u2d47\u2d48\u2d49\u2d4a\u2d4b\u2d4c\u2d4d\u2d4e\u2d4f\u2d50\u2d51\u2d52\u2d53\u2d54\u2d55\u2d56\u2d57\u2d58\u2d59\u2d5a\u2d5b\u2d5c\u2d5d\u2d5e\u2d5f\u2d60\u2d61\u2d62\u2d63\u2d64\u2d65\u2d66\u2d67\u2d6f\u2d7f\u2d80\u2d81\u2d82\u2d83\u2d84\u2d85\u2d86\u2d87\u2d88\u2d89\u2d8a\u2d8b\u2d8c\u2d8d\u2d8e\u2d8f\u2d90\u2d91\u2d92\u2d93\u2d94\u2d95\u2d96\u2da0\u2da1\u2da2\u2da3\u2da4\u2da5\u2da6\u2da8\u2da9\u2daa\u2dab\u2dac\u2dad\u2dae\u2db0\u2db1\u2db2\u2db3\u2db4\u2db5\u2db6\u2db8\u2db9\u2dba\u2dbb\u2dbc\u2dbd\u2dbe\u2dc0\u2dc1\u2dc2\u2dc3\u2dc4\u2dc5\u2dc6\u2dc8\u2dc9\u2dca\u2dcb\u2dcc\u2dcd\u2dce\u2dd0\u2dd1\u2dd2\u2dd3\u2dd4\u2dd5\u2dd6\u2dd8\u2dd9\u2dda\u2ddb\u2ddc\u2ddd\u2dde\u2de0\u2de1\u2de2\u2de3\u2de4\u2de5\u2de6\u2de7\u2de8\u2de9\u2dea\u2deb\u2dec\u2ded\u2dee\u2def\u2df0\u2df1\u2df2\u2df3\u2df4\u2df5\u2df6\u2df7\u2df8\u2df9\u2dfa\u2dfb\u2dfc\u2dfd\u2dfe\u2dff\u2e2f\u3005\u3006\u3007\u3021\u3022\u3023\u3024\u3025\u3026\u3027\u3028\u3029\u302a\u302b\u302c\u302d\u302e\u302f\u3031\u3032\u3033\u3034\u3035\u3038\u3039\u303a\u303b\u303c\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048\u3049\u304a\u304b\u304c\u304d\u304e\u304f\u3050\u3051\u3052\u3053\u3054\u3055\u3056\u3057\u3058\u3059\u305a\u305b\u305c\u305d\u305e\u305f\u3060\u3061\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306a\u306b\u306c\u306d\u306e\u306f\u3070\u3071\u3072\u3073\u3074\u3075\u3076\u3077\u3078\u3079\u307a\u307b\u307c\u307d\u307e\u307f\u3080\u3081\u3082\u3083\u3084\u3085\u3086\u3087\u3088\u3089\u308a\u308b\u308c\u308d\u308e\u308f\u3090\u3091\u3092\u3093\u3094\u3095\u3096\u3099\u309a\u309d\u309e\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8\u30a9\u30aa\u30ab\u30ac\u30ad\u30ae\u30af\u30b0\u30b1\u30b2\u30b3\u30b4\u30b5\u30b6\u30b7\u30b8\u30b9\u30ba\u30bb\u30bc\u30bd\u30be\u30bf\u30c0\u30c1\u30c2\u30c3\u30c4\u30c5\u30c6\u30c7\u30c8\u30c9\u30ca\u30cb\u30cc\u30cd\u30ce\u30cf\u30d0\u30d1\u30d2\u30d3\u30d4\u30d5\u30d6\u30d7\u30d8\u30d9\u30da\u30db\u30dc\u30dd\u30de\u30df\u30e0\u30e1\u30e2\u30e3\u30e4\u30e5\u30e6\u30e7\u30e8\u30e9\u30ea\u30eb\u30ec\u30ed\u30ee\u30ef\u30f0\u30f1\u30f2\u30f3\u30f4\u30f5\u30f6\u30f7\u30f8\u30f9\u30fa\u30fc\u30fd\u30fe\u3105\u3106\u3107\u3108\u3109\u310a\u310b\u310c\u310d\u310e\u310f\u3110\u3111\u3112\u3113\u3114\u3115\u3116\u3117\u3118\u3119\u311a\u311b\u311c\u311d\u311e\u311f\u3120\u3121\u3122\u3123\u3124\u3125\u3126\u3127\u3128\u3129\u312a\u312b\u312c\u312d\u3131\u3132\u3133\u3134\u3135\u3136\u3137\u3138\u3139\u313a\u313b\u313c\u313d\u313e\u313f\u3140\u3141\u3142\u3143\u3144\u3145\u3146\u3147\u3148\u3149\u314a\u314b\u314c\u314d\u314e\u314f\u3150\u3151\u3152\u3153\u3154\u3155\u3156\u3157\u3158\u3159\u315a\u315b\u315c\u315d\u315e\u315f\u3160\u3161\u3162\u3163\u3164\u3165\u3166\u3167\u3168\u3169\u316a\u316b\u316c\u316d\u316e\u316f\u3170\u3171\u3172\u3173\u3174\u3175\u3176\u3177\u3178\u3179\u317a\u317b\u317c\u317d\u317e\u317f\u3180\u3181\u3182\u3183\u3184\u3185\u3186\u3187\u3188\u3189\u318a\u318b\u318c\u318d\u318e\u31a0\u31a1\u31a2\u31a3\u31a4\u31a5\u31a6\u31a7\u31a8\u31a9\u31aa\u31ab\u31ac\u31ad\u31ae\u31af\u31b0\u31b1\u31b2\u31b3\u31b4\u31b5\u31b6\u31b7\u31b8\u31b9\u31ba\u31f0\u31f1\u31f2\u31f3\u31f4\u31f5\u31f6\u31f7\u31f8\u31f9\u31fa\u31fb\u31fc\u31fd\u31fe\u31ff\u3400\u3401\u3402\u3403\u3404\u3405\u3406\u3407\u3408\u3409\u340a\u340b\u340c\u340d\u340e\u340f\u3410\u3411\u3412\u3413\u3414\u3415\u3416\u3417\u3418\u3419\u341a\u341b\u341c\u341d\u341e\u341f\u3420\u3421\u3422\u3423\u3424\u3425\u3426\u3427\u3428\u3429\u342a\u342b\u342c\u342d\u342e\u342f\u3430\u3431\u3432\u3433\u3434\u3435\u3436\u3437\u3438\u3439\u343a\u343b\u343c\u343d\u343e\u343f\u3440\u3441\u3442\u3443\u3444\u3445\u3446\u3447\u3448\u3449\u344a\u344b\u344c\u344d\u344e\u344f\u3450\u3451\u3452\u3453\u3454\u3455\u3456\u3457\u3458\u3459\u345a\u345b\u345c\u345d\u345e\u345f\u3460\u3461\u3462\u3463\u3464\u3465\u3466\u3467\u3468\u3469\u346a\u346b\u346c\u346d\u346e\u346f\u3470\u3471\u3472\u3473\u3474\u3475\u3476\u3477\u3478\u3479\u347a\u347b\u347c\u347d\u347e\u347f\u3480\u3481\u3482\u3483\u3484\u3485\u3486\u3487\u3488\u3489\u348a\u348b\u348c\u348d\u348e\u348f\u3490\u3491\u3492\u3493\u3494\u3495\u3496\u3497\u3498\u3499\u349a\u349b\u349c\u349d\u349e\u349f\u34a0\u34a1\u34a2\u34a3\u34a4\u34a5\u34a6\u34a7\u34a8\u34a9\u34aa\u34ab\u34ac\u34ad\u34ae\u34af\u34b0\u34b1\u34b2\u34b3\u34b4\u34b5\u34b6\u34b7\u34b8\u34b9\u34ba\u34bb\u34bc\u34bd\u34be\u34bf\u34c0\u34c1\u34c2\u34c3\u34c4\u34c5\u34c6\u34c7\u34c8\u34c9\u34ca\u34cb\u34cc\u34cd\u34ce\u34cf\u34d0\u34d1\u34d2\u34d3\u34d4\u34d5\u34d6\u34d7\u34d8\u34d9\u34da\u34db\u34dc\u34dd\u34de\u34df\u34e0\u34e1\u34e2\u34e3\u34e4\u34e5\u34e6\u34e7\u34e8\u34e9\u34ea\u34eb\u34ec\u34ed\u34ee\u34ef\u34f0\u34f1\u34f2\u34f3\u34f4\u34f5\u34f6\u34f7\u34f8\u34f9\u34fa\u34fb\u34fc\u34fd\u34fe\u34ff\u3500\u3501\u3502\u3503\u3504\u3505\u3506\u3507\u3508\u3509\u350a\u350b\u350c\u350d\u350e\u350f\u3510\u3511\u3512\u3513\u3514\u3515\u3516\u3517\u3518\u3519\u351a\u351b\u351c\u351d\u351e\u351f\u3520\u3521\u3522\u3523\u3524\u3525\u3526\u3527\u3528\u3529\u352a\u352b\u352c\u352d\u352e\u352f\u3530\u3531\u3532\u3533\u3534\u3535\u3536\u3537\u3538\u3539\u353a\u353b\u353c\u353d\u353e\u353f\u3540\u3541\u3542\u3543\u3544\u3545\u3546\u3547\u3548\u3549\u354a\u354b\u354c\u354d\u354e\u354f\u3550\u3551\u3552\u3553\u3554\u3555\u3556\u3557\u3558\u3559\u355a\u355b\u355c\u355d\u355e\u355f\u3560\u3561\u3562\u3563\u3564\u3565\u3566\u3567\u3568\u3569\u356a\u356b\u356c\u356d\u356e\u356f\u3570\u3571\u3572\u3573\u3574\u3575\u3576\u3577\u3578\u3579\u357a\u357b\u357c\u357d\u357e\u357f\u3580\u3581\u3582\u3583\u3584\u3585\u3586\u3587\u3588\u3589\u358a\u358b\u358c\u358d\u358e\u358f\u3590\u3591\u3592\u3593\u3594\u3595\u3596\u3597\u3598\u3599\u359a\u359b\u359c\u359d\u359e\u359f\u35a0\u35a1\u35a2\u35a3\u35a4\u35a5\u35a6\u35a7\u35a8\u35a9\u35aa\u35ab\u35ac\u35ad\u35ae\u35af\u35b0\u35b1\u35b2\u35b3\u35b4\u35b5\u35b6\u35b7\u35b8\u35b9\u35ba\u35bb\u35bc\u35bd\u35be\u35bf\u35c0\u35c1\u35c2\u35c3\u35c4\u35c5\u35c6\u35c7\u35c8\u35c9\u35ca\u35cb\u35cc\u35cd\u35ce\u35cf\u35d0\u35d1\u35d2\u35d3\u35d4\u35d5\u35d6\u35d7\u35d8\u35d9\u35da\u35db\u35dc\u35dd\u35de\u35df\u35e0\u35e1\u35e2\u35e3\u35e4\u35e5\u35e6\u35e7\u35e8\u35e9\u35ea\u35eb\u35ec\u35ed\u35ee\u35ef\u35f0\u35f1\u35f2\u35f3\u35f4\u35f5\u35f6\u35f7\u35f8\u35f9\u35fa\u35fb\u35fc\u35fd\u35fe\u35ff\u3600\u3601\u3602\u3603\u3604\u3605\u3606\u3607\u3608\u3609\u360a\u360b\u360c\u360d\u360e\u360f\u3610\u3611\u3612\u3613\u3614\u3615\u3616\u3617\u3618\u3619\u361a\u361b\u361c\u361d\u361e\u361f\u3620\u3621\u3622\u3623\u3624\u3625\u3626\u3627\u3628\u3629\u362a\u362b\u362c\u362d\u362e\u362f\u3630\u3631\u3632\u3633\u3634\u3635\u3636\u3637\u3638\u3639\u363a\u363b\u363c\u363d\u363e\u363f\u3640\u3641\u3642\u3643\u3644\u3645\u3646\u3647\u3648\u3649\u364a\u364b\u364c\u364d\u364e\u364f\u3650\u3651\u3652\u3653\u3654\u3655\u3656\u3657\u3658\u3659\u365a\u365b\u365c\u365d\u365e\u365f\u3660\u3661\u3662\u3663\u3664\u3665\u3666\u3667\u3668\u3669\u366a\u366b\u366c\u366d\u366e\u366f\u3670\u3671\u3672\u3673\u3674\u3675\u3676\u3677\u3678\u3679\u367a\u367b\u367c\u367d\u367e\u367f\u3680\u3681\u3682\u3683\u3684\u3685\u3686\u3687\u3688\u3689\u368a\u368b\u368c\u368d\u368e\u368f\u3690\u3691\u3692\u3693\u3694\u3695\u3696\u3697\u3698\u3699\u369a\u369b\u369c\u369d\u369e\u369f\u36a0\u36a1\u36a2\u36a3\u36a4\u36a5\u36a6\u36a7\u36a8\u36a9\u36aa\u36ab\u36ac\u36ad\u36ae\u36af\u36b0\u36b1\u36b2\u36b3\u36b4\u36b5\u36b6\u36b7\u36b8\u36b9\u36ba\u36bb\u36bc\u36bd\u36be\u36bf\u36c0\u36c1\u36c2\u36c3\u36c4\u36c5\u36c6\u36c7\u36c8\u36c9\u36ca\u36cb\u36cc\u36cd\u36ce\u36cf\u36d0\u36d1\u36d2\u36d3\u36d4\u36d5\u36d6\u36d7\u36d8\u36d9\u36da\u36db\u36dc\u36dd\u36de\u36df\u36e0\u36e1\u36e2\u36e3\u36e4\u36e5\u36e6\u36e7\u36e8\u36e9\u36ea\u36eb\u36ec\u36ed\u36ee\u36ef\u36f0\u36f1\u36f2\u36f3\u36f4\u36f5\u36f6\u36f7\u36f8\u36f9\u36fa\u36fb\u36fc\u36fd\u36fe\u36ff\u3700\u3701\u3702\u3703\u3704\u3705\u3706\u3707\u3708\u3709\u370a\u370b\u370c\u370d\u370e\u370f\u3710\u3711\u3712\u3713\u3714\u3715\u3716\u3717\u3718\u3719\u371a\u371b\u371c\u371d\u371e\u371f\u3720\u3721\u3722\u3723\u3724\u3725\u3726\u3727\u3728\u3729\u372a\u372b\u372c\u372d\u372e\u372f\u3730\u3731\u3732\u3733\u3734\u3735\u3736\u3737\u3738\u3739\u373a\u373b\u373c\u373d\u373e\u373f\u3740\u3741\u3742\u3743\u3744\u3745\u3746\u3747\u3748\u3749\u374a\u374b\u374c\u374d\u374e\u374f\u3750\u3751\u3752\u3753\u3754\u3755\u3756\u3757\u3758\u3759\u375a\u375b\u375c\u375d\u375e\u375f\u3760\u3761\u3762\u3763\u3764\u3765\u3766\u3767\u3768\u3769\u376a\u376b\u376c\u376d\u376e\u376f\u3770\u3771\u3772\u3773\u3774\u3775\u3776\u3777\u3778\u3779\u377a\u377b\u377c\u377d\u377e\u377f\u3780\u3781\u3782\u3783\u3784\u3785\u3786\u3787\u3788\u3789\u378a\u378b\u378c\u378d\u378e\u378f\u3790\u3791\u3792\u3793\u3794\u3795\u3796\u3797\u3798\u3799\u379a\u379b\u379c\u379d\u379e\u379f\u37a0\u37a1\u37a2\u37a3\u37a4\u37a5\u37a6\u37a7\u37a8\u37a9\u37aa\u37ab\u37ac\u37ad\u37ae\u37af\u37b0\u37b1\u37b2\u37b3\u37b4\u37b5\u37b6\u37b7\u37b8\u37b9\u37ba\u37bb\u37bc\u37bd\u37be\u37bf\u37c0\u37c1\u37c2\u37c3\u37c4\u37c5\u37c6\u37c7\u37c8\u37c9\u37ca\u37cb\u37cc\u37cd\u37ce\u37cf\u37d0\u37d1\u37d2\u37d3\u37d4\u37d5\u37d6\u37d7\u37d8\u37d9\u37da\u37db\u37dc\u37dd\u37de\u37df\u37e0\u37e1\u37e2\u37e3\u37e4\u37e5\u37e6\u37e7\u37e8\u37e9\u37ea\u37eb\u37ec\u37ed\u37ee\u37ef\u37f0\u37f1\u37f2\u37f3\u37f4\u37f5\u37f6\u37f7\u37f8\u37f9\u37fa\u37fb\u37fc\u37fd\u37fe\u37ff\u3800\u3801\u3802\u3803\u3804\u3805\u3806\u3807\u3808\u3809\u380a\u380b\u380c\u380d\u380e\u380f\u3810\u3811\u3812\u3813\u3814\u3815\u3816\u3817\u3818\u3819\u381a\u381b\u381c\u381d\u381e\u381f\u3820\u3821\u3822\u3823\u3824\u3825\u3826\u3827\u3828\u3829\u382a\u382b\u382c\u382d\u382e\u382f\u3830\u3831\u3832\u3833\u3834\u3835\u3836\u3837\u3838\u3839\u383a\u383b\u383c\u383d\u383e\u383f\u3840\u3841\u3842\u3843\u3844\u3845\u3846\u3847\u3848\u3849\u384a\u384b\u384c\u384d\u384e\u384f\u3850\u3851\u3852\u3853\u3854\u3855\u3856\u3857\u3858\u3859\u385a\u385b\u385c\u385d\u385e\u385f\u3860\u3861\u3862\u3863\u3864\u3865\u3866\u3867\u3868\u3869\u386a\u386b\u386c\u386d\u386e\u386f\u3870\u3871\u3872\u3873\u3874\u3875\u3876\u3877\u3878\u3879\u387a\u387b\u387c\u387d\u387e\u387f\u3880\u3881\u3882\u3883\u3884\u3885\u3886\u3887\u3888\u3889\u388a\u388b\u388c\u388d\u388e\u388f\u3890\u3891\u3892\u3893\u3894\u3895\u3896\u3897\u3898\u3899\u389a\u389b\u389c\u389d\u389e\u389f\u38a0\u38a1\u38a2\u38a3\u38a4\u38a5\u38a6\u38a7\u38a8\u38a9\u38aa\u38ab\u38ac\u38ad\u38ae\u38af\u38b0\u38b1\u38b2\u38b3\u38b4\u38b5\u38b6\u38b7\u38b8\u38b9\u38ba\u38bb\u38bc\u38bd\u38be\u38bf\u38c0\u38c1\u38c2\u38c3\u38c4\u38c5\u38c6\u38c7\u38c8\u38c9\u38ca\u38cb\u38cc\u38cd\u38ce\u38cf\u38d0\u38d1\u38d2\u38d3\u38d4\u38d5\u38d6\u38d7\u38d8\u38d9\u38da\u38db\u38dc\u38dd\u38de\u38df\u38e0\u38e1\u38e2\u38e3\u38e4\u38e5\u38e6\u38e7\u38e8\u38e9\u38ea\u38eb\u38ec\u38ed\u38ee\u38ef\u38f0\u38f1\u38f2\u38f3\u38f4\u38f5\u38f6\u38f7\u38f8\u38f9\u38fa\u38fb\u38fc\u38fd\u38fe\u38ff\u3900\u3901\u3902\u3903\u3904\u3905\u3906\u3907\u3908\u3909\u390a\u390b\u390c\u390d\u390e\u390f\u3910\u3911\u3912\u3913\u3914\u3915\u3916\u3917\u3918\u3919\u391a\u391b\u391c\u391d\u391e\u391f\u3920\u3921\u3922\u3923\u3924\u3925\u3926\u3927\u3928\u3929\u392a\u392b\u392c\u392d\u392e\u392f\u3930\u3931\u3932\u3933\u3934\u3935\u3936\u3937\u3938\u3939\u393a\u393b\u393c\u393d\u393e\u393f\u3940\u3941\u3942\u3943\u3944\u3945\u3946\u3947\u3948\u3949\u394a\u394b\u394c\u394d\u394e\u394f\u3950\u3951\u3952\u3953\u3954\u3955\u3956\u3957\u3958\u3959\u395a\u395b\u395c\u395d\u395e\u395f\u3960\u3961\u3962\u3963\u3964\u3965\u3966\u3967\u3968\u3969\u396a\u396b\u396c\u396d\u396e\u396f\u3970\u3971\u3972\u3973\u3974\u3975\u3976\u3977\u3978\u3979\u397a\u397b\u397c\u397d\u397e\u397f\u3980\u3981\u3982\u3983\u3984\u3985\u3986\u3987\u3988\u3989\u398a\u398b\u398c\u398d\u398e\u398f\u3990\u3991\u3992\u3993\u3994\u3995\u3996\u3997\u3998\u3999\u399a\u399b\u399c\u399d\u399e\u399f\u39a0\u39a1\u39a2\u39a3\u39a4\u39a5\u39a6\u39a7\u39a8\u39a9\u39aa\u39ab\u39ac\u39ad\u39ae\u39af\u39b0\u39b1\u39b2\u39b3\u39b4\u39b5\u39b6\u39b7\u39b8\u39b9\u39ba\u39bb\u39bc\u39bd\u39be\u39bf\u39c0\u39c1\u39c2\u39c3\u39c4\u39c5\u39c6\u39c7\u39c8\u39c9\u39ca\u39cb\u39cc\u39cd\u39ce\u39cf\u39d0\u39d1\u39d2\u39d3\u39d4\u39d5\u39d6\u39d7\u39d8\u39d9\u39da\u39db\u39dc\u39dd\u39de\u39df\u39e0\u39e1\u39e2\u39e3\u39e4\u39e5\u39e6\u39e7\u39e8\u39e9\u39ea\u39eb\u39ec\u39ed\u39ee\u39ef\u39f0\u39f1\u39f2\u39f3\u39f4\u39f5\u39f6\u39f7\u39f8\u39f9\u39fa\u39fb\u39fc\u39fd\u39fe\u39ff\u3a00\u3a01\u3a02\u3a03\u3a04\u3a05\u3a06\u3a07\u3a08\u3a09\u3a0a\u3a0b\u3a0c\u3a0d\u3a0e\u3a0f\u3a10\u3a11\u3a12\u3a13\u3a14\u3a15\u3a16\u3a17\u3a18\u3a19\u3a1a\u3a1b\u3a1c\u3a1d\u3a1e\u3a1f\u3a20\u3a21\u3a22\u3a23\u3a24\u3a25\u3a26\u3a27\u3a28\u3a29\u3a2a\u3a2b\u3a2c\u3a2d\u3a2e\u3a2f\u3a30\u3a31\u3a32\u3a33\u3a34\u3a35\u3a36\u3a37\u3a38\u3a39\u3a3a\u3a3b\u3a3c\u3a3d\u3a3e\u3a3f\u3a40\u3a41\u3a42\u3a43\u3a44\u3a45\u3a46\u3a47\u3a48\u3a49\u3a4a\u3a4b\u3a4c\u3a4d\u3a4e\u3a4f\u3a50\u3a51\u3a52\u3a53\u3a54\u3a55\u3a56\u3a57\u3a58\u3a59\u3a5a\u3a5b\u3a5c\u3a5d\u3a5e\u3a5f\u3a60\u3a61\u3a62\u3a63\u3a64\u3a65\u3a66\u3a67\u3a68\u3a69\u3a6a\u3a6b\u3a6c\u3a6d\u3a6e\u3a6f\u3a70\u3a71\u3a72\u3a73\u3a74\u3a75\u3a76\u3a77\u3a78\u3a79\u3a7a\u3a7b\u3a7c\u3a7d\u3a7e\u3a7f\u3a80\u3a81\u3a82\u3a83\u3a84\u3a85\u3a86\u3a87\u3a88\u3a89\u3a8a\u3a8b\u3a8c\u3a8d\u3a8e\u3a8f\u3a90\u3a91\u3a92\u3a93\u3a94\u3a95\u3a96\u3a97\u3a98\u3a99\u3a9a\u3a9b\u3a9c\u3a9d\u3a9e\u3a9f\u3aa0\u3aa1\u3aa2\u3aa3\u3aa4\u3aa5\u3aa6\u3aa7\u3aa8\u3aa9\u3aaa\u3aab\u3aac\u3aad\u3aae\u3aaf\u3ab0\u3ab1\u3ab2\u3ab3\u3ab4\u3ab5\u3ab6\u3ab7\u3ab8\u3ab9\u3aba\u3abb\u3abc\u3abd\u3abe\u3abf\u3ac0\u3ac1\u3ac2\u3ac3\u3ac4\u3ac5\u3ac6\u3ac7\u3ac8\u3ac9\u3aca\u3acb\u3acc\u3acd\u3ace\u3acf\u3ad0\u3ad1\u3ad2\u3ad3\u3ad4\u3ad5\u3ad6\u3ad7\u3ad8\u3ad9\u3ada\u3adb\u3adc\u3add\u3ade\u3adf\u3ae0\u3ae1\u3ae2\u3ae3\u3ae4\u3ae5\u3ae6\u3ae7\u3ae8\u3ae9\u3aea\u3aeb\u3aec\u3aed\u3aee\u3aef\u3af0\u3af1\u3af2\u3af3\u3af4\u3af5\u3af6\u3af7\u3af8\u3af9\u3afa\u3afb\u3afc\u3afd\u3afe\u3aff\u3b00\u3b01\u3b02\u3b03\u3b04\u3b05\u3b06\u3b07\u3b08\u3b09\u3b0a\u3b0b\u3b0c\u3b0d\u3b0e\u3b0f\u3b10\u3b11\u3b12\u3b13\u3b14\u3b15\u3b16\u3b17\u3b18\u3b19\u3b1a\u3b1b\u3b1c\u3b1d\u3b1e\u3b1f\u3b20\u3b21\u3b22\u3b23\u3b24\u3b25\u3b26\u3b27\u3b28\u3b29\u3b2a\u3b2b\u3b2c\u3b2d\u3b2e\u3b2f\u3b30\u3b31\u3b32\u3b33\u3b34\u3b35\u3b36\u3b37\u3b38\u3b39\u3b3a\u3b3b\u3b3c\u3b3d\u3b3e\u3b3f\u3b40\u3b41\u3b42\u3b43\u3b44\u3b45\u3b46\u3b47\u3b48\u3b49\u3b4a\u3b4b\u3b4c\u3b4d\u3b4e\u3b4f\u3b50\u3b51\u3b52\u3b53\u3b54\u3b55\u3b56\u3b57\u3b58\u3b59\u3b5a\u3b5b\u3b5c\u3b5d\u3b5e\u3b5f\u3b60\u3b61\u3b62\u3b63\u3b64\u3b65\u3b66\u3b67\u3b68\u3b69\u3b6a\u3b6b\u3b6c\u3b6d\u3b6e\u3b6f\u3b70\u3b71\u3b72\u3b73\u3b74\u3b75\u3b76\u3b77\u3b78\u3b79\u3b7a\u3b7b\u3b7c\u3b7d\u3b7e\u3b7f\u3b80\u3b81\u3b82\u3b83\u3b84\u3b85\u3b86\u3b87\u3b88\u3b89\u3b8a\u3b8b\u3b8c\u3b8d\u3b8e\u3b8f\u3b90\u3b91\u3b92\u3b93\u3b94\u3b95\u3b96\u3b97\u3b98\u3b99\u3b9a\u3b9b\u3b9c\u3b9d\u3b9e\u3b9f\u3ba0\u3ba1\u3ba2\u3ba3\u3ba4\u3ba5\u3ba6\u3ba7\u3ba8\u3ba9\u3baa\u3bab\u3bac\u3bad\u3bae\u3baf\u3bb0\u3bb1\u3bb2\u3bb3\u3bb4\u3bb5\u3bb6\u3bb7\u3bb8\u3bb9\u3bba\u3bbb\u3bbc\u3bbd\u3bbe\u3bbf\u3bc0\u3bc1\u3bc2\u3bc3\u3bc4\u3bc5\u3bc6\u3bc7\u3bc8\u3bc9\u3bca\u3bcb\u3bcc\u3bcd\u3bce\u3bcf\u3bd0\u3bd1\u3bd2\u3bd3\u3bd4\u3bd5\u3bd6\u3bd7\u3bd8\u3bd9\u3bda\u3bdb\u3bdc\u3bdd\u3bde\u3bdf\u3be0\u3be1\u3be2\u3be3\u3be4\u3be5\u3be6\u3be7\u3be8\u3be9\u3bea\u3beb\u3bec\u3bed\u3bee\u3bef\u3bf0\u3bf1\u3bf2\u3bf3\u3bf4\u3bf5\u3bf6\u3bf7\u3bf8\u3bf9\u3bfa\u3bfb\u3bfc\u3bfd\u3bfe\u3bff\u3c00\u3c01\u3c02\u3c03\u3c04\u3c05\u3c06\u3c07\u3c08\u3c09\u3c0a\u3c0b\u3c0c\u3c0d\u3c0e\u3c0f\u3c10\u3c11\u3c12\u3c13\u3c14\u3c15\u3c16\u3c17\u3c18\u3c19\u3c1a\u3c1b\u3c1c\u3c1d\u3c1e\u3c1f\u3c20\u3c21\u3c22\u3c23\u3c24\u3c25\u3c26\u3c27\u3c28\u3c29\u3c2a\u3c2b\u3c2c\u3c2d\u3c2e\u3c2f\u3c30\u3c31\u3c32\u3c33\u3c34\u3c35\u3c36\u3c37\u3c38\u3c39\u3c3a\u3c3b\u3c3c\u3c3d\u3c3e\u3c3f\u3c40\u3c41\u3c42\u3c43\u3c44\u3c45\u3c46\u3c47\u3c48\u3c49\u3c4a\u3c4b\u3c4c\u3c4d\u3c4e\u3c4f\u3c50\u3c51\u3c52\u3c53\u3c54\u3c55\u3c56\u3c57\u3c58\u3c59\u3c5a\u3c5b\u3c5c\u3c5d\u3c5e\u3c5f\u3c60\u3c61\u3c62\u3c63\u3c64\u3c65\u3c66\u3c67\u3c68\u3c69\u3c6a\u3c6b\u3c6c\u3c6d\u3c6e\u3c6f\u3c70\u3c71\u3c72\u3c73\u3c74\u3c75\u3c76\u3c77\u3c78\u3c79\u3c7a\u3c7b\u3c7c\u3c7d\u3c7e\u3c7f\u3c80\u3c81\u3c82\u3c83\u3c84\u3c85\u3c86\u3c87\u3c88\u3c89\u3c8a\u3c8b\u3c8c\u3c8d\u3c8e\u3c8f\u3c90\u3c91\u3c92\u3c93\u3c94\u3c95\u3c96\u3c97\u3c98\u3c99\u3c9a\u3c9b\u3c9c\u3c9d\u3c9e\u3c9f\u3ca0\u3ca1\u3ca2\u3ca3\u3ca4\u3ca5\u3ca6\u3ca7\u3ca8\u3ca9\u3caa\u3cab\u3cac\u3cad\u3cae\u3caf\u3cb0\u3cb1\u3cb2\u3cb3\u3cb4\u3cb5\u3cb6\u3cb7\u3cb8\u3cb9\u3cba\u3cbb\u3cbc\u3cbd\u3cbe\u3cbf\u3cc0\u3cc1\u3cc2\u3cc3\u3cc4\u3cc5\u3cc6\u3cc7\u3cc8\u3cc9\u3cca\u3ccb\u3ccc\u3ccd\u3cce\u3ccf\u3cd0\u3cd1\u3cd2\u3cd3\u3cd4\u3cd5\u3cd6\u3cd7\u3cd8\u3cd9\u3cda\u3cdb\u3cdc\u3cdd\u3cde\u3cdf\u3ce0\u3ce1\u3ce2\u3ce3\u3ce4\u3ce5\u3ce6\u3ce7\u3ce8\u3ce9\u3cea\u3ceb\u3cec\u3ced\u3cee\u3cef\u3cf0\u3cf1\u3cf2\u3cf3\u3cf4\u3cf5\u3cf6\u3cf7\u3cf8\u3cf9\u3cfa\u3cfb\u3cfc\u3cfd\u3cfe\u3cff\u3d00\u3d01\u3d02\u3d03\u3d04\u3d05\u3d06\u3d07\u3d08\u3d09\u3d0a\u3d0b\u3d0c\u3d0d\u3d0e\u3d0f\u3d10\u3d11\u3d12\u3d13\u3d14\u3d15\u3d16\u3d17\u3d18\u3d19\u3d1a\u3d1b\u3d1c\u3d1d\u3d1e\u3d1f\u3d20\u3d21\u3d22\u3d23\u3d24\u3d25\u3d26\u3d27\u3d28\u3d29\u3d2a\u3d2b\u3d2c\u3d2d\u3d2e\u3d2f\u3d30\u3d31\u3d32\u3d33\u3d34\u3d35\u3d36\u3d37\u3d38\u3d39\u3d3a\u3d3b\u3d3c\u3d3d\u3d3e\u3d3f\u3d40\u3d41\u3d42\u3d43\u3d44\u3d45\u3d46\u3d47\u3d48\u3d49\u3d4a\u3d4b\u3d4c\u3d4d\u3d4e\u3d4f\u3d50\u3d51\u3d52\u3d53\u3d54\u3d55\u3d56\u3d57\u3d58\u3d59\u3d5a\u3d5b\u3d5c\u3d5d\u3d5e\u3d5f\u3d60\u3d61\u3d62\u3d63\u3d64\u3d65\u3d66\u3d67\u3d68\u3d69\u3d6a\u3d6b\u3d6c\u3d6d\u3d6e\u3d6f\u3d70\u3d71\u3d72\u3d73\u3d74\u3d75\u3d76\u3d77\u3d78\u3d79\u3d7a\u3d7b\u3d7c\u3d7d\u3d7e\u3d7f\u3d80\u3d81\u3d82\u3d83\u3d84\u3d85\u3d86\u3d87\u3d88\u3d89\u3d8a\u3d8b\u3d8c\u3d8d\u3d8e\u3d8f\u3d90\u3d91\u3d92\u3d93\u3d94\u3d95\u3d96\u3d97\u3d98\u3d99\u3d9a\u3d9b\u3d9c\u3d9d\u3d9e\u3d9f\u3da0\u3da1\u3da2\u3da3\u3da4\u3da5\u3da6\u3da7\u3da8\u3da9\u3daa\u3dab\u3dac\u3dad\u3dae\u3daf\u3db0\u3db1\u3db2\u3db3\u3db4\u3db5\u3db6\u3db7\u3db8\u3db9\u3dba\u3dbb\u3dbc\u3dbd\u3dbe\u3dbf\u3dc0\u3dc1\u3dc2\u3dc3\u3dc4\u3dc5\u3dc6\u3dc7\u3dc8\u3dc9\u3dca\u3dcb\u3dcc\u3dcd\u3dce\u3dcf\u3dd0\u3dd1\u3dd2\u3dd3\u3dd4\u3dd5\u3dd6\u3dd7\u3dd8\u3dd9\u3dda\u3ddb\u3ddc\u3ddd\u3dde\u3ddf\u3de0\u3de1\u3de2\u3de3\u3de4\u3de5\u3de6\u3de7\u3de8\u3de9\u3dea\u3deb\u3dec\u3ded\u3dee\u3def\u3df0\u3df1\u3df2\u3df3\u3df4\u3df5\u3df6\u3df7\u3df8\u3df9\u3dfa\u3dfb\u3dfc\u3dfd\u3dfe\u3dff\u3e00\u3e01\u3e02\u3e03\u3e04\u3e05\u3e06\u3e07\u3e08\u3e09\u3e0a\u3e0b\u3e0c\u3e0d\u3e0e\u3e0f\u3e10\u3e11\u3e12\u3e13\u3e14\u3e15\u3e16\u3e17\u3e18\u3e19\u3e1a\u3e1b\u3e1c\u3e1d\u3e1e\u3e1f\u3e20\u3e21\u3e22\u3e23\u3e24\u3e25\u3e26\u3e27\u3e28\u3e29\u3e2a\u3e2b\u3e2c\u3e2d\u3e2e\u3e2f\u3e30\u3e31\u3e32\u3e33\u3e34\u3e35\u3e36\u3e37\u3e38\u3e39\u3e3a\u3e3b\u3e3c\u3e3d\u3e3e\u3e3f\u3e40\u3e41\u3e42\u3e43\u3e44\u3e45\u3e46\u3e47\u3e48\u3e49\u3e4a\u3e4b\u3e4c\u3e4d\u3e4e\u3e4f\u3e50\u3e51\u3e52\u3e53\u3e54\u3e55\u3e56\u3e57\u3e58\u3e59\u3e5a\u3e5b\u3e5c\u3e5d\u3e5e\u3e5f\u3e60\u3e61\u3e62\u3e63\u3e64\u3e65\u3e66\u3e67\u3e68\u3e69\u3e6a\u3e6b\u3e6c\u3e6d\u3e6e\u3e6f\u3e70\u3e71\u3e72\u3e73\u3e74\u3e75\u3e76\u3e77\u3e78\u3e79\u3e7a\u3e7b\u3e7c\u3e7d\u3e7e\u3e7f\u3e80\u3e81\u3e82\u3e83\u3e84\u3e85\u3e86\u3e87\u3e88\u3e89\u3e8a\u3e8b\u3e8c\u3e8d\u3e8e\u3e8f\u3e90\u3e91\u3e92\u3e93\u3e94\u3e95\u3e96\u3e97\u3e98\u3e99\u3e9a\u3e9b\u3e9c\u3e9d\u3e9e\u3e9f\u3ea0\u3ea1\u3ea2\u3ea3\u3ea4\u3ea5\u3ea6\u3ea7\u3ea8\u3ea9\u3eaa\u3eab\u3eac\u3ead\u3eae\u3eaf\u3eb0\u3eb1\u3eb2\u3eb3\u3eb4\u3eb5\u3eb6\u3eb7\u3eb8\u3eb9\u3eba\u3ebb\u3ebc\u3ebd\u3ebe\u3ebf\u3ec0\u3ec1\u3ec2\u3ec3\u3ec4\u3ec5\u3ec6\u3ec7\u3ec8\u3ec9\u3eca\u3ecb\u3ecc\u3ecd\u3ece\u3ecf\u3ed0\u3ed1\u3ed2\u3ed3\u3ed4\u3ed5\u3ed6\u3ed7\u3ed8\u3ed9\u3eda\u3edb\u3edc\u3edd\u3ede\u3edf\u3ee0\u3ee1\u3ee2\u3ee3\u3ee4\u3ee5\u3ee6\u3ee7\u3ee8\u3ee9\u3eea\u3eeb\u3eec\u3eed\u3eee\u3eef\u3ef0\u3ef1\u3ef2\u3ef3\u3ef4\u3ef5\u3ef6\u3ef7\u3ef8\u3ef9\u3efa\u3efb\u3efc\u3efd\u3efe\u3eff\u3f00\u3f01\u3f02\u3f03\u3f04\u3f05\u3f06\u3f07\u3f08\u3f09\u3f0a\u3f0b\u3f0c\u3f0d\u3f0e\u3f0f\u3f10\u3f11\u3f12\u3f13\u3f14\u3f15\u3f16\u3f17\u3f18\u3f19\u3f1a\u3f1b\u3f1c\u3f1d\u3f1e\u3f1f\u3f20\u3f21\u3f22\u3f23\u3f24\u3f25\u3f26\u3f27\u3f28\u3f29\u3f2a\u3f2b\u3f2c\u3f2d\u3f2e\u3f2f\u3f30\u3f31\u3f32\u3f33\u3f34\u3f35\u3f36\u3f37\u3f38\u3f39\u3f3a\u3f3b\u3f3c\u3f3d\u3f3e\u3f3f\u3f40\u3f41\u3f42\u3f43\u3f44\u3f45\u3f46\u3f47\u3f48\u3f49\u3f4a\u3f4b\u3f4c\u3f4d\u3f4e\u3f4f\u3f50\u3f51\u3f52\u3f53\u3f54\u3f55\u3f56\u3f57\u3f58\u3f59\u3f5a\u3f5b\u3f5c\u3f5d\u3f5e\u3f5f\u3f60\u3f61\u3f62\u3f63\u3f64\u3f65\u3f66\u3f67\u3f68\u3f69\u3f6a\u3f6b\u3f6c\u3f6d\u3f6e\u3f6f\u3f70\u3f71\u3f72\u3f73\u3f74\u3f75\u3f76\u3f77\u3f78\u3f79\u3f7a\u3f7b\u3f7c\u3f7d\u3f7e\u3f7f\u3f80\u3f81\u3f82\u3f83\u3f84\u3f85\u3f86\u3f87\u3f88\u3f89\u3f8a\u3f8b\u3f8c\u3f8d\u3f8e\u3f8f\u3f90\u3f91\u3f92\u3f93\u3f94\u3f95\u3f96\u3f97\u3f98\u3f99\u3f9a\u3f9b\u3f9c\u3f9d\u3f9e\u3f9f\u3fa0\u3fa1\u3fa2\u3fa3\u3fa4\u3fa5\u3fa6\u3fa7\u3fa8\u3fa9\u3faa\u3fab\u3fac\u3fad\u3fae\u3faf\u3fb0\u3fb1\u3fb2\u3fb3\u3fb4\u3fb5\u3fb6\u3fb7\u3fb8\u3fb9\u3fba\u3fbb\u3fbc\u3fbd\u3fbe\u3fbf\u3fc0\u3fc1\u3fc2\u3fc3\u3fc4\u3fc5\u3fc6\u3fc7\u3fc8\u3fc9\u3fca\u3fcb\u3fcc\u3fcd\u3fce\u3fcf\u3fd0\u3fd1\u3fd2\u3fd3\u3fd4\u3fd5\u3fd6\u3fd7\u3fd8\u3fd9\u3fda\u3fdb\u3fdc\u3fdd\u3fde\u3fdf\u3fe0\u3fe1\u3fe2\u3fe3\u3fe4\u3fe5\u3fe6\u3fe7\u3fe8\u3fe9\u3fea\u3feb\u3fec\u3fed\u3fee\u3fef\u3ff0\u3ff1\u3ff2\u3ff3\u3ff4\u3ff5\u3ff6\u3ff7\u3ff8\u3ff9\u3ffa\u3ffb\u3ffc\u3ffd\u3ffe\u3fff\u4000\u4001\u4002\u4003\u4004\u4005\u4006\u4007\u4008\u4009\u400a\u400b\u400c\u400d\u400e\u400f\u4010\u4011\u4012\u4013\u4014\u4015\u4016\u4017\u4018\u4019\u401a\u401b\u401c\u401d\u401e\u401f\u4020\u4021\u4022\u4023\u4024\u4025\u4026\u4027\u4028\u4029\u402a\u402b\u402c\u402d\u402e\u402f\u4030\u4031\u4032\u4033\u4034\u4035\u4036\u4037\u4038\u4039\u403a\u403b\u403c\u403d\u403e\u403f\u4040\u4041\u4042\u4043\u4044\u4045\u4046\u4047\u4048\u4049\u404a\u404b\u404c\u404d\u404e\u404f\u4050\u4051\u4052\u4053\u4054\u4055\u4056\u4057\u4058\u4059\u405a\u405b\u405c\u405d\u405e\u405f\u4060\u4061\u4062\u4063\u4064\u4065\u4066\u4067\u4068\u4069\u406a\u406b\u406c\u406d\u406e\u406f\u4070\u4071\u4072\u4073\u4074\u4075\u4076\u4077\u4078\u4079\u407a\u407b\u407c\u407d\u407e\u407f\u4080\u4081\u4082\u4083\u4084\u4085\u4086\u4087\u4088\u4089\u408a\u408b\u408c\u408d\u408e\u408f\u4090\u4091\u4092\u4093\u4094\u4095\u4096\u4097\u4098\u4099\u409a\u409b\u409c\u409d\u409e\u409f\u40a0\u40a1\u40a2\u40a3\u40a4\u40a5\u40a6\u40a7\u40a8\u40a9\u40aa\u40ab\u40ac\u40ad\u40ae\u40af\u40b0\u40b1\u40b2\u40b3\u40b4\u40b5\u40b6\u40b7\u40b8\u40b9\u40ba\u40bb\u40bc\u40bd\u40be\u40bf\u40c0\u40c1\u40c2\u40c3\u40c4\u40c5\u40c6\u40c7\u40c8\u40c9\u40ca\u40cb\u40cc\u40cd\u40ce\u40cf\u40d0\u40d1\u40d2\u40d3\u40d4\u40d5\u40d6\u40d7\u40d8\u40d9\u40da\u40db\u40dc\u40dd\u40de\u40df\u40e0\u40e1\u40e2\u40e3\u40e4\u40e5\u40e6\u40e7\u40e8\u40e9\u40ea\u40eb\u40ec\u40ed\u40ee\u40ef\u40f0\u40f1\u40f2\u40f3\u40f4\u40f5\u40f6\u40f7\u40f8\u40f9\u40fa\u40fb\u40fc\u40fd\u40fe\u40ff\u4100\u4101\u4102\u4103\u4104\u4105\u4106\u4107\u4108\u4109\u410a\u410b\u410c\u410d\u410e\u410f\u4110\u4111\u4112\u4113\u4114\u4115\u4116\u4117\u4118\u4119\u411a\u411b\u411c\u411d\u411e\u411f\u4120\u4121\u4122\u4123\u4124\u4125\u4126\u4127\u4128\u4129\u412a\u412b\u412c\u412d\u412e\u412f\u4130\u4131\u4132\u4133\u4134\u4135\u4136\u4137\u4138\u4139\u413a\u413b\u413c\u413d\u413e\u413f\u4140\u4141\u4142\u4143\u4144\u4145\u4146\u4147\u4148\u4149\u414a\u414b\u414c\u414d\u414e\u414f\u4150\u4151\u4152\u4153\u4154\u4155\u4156\u4157\u4158\u4159\u415a\u415b\u415c\u415d\u415e\u415f\u4160\u4161\u4162\u4163\u4164\u4165\u4166\u4167\u4168\u4169\u416a\u416b\u416c\u416d\u416e\u416f\u4170\u4171\u4172\u4173\u4174\u4175\u4176\u4177\u4178\u4179\u417a\u417b\u417c\u417d\u417e\u417f\u4180\u4181\u4182\u4183\u4184\u4185\u4186\u4187\u4188\u4189\u418a\u418b\u418c\u418d\u418e\u418f\u4190\u4191\u4192\u4193\u4194\u4195\u4196\u4197\u4198\u4199\u419a\u419b\u419c\u419d\u419e\u419f\u41a0\u41a1\u41a2\u41a3\u41a4\u41a5\u41a6\u41a7\u41a8\u41a9\u41aa\u41ab\u41ac\u41ad\u41ae\u41af\u41b0\u41b1\u41b2\u41b3\u41b4\u41b5\u41b6\u41b7\u41b8\u41b9\u41ba\u41bb\u41bc\u41bd\u41be\u41bf\u41c0\u41c1\u41c2\u41c3\u41c4\u41c5\u41c6\u41c7\u41c8\u41c9\u41ca\u41cb\u41cc\u41cd\u41ce\u41cf\u41d0\u41d1\u41d2\u41d3\u41d4\u41d5\u41d6\u41d7\u41d8\u41d9\u41da\u41db\u41dc\u41dd\u41de\u41df\u41e0\u41e1\u41e2\u41e3\u41e4\u41e5\u41e6\u41e7\u41e8\u41e9\u41ea\u41eb\u41ec\u41ed\u41ee\u41ef\u41f0\u41f1\u41f2\u41f3\u41f4\u41f5\u41f6\u41f7\u41f8\u41f9\u41fa\u41fb\u41fc\u41fd\u41fe\u41ff\u4200\u4201\u4202\u4203\u4204\u4205\u4206\u4207\u4208\u4209\u420a\u420b\u420c\u420d\u420e\u420f\u4210\u4211\u4212\u4213\u4214\u4215\u4216\u4217\u4218\u4219\u421a\u421b\u421c\u421d\u421e\u421f\u4220\u4221\u4222\u4223\u4224\u4225\u4226\u4227\u4228\u4229\u422a\u422b\u422c\u422d\u422e\u422f\u4230\u4231\u4232\u4233\u4234\u4235\u4236\u4237\u4238\u4239\u423a\u423b\u423c\u423d\u423e\u423f\u4240\u4241\u4242\u4243\u4244\u4245\u4246\u4247\u4248\u4249\u424a\u424b\u424c\u424d\u424e\u424f\u4250\u4251\u4252\u4253\u4254\u4255\u4256\u4257\u4258\u4259\u425a\u425b\u425c\u425d\u425e\u425f\u4260\u4261\u4262\u4263\u4264\u4265\u4266\u4267\u4268\u4269\u426a\u426b\u426c\u426d\u426e\u426f\u4270\u4271\u4272\u4273\u4274\u4275\u4276\u4277\u4278\u4279\u427a\u427b\u427c\u427d\u427e\u427f\u4280\u4281\u4282\u4283\u4284\u4285\u4286\u4287\u4288\u4289\u428a\u428b\u428c\u428d\u428e\u428f\u4290\u4291\u4292\u4293\u4294\u4295\u4296\u4297\u4298\u4299\u429a\u429b\u429c\u429d\u429e\u429f\u42a0\u42a1\u42a2\u42a3\u42a4\u42a5\u42a6\u42a7\u42a8\u42a9\u42aa\u42ab\u42ac\u42ad\u42ae\u42af\u42b0\u42b1\u42b2\u42b3\u42b4\u42b5\u42b6\u42b7\u42b8\u42b9\u42ba\u42bb\u42bc\u42bd\u42be\u42bf\u42c0\u42c1\u42c2\u42c3\u42c4\u42c5\u42c6\u42c7\u42c8\u42c9\u42ca\u42cb\u42cc\u42cd\u42ce\u42cf\u42d0\u42d1\u42d2\u42d3\u42d4\u42d5\u42d6\u42d7\u42d8\u42d9\u42da\u42db\u42dc\u42dd\u42de\u42df\u42e0\u42e1\u42e2\u42e3\u42e4\u42e5\u42e6\u42e7\u42e8\u42e9\u42ea\u42eb\u42ec\u42ed\u42ee\u42ef\u42f0\u42f1\u42f2\u42f3\u42f4\u42f5\u42f6\u42f7\u42f8\u42f9\u42fa\u42fb\u42fc\u42fd\u42fe\u42ff\u4300\u4301\u4302\u4303\u4304\u4305\u4306\u4307\u4308\u4309\u430a\u430b\u430c\u430d\u430e\u430f\u4310\u4311\u4312\u4313\u4314\u4315\u4316\u4317\u4318\u4319\u431a\u431b\u431c\u431d\u431e\u431f\u4320\u4321\u4322\u4323\u4324\u4325\u4326\u4327\u4328\u4329\u432a\u432b\u432c\u432d\u432e\u432f\u4330\u4331\u4332\u4333\u4334\u4335\u4336\u4337\u4338\u4339\u433a\u433b\u433c\u433d\u433e\u433f\u4340\u4341\u4342\u4343\u4344\u4345\u4346\u4347\u4348\u4349\u434a\u434b\u434c\u434d\u434e\u434f\u4350\u4351\u4352\u4353\u4354\u4355\u4356\u4357\u4358\u4359\u435a\u435b\u435c\u435d\u435e\u435f\u4360\u4361\u4362\u4363\u4364\u4365\u4366\u4367\u4368\u4369\u436a\u436b\u436c\u436d\u436e\u436f\u4370\u4371\u4372\u4373\u4374\u4375\u4376\u4377\u4378\u4379\u437a\u437b\u437c\u437d\u437e\u437f\u4380\u4381\u4382\u4383\u4384\u4385\u4386\u4387\u4388\u4389\u438a\u438b\u438c\u438d\u438e\u438f\u4390\u4391\u4392\u4393\u4394\u4395\u4396\u4397\u4398\u4399\u439a\u439b\u439c\u439d\u439e\u439f\u43a0\u43a1\u43a2\u43a3\u43a4\u43a5\u43a6\u43a7\u43a8\u43a9\u43aa\u43ab\u43ac\u43ad\u43ae\u43af\u43b0\u43b1\u43b2\u43b3\u43b4\u43b5\u43b6\u43b7\u43b8\u43b9\u43ba\u43bb\u43bc\u43bd\u43be\u43bf\u43c0\u43c1\u43c2\u43c3\u43c4\u43c5\u43c6\u43c7\u43c8\u43c9\u43ca\u43cb\u43cc\u43cd\u43ce\u43cf\u43d0\u43d1\u43d2\u43d3\u43d4\u43d5\u43d6\u43d7\u43d8\u43d9\u43da\u43db\u43dc\u43dd\u43de\u43df\u43e0\u43e1\u43e2\u43e3\u43e4\u43e5\u43e6\u43e7\u43e8\u43e9\u43ea\u43eb\u43ec\u43ed\u43ee\u43ef\u43f0\u43f1\u43f2\u43f3\u43f4\u43f5\u43f6\u43f7\u43f8\u43f9\u43fa\u43fb\u43fc\u43fd\u43fe\u43ff\u4400\u4401\u4402\u4403\u4404\u4405\u4406\u4407\u4408\u4409\u440a\u440b\u440c\u440d\u440e\u440f\u4410\u4411\u4412\u4413\u4414\u4415\u4416\u4417\u4418\u4419\u441a\u441b\u441c\u441d\u441e\u441f\u4420\u4421\u4422\u4423\u4424\u4425\u4426\u4427\u4428\u4429\u442a\u442b\u442c\u442d\u442e\u442f\u4430\u4431\u4432\u4433\u4434\u4435\u4436\u4437\u4438\u4439\u443a\u443b\u443c\u443d\u443e\u443f\u4440\u4441\u4442\u4443\u4444\u4445\u4446\u4447\u4448\u4449\u444a\u444b\u444c\u444d\u444e\u444f\u4450\u4451\u4452\u4453\u4454\u4455\u4456\u4457\u4458\u4459\u445a\u445b\u445c\u445d\u445e\u445f\u4460\u4461\u4462\u4463\u4464\u4465\u4466\u4467\u4468\u4469\u446a\u446b\u446c\u446d\u446e\u446f\u4470\u4471\u4472\u4473\u4474\u4475\u4476\u4477\u4478\u4479\u447a\u447b\u447c\u447d\u447e\u447f\u4480\u4481\u4482\u4483\u4484\u4485\u4486\u4487\u4488\u4489\u448a\u448b\u448c\u448d\u448e\u448f\u4490\u4491\u4492\u4493\u4494\u4495\u4496\u4497\u4498\u4499\u449a\u449b\u449c\u449d\u449e\u449f\u44a0\u44a1\u44a2\u44a3\u44a4\u44a5\u44a6\u44a7\u44a8\u44a9\u44aa\u44ab\u44ac\u44ad\u44ae\u44af\u44b0\u44b1\u44b2\u44b3\u44b4\u44b5\u44b6\u44b7\u44b8\u44b9\u44ba\u44bb\u44bc\u44bd\u44be\u44bf\u44c0\u44c1\u44c2\u44c3\u44c4\u44c5\u44c6\u44c7\u44c8\u44c9\u44ca\u44cb\u44cc\u44cd\u44ce\u44cf\u44d0\u44d1\u44d2\u44d3\u44d4\u44d5\u44d6\u44d7\u44d8\u44d9\u44da\u44db\u44dc\u44dd\u44de\u44df\u44e0\u44e1\u44e2\u44e3\u44e4\u44e5\u44e6\u44e7\u44e8\u44e9\u44ea\u44eb\u44ec\u44ed\u44ee\u44ef\u44f0\u44f1\u44f2\u44f3\u44f4\u44f5\u44f6\u44f7\u44f8\u44f9\u44fa\u44fb\u44fc\u44fd\u44fe\u44ff\u4500\u4501\u4502\u4503\u4504\u4505\u4506\u4507\u4508\u4509\u450a\u450b\u450c\u450d\u450e\u450f\u4510\u4511\u4512\u4513\u4514\u4515\u4516\u4517\u4518\u4519\u451a\u451b\u451c\u451d\u451e\u451f\u4520\u4521\u4522\u4523\u4524\u4525\u4526\u4527\u4528\u4529\u452a\u452b\u452c\u452d\u452e\u452f\u4530\u4531\u4532\u4533\u4534\u4535\u4536\u4537\u4538\u4539\u453a\u453b\u453c\u453d\u453e\u453f\u4540\u4541\u4542\u4543\u4544\u4545\u4546\u4547\u4548\u4549\u454a\u454b\u454c\u454d\u454e\u454f\u4550\u4551\u4552\u4553\u4554\u4555\u4556\u4557\u4558\u4559\u455a\u455b\u455c\u455d\u455e\u455f\u4560\u4561\u4562\u4563\u4564\u4565\u4566\u4567\u4568\u4569\u456a\u456b\u456c\u456d\u456e\u456f\u4570\u4571\u4572\u4573\u4574\u4575\u4576\u4577\u4578\u4579\u457a\u457b\u457c\u457d\u457e\u457f\u4580\u4581\u4582\u4583\u4584\u4585\u4586\u4587\u4588\u4589\u458a\u458b\u458c\u458d\u458e\u458f\u4590\u4591\u4592\u4593\u4594\u4595\u4596\u4597\u4598\u4599\u459a\u459b\u459c\u459d\u459e\u459f\u45a0\u45a1\u45a2\u45a3\u45a4\u45a5\u45a6\u45a7\u45a8\u45a9\u45aa\u45ab\u45ac\u45ad\u45ae\u45af\u45b0\u45b1\u45b2\u45b3\u45b4\u45b5\u45b6\u45b7\u45b8\u45b9\u45ba\u45bb\u45bc\u45bd\u45be\u45bf\u45c0\u45c1\u45c2\u45c3\u45c4\u45c5\u45c6\u45c7\u45c8\u45c9\u45ca\u45cb\u45cc\u45cd\u45ce\u45cf\u45d0\u45d1\u45d2\u45d3\u45d4\u45d5\u45d6\u45d7\u45d8\u45d9\u45da\u45db\u45dc\u45dd\u45de\u45df\u45e0\u45e1\u45e2\u45e3\u45e4\u45e5\u45e6\u45e7\u45e8\u45e9\u45ea\u45eb\u45ec\u45ed\u45ee\u45ef\u45f0\u45f1\u45f2\u45f3\u45f4\u45f5\u45f6\u45f7\u45f8\u45f9\u45fa\u45fb\u45fc\u45fd\u45fe\u45ff\u4600\u4601\u4602\u4603\u4604\u4605\u4606\u4607\u4608\u4609\u460a\u460b\u460c\u460d\u460e\u460f\u4610\u4611\u4612\u4613\u4614\u4615\u4616\u4617\u4618\u4619\u461a\u461b\u461c\u461d\u461e\u461f\u4620\u4621\u4622\u4623\u4624\u4625\u4626\u4627\u4628\u4629\u462a\u462b\u462c\u462d\u462e\u462f\u4630\u4631\u4632\u4633\u4634\u4635\u4636\u4637\u4638\u4639\u463a\u463b\u463c\u463d\u463e\u463f\u4640\u4641\u4642\u4643\u4644\u4645\u4646\u4647\u4648\u4649\u464a\u464b\u464c\u464d\u464e\u464f\u4650\u4651\u4652\u4653\u4654\u4655\u4656\u4657\u4658\u4659\u465a\u465b\u465c\u465d\u465e\u465f\u4660\u4661\u4662\u4663\u4664\u4665\u4666\u4667\u4668\u4669\u466a\u466b\u466c\u466d\u466e\u466f\u4670\u4671\u4672\u4673\u4674\u4675\u4676\u4677\u4678\u4679\u467a\u467b\u467c\u467d\u467e\u467f\u4680\u4681\u4682\u4683\u4684\u4685\u4686\u4687\u4688\u4689\u468a\u468b\u468c\u468d\u468e\u468f\u4690\u4691\u4692\u4693\u4694\u4695\u4696\u4697\u4698\u4699\u469a\u469b\u469c\u469d\u469e\u469f\u46a0\u46a1\u46a2\u46a3\u46a4\u46a5\u46a6\u46a7\u46a8\u46a9\u46aa\u46ab\u46ac\u46ad\u46ae\u46af\u46b0\u46b1\u46b2\u46b3\u46b4\u46b5\u46b6\u46b7\u46b8\u46b9\u46ba\u46bb\u46bc\u46bd\u46be\u46bf\u46c0\u46c1\u46c2\u46c3\u46c4\u46c5\u46c6\u46c7\u46c8\u46c9\u46ca\u46cb\u46cc\u46cd\u46ce\u46cf\u46d0\u46d1\u46d2\u46d3\u46d4\u46d5\u46d6\u46d7\u46d8\u46d9\u46da\u46db\u46dc\u46dd\u46de\u46df\u46e0\u46e1\u46e2\u46e3\u46e4\u46e5\u46e6\u46e7\u46e8\u46e9\u46ea\u46eb\u46ec\u46ed\u46ee\u46ef\u46f0\u46f1\u46f2\u46f3\u46f4\u46f5\u46f6\u46f7\u46f8\u46f9\u46fa\u46fb\u46fc\u46fd\u46fe\u46ff\u4700\u4701\u4702\u4703\u4704\u4705\u4706\u4707\u4708\u4709\u470a\u470b\u470c\u470d\u470e\u470f\u4710\u4711\u4712\u4713\u4714\u4715\u4716\u4717\u4718\u4719\u471a\u471b\u471c\u471d\u471e\u471f\u4720\u4721\u4722\u4723\u4724\u4725\u4726\u4727\u4728\u4729\u472a\u472b\u472c\u472d\u472e\u472f\u4730\u4731\u4732\u4733\u4734\u4735\u4736\u4737\u4738\u4739\u473a\u473b\u473c\u473d\u473e\u473f\u4740\u4741\u4742\u4743\u4744\u4745\u4746\u4747\u4748\u4749\u474a\u474b\u474c\u474d\u474e\u474f\u4750\u4751\u4752\u4753\u4754\u4755\u4756\u4757\u4758\u4759\u475a\u475b\u475c\u475d\u475e\u475f\u4760\u4761\u4762\u4763\u4764\u4765\u4766\u4767\u4768\u4769\u476a\u476b\u476c\u476d\u476e\u476f\u4770\u4771\u4772\u4773\u4774\u4775\u4776\u4777\u4778\u4779\u477a\u477b\u477c\u477d\u477e\u477f\u4780\u4781\u4782\u4783\u4784\u4785\u4786\u4787\u4788\u4789\u478a\u478b\u478c\u478d\u478e\u478f\u4790\u4791\u4792\u4793\u4794\u4795\u4796\u4797\u4798\u4799\u479a\u479b\u479c\u479d\u479e\u479f\u47a0\u47a1\u47a2\u47a3\u47a4\u47a5\u47a6\u47a7\u47a8\u47a9\u47aa\u47ab\u47ac\u47ad\u47ae\u47af\u47b0\u47b1\u47b2\u47b3\u47b4\u47b5\u47b6\u47b7\u47b8\u47b9\u47ba\u47bb\u47bc\u47bd\u47be\u47bf\u47c0\u47c1\u47c2\u47c3\u47c4\u47c5\u47c6\u47c7\u47c8\u47c9\u47ca\u47cb\u47cc\u47cd\u47ce\u47cf\u47d0\u47d1\u47d2\u47d3\u47d4\u47d5\u47d6\u47d7\u47d8\u47d9\u47da\u47db\u47dc\u47dd\u47de\u47df\u47e0\u47e1\u47e2\u47e3\u47e4\u47e5\u47e6\u47e7\u47e8\u47e9\u47ea\u47eb\u47ec\u47ed\u47ee\u47ef\u47f0\u47f1\u47f2\u47f3\u47f4\u47f5\u47f6\u47f7\u47f8\u47f9\u47fa\u47fb\u47fc\u47fd\u47fe\u47ff\u4800\u4801\u4802\u4803\u4804\u4805\u4806\u4807\u4808\u4809\u480a\u480b\u480c\u480d\u480e\u480f\u4810\u4811\u4812\u4813\u4814\u4815\u4816\u4817\u4818\u4819\u481a\u481b\u481c\u481d\u481e\u481f\u4820\u4821\u4822\u4823\u4824\u4825\u4826\u4827\u4828\u4829\u482a\u482b\u482c\u482d\u482e\u482f\u4830\u4831\u4832\u4833\u4834\u4835\u4836\u4837\u4838\u4839\u483a\u483b\u483c\u483d\u483e\u483f\u4840\u4841\u4842\u4843\u4844\u4845\u4846\u4847\u4848\u4849\u484a\u484b\u484c\u484d\u484e\u484f\u4850\u4851\u4852\u4853\u4854\u4855\u4856\u4857\u4858\u4859\u485a\u485b\u485c\u485d\u485e\u485f\u4860\u4861\u4862\u4863\u4864\u4865\u4866\u4867\u4868\u4869\u486a\u486b\u486c\u486d\u486e\u486f\u4870\u4871\u4872\u4873\u4874\u4875\u4876\u4877\u4878\u4879\u487a\u487b\u487c\u487d\u487e\u487f\u4880\u4881\u4882\u4883\u4884\u4885\u4886\u4887\u4888\u4889\u488a\u488b\u488c\u488d\u488e\u488f\u4890\u4891\u4892\u4893\u4894\u4895\u4896\u4897\u4898\u4899\u489a\u489b\u489c\u489d\u489e\u489f\u48a0\u48a1\u48a2\u48a3\u48a4\u48a5\u48a6\u48a7\u48a8\u48a9\u48aa\u48ab\u48ac\u48ad\u48ae\u48af\u48b0\u48b1\u48b2\u48b3\u48b4\u48b5\u48b6\u48b7\u48b8\u48b9\u48ba\u48bb\u48bc\u48bd\u48be\u48bf\u48c0\u48c1\u48c2\u48c3\u48c4\u48c5\u48c6\u48c7\u48c8\u48c9\u48ca\u48cb\u48cc\u48cd\u48ce\u48cf\u48d0\u48d1\u48d2\u48d3\u48d4\u48d5\u48d6\u48d7\u48d8\u48d9\u48da\u48db\u48dc\u48dd\u48de\u48df\u48e0\u48e1\u48e2\u48e3\u48e4\u48e5\u48e6\u48e7\u48e8\u48e9\u48ea\u48eb\u48ec\u48ed\u48ee\u48ef\u48f0\u48f1\u48f2\u48f3\u48f4\u48f5\u48f6\u48f7\u48f8\u48f9\u48fa\u48fb\u48fc\u48fd\u48fe\u48ff\u4900\u4901\u4902\u4903\u4904\u4905\u4906\u4907\u4908\u4909\u490a\u490b\u490c\u490d\u490e\u490f\u4910\u4911\u4912\u4913\u4914\u4915\u4916\u4917\u4918\u4919\u491a\u491b\u491c\u491d\u491e\u491f\u4920\u4921\u4922\u4923\u4924\u4925\u4926\u4927\u4928\u4929\u492a\u492b\u492c\u492d\u492e\u492f\u4930\u4931\u4932\u4933\u4934\u4935\u4936\u4937\u4938\u4939\u493a\u493b\u493c\u493d\u493e\u493f\u4940\u4941\u4942\u4943\u4944\u4945\u4946\u4947\u4948\u4949\u494a\u494b\u494c\u494d\u494e\u494f\u4950\u4951\u4952\u4953\u4954\u4955\u4956\u4957\u4958\u4959\u495a\u495b\u495c\u495d\u495e\u495f\u4960\u4961\u4962\u4963\u4964\u4965\u4966\u4967\u4968\u4969\u496a\u496b\u496c\u496d\u496e\u496f\u4970\u4971\u4972\u4973\u4974\u4975\u4976\u4977\u4978\u4979\u497a\u497b\u497c\u497d\u497e\u497f\u4980\u4981\u4982\u4983\u4984\u4985\u4986\u4987\u4988\u4989\u498a\u498b\u498c\u498d\u498e\u498f\u4990\u4991\u4992\u4993\u4994\u4995\u4996\u4997\u4998\u4999\u499a\u499b\u499c\u499d\u499e\u499f\u49a0\u49a1\u49a2\u49a3\u49a4\u49a5\u49a6\u49a7\u49a8\u49a9\u49aa\u49ab\u49ac\u49ad\u49ae\u49af\u49b0\u49b1\u49b2\u49b3\u49b4\u49b5\u49b6\u49b7\u49b8\u49b9\u49ba\u49bb\u49bc\u49bd\u49be\u49bf\u49c0\u49c1\u49c2\u49c3\u49c4\u49c5\u49c6\u49c7\u49c8\u49c9\u49ca\u49cb\u49cc\u49cd\u49ce\u49cf\u49d0\u49d1\u49d2\u49d3\u49d4\u49d5\u49d6\u49d7\u49d8\u49d9\u49da\u49db\u49dc\u49dd\u49de\u49df\u49e0\u49e1\u49e2\u49e3\u49e4\u49e5\u49e6\u49e7\u49e8\u49e9\u49ea\u49eb\u49ec\u49ed\u49ee\u49ef\u49f0\u49f1\u49f2\u49f3\u49f4\u49f5\u49f6\u49f7\u49f8\u49f9\u49fa\u49fb\u49fc\u49fd\u49fe\u49ff\u4a00\u4a01\u4a02\u4a03\u4a04\u4a05\u4a06\u4a07\u4a08\u4a09\u4a0a\u4a0b\u4a0c\u4a0d\u4a0e\u4a0f\u4a10\u4a11\u4a12\u4a13\u4a14\u4a15\u4a16\u4a17\u4a18\u4a19\u4a1a\u4a1b\u4a1c\u4a1d\u4a1e\u4a1f\u4a20\u4a21\u4a22\u4a23\u4a24\u4a25\u4a26\u4a27\u4a28\u4a29\u4a2a\u4a2b\u4a2c\u4a2d\u4a2e\u4a2f\u4a30\u4a31\u4a32\u4a33\u4a34\u4a35\u4a36\u4a37\u4a38\u4a39\u4a3a\u4a3b\u4a3c\u4a3d\u4a3e\u4a3f\u4a40\u4a41\u4a42\u4a43\u4a44\u4a45\u4a46\u4a47\u4a48\u4a49\u4a4a\u4a4b\u4a4c\u4a4d\u4a4e\u4a4f\u4a50\u4a51\u4a52\u4a53\u4a54\u4a55\u4a56\u4a57\u4a58\u4a59\u4a5a\u4a5b\u4a5c\u4a5d\u4a5e\u4a5f\u4a60\u4a61\u4a62\u4a63\u4a64\u4a65\u4a66\u4a67\u4a68\u4a69\u4a6a\u4a6b\u4a6c\u4a6d\u4a6e\u4a6f\u4a70\u4a71\u4a72\u4a73\u4a74\u4a75\u4a76\u4a77\u4a78\u4a79\u4a7a\u4a7b\u4a7c\u4a7d\u4a7e\u4a7f\u4a80\u4a81\u4a82\u4a83\u4a84\u4a85\u4a86\u4a87\u4a88\u4a89\u4a8a\u4a8b\u4a8c\u4a8d\u4a8e\u4a8f\u4a90\u4a91\u4a92\u4a93\u4a94\u4a95\u4a96\u4a97\u4a98\u4a99\u4a9a\u4a9b\u4a9c\u4a9d\u4a9e\u4a9f\u4aa0\u4aa1\u4aa2\u4aa3\u4aa4\u4aa5\u4aa6\u4aa7\u4aa8\u4aa9\u4aaa\u4aab\u4aac\u4aad\u4aae\u4aaf\u4ab0\u4ab1\u4ab2\u4ab3\u4ab4\u4ab5\u4ab6\u4ab7\u4ab8\u4ab9\u4aba\u4abb\u4abc\u4abd\u4abe\u4abf\u4ac0\u4ac1\u4ac2\u4ac3\u4ac4\u4ac5\u4ac6\u4ac7\u4ac8\u4ac9\u4aca\u4acb\u4acc\u4acd\u4ace\u4acf\u4ad0\u4ad1\u4ad2\u4ad3\u4ad4\u4ad5\u4ad6\u4ad7\u4ad8\u4ad9\u4ada\u4adb\u4adc\u4add\u4ade\u4adf\u4ae0\u4ae1\u4ae2\u4ae3\u4ae4\u4ae5\u4ae6\u4ae7\u4ae8\u4ae9\u4aea\u4aeb\u4aec\u4aed\u4aee\u4aef\u4af0\u4af1\u4af2\u4af3\u4af4\u4af5\u4af6\u4af7\u4af8\u4af9\u4afa\u4afb\u4afc\u4afd\u4afe\u4aff\u4b00\u4b01\u4b02\u4b03\u4b04\u4b05\u4b06\u4b07\u4b08\u4b09\u4b0a\u4b0b\u4b0c\u4b0d\u4b0e\u4b0f\u4b10\u4b11\u4b12\u4b13\u4b14\u4b15\u4b16\u4b17\u4b18\u4b19\u4b1a\u4b1b\u4b1c\u4b1d\u4b1e\u4b1f\u4b20\u4b21\u4b22\u4b23\u4b24\u4b25\u4b26\u4b27\u4b28\u4b29\u4b2a\u4b2b\u4b2c\u4b2d\u4b2e\u4b2f\u4b30\u4b31\u4b32\u4b33\u4b34\u4b35\u4b36\u4b37\u4b38\u4b39\u4b3a\u4b3b\u4b3c\u4b3d\u4b3e\u4b3f\u4b40\u4b41\u4b42\u4b43\u4b44\u4b45\u4b46\u4b47\u4b48\u4b49\u4b4a\u4b4b\u4b4c\u4b4d\u4b4e\u4b4f\u4b50\u4b51\u4b52\u4b53\u4b54\u4b55\u4b56\u4b57\u4b58\u4b59\u4b5a\u4b5b\u4b5c\u4b5d\u4b5e\u4b5f\u4b60\u4b61\u4b62\u4b63\u4b64\u4b65\u4b66\u4b67\u4b68\u4b69\u4b6a\u4b6b\u4b6c\u4b6d\u4b6e\u4b6f\u4b70\u4b71\u4b72\u4b73\u4b74\u4b75\u4b76\u4b77\u4b78\u4b79\u4b7a\u4b7b\u4b7c\u4b7d\u4b7e\u4b7f\u4b80\u4b81\u4b82\u4b83\u4b84\u4b85\u4b86\u4b87\u4b88\u4b89\u4b8a\u4b8b\u4b8c\u4b8d\u4b8e\u4b8f\u4b90\u4b91\u4b92\u4b93\u4b94\u4b95\u4b96\u4b97\u4b98\u4b99\u4b9a\u4b9b\u4b9c\u4b9d\u4b9e\u4b9f\u4ba0\u4ba1\u4ba2\u4ba3\u4ba4\u4ba5\u4ba6\u4ba7\u4ba8\u4ba9\u4baa\u4bab\u4bac\u4bad\u4bae\u4baf\u4bb0\u4bb1\u4bb2\u4bb3\u4bb4\u4bb5\u4bb6\u4bb7\u4bb8\u4bb9\u4bba\u4bbb\u4bbc\u4bbd\u4bbe\u4bbf\u4bc0\u4bc1\u4bc2\u4bc3\u4bc4\u4bc5\u4bc6\u4bc7\u4bc8\u4bc9\u4bca\u4bcb\u4bcc\u4bcd\u4bce\u4bcf\u4bd0\u4bd1\u4bd2\u4bd3\u4bd4\u4bd5\u4bd6\u4bd7\u4bd8\u4bd9\u4bda\u4bdb\u4bdc\u4bdd\u4bde\u4bdf\u4be0\u4be1\u4be2\u4be3\u4be4\u4be5\u4be6\u4be7\u4be8\u4be9\u4bea\u4beb\u4bec\u4bed\u4bee\u4bef\u4bf0\u4bf1\u4bf2\u4bf3\u4bf4\u4bf5\u4bf6\u4bf7\u4bf8\u4bf9\u4bfa\u4bfb\u4bfc\u4bfd\u4bfe\u4bff\u4c00\u4c01\u4c02\u4c03\u4c04\u4c05\u4c06\u4c07\u4c08\u4c09\u4c0a\u4c0b\u4c0c\u4c0d\u4c0e\u4c0f\u4c10\u4c11\u4c12\u4c13\u4c14\u4c15\u4c16\u4c17\u4c18\u4c19\u4c1a\u4c1b\u4c1c\u4c1d\u4c1e\u4c1f\u4c20\u4c21\u4c22\u4c23\u4c24\u4c25\u4c26\u4c27\u4c28\u4c29\u4c2a\u4c2b\u4c2c\u4c2d\u4c2e\u4c2f\u4c30\u4c31\u4c32\u4c33\u4c34\u4c35\u4c36\u4c37\u4c38\u4c39\u4c3a\u4c3b\u4c3c\u4c3d\u4c3e\u4c3f\u4c40\u4c41\u4c42\u4c43\u4c44\u4c45\u4c46\u4c47\u4c48\u4c49\u4c4a\u4c4b\u4c4c\u4c4d\u4c4e\u4c4f\u4c50\u4c51\u4c52\u4c53\u4c54\u4c55\u4c56\u4c57\u4c58\u4c59\u4c5a\u4c5b\u4c5c\u4c5d\u4c5e\u4c5f\u4c60\u4c61\u4c62\u4c63\u4c64\u4c65\u4c66\u4c67\u4c68\u4c69\u4c6a\u4c6b\u4c6c\u4c6d\u4c6e\u4c6f\u4c70\u4c71\u4c72\u4c73\u4c74\u4c75\u4c76\u4c77\u4c78\u4c79\u4c7a\u4c7b\u4c7c\u4c7d\u4c7e\u4c7f\u4c80\u4c81\u4c82\u4c83\u4c84\u4c85\u4c86\u4c87\u4c88\u4c89\u4c8a\u4c8b\u4c8c\u4c8d\u4c8e\u4c8f\u4c90\u4c91\u4c92\u4c93\u4c94\u4c95\u4c96\u4c97\u4c98\u4c99\u4c9a\u4c9b\u4c9c\u4c9d\u4c9e\u4c9f\u4ca0\u4ca1\u4ca2\u4ca3\u4ca4\u4ca5\u4ca6\u4ca7\u4ca8\u4ca9\u4caa\u4cab\u4cac\u4cad\u4cae\u4caf\u4cb0\u4cb1\u4cb2\u4cb3\u4cb4\u4cb5\u4cb6\u4cb7\u4cb8\u4cb9\u4cba\u4cbb\u4cbc\u4cbd\u4cbe\u4cbf\u4cc0\u4cc1\u4cc2\u4cc3\u4cc4\u4cc5\u4cc6\u4cc7\u4cc8\u4cc9\u4cca\u4ccb\u4ccc\u4ccd\u4cce\u4ccf\u4cd0\u4cd1\u4cd2\u4cd3\u4cd4\u4cd5\u4cd6\u4cd7\u4cd8\u4cd9\u4cda\u4cdb\u4cdc\u4cdd\u4cde\u4cdf\u4ce0\u4ce1\u4ce2\u4ce3\u4ce4\u4ce5\u4ce6\u4ce7\u4ce8\u4ce9\u4cea\u4ceb\u4cec\u4ced\u4cee\u4cef\u4cf0\u4cf1\u4cf2\u4cf3\u4cf4\u4cf5\u4cf6\u4cf7\u4cf8\u4cf9\u4cfa\u4cfb\u4cfc\u4cfd\u4cfe\u4cff\u4d00\u4d01\u4d02\u4d03\u4d04\u4d05\u4d06\u4d07\u4d08\u4d09\u4d0a\u4d0b\u4d0c\u4d0d\u4d0e\u4d0f\u4d10\u4d11\u4d12\u4d13\u4d14\u4d15\u4d16\u4d17\u4d18\u4d19\u4d1a\u4d1b\u4d1c\u4d1d\u4d1e\u4d1f\u4d20\u4d21\u4d22\u4d23\u4d24\u4d25\u4d26\u4d27\u4d28\u4d29\u4d2a\u4d2b\u4d2c\u4d2d\u4d2e\u4d2f\u4d30\u4d31\u4d32\u4d33\u4d34\u4d35\u4d36\u4d37\u4d38\u4d39\u4d3a\u4d3b\u4d3c\u4d3d\u4d3e\u4d3f\u4d40\u4d41\u4d42\u4d43\u4d44\u4d45\u4d46\u4d47\u4d48\u4d49\u4d4a\u4d4b\u4d4c\u4d4d\u4d4e\u4d4f\u4d50\u4d51\u4d52\u4d53\u4d54\u4d55\u4d56\u4d57\u4d58\u4d59\u4d5a\u4d5b\u4d5c\u4d5d\u4d5e\u4d5f\u4d60\u4d61\u4d62\u4d63\u4d64\u4d65\u4d66\u4d67\u4d68\u4d69\u4d6a\u4d6b\u4d6c\u4d6d\u4d6e\u4d6f\u4d70\u4d71\u4d72\u4d73\u4d74\u4d75\u4d76\u4d77\u4d78\u4d79\u4d7a\u4d7b\u4d7c\u4d7d\u4d7e\u4d7f\u4d80\u4d81\u4d82\u4d83\u4d84\u4d85\u4d86\u4d87\u4d88\u4d89\u4d8a\u4d8b\u4d8c\u4d8d\u4d8e\u4d8f\u4d90\u4d91\u4d92\u4d93\u4d94\u4d95\u4d96\u4d97\u4d98\u4d99\u4d9a\u4d9b\u4d9c\u4d9d\u4d9e\u4d9f\u4da0\u4da1\u4da2\u4da3\u4da4\u4da5\u4da6\u4da7\u4da8\u4da9\u4daa\u4dab\u4dac\u4dad\u4dae\u4daf\u4db0\u4db1\u4db2\u4db3\u4db4\u4db5\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d\u4e0e\u4e0f\u4e10\u4e11\u4e12\u4e13\u4e14\u4e15\u4e16\u4e17\u4e18\u4e19\u4e1a\u4e1b\u4e1c\u4e1d\u4e1e\u4e1f\u4e20\u4e21\u4e22\u4e23\u4e24\u4e25\u4e26\u4e27\u4e28\u4e29\u4e2a\u4e2b\u4e2c\u4e2d\u4e2e\u4e2f\u4e30\u4e31\u4e32\u4e33\u4e34\u4e35\u4e36\u4e37\u4e38\u4e39\u4e3a\u4e3b\u4e3c\u4e3d\u4e3e\u4e3f\u4e40\u4e41\u4e42\u4e43\u4e44\u4e45\u4e46\u4e47\u4e48\u4e49\u4e4a\u4e4b\u4e4c\u4e4d\u4e4e\u4e4f\u4e50\u4e51\u4e52\u4e53\u4e54\u4e55\u4e56\u4e57\u4e58\u4e59\u4e5a\u4e5b\u4e5c\u4e5d\u4e5e\u4e5f\u4e60\u4e61\u4e62\u4e63\u4e64\u4e65\u4e66\u4e67\u4e68\u4e69\u4e6a\u4e6b\u4e6c\u4e6d\u4e6e\u4e6f\u4e70\u4e71\u4e72\u4e73\u4e74\u4e75\u4e76\u4e77\u4e78\u4e79\u4e7a\u4e7b\u4e7c\u4e7d\u4e7e\u4e7f\u4e80\u4e81\u4e82\u4e83\u4e84\u4e85\u4e86\u4e87\u4e88\u4e89\u4e8a\u4e8b\u4e8c\u4e8d\u4e8e\u4e8f\u4e90\u4e91\u4e92\u4e93\u4e94\u4e95\u4e96\u4e97\u4e98\u4e99\u4e9a\u4e9b\u4e9c\u4e9d\u4e9e\u4e9f\u4ea0\u4ea1\u4ea2\u4ea3\u4ea4\u4ea5\u4ea6\u4ea7\u4ea8\u4ea9\u4eaa\u4eab\u4eac\u4ead\u4eae\u4eaf\u4eb0\u4eb1\u4eb2\u4eb3\u4eb4\u4eb5\u4eb6\u4eb7\u4eb8\u4eb9\u4eba\u4ebb\u4ebc\u4ebd\u4ebe\u4ebf\u4ec0\u4ec1\u4ec2\u4ec3\u4ec4\u4ec5\u4ec6\u4ec7\u4ec8\u4ec9\u4eca\u4ecb\u4ecc\u4ecd\u4ece\u4ecf\u4ed0\u4ed1\u4ed2\u4ed3\u4ed4\u4ed5\u4ed6\u4ed7\u4ed8\u4ed9\u4eda\u4edb\u4edc\u4edd\u4ede\u4edf\u4ee0\u4ee1\u4ee2\u4ee3\u4ee4\u4ee5\u4ee6\u4ee7\u4ee8\u4ee9\u4eea\u4eeb\u4eec\u4eed\u4eee\u4eef\u4ef0\u4ef1\u4ef2\u4ef3\u4ef4\u4ef5\u4ef6\u4ef7\u4ef8\u4ef9\u4efa\u4efb\u4efc\u4efd\u4efe\u4eff\u4f00\u4f01\u4f02\u4f03\u4f04\u4f05\u4f06\u4f07\u4f08\u4f09\u4f0a\u4f0b\u4f0c\u4f0d\u4f0e\u4f0f\u4f10\u4f11\u4f12\u4f13\u4f14\u4f15\u4f16\u4f17\u4f18\u4f19\u4f1a\u4f1b\u4f1c\u4f1d\u4f1e\u4f1f\u4f20\u4f21\u4f22\u4f23\u4f24\u4f25\u4f26\u4f27\u4f28\u4f29\u4f2a\u4f2b\u4f2c\u4f2d\u4f2e\u4f2f\u4f30\u4f31\u4f32\u4f33\u4f34\u4f35\u4f36\u4f37\u4f38\u4f39\u4f3a\u4f3b\u4f3c\u4f3d\u4f3e\u4f3f\u4f40\u4f41\u4f42\u4f43\u4f44\u4f45\u4f46\u4f47\u4f48\u4f49\u4f4a\u4f4b\u4f4c\u4f4d\u4f4e\u4f4f\u4f50\u4f51\u4f52\u4f53\u4f54\u4f55\u4f56\u4f57\u4f58\u4f59\u4f5a\u4f5b\u4f5c\u4f5d\u4f5e\u4f5f\u4f60\u4f61\u4f62\u4f63\u4f64\u4f65\u4f66\u4f67\u4f68\u4f69\u4f6a\u4f6b\u4f6c\u4f6d\u4f6e\u4f6f\u4f70\u4f71\u4f72\u4f73\u4f74\u4f75\u4f76\u4f77\u4f78\u4f79\u4f7a\u4f7b\u4f7c\u4f7d\u4f7e\u4f7f\u4f80\u4f81\u4f82\u4f83\u4f84\u4f85\u4f86\u4f87\u4f88\u4f89\u4f8a\u4f8b\u4f8c\u4f8d\u4f8e\u4f8f\u4f90\u4f91\u4f92\u4f93\u4f94\u4f95\u4f96\u4f97\u4f98\u4f99\u4f9a\u4f9b\u4f9c\u4f9d\u4f9e\u4f9f\u4fa0\u4fa1\u4fa2\u4fa3\u4fa4\u4fa5\u4fa6\u4fa7\u4fa8\u4fa9\u4faa\u4fab\u4fac\u4fad\u4fae\u4faf\u4fb0\u4fb1\u4fb2\u4fb3\u4fb4\u4fb5\u4fb6\u4fb7\u4fb8\u4fb9\u4fba\u4fbb\u4fbc\u4fbd\u4fbe\u4fbf\u4fc0\u4fc1\u4fc2\u4fc3\u4fc4\u4fc5\u4fc6\u4fc7\u4fc8\u4fc9\u4fca\u4fcb\u4fcc\u4fcd\u4fce\u4fcf\u4fd0\u4fd1\u4fd2\u4fd3\u4fd4\u4fd5\u4fd6\u4fd7\u4fd8\u4fd9\u4fda\u4fdb\u4fdc\u4fdd\u4fde\u4fdf\u4fe0\u4fe1\u4fe2\u4fe3\u4fe4\u4fe5\u4fe6\u4fe7\u4fe8\u4fe9\u4fea\u4feb\u4fec\u4fed\u4fee\u4fef\u4ff0\u4ff1\u4ff2\u4ff3\u4ff4\u4ff5\u4ff6\u4ff7\u4ff8\u4ff9\u4ffa\u4ffb\u4ffc\u4ffd\u4ffe\u4fff\u5000\u5001\u5002\u5003\u5004\u5005\u5006\u5007\u5008\u5009\u500a\u500b\u500c\u500d\u500e\u500f\u5010\u5011\u5012\u5013\u5014\u5015\u5016\u5017\u5018\u5019\u501a\u501b\u501c\u501d\u501e\u501f\u5020\u5021\u5022\u5023\u5024\u5025\u5026\u5027\u5028\u5029\u502a\u502b\u502c\u502d\u502e\u502f\u5030\u5031\u5032\u5033\u5034\u5035\u5036\u5037\u5038\u5039\u503a\u503b\u503c\u503d\u503e\u503f\u5040\u5041\u5042\u5043\u5044\u5045\u5046\u5047\u5048\u5049\u504a\u504b\u504c\u504d\u504e\u504f\u5050\u5051\u5052\u5053\u5054\u5055\u5056\u5057\u5058\u5059\u505a\u505b\u505c\u505d\u505e\u505f\u5060\u5061\u5062\u5063\u5064\u5065\u5066\u5067\u5068\u5069\u506a\u506b\u506c\u506d\u506e\u506f\u5070\u5071\u5072\u5073\u5074\u5075\u5076\u5077\u5078\u5079\u507a\u507b\u507c\u507d\u507e\u507f\u5080\u5081\u5082\u5083\u5084\u5085\u5086\u5087\u5088\u5089\u508a\u508b\u508c\u508d\u508e\u508f\u5090\u5091\u5092\u5093\u5094\u5095\u5096\u5097\u5098\u5099\u509a\u509b\u509c\u509d\u509e\u509f\u50a0\u50a1\u50a2\u50a3\u50a4\u50a5\u50a6\u50a7\u50a8\u50a9\u50aa\u50ab\u50ac\u50ad\u50ae\u50af\u50b0\u50b1\u50b2\u50b3\u50b4\u50b5\u50b6\u50b7\u50b8\u50b9\u50ba\u50bb\u50bc\u50bd\u50be\u50bf\u50c0\u50c1\u50c2\u50c3\u50c4\u50c5\u50c6\u50c7\u50c8\u50c9\u50ca\u50cb\u50cc\u50cd\u50ce\u50cf\u50d0\u50d1\u50d2\u50d3\u50d4\u50d5\u50d6\u50d7\u50d8\u50d9\u50da\u50db\u50dc\u50dd\u50de\u50df\u50e0\u50e1\u50e2\u50e3\u50e4\u50e5\u50e6\u50e7\u50e8\u50e9\u50ea\u50eb\u50ec\u50ed\u50ee\u50ef\u50f0\u50f1\u50f2\u50f3\u50f4\u50f5\u50f6\u50f7\u50f8\u50f9\u50fa\u50fb\u50fc\u50fd\u50fe\u50ff\u5100\u5101\u5102\u5103\u5104\u5105\u5106\u5107\u5108\u5109\u510a\u510b\u510c\u510d\u510e\u510f\u5110\u5111\u5112\u5113\u5114\u5115\u5116\u5117\u5118\u5119\u511a\u511b\u511c\u511d\u511e\u511f\u5120\u5121\u5122\u5123\u5124\u5125\u5126\u5127\u5128\u5129\u512a\u512b\u512c\u512d\u512e\u512f\u5130\u5131\u5132\u5133\u5134\u5135\u5136\u5137\u5138\u5139\u513a\u513b\u513c\u513d\u513e\u513f\u5140\u5141\u5142\u5143\u5144\u5145\u5146\u5147\u5148\u5149\u514a\u514b\u514c\u514d\u514e\u514f\u5150\u5151\u5152\u5153\u5154\u5155\u5156\u5157\u5158\u5159\u515a\u515b\u515c\u515d\u515e\u515f\u5160\u5161\u5162\u5163\u5164\u5165\u5166\u5167\u5168\u5169\u516a\u516b\u516c\u516d\u516e\u516f\u5170\u5171\u5172\u5173\u5174\u5175\u5176\u5177\u5178\u5179\u517a\u517b\u517c\u517d\u517e\u517f\u5180\u5181\u5182\u5183\u5184\u5185\u5186\u5187\u5188\u5189\u518a\u518b\u518c\u518d\u518e\u518f\u5190\u5191\u5192\u5193\u5194\u5195\u5196\u5197\u5198\u5199\u519a\u519b\u519c\u519d\u519e\u519f\u51a0\u51a1\u51a2\u51a3\u51a4\u51a5\u51a6\u51a7\u51a8\u51a9\u51aa\u51ab\u51ac\u51ad\u51ae\u51af\u51b0\u51b1\u51b2\u51b3\u51b4\u51b5\u51b6\u51b7\u51b8\u51b9\u51ba\u51bb\u51bc\u51bd\u51be\u51bf\u51c0\u51c1\u51c2\u51c3\u51c4\u51c5\u51c6\u51c7\u51c8\u51c9\u51ca\u51cb\u51cc\u51cd\u51ce\u51cf\u51d0\u51d1\u51d2\u51d3\u51d4\u51d5\u51d6\u51d7\u51d8\u51d9\u51da\u51db\u51dc\u51dd\u51de\u51df\u51e0\u51e1\u51e2\u51e3\u51e4\u51e5\u51e6\u51e7\u51e8\u51e9\u51ea\u51eb\u51ec\u51ed\u51ee\u51ef\u51f0\u51f1\u51f2\u51f3\u51f4\u51f5\u51f6\u51f7\u51f8\u51f9\u51fa\u51fb\u51fc\u51fd\u51fe\u51ff\u5200\u5201\u5202\u5203\u5204\u5205\u5206\u5207\u5208\u5209\u520a\u520b\u520c\u520d\u520e\u520f\u5210\u5211\u5212\u5213\u5214\u5215\u5216\u5217\u5218\u5219\u521a\u521b\u521c\u521d\u521e\u521f\u5220\u5221\u5222\u5223\u5224\u5225\u5226\u5227\u5228\u5229\u522a\u522b\u522c\u522d\u522e\u522f\u5230\u5231\u5232\u5233\u5234\u5235\u5236\u5237\u5238\u5239\u523a\u523b\u523c\u523d\u523e\u523f\u5240\u5241\u5242\u5243\u5244\u5245\u5246\u5247\u5248\u5249\u524a\u524b\u524c\u524d\u524e\u524f\u5250\u5251\u5252\u5253\u5254\u5255\u5256\u5257\u5258\u5259\u525a\u525b\u525c\u525d\u525e\u525f\u5260\u5261\u5262\u5263\u5264\u5265\u5266\u5267\u5268\u5269\u526a\u526b\u526c\u526d\u526e\u526f\u5270\u5271\u5272\u5273\u5274\u5275\u5276\u5277\u5278\u5279\u527a\u527b\u527c\u527d\u527e\u527f\u5280\u5281\u5282\u5283\u5284\u5285\u5286\u5287\u5288\u5289\u528a\u528b\u528c\u528d\u528e\u528f\u5290\u5291\u5292\u5293\u5294\u5295\u5296\u5297\u5298\u5299\u529a\u529b\u529c\u529d\u529e\u529f\u52a0\u52a1\u52a2\u52a3\u52a4\u52a5\u52a6\u52a7\u52a8\u52a9\u52aa\u52ab\u52ac\u52ad\u52ae\u52af\u52b0\u52b1\u52b2\u52b3\u52b4\u52b5\u52b6\u52b7\u52b8\u52b9\u52ba\u52bb\u52bc\u52bd\u52be\u52bf\u52c0\u52c1\u52c2\u52c3\u52c4\u52c5\u52c6\u52c7\u52c8\u52c9\u52ca\u52cb\u52cc\u52cd\u52ce\u52cf\u52d0\u52d1\u52d2\u52d3\u52d4\u52d5\u52d6\u52d7\u52d8\u52d9\u52da\u52db\u52dc\u52dd\u52de\u52df\u52e0\u52e1\u52e2\u52e3\u52e4\u52e5\u52e6\u52e7\u52e8\u52e9\u52ea\u52eb\u52ec\u52ed\u52ee\u52ef\u52f0\u52f1\u52f2\u52f3\u52f4\u52f5\u52f6\u52f7\u52f8\u52f9\u52fa\u52fb\u52fc\u52fd\u52fe\u52ff\u5300\u5301\u5302\u5303\u5304\u5305\u5306\u5307\u5308\u5309\u530a\u530b\u530c\u530d\u530e\u530f\u5310\u5311\u5312\u5313\u5314\u5315\u5316\u5317\u5318\u5319\u531a\u531b\u531c\u531d\u531e\u531f\u5320\u5321\u5322\u5323\u5324\u5325\u5326\u5327\u5328\u5329\u532a\u532b\u532c\u532d\u532e\u532f\u5330\u5331\u5332\u5333\u5334\u5335\u5336\u5337\u5338\u5339\u533a\u533b\u533c\u533d\u533e\u533f\u5340\u5341\u5342\u5343\u5344\u5345\u5346\u5347\u5348\u5349\u534a\u534b\u534c\u534d\u534e\u534f\u5350\u5351\u5352\u5353\u5354\u5355\u5356\u5357\u5358\u5359\u535a\u535b\u535c\u535d\u535e\u535f\u5360\u5361\u5362\u5363\u5364\u5365\u5366\u5367\u5368\u5369\u536a\u536b\u536c\u536d\u536e\u536f\u5370\u5371\u5372\u5373\u5374\u5375\u5376\u5377\u5378\u5379\u537a\u537b\u537c\u537d\u537e\u537f\u5380\u5381\u5382\u5383\u5384\u5385\u5386\u5387\u5388\u5389\u538a\u538b\u538c\u538d\u538e\u538f\u5390\u5391\u5392\u5393\u5394\u5395\u5396\u5397\u5398\u5399\u539a\u539b\u539c\u539d\u539e\u539f\u53a0\u53a1\u53a2\u53a3\u53a4\u53a5\u53a6\u53a7\u53a8\u53a9\u53aa\u53ab\u53ac\u53ad\u53ae\u53af\u53b0\u53b1\u53b2\u53b3\u53b4\u53b5\u53b6\u53b7\u53b8\u53b9\u53ba\u53bb\u53bc\u53bd\u53be\u53bf\u53c0\u53c1\u53c2\u53c3\u53c4\u53c5\u53c6\u53c7\u53c8\u53c9\u53ca\u53cb\u53cc\u53cd\u53ce\u53cf\u53d0\u53d1\u53d2\u53d3\u53d4\u53d5\u53d6\u53d7\u53d8\u53d9\u53da\u53db\u53dc\u53dd\u53de\u53df\u53e0\u53e1\u53e2\u53e3\u53e4\u53e5\u53e6\u53e7\u53e8\u53e9\u53ea\u53eb\u53ec\u53ed\u53ee\u53ef\u53f0\u53f1\u53f2\u53f3\u53f4\u53f5\u53f6\u53f7\u53f8\u53f9\u53fa\u53fb\u53fc\u53fd\u53fe\u53ff\u5400\u5401\u5402\u5403\u5404\u5405\u5406\u5407\u5408\u5409\u540a\u540b\u540c\u540d\u540e\u540f\u5410\u5411\u5412\u5413\u5414\u5415\u5416\u5417\u5418\u5419\u541a\u541b\u541c\u541d\u541e\u541f\u5420\u5421\u5422\u5423\u5424\u5425\u5426\u5427\u5428\u5429\u542a\u542b\u542c\u542d\u542e\u542f\u5430\u5431\u5432\u5433\u5434\u5435\u5436\u5437\u5438\u5439\u543a\u543b\u543c\u543d\u543e\u543f\u5440\u5441\u5442\u5443\u5444\u5445\u5446\u5447\u5448\u5449\u544a\u544b\u544c\u544d\u544e\u544f\u5450\u5451\u5452\u5453\u5454\u5455\u5456\u5457\u5458\u5459\u545a\u545b\u545c\u545d\u545e\u545f\u5460\u5461\u5462\u5463\u5464\u5465\u5466\u5467\u5468\u5469\u546a\u546b\u546c\u546d\u546e\u546f\u5470\u5471\u5472\u5473\u5474\u5475\u5476\u5477\u5478\u5479\u547a\u547b\u547c\u547d\u547e\u547f\u5480\u5481\u5482\u5483\u5484\u5485\u5486\u5487\u5488\u5489\u548a\u548b\u548c\u548d\u548e\u548f\u5490\u5491\u5492\u5493\u5494\u5495\u5496\u5497\u5498\u5499\u549a\u549b\u549c\u549d\u549e\u549f\u54a0\u54a1\u54a2\u54a3\u54a4\u54a5\u54a6\u54a7\u54a8\u54a9\u54aa\u54ab\u54ac\u54ad\u54ae\u54af\u54b0\u54b1\u54b2\u54b3\u54b4\u54b5\u54b6\u54b7\u54b8\u54b9\u54ba\u54bb\u54bc\u54bd\u54be\u54bf\u54c0\u54c1\u54c2\u54c3\u54c4\u54c5\u54c6\u54c7\u54c8\u54c9\u54ca\u54cb\u54cc\u54cd\u54ce\u54cf\u54d0\u54d1\u54d2\u54d3\u54d4\u54d5\u54d6\u54d7\u54d8\u54d9\u54da\u54db\u54dc\u54dd\u54de\u54df\u54e0\u54e1\u54e2\u54e3\u54e4\u54e5\u54e6\u54e7\u54e8\u54e9\u54ea\u54eb\u54ec\u54ed\u54ee\u54ef\u54f0\u54f1\u54f2\u54f3\u54f4\u54f5\u54f6\u54f7\u54f8\u54f9\u54fa\u54fb\u54fc\u54fd\u54fe\u54ff\u5500\u5501\u5502\u5503\u5504\u5505\u5506\u5507\u5508\u5509\u550a\u550b\u550c\u550d\u550e\u550f\u5510\u5511\u5512\u5513\u5514\u5515\u5516\u5517\u5518\u5519\u551a\u551b\u551c\u551d\u551e\u551f\u5520\u5521\u5522\u5523\u5524\u5525\u5526\u5527\u5528\u5529\u552a\u552b\u552c\u552d\u552e\u552f\u5530\u5531\u5532\u5533\u5534\u5535\u5536\u5537\u5538\u5539\u553a\u553b\u553c\u553d\u553e\u553f\u5540\u5541\u5542\u5543\u5544\u5545\u5546\u5547\u5548\u5549\u554a\u554b\u554c\u554d\u554e\u554f\u5550\u5551\u5552\u5553\u5554\u5555\u5556\u5557\u5558\u5559\u555a\u555b\u555c\u555d\u555e\u555f\u5560\u5561\u5562\u5563\u5564\u5565\u5566\u5567\u5568\u5569\u556a\u556b\u556c\u556d\u556e\u556f\u5570\u5571\u5572\u5573\u5574\u5575\u5576\u5577\u5578\u5579\u557a\u557b\u557c\u557d\u557e\u557f\u5580\u5581\u5582\u5583\u5584\u5585\u5586\u5587\u5588\u5589\u558a\u558b\u558c\u558d\u558e\u558f\u5590\u5591\u5592\u5593\u5594\u5595\u5596\u5597\u5598\u5599\u559a\u559b\u559c\u559d\u559e\u559f\u55a0\u55a1\u55a2\u55a3\u55a4\u55a5\u55a6\u55a7\u55a8\u55a9\u55aa\u55ab\u55ac\u55ad\u55ae\u55af\u55b0\u55b1\u55b2\u55b3\u55b4\u55b5\u55b6\u55b7\u55b8\u55b9\u55ba\u55bb\u55bc\u55bd\u55be\u55bf\u55c0\u55c1\u55c2\u55c3\u55c4\u55c5\u55c6\u55c7\u55c8\u55c9\u55ca\u55cb\u55cc\u55cd\u55ce\u55cf\u55d0\u55d1\u55d2\u55d3\u55d4\u55d5\u55d6\u55d7\u55d8\u55d9\u55da\u55db\u55dc\u55dd\u55de\u55df\u55e0\u55e1\u55e2\u55e3\u55e4\u55e5\u55e6\u55e7\u55e8\u55e9\u55ea\u55eb\u55ec\u55ed\u55ee\u55ef\u55f0\u55f1\u55f2\u55f3\u55f4\u55f5\u55f6\u55f7\u55f8\u55f9\u55fa\u55fb\u55fc\u55fd\u55fe\u55ff\u5600\u5601\u5602\u5603\u5604\u5605\u5606\u5607\u5608\u5609\u560a\u560b\u560c\u560d\u560e\u560f\u5610\u5611\u5612\u5613\u5614\u5615\u5616\u5617\u5618\u5619\u561a\u561b\u561c\u561d\u561e\u561f\u5620\u5621\u5622\u5623\u5624\u5625\u5626\u5627\u5628\u5629\u562a\u562b\u562c\u562d\u562e\u562f\u5630\u5631\u5632\u5633\u5634\u5635\u5636\u5637\u5638\u5639\u563a\u563b\u563c\u563d\u563e\u563f\u5640\u5641\u5642\u5643\u5644\u5645\u5646\u5647\u5648\u5649\u564a\u564b\u564c\u564d\u564e\u564f\u5650\u5651\u5652\u5653\u5654\u5655\u5656\u5657\u5658\u5659\u565a\u565b\u565c\u565d\u565e\u565f\u5660\u5661\u5662\u5663\u5664\u5665\u5666\u5667\u5668\u5669\u566a\u566b\u566c\u566d\u566e\u566f\u5670\u5671\u5672\u5673\u5674\u5675\u5676\u5677\u5678\u5679\u567a\u567b\u567c\u567d\u567e\u567f\u5680\u5681\u5682\u5683\u5684\u5685\u5686\u5687\u5688\u5689\u568a\u568b\u568c\u568d\u568e\u568f\u5690\u5691\u5692\u5693\u5694\u5695\u5696\u5697\u5698\u5699\u569a\u569b\u569c\u569d\u569e\u569f\u56a0\u56a1\u56a2\u56a3\u56a4\u56a5\u56a6\u56a7\u56a8\u56a9\u56aa\u56ab\u56ac\u56ad\u56ae\u56af\u56b0\u56b1\u56b2\u56b3\u56b4\u56b5\u56b6\u56b7\u56b8\u56b9\u56ba\u56bb\u56bc\u56bd\u56be\u56bf\u56c0\u56c1\u56c2\u56c3\u56c4\u56c5\u56c6\u56c7\u56c8\u56c9\u56ca\u56cb\u56cc\u56cd\u56ce\u56cf\u56d0\u56d1\u56d2\u56d3\u56d4\u56d5\u56d6\u56d7\u56d8\u56d9\u56da\u56db\u56dc\u56dd\u56de\u56df\u56e0\u56e1\u56e2\u56e3\u56e4\u56e5\u56e6\u56e7\u56e8\u56e9\u56ea\u56eb\u56ec\u56ed\u56ee\u56ef\u56f0\u56f1\u56f2\u56f3\u56f4\u56f5\u56f6\u56f7\u56f8\u56f9\u56fa\u56fb\u56fc\u56fd\u56fe\u56ff\u5700\u5701\u5702\u5703\u5704\u5705\u5706\u5707\u5708\u5709\u570a\u570b\u570c\u570d\u570e\u570f\u5710\u5711\u5712\u5713\u5714\u5715\u5716\u5717\u5718\u5719\u571a\u571b\u571c\u571d\u571e\u571f\u5720\u5721\u5722\u5723\u5724\u5725\u5726\u5727\u5728\u5729\u572a\u572b\u572c\u572d\u572e\u572f\u5730\u5731\u5732\u5733\u5734\u5735\u5736\u5737\u5738\u5739\u573a\u573b\u573c\u573d\u573e\u573f\u5740\u5741\u5742\u5743\u5744\u5745\u5746\u5747\u5748\u5749\u574a\u574b\u574c\u574d\u574e\u574f\u5750\u5751\u5752\u5753\u5754\u5755\u5756\u5757\u5758\u5759\u575a\u575b\u575c\u575d\u575e\u575f\u5760\u5761\u5762\u5763\u5764\u5765\u5766\u5767\u5768\u5769\u576a\u576b\u576c\u576d\u576e\u576f\u5770\u5771\u5772\u5773\u5774\u5775\u5776\u5777\u5778\u5779\u577a\u577b\u577c\u577d\u577e\u577f\u5780\u5781\u5782\u5783\u5784\u5785\u5786\u5787\u5788\u5789\u578a\u578b\u578c\u578d\u578e\u578f\u5790\u5791\u5792\u5793\u5794\u5795\u5796\u5797\u5798\u5799\u579a\u579b\u579c\u579d\u579e\u579f\u57a0\u57a1\u57a2\u57a3\u57a4\u57a5\u57a6\u57a7\u57a8\u57a9\u57aa\u57ab\u57ac\u57ad\u57ae\u57af\u57b0\u57b1\u57b2\u57b3\u57b4\u57b5\u57b6\u57b7\u57b8\u57b9\u57ba\u57bb\u57bc\u57bd\u57be\u57bf\u57c0\u57c1\u57c2\u57c3\u57c4\u57c5\u57c6\u57c7\u57c8\u57c9\u57ca\u57cb\u57cc\u57cd\u57ce\u57cf\u57d0\u57d1\u57d2\u57d3\u57d4\u57d5\u57d6\u57d7\u57d8\u57d9\u57da\u57db\u57dc\u57dd\u57de\u57df\u57e0\u57e1\u57e2\u57e3\u57e4\u57e5\u57e6\u57e7\u57e8\u57e9\u57ea\u57eb\u57ec\u57ed\u57ee\u57ef\u57f0\u57f1\u57f2\u57f3\u57f4\u57f5\u57f6\u57f7\u57f8\u57f9\u57fa\u57fb\u57fc\u57fd\u57fe\u57ff\u5800\u5801\u5802\u5803\u5804\u5805\u5806\u5807\u5808\u5809\u580a\u580b\u580c\u580d\u580e\u580f\u5810\u5811\u5812\u5813\u5814\u5815\u5816\u5817\u5818\u5819\u581a\u581b\u581c\u581d\u581e\u581f\u5820\u5821\u5822\u5823\u5824\u5825\u5826\u5827\u5828\u5829\u582a\u582b\u582c\u582d\u582e\u582f\u5830\u5831\u5832\u5833\u5834\u5835\u5836\u5837\u5838\u5839\u583a\u583b\u583c\u583d\u583e\u583f\u5840\u5841\u5842\u5843\u5844\u5845\u5846\u5847\u5848\u5849\u584a\u584b\u584c\u584d\u584e\u584f\u5850\u5851\u5852\u5853\u5854\u5855\u5856\u5857\u5858\u5859\u585a\u585b\u585c\u585d\u585e\u585f\u5860\u5861\u5862\u5863\u5864\u5865\u5866\u5867\u5868\u5869\u586a\u586b\u586c\u586d\u586e\u586f\u5870\u5871\u5872\u5873\u5874\u5875\u5876\u5877\u5878\u5879\u587a\u587b\u587c\u587d\u587e\u587f\u5880\u5881\u5882\u5883\u5884\u5885\u5886\u5887\u5888\u5889\u588a\u588b\u588c\u588d\u588e\u588f\u5890\u5891\u5892\u5893\u5894\u5895\u5896\u5897\u5898\u5899\u589a\u589b\u589c\u589d\u589e\u589f\u58a0\u58a1\u58a2\u58a3\u58a4\u58a5\u58a6\u58a7\u58a8\u58a9\u58aa\u58ab\u58ac\u58ad\u58ae\u58af\u58b0\u58b1\u58b2\u58b3\u58b4\u58b5\u58b6\u58b7\u58b8\u58b9\u58ba\u58bb\u58bc\u58bd\u58be\u58bf\u58c0\u58c1\u58c2\u58c3\u58c4\u58c5\u58c6\u58c7\u58c8\u58c9\u58ca\u58cb\u58cc\u58cd\u58ce\u58cf\u58d0\u58d1\u58d2\u58d3\u58d4\u58d5\u58d6\u58d7\u58d8\u58d9\u58da\u58db\u58dc\u58dd\u58de\u58df\u58e0\u58e1\u58e2\u58e3\u58e4\u58e5\u58e6\u58e7\u58e8\u58e9\u58ea\u58eb\u58ec\u58ed\u58ee\u58ef\u58f0\u58f1\u58f2\u58f3\u58f4\u58f5\u58f6\u58f7\u58f8\u58f9\u58fa\u58fb\u58fc\u58fd\u58fe\u58ff\u5900\u5901\u5902\u5903\u5904\u5905\u5906\u5907\u5908\u5909\u590a\u590b\u590c\u590d\u590e\u590f\u5910\u5911\u5912\u5913\u5914\u5915\u5916\u5917\u5918\u5919\u591a\u591b\u591c\u591d\u591e\u591f\u5920\u5921\u5922\u5923\u5924\u5925\u5926\u5927\u5928\u5929\u592a\u592b\u592c\u592d\u592e\u592f\u5930\u5931\u5932\u5933\u5934\u5935\u5936\u5937\u5938\u5939\u593a\u593b\u593c\u593d\u593e\u593f\u5940\u5941\u5942\u5943\u5944\u5945\u5946\u5947\u5948\u5949\u594a\u594b\u594c\u594d\u594e\u594f\u5950\u5951\u5952\u5953\u5954\u5955\u5956\u5957\u5958\u5959\u595a\u595b\u595c\u595d\u595e\u595f\u5960\u5961\u5962\u5963\u5964\u5965\u5966\u5967\u5968\u5969\u596a\u596b\u596c\u596d\u596e\u596f\u5970\u5971\u5972\u5973\u5974\u5975\u5976\u5977\u5978\u5979\u597a\u597b\u597c\u597d\u597e\u597f\u5980\u5981\u5982\u5983\u5984\u5985\u5986\u5987\u5988\u5989\u598a\u598b\u598c\u598d\u598e\u598f\u5990\u5991\u5992\u5993\u5994\u5995\u5996\u5997\u5998\u5999\u599a\u599b\u599c\u599d\u599e\u599f\u59a0\u59a1\u59a2\u59a3\u59a4\u59a5\u59a6\u59a7\u59a8\u59a9\u59aa\u59ab\u59ac\u59ad\u59ae\u59af\u59b0\u59b1\u59b2\u59b3\u59b4\u59b5\u59b6\u59b7\u59b8\u59b9\u59ba\u59bb\u59bc\u59bd\u59be\u59bf\u59c0\u59c1\u59c2\u59c3\u59c4\u59c5\u59c6\u59c7\u59c8\u59c9\u59ca\u59cb\u59cc\u59cd\u59ce\u59cf\u59d0\u59d1\u59d2\u59d3\u59d4\u59d5\u59d6\u59d7\u59d8\u59d9\u59da\u59db\u59dc\u59dd\u59de\u59df\u59e0\u59e1\u59e2\u59e3\u59e4\u59e5\u59e6\u59e7\u59e8\u59e9\u59ea\u59eb\u59ec\u59ed\u59ee\u59ef\u59f0\u59f1\u59f2\u59f3\u59f4\u59f5\u59f6\u59f7\u59f8\u59f9\u59fa\u59fb\u59fc\u59fd\u59fe\u59ff\u5a00\u5a01\u5a02\u5a03\u5a04\u5a05\u5a06\u5a07\u5a08\u5a09\u5a0a\u5a0b\u5a0c\u5a0d\u5a0e\u5a0f\u5a10\u5a11\u5a12\u5a13\u5a14\u5a15\u5a16\u5a17\u5a18\u5a19\u5a1a\u5a1b\u5a1c\u5a1d\u5a1e\u5a1f\u5a20\u5a21\u5a22\u5a23\u5a24\u5a25\u5a26\u5a27\u5a28\u5a29\u5a2a\u5a2b\u5a2c\u5a2d\u5a2e\u5a2f\u5a30\u5a31\u5a32\u5a33\u5a34\u5a35\u5a36\u5a37\u5a38\u5a39\u5a3a\u5a3b\u5a3c\u5a3d\u5a3e\u5a3f\u5a40\u5a41\u5a42\u5a43\u5a44\u5a45\u5a46\u5a47\u5a48\u5a49\u5a4a\u5a4b\u5a4c\u5a4d\u5a4e\u5a4f\u5a50\u5a51\u5a52\u5a53\u5a54\u5a55\u5a56\u5a57\u5a58\u5a59\u5a5a\u5a5b\u5a5c\u5a5d\u5a5e\u5a5f\u5a60\u5a61\u5a62\u5a63\u5a64\u5a65\u5a66\u5a67\u5a68\u5a69\u5a6a\u5a6b\u5a6c\u5a6d\u5a6e\u5a6f\u5a70\u5a71\u5a72\u5a73\u5a74\u5a75\u5a76\u5a77\u5a78\u5a79\u5a7a\u5a7b\u5a7c\u5a7d\u5a7e\u5a7f\u5a80\u5a81\u5a82\u5a83\u5a84\u5a85\u5a86\u5a87\u5a88\u5a89\u5a8a\u5a8b\u5a8c\u5a8d\u5a8e\u5a8f\u5a90\u5a91\u5a92\u5a93\u5a94\u5a95\u5a96\u5a97\u5a98\u5a99\u5a9a\u5a9b\u5a9c\u5a9d\u5a9e\u5a9f\u5aa0\u5aa1\u5aa2\u5aa3\u5aa4\u5aa5\u5aa6\u5aa7\u5aa8\u5aa9\u5aaa\u5aab\u5aac\u5aad\u5aae\u5aaf\u5ab0\u5ab1\u5ab2\u5ab3\u5ab4\u5ab5\u5ab6\u5ab7\u5ab8\u5ab9\u5aba\u5abb\u5abc\u5abd\u5abe\u5abf\u5ac0\u5ac1\u5ac2\u5ac3\u5ac4\u5ac5\u5ac6\u5ac7\u5ac8\u5ac9\u5aca\u5acb\u5acc\u5acd\u5ace\u5acf\u5ad0\u5ad1\u5ad2\u5ad3\u5ad4\u5ad5\u5ad6\u5ad7\u5ad8\u5ad9\u5ada\u5adb\u5adc\u5add\u5ade\u5adf\u5ae0\u5ae1\u5ae2\u5ae3\u5ae4\u5ae5\u5ae6\u5ae7\u5ae8\u5ae9\u5aea\u5aeb\u5aec\u5aed\u5aee\u5aef\u5af0\u5af1\u5af2\u5af3\u5af4\u5af5\u5af6\u5af7\u5af8\u5af9\u5afa\u5afb\u5afc\u5afd\u5afe\u5aff\u5b00\u5b01\u5b02\u5b03\u5b04\u5b05\u5b06\u5b07\u5b08\u5b09\u5b0a\u5b0b\u5b0c\u5b0d\u5b0e\u5b0f\u5b10\u5b11\u5b12\u5b13\u5b14\u5b15\u5b16\u5b17\u5b18\u5b19\u5b1a\u5b1b\u5b1c\u5b1d\u5b1e\u5b1f\u5b20\u5b21\u5b22\u5b23\u5b24\u5b25\u5b26\u5b27\u5b28\u5b29\u5b2a\u5b2b\u5b2c\u5b2d\u5b2e\u5b2f\u5b30\u5b31\u5b32\u5b33\u5b34\u5b35\u5b36\u5b37\u5b38\u5b39\u5b3a\u5b3b\u5b3c\u5b3d\u5b3e\u5b3f\u5b40\u5b41\u5b42\u5b43\u5b44\u5b45\u5b46\u5b47\u5b48\u5b49\u5b4a\u5b4b\u5b4c\u5b4d\u5b4e\u5b4f\u5b50\u5b51\u5b52\u5b53\u5b54\u5b55\u5b56\u5b57\u5b58\u5b59\u5b5a\u5b5b\u5b5c\u5b5d\u5b5e\u5b5f\u5b60\u5b61\u5b62\u5b63\u5b64\u5b65\u5b66\u5b67\u5b68\u5b69\u5b6a\u5b6b\u5b6c\u5b6d\u5b6e\u5b6f\u5b70\u5b71\u5b72\u5b73\u5b74\u5b75\u5b76\u5b77\u5b78\u5b79\u5b7a\u5b7b\u5b7c\u5b7d\u5b7e\u5b7f\u5b80\u5b81\u5b82\u5b83\u5b84\u5b85\u5b86\u5b87\u5b88\u5b89\u5b8a\u5b8b\u5b8c\u5b8d\u5b8e\u5b8f\u5b90\u5b91\u5b92\u5b93\u5b94\u5b95\u5b96\u5b97\u5b98\u5b99\u5b9a\u5b9b\u5b9c\u5b9d\u5b9e\u5b9f\u5ba0\u5ba1\u5ba2\u5ba3\u5ba4\u5ba5\u5ba6\u5ba7\u5ba8\u5ba9\u5baa\u5bab\u5bac\u5bad\u5bae\u5baf\u5bb0\u5bb1\u5bb2\u5bb3\u5bb4\u5bb5\u5bb6\u5bb7\u5bb8\u5bb9\u5bba\u5bbb\u5bbc\u5bbd\u5bbe\u5bbf\u5bc0\u5bc1\u5bc2\u5bc3\u5bc4\u5bc5\u5bc6\u5bc7\u5bc8\u5bc9\u5bca\u5bcb\u5bcc\u5bcd\u5bce\u5bcf\u5bd0\u5bd1\u5bd2\u5bd3\u5bd4\u5bd5\u5bd6\u5bd7\u5bd8\u5bd9\u5bda\u5bdb\u5bdc\u5bdd\u5bde\u5bdf\u5be0\u5be1\u5be2\u5be3\u5be4\u5be5\u5be6\u5be7\u5be8\u5be9\u5bea\u5beb\u5bec\u5bed\u5bee\u5bef\u5bf0\u5bf1\u5bf2\u5bf3\u5bf4\u5bf5\u5bf6\u5bf7\u5bf8\u5bf9\u5bfa\u5bfb\u5bfc\u5bfd\u5bfe\u5bff\u5c00\u5c01\u5c02\u5c03\u5c04\u5c05\u5c06\u5c07\u5c08\u5c09\u5c0a\u5c0b\u5c0c\u5c0d\u5c0e\u5c0f\u5c10\u5c11\u5c12\u5c13\u5c14\u5c15\u5c16\u5c17\u5c18\u5c19\u5c1a\u5c1b\u5c1c\u5c1d\u5c1e\u5c1f\u5c20\u5c21\u5c22\u5c23\u5c24\u5c25\u5c26\u5c27\u5c28\u5c29\u5c2a\u5c2b\u5c2c\u5c2d\u5c2e\u5c2f\u5c30\u5c31\u5c32\u5c33\u5c34\u5c35\u5c36\u5c37\u5c38\u5c39\u5c3a\u5c3b\u5c3c\u5c3d\u5c3e\u5c3f\u5c40\u5c41\u5c42\u5c43\u5c44\u5c45\u5c46\u5c47\u5c48\u5c49\u5c4a\u5c4b\u5c4c\u5c4d\u5c4e\u5c4f\u5c50\u5c51\u5c52\u5c53\u5c54\u5c55\u5c56\u5c57\u5c58\u5c59\u5c5a\u5c5b\u5c5c\u5c5d\u5c5e\u5c5f\u5c60\u5c61\u5c62\u5c63\u5c64\u5c65\u5c66\u5c67\u5c68\u5c69\u5c6a\u5c6b\u5c6c\u5c6d\u5c6e\u5c6f\u5c70\u5c71\u5c72\u5c73\u5c74\u5c75\u5c76\u5c77\u5c78\u5c79\u5c7a\u5c7b\u5c7c\u5c7d\u5c7e\u5c7f\u5c80\u5c81\u5c82\u5c83\u5c84\u5c85\u5c86\u5c87\u5c88\u5c89\u5c8a\u5c8b\u5c8c\u5c8d\u5c8e\u5c8f\u5c90\u5c91\u5c92\u5c93\u5c94\u5c95\u5c96\u5c97\u5c98\u5c99\u5c9a\u5c9b\u5c9c\u5c9d\u5c9e\u5c9f\u5ca0\u5ca1\u5ca2\u5ca3\u5ca4\u5ca5\u5ca6\u5ca7\u5ca8\u5ca9\u5caa\u5cab\u5cac\u5cad\u5cae\u5caf\u5cb0\u5cb1\u5cb2\u5cb3\u5cb4\u5cb5\u5cb6\u5cb7\u5cb8\u5cb9\u5cba\u5cbb\u5cbc\u5cbd\u5cbe\u5cbf\u5cc0\u5cc1\u5cc2\u5cc3\u5cc4\u5cc5\u5cc6\u5cc7\u5cc8\u5cc9\u5cca\u5ccb\u5ccc\u5ccd\u5cce\u5ccf\u5cd0\u5cd1\u5cd2\u5cd3\u5cd4\u5cd5\u5cd6\u5cd7\u5cd8\u5cd9\u5cda\u5cdb\u5cdc\u5cdd\u5cde\u5cdf\u5ce0\u5ce1\u5ce2\u5ce3\u5ce4\u5ce5\u5ce6\u5ce7\u5ce8\u5ce9\u5cea\u5ceb\u5cec\u5ced\u5cee\u5cef\u5cf0\u5cf1\u5cf2\u5cf3\u5cf4\u5cf5\u5cf6\u5cf7\u5cf8\u5cf9\u5cfa\u5cfb\u5cfc\u5cfd\u5cfe\u5cff\u5d00\u5d01\u5d02\u5d03\u5d04\u5d05\u5d06\u5d07\u5d08\u5d09\u5d0a\u5d0b\u5d0c\u5d0d\u5d0e\u5d0f\u5d10\u5d11\u5d12\u5d13\u5d14\u5d15\u5d16\u5d17\u5d18\u5d19\u5d1a\u5d1b\u5d1c\u5d1d\u5d1e\u5d1f\u5d20\u5d21\u5d22\u5d23\u5d24\u5d25\u5d26\u5d27\u5d28\u5d29\u5d2a\u5d2b\u5d2c\u5d2d\u5d2e\u5d2f\u5d30\u5d31\u5d32\u5d33\u5d34\u5d35\u5d36\u5d37\u5d38\u5d39\u5d3a\u5d3b\u5d3c\u5d3d\u5d3e\u5d3f\u5d40\u5d41\u5d42\u5d43\u5d44\u5d45\u5d46\u5d47\u5d48\u5d49\u5d4a\u5d4b\u5d4c\u5d4d\u5d4e\u5d4f\u5d50\u5d51\u5d52\u5d53\u5d54\u5d55\u5d56\u5d57\u5d58\u5d59\u5d5a\u5d5b\u5d5c\u5d5d\u5d5e\u5d5f\u5d60\u5d61\u5d62\u5d63\u5d64\u5d65\u5d66\u5d67\u5d68\u5d69\u5d6a\u5d6b\u5d6c\u5d6d\u5d6e\u5d6f\u5d70\u5d71\u5d72\u5d73\u5d74\u5d75\u5d76\u5d77\u5d78\u5d79\u5d7a\u5d7b\u5d7c\u5d7d\u5d7e\u5d7f\u5d80\u5d81\u5d82\u5d83\u5d84\u5d85\u5d86\u5d87\u5d88\u5d89\u5d8a\u5d8b\u5d8c\u5d8d\u5d8e\u5d8f\u5d90\u5d91\u5d92\u5d93\u5d94\u5d95\u5d96\u5d97\u5d98\u5d99\u5d9a\u5d9b\u5d9c\u5d9d\u5d9e\u5d9f\u5da0\u5da1\u5da2\u5da3\u5da4\u5da5\u5da6\u5da7\u5da8\u5da9\u5daa\u5dab\u5dac\u5dad\u5dae\u5daf\u5db0\u5db1\u5db2\u5db3\u5db4\u5db5\u5db6\u5db7\u5db8\u5db9\u5dba\u5dbb\u5dbc\u5dbd\u5dbe\u5dbf\u5dc0\u5dc1\u5dc2\u5dc3\u5dc4\u5dc5\u5dc6\u5dc7\u5dc8\u5dc9\u5dca\u5dcb\u5dcc\u5dcd\u5dce\u5dcf\u5dd0\u5dd1\u5dd2\u5dd3\u5dd4\u5dd5\u5dd6\u5dd7\u5dd8\u5dd9\u5dda\u5ddb\u5ddc\u5ddd\u5dde\u5ddf\u5de0\u5de1\u5de2\u5de3\u5de4\u5de5\u5de6\u5de7\u5de8\u5de9\u5dea\u5deb\u5dec\u5ded\u5dee\u5def\u5df0\u5df1\u5df2\u5df3\u5df4\u5df5\u5df6\u5df7\u5df8\u5df9\u5dfa\u5dfb\u5dfc\u5dfd\u5dfe\u5dff\u5e00\u5e01\u5e02\u5e03\u5e04\u5e05\u5e06\u5e07\u5e08\u5e09\u5e0a\u5e0b\u5e0c\u5e0d\u5e0e\u5e0f\u5e10\u5e11\u5e12\u5e13\u5e14\u5e15\u5e16\u5e17\u5e18\u5e19\u5e1a\u5e1b\u5e1c\u5e1d\u5e1e\u5e1f\u5e20\u5e21\u5e22\u5e23\u5e24\u5e25\u5e26\u5e27\u5e28\u5e29\u5e2a\u5e2b\u5e2c\u5e2d\u5e2e\u5e2f\u5e30\u5e31\u5e32\u5e33\u5e34\u5e35\u5e36\u5e37\u5e38\u5e39\u5e3a\u5e3b\u5e3c\u5e3d\u5e3e\u5e3f\u5e40\u5e41\u5e42\u5e43\u5e44\u5e45\u5e46\u5e47\u5e48\u5e49\u5e4a\u5e4b\u5e4c\u5e4d\u5e4e\u5e4f\u5e50\u5e51\u5e52\u5e53\u5e54\u5e55\u5e56\u5e57\u5e58\u5e59\u5e5a\u5e5b\u5e5c\u5e5d\u5e5e\u5e5f\u5e60\u5e61\u5e62\u5e63\u5e64\u5e65\u5e66\u5e67\u5e68\u5e69\u5e6a\u5e6b\u5e6c\u5e6d\u5e6e\u5e6f\u5e70\u5e71\u5e72\u5e73\u5e74\u5e75\u5e76\u5e77\u5e78\u5e79\u5e7a\u5e7b\u5e7c\u5e7d\u5e7e\u5e7f\u5e80\u5e81\u5e82\u5e83\u5e84\u5e85\u5e86\u5e87\u5e88\u5e89\u5e8a\u5e8b\u5e8c\u5e8d\u5e8e\u5e8f\u5e90\u5e91\u5e92\u5e93\u5e94\u5e95\u5e96\u5e97\u5e98\u5e99\u5e9a\u5e9b\u5e9c\u5e9d\u5e9e\u5e9f\u5ea0\u5ea1\u5ea2\u5ea3\u5ea4\u5ea5\u5ea6\u5ea7\u5ea8\u5ea9\u5eaa\u5eab\u5eac\u5ead\u5eae\u5eaf\u5eb0\u5eb1\u5eb2\u5eb3\u5eb4\u5eb5\u5eb6\u5eb7\u5eb8\u5eb9\u5eba\u5ebb\u5ebc\u5ebd\u5ebe\u5ebf\u5ec0\u5ec1\u5ec2\u5ec3\u5ec4\u5ec5\u5ec6\u5ec7\u5ec8\u5ec9\u5eca\u5ecb\u5ecc\u5ecd\u5ece\u5ecf\u5ed0\u5ed1\u5ed2\u5ed3\u5ed4\u5ed5\u5ed6\u5ed7\u5ed8\u5ed9\u5eda\u5edb\u5edc\u5edd\u5ede\u5edf\u5ee0\u5ee1\u5ee2\u5ee3\u5ee4\u5ee5\u5ee6\u5ee7\u5ee8\u5ee9\u5eea\u5eeb\u5eec\u5eed\u5eee\u5eef\u5ef0\u5ef1\u5ef2\u5ef3\u5ef4\u5ef5\u5ef6\u5ef7\u5ef8\u5ef9\u5efa\u5efb\u5efc\u5efd\u5efe\u5eff\u5f00\u5f01\u5f02\u5f03\u5f04\u5f05\u5f06\u5f07\u5f08\u5f09\u5f0a\u5f0b\u5f0c\u5f0d\u5f0e\u5f0f\u5f10\u5f11\u5f12\u5f13\u5f14\u5f15\u5f16\u5f17\u5f18\u5f19\u5f1a\u5f1b\u5f1c\u5f1d\u5f1e\u5f1f\u5f20\u5f21\u5f22\u5f23\u5f24\u5f25\u5f26\u5f27\u5f28\u5f29\u5f2a\u5f2b\u5f2c\u5f2d\u5f2e\u5f2f\u5f30\u5f31\u5f32\u5f33\u5f34\u5f35\u5f36\u5f37\u5f38\u5f39\u5f3a\u5f3b\u5f3c\u5f3d\u5f3e\u5f3f\u5f40\u5f41\u5f42\u5f43\u5f44\u5f45\u5f46\u5f47\u5f48\u5f49\u5f4a\u5f4b\u5f4c\u5f4d\u5f4e\u5f4f\u5f50\u5f51\u5f52\u5f53\u5f54\u5f55\u5f56\u5f57\u5f58\u5f59\u5f5a\u5f5b\u5f5c\u5f5d\u5f5e\u5f5f\u5f60\u5f61\u5f62\u5f63\u5f64\u5f65\u5f66\u5f67\u5f68\u5f69\u5f6a\u5f6b\u5f6c\u5f6d\u5f6e\u5f6f\u5f70\u5f71\u5f72\u5f73\u5f74\u5f75\u5f76\u5f77\u5f78\u5f79\u5f7a\u5f7b\u5f7c\u5f7d\u5f7e\u5f7f\u5f80\u5f81\u5f82\u5f83\u5f84\u5f85\u5f86\u5f87\u5f88\u5f89\u5f8a\u5f8b\u5f8c\u5f8d\u5f8e\u5f8f\u5f90\u5f91\u5f92\u5f93\u5f94\u5f95\u5f96\u5f97\u5f98\u5f99\u5f9a\u5f9b\u5f9c\u5f9d\u5f9e\u5f9f\u5fa0\u5fa1\u5fa2\u5fa3\u5fa4\u5fa5\u5fa6\u5fa7\u5fa8\u5fa9\u5faa\u5fab\u5fac\u5fad\u5fae\u5faf\u5fb0\u5fb1\u5fb2\u5fb3\u5fb4\u5fb5\u5fb6\u5fb7\u5fb8\u5fb9\u5fba\u5fbb\u5fbc\u5fbd\u5fbe\u5fbf\u5fc0\u5fc1\u5fc2\u5fc3\u5fc4\u5fc5\u5fc6\u5fc7\u5fc8\u5fc9\u5fca\u5fcb\u5fcc\u5fcd\u5fce\u5fcf\u5fd0\u5fd1\u5fd2\u5fd3\u5fd4\u5fd5\u5fd6\u5fd7\u5fd8\u5fd9\u5fda\u5fdb\u5fdc\u5fdd\u5fde\u5fdf\u5fe0\u5fe1\u5fe2\u5fe3\u5fe4\u5fe5\u5fe6\u5fe7\u5fe8\u5fe9\u5fea\u5feb\u5fec\u5fed\u5fee\u5fef\u5ff0\u5ff1\u5ff2\u5ff3\u5ff4\u5ff5\u5ff6\u5ff7\u5ff8\u5ff9\u5ffa\u5ffb\u5ffc\u5ffd\u5ffe\u5fff\u6000\u6001\u6002\u6003\u6004\u6005\u6006\u6007\u6008\u6009\u600a\u600b\u600c\u600d\u600e\u600f\u6010\u6011\u6012\u6013\u6014\u6015\u6016\u6017\u6018\u6019\u601a\u601b\u601c\u601d\u601e\u601f\u6020\u6021\u6022\u6023\u6024\u6025\u6026\u6027\u6028\u6029\u602a\u602b\u602c\u602d\u602e\u602f\u6030\u6031\u6032\u6033\u6034\u6035\u6036\u6037\u6038\u6039\u603a\u603b\u603c\u603d\u603e\u603f\u6040\u6041\u6042\u6043\u6044\u6045\u6046\u6047\u6048\u6049\u604a\u604b\u604c\u604d\u604e\u604f\u6050\u6051\u6052\u6053\u6054\u6055\u6056\u6057\u6058\u6059\u605a\u605b\u605c\u605d\u605e\u605f\u6060\u6061\u6062\u6063\u6064\u6065\u6066\u6067\u6068\u6069\u606a\u606b\u606c\u606d\u606e\u606f\u6070\u6071\u6072\u6073\u6074\u6075\u6076\u6077\u6078\u6079\u607a\u607b\u607c\u607d\u607e\u607f\u6080\u6081\u6082\u6083\u6084\u6085\u6086\u6087\u6088\u6089\u608a\u608b\u608c\u608d\u608e\u608f\u6090\u6091\u6092\u6093\u6094\u6095\u6096\u6097\u6098\u6099\u609a\u609b\u609c\u609d\u609e\u609f\u60a0\u60a1\u60a2\u60a3\u60a4\u60a5\u60a6\u60a7\u60a8\u60a9\u60aa\u60ab\u60ac\u60ad\u60ae\u60af\u60b0\u60b1\u60b2\u60b3\u60b4\u60b5\u60b6\u60b7\u60b8\u60b9\u60ba\u60bb\u60bc\u60bd\u60be\u60bf\u60c0\u60c1\u60c2\u60c3\u60c4\u60c5\u60c6\u60c7\u60c8\u60c9\u60ca\u60cb\u60cc\u60cd\u60ce\u60cf\u60d0\u60d1\u60d2\u60d3\u60d4\u60d5\u60d6\u60d7\u60d8\u60d9\u60da\u60db\u60dc\u60dd\u60de\u60df\u60e0\u60e1\u60e2\u60e3\u60e4\u60e5\u60e6\u60e7\u60e8\u60e9\u60ea\u60eb\u60ec\u60ed\u60ee\u60ef\u60f0\u60f1\u60f2\u60f3\u60f4\u60f5\u60f6\u60f7\u60f8\u60f9\u60fa\u60fb\u60fc\u60fd\u60fe\u60ff\u6100\u6101\u6102\u6103\u6104\u6105\u6106\u6107\u6108\u6109\u610a\u610b\u610c\u610d\u610e\u610f\u6110\u6111\u6112\u6113\u6114\u6115\u6116\u6117\u6118\u6119\u611a\u611b\u611c\u611d\u611e\u611f\u6120\u6121\u6122\u6123\u6124\u6125\u6126\u6127\u6128\u6129\u612a\u612b\u612c\u612d\u612e\u612f\u6130\u6131\u6132\u6133\u6134\u6135\u6136\u6137\u6138\u6139\u613a\u613b\u613c\u613d\u613e\u613f\u6140\u6141\u6142\u6143\u6144\u6145\u6146\u6147\u6148\u6149\u614a\u614b\u614c\u614d\u614e\u614f\u6150\u6151\u6152\u6153\u6154\u6155\u6156\u6157\u6158\u6159\u615a\u615b\u615c\u615d\u615e\u615f\u6160\u6161\u6162\u6163\u6164\u6165\u6166\u6167\u6168\u6169\u616a\u616b\u616c\u616d\u616e\u616f\u6170\u6171\u6172\u6173\u6174\u6175\u6176\u6177\u6178\u6179\u617a\u617b\u617c\u617d\u617e\u617f\u6180\u6181\u6182\u6183\u6184\u6185\u6186\u6187\u6188\u6189\u618a\u618b\u618c\u618d\u618e\u618f\u6190\u6191\u6192\u6193\u6194\u6195\u6196\u6197\u6198\u6199\u619a\u619b\u619c\u619d\u619e\u619f\u61a0\u61a1\u61a2\u61a3\u61a4\u61a5\u61a6\u61a7\u61a8\u61a9\u61aa\u61ab\u61ac\u61ad\u61ae\u61af\u61b0\u61b1\u61b2\u61b3\u61b4\u61b5\u61b6\u61b7\u61b8\u61b9\u61ba\u61bb\u61bc\u61bd\u61be\u61bf\u61c0\u61c1\u61c2\u61c3\u61c4\u61c5\u61c6\u61c7\u61c8\u61c9\u61ca\u61cb\u61cc\u61cd\u61ce\u61cf\u61d0\u61d1\u61d2\u61d3\u61d4\u61d5\u61d6\u61d7\u61d8\u61d9\u61da\u61db\u61dc\u61dd\u61de\u61df\u61e0\u61e1\u61e2\u61e3\u61e4\u61e5\u61e6\u61e7\u61e8\u61e9\u61ea\u61eb\u61ec\u61ed\u61ee\u61ef\u61f0\u61f1\u61f2\u61f3\u61f4\u61f5\u61f6\u61f7\u61f8\u61f9\u61fa\u61fb\u61fc\u61fd\u61fe\u61ff\u6200\u6201\u6202\u6203\u6204\u6205\u6206\u6207\u6208\u6209\u620a\u620b\u620c\u620d\u620e\u620f\u6210\u6211\u6212\u6213\u6214\u6215\u6216\u6217\u6218\u6219\u621a\u621b\u621c\u621d\u621e\u621f\u6220\u6221\u6222\u6223\u6224\u6225\u6226\u6227\u6228\u6229\u622a\u622b\u622c\u622d\u622e\u622f\u6230\u6231\u6232\u6233\u6234\u6235\u6236\u6237\u6238\u6239\u623a\u623b\u623c\u623d\u623e\u623f\u6240\u6241\u6242\u6243\u6244\u6245\u6246\u6247\u6248\u6249\u624a\u624b\u624c\u624d\u624e\u624f\u6250\u6251\u6252\u6253\u6254\u6255\u6256\u6257\u6258\u6259\u625a\u625b\u625c\u625d\u625e\u625f\u6260\u6261\u6262\u6263\u6264\u6265\u6266\u6267\u6268\u6269\u626a\u626b\u626c\u626d\u626e\u626f\u6270\u6271\u6272\u6273\u6274\u6275\u6276\u6277\u6278\u6279\u627a\u627b\u627c\u627d\u627e\u627f\u6280\u6281\u6282\u6283\u6284\u6285\u6286\u6287\u6288\u6289\u628a\u628b\u628c\u628d\u628e\u628f\u6290\u6291\u6292\u6293\u6294\u6295\u6296\u6297\u6298\u6299\u629a\u629b\u629c\u629d\u629e\u629f\u62a0\u62a1\u62a2\u62a3\u62a4\u62a5\u62a6\u62a7\u62a8\u62a9\u62aa\u62ab\u62ac\u62ad\u62ae\u62af\u62b0\u62b1\u62b2\u62b3\u62b4\u62b5\u62b6\u62b7\u62b8\u62b9\u62ba\u62bb\u62bc\u62bd\u62be\u62bf\u62c0\u62c1\u62c2\u62c3\u62c4\u62c5\u62c6\u62c7\u62c8\u62c9\u62ca\u62cb\u62cc\u62cd\u62ce\u62cf\u62d0\u62d1\u62d2\u62d3\u62d4\u62d5\u62d6\u62d7\u62d8\u62d9\u62da\u62db\u62dc\u62dd\u62de\u62df\u62e0\u62e1\u62e2\u62e3\u62e4\u62e5\u62e6\u62e7\u62e8\u62e9\u62ea\u62eb\u62ec\u62ed\u62ee\u62ef\u62f0\u62f1\u62f2\u62f3\u62f4\u62f5\u62f6\u62f7\u62f8\u62f9\u62fa\u62fb\u62fc\u62fd\u62fe\u62ff\u6300\u6301\u6302\u6303\u6304\u6305\u6306\u6307\u6308\u6309\u630a\u630b\u630c\u630d\u630e\u630f\u6310\u6311\u6312\u6313\u6314\u6315\u6316\u6317\u6318\u6319\u631a\u631b\u631c\u631d\u631e\u631f\u6320\u6321\u6322\u6323\u6324\u6325\u6326\u6327\u6328\u6329\u632a\u632b\u632c\u632d\u632e\u632f\u6330\u6331\u6332\u6333\u6334\u6335\u6336\u6337\u6338\u6339\u633a\u633b\u633c\u633d\u633e\u633f\u6340\u6341\u6342\u6343\u6344\u6345\u6346\u6347\u6348\u6349\u634a\u634b\u634c\u634d\u634e\u634f\u6350\u6351\u6352\u6353\u6354\u6355\u6356\u6357\u6358\u6359\u635a\u635b\u635c\u635d\u635e\u635f\u6360\u6361\u6362\u6363\u6364\u6365\u6366\u6367\u6368\u6369\u636a\u636b\u636c\u636d\u636e\u636f\u6370\u6371\u6372\u6373\u6374\u6375\u6376\u6377\u6378\u6379\u637a\u637b\u637c\u637d\u637e\u637f\u6380\u6381\u6382\u6383\u6384\u6385\u6386\u6387\u6388\u6389\u638a\u638b\u638c\u638d\u638e\u638f\u6390\u6391\u6392\u6393\u6394\u6395\u6396\u6397\u6398\u6399\u639a\u639b\u639c\u639d\u639e\u639f\u63a0\u63a1\u63a2\u63a3\u63a4\u63a5\u63a6\u63a7\u63a8\u63a9\u63aa\u63ab\u63ac\u63ad\u63ae\u63af\u63b0\u63b1\u63b2\u63b3\u63b4\u63b5\u63b6\u63b7\u63b8\u63b9\u63ba\u63bb\u63bc\u63bd\u63be\u63bf\u63c0\u63c1\u63c2\u63c3\u63c4\u63c5\u63c6\u63c7\u63c8\u63c9\u63ca\u63cb\u63cc\u63cd\u63ce\u63cf\u63d0\u63d1\u63d2\u63d3\u63d4\u63d5\u63d6\u63d7\u63d8\u63d9\u63da\u63db\u63dc\u63dd\u63de\u63df\u63e0\u63e1\u63e2\u63e3\u63e4\u63e5\u63e6\u63e7\u63e8\u63e9\u63ea\u63eb\u63ec\u63ed\u63ee\u63ef\u63f0\u63f1\u63f2\u63f3\u63f4\u63f5\u63f6\u63f7\u63f8\u63f9\u63fa\u63fb\u63fc\u63fd\u63fe\u63ff\u6400\u6401\u6402\u6403\u6404\u6405\u6406\u6407\u6408\u6409\u640a\u640b\u640c\u640d\u640e\u640f\u6410\u6411\u6412\u6413\u6414\u6415\u6416\u6417\u6418\u6419\u641a\u641b\u641c\u641d\u641e\u641f\u6420\u6421\u6422\u6423\u6424\u6425\u6426\u6427\u6428\u6429\u642a\u642b\u642c\u642d\u642e\u642f\u6430\u6431\u6432\u6433\u6434\u6435\u6436\u6437\u6438\u6439\u643a\u643b\u643c\u643d\u643e\u643f\u6440\u6441\u6442\u6443\u6444\u6445\u6446\u6447\u6448\u6449\u644a\u644b\u644c\u644d\u644e\u644f\u6450\u6451\u6452\u6453\u6454\u6455\u6456\u6457\u6458\u6459\u645a\u645b\u645c\u645d\u645e\u645f\u6460\u6461\u6462\u6463\u6464\u6465\u6466\u6467\u6468\u6469\u646a\u646b\u646c\u646d\u646e\u646f\u6470\u6471\u6472\u6473\u6474\u6475\u6476\u6477\u6478\u6479\u647a\u647b\u647c\u647d\u647e\u647f\u6480\u6481\u6482\u6483\u6484\u6485\u6486\u6487\u6488\u6489\u648a\u648b\u648c\u648d\u648e\u648f\u6490\u6491\u6492\u6493\u6494\u6495\u6496\u6497\u6498\u6499\u649a\u649b\u649c\u649d\u649e\u649f\u64a0\u64a1\u64a2\u64a3\u64a4\u64a5\u64a6\u64a7\u64a8\u64a9\u64aa\u64ab\u64ac\u64ad\u64ae\u64af\u64b0\u64b1\u64b2\u64b3\u64b4\u64b5\u64b6\u64b7\u64b8\u64b9\u64ba\u64bb\u64bc\u64bd\u64be\u64bf\u64c0\u64c1\u64c2\u64c3\u64c4\u64c5\u64c6\u64c7\u64c8\u64c9\u64ca\u64cb\u64cc\u64cd\u64ce\u64cf\u64d0\u64d1\u64d2\u64d3\u64d4\u64d5\u64d6\u64d7\u64d8\u64d9\u64da\u64db\u64dc\u64dd\u64de\u64df\u64e0\u64e1\u64e2\u64e3\u64e4\u64e5\u64e6\u64e7\u64e8\u64e9\u64ea\u64eb\u64ec\u64ed\u64ee\u64ef\u64f0\u64f1\u64f2\u64f3\u64f4\u64f5\u64f6\u64f7\u64f8\u64f9\u64fa\u64fb\u64fc\u64fd\u64fe\u64ff\u6500\u6501\u6502\u6503\u6504\u6505\u6506\u6507\u6508\u6509\u650a\u650b\u650c\u650d\u650e\u650f\u6510\u6511\u6512\u6513\u6514\u6515\u6516\u6517\u6518\u6519\u651a\u651b\u651c\u651d\u651e\u651f\u6520\u6521\u6522\u6523\u6524\u6525\u6526\u6527\u6528\u6529\u652a\u652b\u652c\u652d\u652e\u652f\u6530\u6531\u6532\u6533\u6534\u6535\u6536\u6537\u6538\u6539\u653a\u653b\u653c\u653d\u653e\u653f\u6540\u6541\u6542\u6543\u6544\u6545\u6546\u6547\u6548\u6549\u654a\u654b\u654c\u654d\u654e\u654f\u6550\u6551\u6552\u6553\u6554\u6555\u6556\u6557\u6558\u6559\u655a\u655b\u655c\u655d\u655e\u655f\u6560\u6561\u6562\u6563\u6564\u6565\u6566\u6567\u6568\u6569\u656a\u656b\u656c\u656d\u656e\u656f\u6570\u6571\u6572\u6573\u6574\u6575\u6576\u6577\u6578\u6579\u657a\u657b\u657c\u657d\u657e\u657f\u6580\u6581\u6582\u6583\u6584\u6585\u6586\u6587\u6588\u6589\u658a\u658b\u658c\u658d\u658e\u658f\u6590\u6591\u6592\u6593\u6594\u6595\u6596\u6597\u6598\u6599\u659a\u659b\u659c\u659d\u659e\u659f\u65a0\u65a1\u65a2\u65a3\u65a4\u65a5\u65a6\u65a7\u65a8\u65a9\u65aa\u65ab\u65ac\u65ad\u65ae\u65af\u65b0\u65b1\u65b2\u65b3\u65b4\u65b5\u65b6\u65b7\u65b8\u65b9\u65ba\u65bb\u65bc\u65bd\u65be\u65bf\u65c0\u65c1\u65c2\u65c3\u65c4\u65c5\u65c6\u65c7\u65c8\u65c9\u65ca\u65cb\u65cc\u65cd\u65ce\u65cf\u65d0\u65d1\u65d2\u65d3\u65d4\u65d5\u65d6\u65d7\u65d8\u65d9\u65da\u65db\u65dc\u65dd\u65de\u65df\u65e0\u65e1\u65e2\u65e3\u65e4\u65e5\u65e6\u65e7\u65e8\u65e9\u65ea\u65eb\u65ec\u65ed\u65ee\u65ef\u65f0\u65f1\u65f2\u65f3\u65f4\u65f5\u65f6\u65f7\u65f8\u65f9\u65fa\u65fb\u65fc\u65fd\u65fe\u65ff\u6600\u6601\u6602\u6603\u6604\u6605\u6606\u6607\u6608\u6609\u660a\u660b\u660c\u660d\u660e\u660f\u6610\u6611\u6612\u6613\u6614\u6615\u6616\u6617\u6618\u6619\u661a\u661b\u661c\u661d\u661e\u661f\u6620\u6621\u6622\u6623\u6624\u6625\u6626\u6627\u6628\u6629\u662a\u662b\u662c\u662d\u662e\u662f\u6630\u6631\u6632\u6633\u6634\u6635\u6636\u6637\u6638\u6639\u663a\u663b\u663c\u663d\u663e\u663f\u6640\u6641\u6642\u6643\u6644\u6645\u6646\u6647\u6648\u6649\u664a\u664b\u664c\u664d\u664e\u664f\u6650\u6651\u6652\u6653\u6654\u6655\u6656\u6657\u6658\u6659\u665a\u665b\u665c\u665d\u665e\u665f\u6660\u6661\u6662\u6663\u6664\u6665\u6666\u6667\u6668\u6669\u666a\u666b\u666c\u666d\u666e\u666f\u6670\u6671\u6672\u6673\u6674\u6675\u6676\u6677\u6678\u6679\u667a\u667b\u667c\u667d\u667e\u667f\u6680\u6681\u6682\u6683\u6684\u6685\u6686\u6687\u6688\u6689\u668a\u668b\u668c\u668d\u668e\u668f\u6690\u6691\u6692\u6693\u6694\u6695\u6696\u6697\u6698\u6699\u669a\u669b\u669c\u669d\u669e\u669f\u66a0\u66a1\u66a2\u66a3\u66a4\u66a5\u66a6\u66a7\u66a8\u66a9\u66aa\u66ab\u66ac\u66ad\u66ae\u66af\u66b0\u66b1\u66b2\u66b3\u66b4\u66b5\u66b6\u66b7\u66b8\u66b9\u66ba\u66bb\u66bc\u66bd\u66be\u66bf\u66c0\u66c1\u66c2\u66c3\u66c4\u66c5\u66c6\u66c7\u66c8\u66c9\u66ca\u66cb\u66cc\u66cd\u66ce\u66cf\u66d0\u66d1\u66d2\u66d3\u66d4\u66d5\u66d6\u66d7\u66d8\u66d9\u66da\u66db\u66dc\u66dd\u66de\u66df\u66e0\u66e1\u66e2\u66e3\u66e4\u66e5\u66e6\u66e7\u66e8\u66e9\u66ea\u66eb\u66ec\u66ed\u66ee\u66ef\u66f0\u66f1\u66f2\u66f3\u66f4\u66f5\u66f6\u66f7\u66f8\u66f9\u66fa\u66fb\u66fc\u66fd\u66fe\u66ff\u6700\u6701\u6702\u6703\u6704\u6705\u6706\u6707\u6708\u6709\u670a\u670b\u670c\u670d\u670e\u670f\u6710\u6711\u6712\u6713\u6714\u6715\u6716\u6717\u6718\u6719\u671a\u671b\u671c\u671d\u671e\u671f\u6720\u6721\u6722\u6723\u6724\u6725\u6726\u6727\u6728\u6729\u672a\u672b\u672c\u672d\u672e\u672f\u6730\u6731\u6732\u6733\u6734\u6735\u6736\u6737\u6738\u6739\u673a\u673b\u673c\u673d\u673e\u673f\u6740\u6741\u6742\u6743\u6744\u6745\u6746\u6747\u6748\u6749\u674a\u674b\u674c\u674d\u674e\u674f\u6750\u6751\u6752\u6753\u6754\u6755\u6756\u6757\u6758\u6759\u675a\u675b\u675c\u675d\u675e\u675f\u6760\u6761\u6762\u6763\u6764\u6765\u6766\u6767\u6768\u6769\u676a\u676b\u676c\u676d\u676e\u676f\u6770\u6771\u6772\u6773\u6774\u6775\u6776\u6777\u6778\u6779\u677a\u677b\u677c\u677d\u677e\u677f\u6780\u6781\u6782\u6783\u6784\u6785\u6786\u6787\u6788\u6789\u678a\u678b\u678c\u678d\u678e\u678f\u6790\u6791\u6792\u6793\u6794\u6795\u6796\u6797\u6798\u6799\u679a\u679b\u679c\u679d\u679e\u679f\u67a0\u67a1\u67a2\u67a3\u67a4\u67a5\u67a6\u67a7\u67a8\u67a9\u67aa\u67ab\u67ac\u67ad\u67ae\u67af\u67b0\u67b1\u67b2\u67b3\u67b4\u67b5\u67b6\u67b7\u67b8\u67b9\u67ba\u67bb\u67bc\u67bd\u67be\u67bf\u67c0\u67c1\u67c2\u67c3\u67c4\u67c5\u67c6\u67c7\u67c8\u67c9\u67ca\u67cb\u67cc\u67cd\u67ce\u67cf\u67d0\u67d1\u67d2\u67d3\u67d4\u67d5\u67d6\u67d7\u67d8\u67d9\u67da\u67db\u67dc\u67dd\u67de\u67df\u67e0\u67e1\u67e2\u67e3\u67e4\u67e5\u67e6\u67e7\u67e8\u67e9\u67ea\u67eb\u67ec\u67ed\u67ee\u67ef\u67f0\u67f1\u67f2\u67f3\u67f4\u67f5\u67f6\u67f7\u67f8\u67f9\u67fa\u67fb\u67fc\u67fd\u67fe\u67ff\u6800\u6801\u6802\u6803\u6804\u6805\u6806\u6807\u6808\u6809\u680a\u680b\u680c\u680d\u680e\u680f\u6810\u6811\u6812\u6813\u6814\u6815\u6816\u6817\u6818\u6819\u681a\u681b\u681c\u681d\u681e\u681f\u6820\u6821\u6822\u6823\u6824\u6825\u6826\u6827\u6828\u6829\u682a\u682b\u682c\u682d\u682e\u682f\u6830\u6831\u6832\u6833\u6834\u6835\u6836\u6837\u6838\u6839\u683a\u683b\u683c\u683d\u683e\u683f\u6840\u6841\u6842\u6843\u6844\u6845\u6846\u6847\u6848\u6849\u684a\u684b\u684c\u684d\u684e\u684f\u6850\u6851\u6852\u6853\u6854\u6855\u6856\u6857\u6858\u6859\u685a\u685b\u685c\u685d\u685e\u685f\u6860\u6861\u6862\u6863\u6864\u6865\u6866\u6867\u6868\u6869\u686a\u686b\u686c\u686d\u686e\u686f\u6870\u6871\u6872\u6873\u6874\u6875\u6876\u6877\u6878\u6879\u687a\u687b\u687c\u687d\u687e\u687f\u6880\u6881\u6882\u6883\u6884\u6885\u6886\u6887\u6888\u6889\u688a\u688b\u688c\u688d\u688e\u688f\u6890\u6891\u6892\u6893\u6894\u6895\u6896\u6897\u6898\u6899\u689a\u689b\u689c\u689d\u689e\u689f\u68a0\u68a1\u68a2\u68a3\u68a4\u68a5\u68a6\u68a7\u68a8\u68a9\u68aa\u68ab\u68ac\u68ad\u68ae\u68af\u68b0\u68b1\u68b2\u68b3\u68b4\u68b5\u68b6\u68b7\u68b8\u68b9\u68ba\u68bb\u68bc\u68bd\u68be\u68bf\u68c0\u68c1\u68c2\u68c3\u68c4\u68c5\u68c6\u68c7\u68c8\u68c9\u68ca\u68cb\u68cc\u68cd\u68ce\u68cf\u68d0\u68d1\u68d2\u68d3\u68d4\u68d5\u68d6\u68d7\u68d8\u68d9\u68da\u68db\u68dc\u68dd\u68de\u68df\u68e0\u68e1\u68e2\u68e3\u68e4\u68e5\u68e6\u68e7\u68e8\u68e9\u68ea\u68eb\u68ec\u68ed\u68ee\u68ef\u68f0\u68f1\u68f2\u68f3\u68f4\u68f5\u68f6\u68f7\u68f8\u68f9\u68fa\u68fb\u68fc\u68fd\u68fe\u68ff\u6900\u6901\u6902\u6903\u6904\u6905\u6906\u6907\u6908\u6909\u690a\u690b\u690c\u690d\u690e\u690f\u6910\u6911\u6912\u6913\u6914\u6915\u6916\u6917\u6918\u6919\u691a\u691b\u691c\u691d\u691e\u691f\u6920\u6921\u6922\u6923\u6924\u6925\u6926\u6927\u6928\u6929\u692a\u692b\u692c\u692d\u692e\u692f\u6930\u6931\u6932\u6933\u6934\u6935\u6936\u6937\u6938\u6939\u693a\u693b\u693c\u693d\u693e\u693f\u6940\u6941\u6942\u6943\u6944\u6945\u6946\u6947\u6948\u6949\u694a\u694b\u694c\u694d\u694e\u694f\u6950\u6951\u6952\u6953\u6954\u6955\u6956\u6957\u6958\u6959\u695a\u695b\u695c\u695d\u695e\u695f\u6960\u6961\u6962\u6963\u6964\u6965\u6966\u6967\u6968\u6969\u696a\u696b\u696c\u696d\u696e\u696f\u6970\u6971\u6972\u6973\u6974\u6975\u6976\u6977\u6978\u6979\u697a\u697b\u697c\u697d\u697e\u697f\u6980\u6981\u6982\u6983\u6984\u6985\u6986\u6987\u6988\u6989\u698a\u698b\u698c\u698d\u698e\u698f\u6990\u6991\u6992\u6993\u6994\u6995\u6996\u6997\u6998\u6999\u699a\u699b\u699c\u699d\u699e\u699f\u69a0\u69a1\u69a2\u69a3\u69a4\u69a5\u69a6\u69a7\u69a8\u69a9\u69aa\u69ab\u69ac\u69ad\u69ae\u69af\u69b0\u69b1\u69b2\u69b3\u69b4\u69b5\u69b6\u69b7\u69b8\u69b9\u69ba\u69bb\u69bc\u69bd\u69be\u69bf\u69c0\u69c1\u69c2\u69c3\u69c4\u69c5\u69c6\u69c7\u69c8\u69c9\u69ca\u69cb\u69cc\u69cd\u69ce\u69cf\u69d0\u69d1\u69d2\u69d3\u69d4\u69d5\u69d6\u69d7\u69d8\u69d9\u69da\u69db\u69dc\u69dd\u69de\u69df\u69e0\u69e1\u69e2\u69e3\u69e4\u69e5\u69e6\u69e7\u69e8\u69e9\u69ea\u69eb\u69ec\u69ed\u69ee\u69ef\u69f0\u69f1\u69f2\u69f3\u69f4\u69f5\u69f6\u69f7\u69f8\u69f9\u69fa\u69fb\u69fc\u69fd\u69fe\u69ff\u6a00\u6a01\u6a02\u6a03\u6a04\u6a05\u6a06\u6a07\u6a08\u6a09\u6a0a\u6a0b\u6a0c\u6a0d\u6a0e\u6a0f\u6a10\u6a11\u6a12\u6a13\u6a14\u6a15\u6a16\u6a17\u6a18\u6a19\u6a1a\u6a1b\u6a1c\u6a1d\u6a1e\u6a1f\u6a20\u6a21\u6a22\u6a23\u6a24\u6a25\u6a26\u6a27\u6a28\u6a29\u6a2a\u6a2b\u6a2c\u6a2d\u6a2e\u6a2f\u6a30\u6a31\u6a32\u6a33\u6a34\u6a35\u6a36\u6a37\u6a38\u6a39\u6a3a\u6a3b\u6a3c\u6a3d\u6a3e\u6a3f\u6a40\u6a41\u6a42\u6a43\u6a44\u6a45\u6a46\u6a47\u6a48\u6a49\u6a4a\u6a4b\u6a4c\u6a4d\u6a4e\u6a4f\u6a50\u6a51\u6a52\u6a53\u6a54\u6a55\u6a56\u6a57\u6a58\u6a59\u6a5a\u6a5b\u6a5c\u6a5d\u6a5e\u6a5f\u6a60\u6a61\u6a62\u6a63\u6a64\u6a65\u6a66\u6a67\u6a68\u6a69\u6a6a\u6a6b\u6a6c\u6a6d\u6a6e\u6a6f\u6a70\u6a71\u6a72\u6a73\u6a74\u6a75\u6a76\u6a77\u6a78\u6a79\u6a7a\u6a7b\u6a7c\u6a7d\u6a7e\u6a7f\u6a80\u6a81\u6a82\u6a83\u6a84\u6a85\u6a86\u6a87\u6a88\u6a89\u6a8a\u6a8b\u6a8c\u6a8d\u6a8e\u6a8f\u6a90\u6a91\u6a92\u6a93\u6a94\u6a95\u6a96\u6a97\u6a98\u6a99\u6a9a\u6a9b\u6a9c\u6a9d\u6a9e\u6a9f\u6aa0\u6aa1\u6aa2\u6aa3\u6aa4\u6aa5\u6aa6\u6aa7\u6aa8\u6aa9\u6aaa\u6aab\u6aac\u6aad\u6aae\u6aaf\u6ab0\u6ab1\u6ab2\u6ab3\u6ab4\u6ab5\u6ab6\u6ab7\u6ab8\u6ab9\u6aba\u6abb\u6abc\u6abd\u6abe\u6abf\u6ac0\u6ac1\u6ac2\u6ac3\u6ac4\u6ac5\u6ac6\u6ac7\u6ac8\u6ac9\u6aca\u6acb\u6acc\u6acd\u6ace\u6acf\u6ad0\u6ad1\u6ad2\u6ad3\u6ad4\u6ad5\u6ad6\u6ad7\u6ad8\u6ad9\u6ada\u6adb\u6adc\u6add\u6ade\u6adf\u6ae0\u6ae1\u6ae2\u6ae3\u6ae4\u6ae5\u6ae6\u6ae7\u6ae8\u6ae9\u6aea\u6aeb\u6aec\u6aed\u6aee\u6aef\u6af0\u6af1\u6af2\u6af3\u6af4\u6af5\u6af6\u6af7\u6af8\u6af9\u6afa\u6afb\u6afc\u6afd\u6afe\u6aff\u6b00\u6b01\u6b02\u6b03\u6b04\u6b05\u6b06\u6b07\u6b08\u6b09\u6b0a\u6b0b\u6b0c\u6b0d\u6b0e\u6b0f\u6b10\u6b11\u6b12\u6b13\u6b14\u6b15\u6b16\u6b17\u6b18\u6b19\u6b1a\u6b1b\u6b1c\u6b1d\u6b1e\u6b1f\u6b20\u6b21\u6b22\u6b23\u6b24\u6b25\u6b26\u6b27\u6b28\u6b29\u6b2a\u6b2b\u6b2c\u6b2d\u6b2e\u6b2f\u6b30\u6b31\u6b32\u6b33\u6b34\u6b35\u6b36\u6b37\u6b38\u6b39\u6b3a\u6b3b\u6b3c\u6b3d\u6b3e\u6b3f\u6b40\u6b41\u6b42\u6b43\u6b44\u6b45\u6b46\u6b47\u6b48\u6b49\u6b4a\u6b4b\u6b4c\u6b4d\u6b4e\u6b4f\u6b50\u6b51\u6b52\u6b53\u6b54\u6b55\u6b56\u6b57\u6b58\u6b59\u6b5a\u6b5b\u6b5c\u6b5d\u6b5e\u6b5f\u6b60\u6b61\u6b62\u6b63\u6b64\u6b65\u6b66\u6b67\u6b68\u6b69\u6b6a\u6b6b\u6b6c\u6b6d\u6b6e\u6b6f\u6b70\u6b71\u6b72\u6b73\u6b74\u6b75\u6b76\u6b77\u6b78\u6b79\u6b7a\u6b7b\u6b7c\u6b7d\u6b7e\u6b7f\u6b80\u6b81\u6b82\u6b83\u6b84\u6b85\u6b86\u6b87\u6b88\u6b89\u6b8a\u6b8b\u6b8c\u6b8d\u6b8e\u6b8f\u6b90\u6b91\u6b92\u6b93\u6b94\u6b95\u6b96\u6b97\u6b98\u6b99\u6b9a\u6b9b\u6b9c\u6b9d\u6b9e\u6b9f\u6ba0\u6ba1\u6ba2\u6ba3\u6ba4\u6ba5\u6ba6\u6ba7\u6ba8\u6ba9\u6baa\u6bab\u6bac\u6bad\u6bae\u6baf\u6bb0\u6bb1\u6bb2\u6bb3\u6bb4\u6bb5\u6bb6\u6bb7\u6bb8\u6bb9\u6bba\u6bbb\u6bbc\u6bbd\u6bbe\u6bbf\u6bc0\u6bc1\u6bc2\u6bc3\u6bc4\u6bc5\u6bc6\u6bc7\u6bc8\u6bc9\u6bca\u6bcb\u6bcc\u6bcd\u6bce\u6bcf\u6bd0\u6bd1\u6bd2\u6bd3\u6bd4\u6bd5\u6bd6\u6bd7\u6bd8\u6bd9\u6bda\u6bdb\u6bdc\u6bdd\u6bde\u6bdf\u6be0\u6be1\u6be2\u6be3\u6be4\u6be5\u6be6\u6be7\u6be8\u6be9\u6bea\u6beb\u6bec\u6bed\u6bee\u6bef\u6bf0\u6bf1\u6bf2\u6bf3\u6bf4\u6bf5\u6bf6\u6bf7\u6bf8\u6bf9\u6bfa\u6bfb\u6bfc\u6bfd\u6bfe\u6bff\u6c00\u6c01\u6c02\u6c03\u6c04\u6c05\u6c06\u6c07\u6c08\u6c09\u6c0a\u6c0b\u6c0c\u6c0d\u6c0e\u6c0f\u6c10\u6c11\u6c12\u6c13\u6c14\u6c15\u6c16\u6c17\u6c18\u6c19\u6c1a\u6c1b\u6c1c\u6c1d\u6c1e\u6c1f\u6c20\u6c21\u6c22\u6c23\u6c24\u6c25\u6c26\u6c27\u6c28\u6c29\u6c2a\u6c2b\u6c2c\u6c2d\u6c2e\u6c2f\u6c30\u6c31\u6c32\u6c33\u6c34\u6c35\u6c36\u6c37\u6c38\u6c39\u6c3a\u6c3b\u6c3c\u6c3d\u6c3e\u6c3f\u6c40\u6c41\u6c42\u6c43\u6c44\u6c45\u6c46\u6c47\u6c48\u6c49\u6c4a\u6c4b\u6c4c\u6c4d\u6c4e\u6c4f\u6c50\u6c51\u6c52\u6c53\u6c54\u6c55\u6c56\u6c57\u6c58\u6c59\u6c5a\u6c5b\u6c5c\u6c5d\u6c5e\u6c5f\u6c60\u6c61\u6c62\u6c63\u6c64\u6c65\u6c66\u6c67\u6c68\u6c69\u6c6a\u6c6b\u6c6c\u6c6d\u6c6e\u6c6f\u6c70\u6c71\u6c72\u6c73\u6c74\u6c75\u6c76\u6c77\u6c78\u6c79\u6c7a\u6c7b\u6c7c\u6c7d\u6c7e\u6c7f\u6c80\u6c81\u6c82\u6c83\u6c84\u6c85\u6c86\u6c87\u6c88\u6c89\u6c8a\u6c8b\u6c8c\u6c8d\u6c8e\u6c8f\u6c90\u6c91\u6c92\u6c93\u6c94\u6c95\u6c96\u6c97\u6c98\u6c99\u6c9a\u6c9b\u6c9c\u6c9d\u6c9e\u6c9f\u6ca0\u6ca1\u6ca2\u6ca3\u6ca4\u6ca5\u6ca6\u6ca7\u6ca8\u6ca9\u6caa\u6cab\u6cac\u6cad\u6cae\u6caf\u6cb0\u6cb1\u6cb2\u6cb3\u6cb4\u6cb5\u6cb6\u6cb7\u6cb8\u6cb9\u6cba\u6cbb\u6cbc\u6cbd\u6cbe\u6cbf\u6cc0\u6cc1\u6cc2\u6cc3\u6cc4\u6cc5\u6cc6\u6cc7\u6cc8\u6cc9\u6cca\u6ccb\u6ccc\u6ccd\u6cce\u6ccf\u6cd0\u6cd1\u6cd2\u6cd3\u6cd4\u6cd5\u6cd6\u6cd7\u6cd8\u6cd9\u6cda\u6cdb\u6cdc\u6cdd\u6cde\u6cdf\u6ce0\u6ce1\u6ce2\u6ce3\u6ce4\u6ce5\u6ce6\u6ce7\u6ce8\u6ce9\u6cea\u6ceb\u6cec\u6ced\u6cee\u6cef\u6cf0\u6cf1\u6cf2\u6cf3\u6cf4\u6cf5\u6cf6\u6cf7\u6cf8\u6cf9\u6cfa\u6cfb\u6cfc\u6cfd\u6cfe\u6cff\u6d00\u6d01\u6d02\u6d03\u6d04\u6d05\u6d06\u6d07\u6d08\u6d09\u6d0a\u6d0b\u6d0c\u6d0d\u6d0e\u6d0f\u6d10\u6d11\u6d12\u6d13\u6d14\u6d15\u6d16\u6d17\u6d18\u6d19\u6d1a\u6d1b\u6d1c\u6d1d\u6d1e\u6d1f\u6d20\u6d21\u6d22\u6d23\u6d24\u6d25\u6d26\u6d27\u6d28\u6d29\u6d2a\u6d2b\u6d2c\u6d2d\u6d2e\u6d2f\u6d30\u6d31\u6d32\u6d33\u6d34\u6d35\u6d36\u6d37\u6d38\u6d39\u6d3a\u6d3b\u6d3c\u6d3d\u6d3e\u6d3f\u6d40\u6d41\u6d42\u6d43\u6d44\u6d45\u6d46\u6d47\u6d48\u6d49\u6d4a\u6d4b\u6d4c\u6d4d\u6d4e\u6d4f\u6d50\u6d51\u6d52\u6d53\u6d54\u6d55\u6d56\u6d57\u6d58\u6d59\u6d5a\u6d5b\u6d5c\u6d5d\u6d5e\u6d5f\u6d60\u6d61\u6d62\u6d63\u6d64\u6d65\u6d66\u6d67\u6d68\u6d69\u6d6a\u6d6b\u6d6c\u6d6d\u6d6e\u6d6f\u6d70\u6d71\u6d72\u6d73\u6d74\u6d75\u6d76\u6d77\u6d78\u6d79\u6d7a\u6d7b\u6d7c\u6d7d\u6d7e\u6d7f\u6d80\u6d81\u6d82\u6d83\u6d84\u6d85\u6d86\u6d87\u6d88\u6d89\u6d8a\u6d8b\u6d8c\u6d8d\u6d8e\u6d8f\u6d90\u6d91\u6d92\u6d93\u6d94\u6d95\u6d96\u6d97\u6d98\u6d99\u6d9a\u6d9b\u6d9c\u6d9d\u6d9e\u6d9f\u6da0\u6da1\u6da2\u6da3\u6da4\u6da5\u6da6\u6da7\u6da8\u6da9\u6daa\u6dab\u6dac\u6dad\u6dae\u6daf\u6db0\u6db1\u6db2\u6db3\u6db4\u6db5\u6db6\u6db7\u6db8\u6db9\u6dba\u6dbb\u6dbc\u6dbd\u6dbe\u6dbf\u6dc0\u6dc1\u6dc2\u6dc3\u6dc4\u6dc5\u6dc6\u6dc7\u6dc8\u6dc9\u6dca\u6dcb\u6dcc\u6dcd\u6dce\u6dcf\u6dd0\u6dd1\u6dd2\u6dd3\u6dd4\u6dd5\u6dd6\u6dd7\u6dd8\u6dd9\u6dda\u6ddb\u6ddc\u6ddd\u6dde\u6ddf\u6de0\u6de1\u6de2\u6de3\u6de4\u6de5\u6de6\u6de7\u6de8\u6de9\u6dea\u6deb\u6dec\u6ded\u6dee\u6def\u6df0\u6df1\u6df2\u6df3\u6df4\u6df5\u6df6\u6df7\u6df8\u6df9\u6dfa\u6dfb\u6dfc\u6dfd\u6dfe\u6dff\u6e00\u6e01\u6e02\u6e03\u6e04\u6e05\u6e06\u6e07\u6e08\u6e09\u6e0a\u6e0b\u6e0c\u6e0d\u6e0e\u6e0f\u6e10\u6e11\u6e12\u6e13\u6e14\u6e15\u6e16\u6e17\u6e18\u6e19\u6e1a\u6e1b\u6e1c\u6e1d\u6e1e\u6e1f\u6e20\u6e21\u6e22\u6e23\u6e24\u6e25\u6e26\u6e27\u6e28\u6e29\u6e2a\u6e2b\u6e2c\u6e2d\u6e2e\u6e2f\u6e30\u6e31\u6e32\u6e33\u6e34\u6e35\u6e36\u6e37\u6e38\u6e39\u6e3a\u6e3b\u6e3c\u6e3d\u6e3e\u6e3f\u6e40\u6e41\u6e42\u6e43\u6e44\u6e45\u6e46\u6e47\u6e48\u6e49\u6e4a\u6e4b\u6e4c\u6e4d\u6e4e\u6e4f\u6e50\u6e51\u6e52\u6e53\u6e54\u6e55\u6e56\u6e57\u6e58\u6e59\u6e5a\u6e5b\u6e5c\u6e5d\u6e5e\u6e5f\u6e60\u6e61\u6e62\u6e63\u6e64\u6e65\u6e66\u6e67\u6e68\u6e69\u6e6a\u6e6b\u6e6c\u6e6d\u6e6e\u6e6f\u6e70\u6e71\u6e72\u6e73\u6e74\u6e75\u6e76\u6e77\u6e78\u6e79\u6e7a\u6e7b\u6e7c\u6e7d\u6e7e\u6e7f\u6e80\u6e81\u6e82\u6e83\u6e84\u6e85\u6e86\u6e87\u6e88\u6e89\u6e8a\u6e8b\u6e8c\u6e8d\u6e8e\u6e8f\u6e90\u6e91\u6e92\u6e93\u6e94\u6e95\u6e96\u6e97\u6e98\u6e99\u6e9a\u6e9b\u6e9c\u6e9d\u6e9e\u6e9f\u6ea0\u6ea1\u6ea2\u6ea3\u6ea4\u6ea5\u6ea6\u6ea7\u6ea8\u6ea9\u6eaa\u6eab\u6eac\u6ead\u6eae\u6eaf\u6eb0\u6eb1\u6eb2\u6eb3\u6eb4\u6eb5\u6eb6\u6eb7\u6eb8\u6eb9\u6eba\u6ebb\u6ebc\u6ebd\u6ebe\u6ebf\u6ec0\u6ec1\u6ec2\u6ec3\u6ec4\u6ec5\u6ec6\u6ec7\u6ec8\u6ec9\u6eca\u6ecb\u6ecc\u6ecd\u6ece\u6ecf\u6ed0\u6ed1\u6ed2\u6ed3\u6ed4\u6ed5\u6ed6\u6ed7\u6ed8\u6ed9\u6eda\u6edb\u6edc\u6edd\u6ede\u6edf\u6ee0\u6ee1\u6ee2\u6ee3\u6ee4\u6ee5\u6ee6\u6ee7\u6ee8\u6ee9\u6eea\u6eeb\u6eec\u6eed\u6eee\u6eef\u6ef0\u6ef1\u6ef2\u6ef3\u6ef4\u6ef5\u6ef6\u6ef7\u6ef8\u6ef9\u6efa\u6efb\u6efc\u6efd\u6efe\u6eff\u6f00\u6f01\u6f02\u6f03\u6f04\u6f05\u6f06\u6f07\u6f08\u6f09\u6f0a\u6f0b\u6f0c\u6f0d\u6f0e\u6f0f\u6f10\u6f11\u6f12\u6f13\u6f14\u6f15\u6f16\u6f17\u6f18\u6f19\u6f1a\u6f1b\u6f1c\u6f1d\u6f1e\u6f1f\u6f20\u6f21\u6f22\u6f23\u6f24\u6f25\u6f26\u6f27\u6f28\u6f29\u6f2a\u6f2b\u6f2c\u6f2d\u6f2e\u6f2f\u6f30\u6f31\u6f32\u6f33\u6f34\u6f35\u6f36\u6f37\u6f38\u6f39\u6f3a\u6f3b\u6f3c\u6f3d\u6f3e\u6f3f\u6f40\u6f41\u6f42\u6f43\u6f44\u6f45\u6f46\u6f47\u6f48\u6f49\u6f4a\u6f4b\u6f4c\u6f4d\u6f4e\u6f4f\u6f50\u6f51\u6f52\u6f53\u6f54\u6f55\u6f56\u6f57\u6f58\u6f59\u6f5a\u6f5b\u6f5c\u6f5d\u6f5e\u6f5f\u6f60\u6f61\u6f62\u6f63\u6f64\u6f65\u6f66\u6f67\u6f68\u6f69\u6f6a\u6f6b\u6f6c\u6f6d\u6f6e\u6f6f\u6f70\u6f71\u6f72\u6f73\u6f74\u6f75\u6f76\u6f77\u6f78\u6f79\u6f7a\u6f7b\u6f7c\u6f7d\u6f7e\u6f7f\u6f80\u6f81\u6f82\u6f83\u6f84\u6f85\u6f86\u6f87\u6f88\u6f89\u6f8a\u6f8b\u6f8c\u6f8d\u6f8e\u6f8f\u6f90\u6f91\u6f92\u6f93\u6f94\u6f95\u6f96\u6f97\u6f98\u6f99\u6f9a\u6f9b\u6f9c\u6f9d\u6f9e\u6f9f\u6fa0\u6fa1\u6fa2\u6fa3\u6fa4\u6fa5\u6fa6\u6fa7\u6fa8\u6fa9\u6faa\u6fab\u6fac\u6fad\u6fae\u6faf\u6fb0\u6fb1\u6fb2\u6fb3\u6fb4\u6fb5\u6fb6\u6fb7\u6fb8\u6fb9\u6fba\u6fbb\u6fbc\u6fbd\u6fbe\u6fbf\u6fc0\u6fc1\u6fc2\u6fc3\u6fc4\u6fc5\u6fc6\u6fc7\u6fc8\u6fc9\u6fca\u6fcb\u6fcc\u6fcd\u6fce\u6fcf\u6fd0\u6fd1\u6fd2\u6fd3\u6fd4\u6fd5\u6fd6\u6fd7\u6fd8\u6fd9\u6fda\u6fdb\u6fdc\u6fdd\u6fde\u6fdf\u6fe0\u6fe1\u6fe2\u6fe3\u6fe4\u6fe5\u6fe6\u6fe7\u6fe8\u6fe9\u6fea\u6feb\u6fec\u6fed\u6fee\u6fef\u6ff0\u6ff1\u6ff2\u6ff3\u6ff4\u6ff5\u6ff6\u6ff7\u6ff8\u6ff9\u6ffa\u6ffb\u6ffc\u6ffd\u6ffe\u6fff\u7000\u7001\u7002\u7003\u7004\u7005\u7006\u7007\u7008\u7009\u700a\u700b\u700c\u700d\u700e\u700f\u7010\u7011\u7012\u7013\u7014\u7015\u7016\u7017\u7018\u7019\u701a\u701b\u701c\u701d\u701e\u701f\u7020\u7021\u7022\u7023\u7024\u7025\u7026\u7027\u7028\u7029\u702a\u702b\u702c\u702d\u702e\u702f\u7030\u7031\u7032\u7033\u7034\u7035\u7036\u7037\u7038\u7039\u703a\u703b\u703c\u703d\u703e\u703f\u7040\u7041\u7042\u7043\u7044\u7045\u7046\u7047\u7048\u7049\u704a\u704b\u704c\u704d\u704e\u704f\u7050\u7051\u7052\u7053\u7054\u7055\u7056\u7057\u7058\u7059\u705a\u705b\u705c\u705d\u705e\u705f\u7060\u7061\u7062\u7063\u7064\u7065\u7066\u7067\u7068\u7069\u706a\u706b\u706c\u706d\u706e\u706f\u7070\u7071\u7072\u7073\u7074\u7075\u7076\u7077\u7078\u7079\u707a\u707b\u707c\u707d\u707e\u707f\u7080\u7081\u7082\u7083\u7084\u7085\u7086\u7087\u7088\u7089\u708a\u708b\u708c\u708d\u708e\u708f\u7090\u7091\u7092\u7093\u7094\u7095\u7096\u7097\u7098\u7099\u709a\u709b\u709c\u709d\u709e\u709f\u70a0\u70a1\u70a2\u70a3\u70a4\u70a5\u70a6\u70a7\u70a8\u70a9\u70aa\u70ab\u70ac\u70ad\u70ae\u70af\u70b0\u70b1\u70b2\u70b3\u70b4\u70b5\u70b6\u70b7\u70b8\u70b9\u70ba\u70bb\u70bc\u70bd\u70be\u70bf\u70c0\u70c1\u70c2\u70c3\u70c4\u70c5\u70c6\u70c7\u70c8\u70c9\u70ca\u70cb\u70cc\u70cd\u70ce\u70cf\u70d0\u70d1\u70d2\u70d3\u70d4\u70d5\u70d6\u70d7\u70d8\u70d9\u70da\u70db\u70dc\u70dd\u70de\u70df\u70e0\u70e1\u70e2\u70e3\u70e4\u70e5\u70e6\u70e7\u70e8\u70e9\u70ea\u70eb\u70ec\u70ed\u70ee\u70ef\u70f0\u70f1\u70f2\u70f3\u70f4\u70f5\u70f6\u70f7\u70f8\u70f9\u70fa\u70fb\u70fc\u70fd\u70fe\u70ff\u7100\u7101\u7102\u7103\u7104\u7105\u7106\u7107\u7108\u7109\u710a\u710b\u710c\u710d\u710e\u710f\u7110\u7111\u7112\u7113\u7114\u7115\u7116\u7117\u7118\u7119\u711a\u711b\u711c\u711d\u711e\u711f\u7120\u7121\u7122\u7123\u7124\u7125\u7126\u7127\u7128\u7129\u712a\u712b\u712c\u712d\u712e\u712f\u7130\u7131\u7132\u7133\u7134\u7135\u7136\u7137\u7138\u7139\u713a\u713b\u713c\u713d\u713e\u713f\u7140\u7141\u7142\u7143\u7144\u7145\u7146\u7147\u7148\u7149\u714a\u714b\u714c\u714d\u714e\u714f\u7150\u7151\u7152\u7153\u7154\u7155\u7156\u7157\u7158\u7159\u715a\u715b\u715c\u715d\u715e\u715f\u7160\u7161\u7162\u7163\u7164\u7165\u7166\u7167\u7168\u7169\u716a\u716b\u716c\u716d\u716e\u716f\u7170\u7171\u7172\u7173\u7174\u7175\u7176\u7177\u7178\u7179\u717a\u717b\u717c\u717d\u717e\u717f\u7180\u7181\u7182\u7183\u7184\u7185\u7186\u7187\u7188\u7189\u718a\u718b\u718c\u718d\u718e\u718f\u7190\u7191\u7192\u7193\u7194\u7195\u7196\u7197\u7198\u7199\u719a\u719b\u719c\u719d\u719e\u719f\u71a0\u71a1\u71a2\u71a3\u71a4\u71a5\u71a6\u71a7\u71a8\u71a9\u71aa\u71ab\u71ac\u71ad\u71ae\u71af\u71b0\u71b1\u71b2\u71b3\u71b4\u71b5\u71b6\u71b7\u71b8\u71b9\u71ba\u71bb\u71bc\u71bd\u71be\u71bf\u71c0\u71c1\u71c2\u71c3\u71c4\u71c5\u71c6\u71c7\u71c8\u71c9\u71ca\u71cb\u71cc\u71cd\u71ce\u71cf\u71d0\u71d1\u71d2\u71d3\u71d4\u71d5\u71d6\u71d7\u71d8\u71d9\u71da\u71db\u71dc\u71dd\u71de\u71df\u71e0\u71e1\u71e2\u71e3\u71e4\u71e5\u71e6\u71e7\u71e8\u71e9\u71ea\u71eb\u71ec\u71ed\u71ee\u71ef\u71f0\u71f1\u71f2\u71f3\u71f4\u71f5\u71f6\u71f7\u71f8\u71f9\u71fa\u71fb\u71fc\u71fd\u71fe\u71ff\u7200\u7201\u7202\u7203\u7204\u7205\u7206\u7207\u7208\u7209\u720a\u720b\u720c\u720d\u720e\u720f\u7210\u7211\u7212\u7213\u7214\u7215\u7216\u7217\u7218\u7219\u721a\u721b\u721c\u721d\u721e\u721f\u7220\u7221\u7222\u7223\u7224\u7225\u7226\u7227\u7228\u7229\u722a\u722b\u722c\u722d\u722e\u722f\u7230\u7231\u7232\u7233\u7234\u7235\u7236\u7237\u7238\u7239\u723a\u723b\u723c\u723d\u723e\u723f\u7240\u7241\u7242\u7243\u7244\u7245\u7246\u7247\u7248\u7249\u724a\u724b\u724c\u724d\u724e\u724f\u7250\u7251\u7252\u7253\u7254\u7255\u7256\u7257\u7258\u7259\u725a\u725b\u725c\u725d\u725e\u725f\u7260\u7261\u7262\u7263\u7264\u7265\u7266\u7267\u7268\u7269\u726a\u726b\u726c\u726d\u726e\u726f\u7270\u7271\u7272\u7273\u7274\u7275\u7276\u7277\u7278\u7279\u727a\u727b\u727c\u727d\u727e\u727f\u7280\u7281\u7282\u7283\u7284\u7285\u7286\u7287\u7288\u7289\u728a\u728b\u728c\u728d\u728e\u728f\u7290\u7291\u7292\u7293\u7294\u7295\u7296\u7297\u7298\u7299\u729a\u729b\u729c\u729d\u729e\u729f\u72a0\u72a1\u72a2\u72a3\u72a4\u72a5\u72a6\u72a7\u72a8\u72a9\u72aa\u72ab\u72ac\u72ad\u72ae\u72af\u72b0\u72b1\u72b2\u72b3\u72b4\u72b5\u72b6\u72b7\u72b8\u72b9\u72ba\u72bb\u72bc\u72bd\u72be\u72bf\u72c0\u72c1\u72c2\u72c3\u72c4\u72c5\u72c6\u72c7\u72c8\u72c9\u72ca\u72cb\u72cc\u72cd\u72ce\u72cf\u72d0\u72d1\u72d2\u72d3\u72d4\u72d5\u72d6\u72d7\u72d8\u72d9\u72da\u72db\u72dc\u72dd\u72de\u72df\u72e0\u72e1\u72e2\u72e3\u72e4\u72e5\u72e6\u72e7\u72e8\u72e9\u72ea\u72eb\u72ec\u72ed\u72ee\u72ef\u72f0\u72f1\u72f2\u72f3\u72f4\u72f5\u72f6\u72f7\u72f8\u72f9\u72fa\u72fb\u72fc\u72fd\u72fe\u72ff\u7300\u7301\u7302\u7303\u7304\u7305\u7306\u7307\u7308\u7309\u730a\u730b\u730c\u730d\u730e\u730f\u7310\u7311\u7312\u7313\u7314\u7315\u7316\u7317\u7318\u7319\u731a\u731b\u731c\u731d\u731e\u731f\u7320\u7321\u7322\u7323\u7324\u7325\u7326\u7327\u7328\u7329\u732a\u732b\u732c\u732d\u732e\u732f\u7330\u7331\u7332\u7333\u7334\u7335\u7336\u7337\u7338\u7339\u733a\u733b\u733c\u733d\u733e\u733f\u7340\u7341\u7342\u7343\u7344\u7345\u7346\u7347\u7348\u7349\u734a\u734b\u734c\u734d\u734e\u734f\u7350\u7351\u7352\u7353\u7354\u7355\u7356\u7357\u7358\u7359\u735a\u735b\u735c\u735d\u735e\u735f\u7360\u7361\u7362\u7363\u7364\u7365\u7366\u7367\u7368\u7369\u736a\u736b\u736c\u736d\u736e\u736f\u7370\u7371\u7372\u7373\u7374\u7375\u7376\u7377\u7378\u7379\u737a\u737b\u737c\u737d\u737e\u737f\u7380\u7381\u7382\u7383\u7384\u7385\u7386\u7387\u7388\u7389\u738a\u738b\u738c\u738d\u738e\u738f\u7390\u7391\u7392\u7393\u7394\u7395\u7396\u7397\u7398\u7399\u739a\u739b\u739c\u739d\u739e\u739f\u73a0\u73a1\u73a2\u73a3\u73a4\u73a5\u73a6\u73a7\u73a8\u73a9\u73aa\u73ab\u73ac\u73ad\u73ae\u73af\u73b0\u73b1\u73b2\u73b3\u73b4\u73b5\u73b6\u73b7\u73b8\u73b9\u73ba\u73bb\u73bc\u73bd\u73be\u73bf\u73c0\u73c1\u73c2\u73c3\u73c4\u73c5\u73c6\u73c7\u73c8\u73c9\u73ca\u73cb\u73cc\u73cd\u73ce\u73cf\u73d0\u73d1\u73d2\u73d3\u73d4\u73d5\u73d6\u73d7\u73d8\u73d9\u73da\u73db\u73dc\u73dd\u73de\u73df\u73e0\u73e1\u73e2\u73e3\u73e4\u73e5\u73e6\u73e7\u73e8\u73e9\u73ea\u73eb\u73ec\u73ed\u73ee\u73ef\u73f0\u73f1\u73f2\u73f3\u73f4\u73f5\u73f6\u73f7\u73f8\u73f9\u73fa\u73fb\u73fc\u73fd\u73fe\u73ff\u7400\u7401\u7402\u7403\u7404\u7405\u7406\u7407\u7408\u7409\u740a\u740b\u740c\u740d\u740e\u740f\u7410\u7411\u7412\u7413\u7414\u7415\u7416\u7417\u7418\u7419\u741a\u741b\u741c\u741d\u741e\u741f\u7420\u7421\u7422\u7423\u7424\u7425\u7426\u7427\u7428\u7429\u742a\u742b\u742c\u742d\u742e\u742f\u7430\u7431\u7432\u7433\u7434\u7435\u7436\u7437\u7438\u7439\u743a\u743b\u743c\u743d\u743e\u743f\u7440\u7441\u7442\u7443\u7444\u7445\u7446\u7447\u7448\u7449\u744a\u744b\u744c\u744d\u744e\u744f\u7450\u7451\u7452\u7453\u7454\u7455\u7456\u7457\u7458\u7459\u745a\u745b\u745c\u745d\u745e\u745f\u7460\u7461\u7462\u7463\u7464\u7465\u7466\u7467\u7468\u7469\u746a\u746b\u746c\u746d\u746e\u746f\u7470\u7471\u7472\u7473\u7474\u7475\u7476\u7477\u7478\u7479\u747a\u747b\u747c\u747d\u747e\u747f\u7480\u7481\u7482\u7483\u7484\u7485\u7486\u7487\u7488\u7489\u748a\u748b\u748c\u748d\u748e\u748f\u7490\u7491\u7492\u7493\u7494\u7495\u7496\u7497\u7498\u7499\u749a\u749b\u749c\u749d\u749e\u749f\u74a0\u74a1\u74a2\u74a3\u74a4\u74a5\u74a6\u74a7\u74a8\u74a9\u74aa\u74ab\u74ac\u74ad\u74ae\u74af\u74b0\u74b1\u74b2\u74b3\u74b4\u74b5\u74b6\u74b7\u74b8\u74b9\u74ba\u74bb\u74bc\u74bd\u74be\u74bf\u74c0\u74c1\u74c2\u74c3\u74c4\u74c5\u74c6\u74c7\u74c8\u74c9\u74ca\u74cb\u74cc\u74cd\u74ce\u74cf\u74d0\u74d1\u74d2\u74d3\u74d4\u74d5\u74d6\u74d7\u74d8\u74d9\u74da\u74db\u74dc\u74dd\u74de\u74df\u74e0\u74e1\u74e2\u74e3\u74e4\u74e5\u74e6\u74e7\u74e8\u74e9\u74ea\u74eb\u74ec\u74ed\u74ee\u74ef\u74f0\u74f1\u74f2\u74f3\u74f4\u74f5\u74f6\u74f7\u74f8\u74f9\u74fa\u74fb\u74fc\u74fd\u74fe\u74ff\u7500\u7501\u7502\u7503\u7504\u7505\u7506\u7507\u7508\u7509\u750a\u750b\u750c\u750d\u750e\u750f\u7510\u7511\u7512\u7513\u7514\u7515\u7516\u7517\u7518\u7519\u751a\u751b\u751c\u751d\u751e\u751f\u7520\u7521\u7522\u7523\u7524\u7525\u7526\u7527\u7528\u7529\u752a\u752b\u752c\u752d\u752e\u752f\u7530\u7531\u7532\u7533\u7534\u7535\u7536\u7537\u7538\u7539\u753a\u753b\u753c\u753d\u753e\u753f\u7540\u7541\u7542\u7543\u7544\u7545\u7546\u7547\u7548\u7549\u754a\u754b\u754c\u754d\u754e\u754f\u7550\u7551\u7552\u7553\u7554\u7555\u7556\u7557\u7558\u7559\u755a\u755b\u755c\u755d\u755e\u755f\u7560\u7561\u7562\u7563\u7564\u7565\u7566\u7567\u7568\u7569\u756a\u756b\u756c\u756d\u756e\u756f\u7570\u7571\u7572\u7573\u7574\u7575\u7576\u7577\u7578\u7579\u757a\u757b\u757c\u757d\u757e\u757f\u7580\u7581\u7582\u7583\u7584\u7585\u7586\u7587\u7588\u7589\u758a\u758b\u758c\u758d\u758e\u758f\u7590\u7591\u7592\u7593\u7594\u7595\u7596\u7597\u7598\u7599\u759a\u759b\u759c\u759d\u759e\u759f\u75a0\u75a1\u75a2\u75a3\u75a4\u75a5\u75a6\u75a7\u75a8\u75a9\u75aa\u75ab\u75ac\u75ad\u75ae\u75af\u75b0\u75b1\u75b2\u75b3\u75b4\u75b5\u75b6\u75b7\u75b8\u75b9\u75ba\u75bb\u75bc\u75bd\u75be\u75bf\u75c0\u75c1\u75c2\u75c3\u75c4\u75c5\u75c6\u75c7\u75c8\u75c9\u75ca\u75cb\u75cc\u75cd\u75ce\u75cf\u75d0\u75d1\u75d2\u75d3\u75d4\u75d5\u75d6\u75d7\u75d8\u75d9\u75da\u75db\u75dc\u75dd\u75de\u75df\u75e0\u75e1\u75e2\u75e3\u75e4\u75e5\u75e6\u75e7\u75e8\u75e9\u75ea\u75eb\u75ec\u75ed\u75ee\u75ef\u75f0\u75f1\u75f2\u75f3\u75f4\u75f5\u75f6\u75f7\u75f8\u75f9\u75fa\u75fb\u75fc\u75fd\u75fe\u75ff\u7600\u7601\u7602\u7603\u7604\u7605\u7606\u7607\u7608\u7609\u760a\u760b\u760c\u760d\u760e\u760f\u7610\u7611\u7612\u7613\u7614\u7615\u7616\u7617\u7618\u7619\u761a\u761b\u761c\u761d\u761e\u761f\u7620\u7621\u7622\u7623\u7624\u7625\u7626\u7627\u7628\u7629\u762a\u762b\u762c\u762d\u762e\u762f\u7630\u7631\u7632\u7633\u7634\u7635\u7636\u7637\u7638\u7639\u763a\u763b\u763c\u763d\u763e\u763f\u7640\u7641\u7642\u7643\u7644\u7645\u7646\u7647\u7648\u7649\u764a\u764b\u764c\u764d\u764e\u764f\u7650\u7651\u7652\u7653\u7654\u7655\u7656\u7657\u7658\u7659\u765a\u765b\u765c\u765d\u765e\u765f\u7660\u7661\u7662\u7663\u7664\u7665\u7666\u7667\u7668\u7669\u766a\u766b\u766c\u766d\u766e\u766f\u7670\u7671\u7672\u7673\u7674\u7675\u7676\u7677\u7678\u7679\u767a\u767b\u767c\u767d\u767e\u767f\u7680\u7681\u7682\u7683\u7684\u7685\u7686\u7687\u7688\u7689\u768a\u768b\u768c\u768d\u768e\u768f\u7690\u7691\u7692\u7693\u7694\u7695\u7696\u7697\u7698\u7699\u769a\u769b\u769c\u769d\u769e\u769f\u76a0\u76a1\u76a2\u76a3\u76a4\u76a5\u76a6\u76a7\u76a8\u76a9\u76aa\u76ab\u76ac\u76ad\u76ae\u76af\u76b0\u76b1\u76b2\u76b3\u76b4\u76b5\u76b6\u76b7\u76b8\u76b9\u76ba\u76bb\u76bc\u76bd\u76be\u76bf\u76c0\u76c1\u76c2\u76c3\u76c4\u76c5\u76c6\u76c7\u76c8\u76c9\u76ca\u76cb\u76cc\u76cd\u76ce\u76cf\u76d0\u76d1\u76d2\u76d3\u76d4\u76d5\u76d6\u76d7\u76d8\u76d9\u76da\u76db\u76dc\u76dd\u76de\u76df\u76e0\u76e1\u76e2\u76e3\u76e4\u76e5\u76e6\u76e7\u76e8\u76e9\u76ea\u76eb\u76ec\u76ed\u76ee\u76ef\u76f0\u76f1\u76f2\u76f3\u76f4\u76f5\u76f6\u76f7\u76f8\u76f9\u76fa\u76fb\u76fc\u76fd\u76fe\u76ff\u7700\u7701\u7702\u7703\u7704\u7705\u7706\u7707\u7708\u7709\u770a\u770b\u770c\u770d\u770e\u770f\u7710\u7711\u7712\u7713\u7714\u7715\u7716\u7717\u7718\u7719\u771a\u771b\u771c\u771d\u771e\u771f\u7720\u7721\u7722\u7723\u7724\u7725\u7726\u7727\u7728\u7729\u772a\u772b\u772c\u772d\u772e\u772f\u7730\u7731\u7732\u7733\u7734\u7735\u7736\u7737\u7738\u7739\u773a\u773b\u773c\u773d\u773e\u773f\u7740\u7741\u7742\u7743\u7744\u7745\u7746\u7747\u7748\u7749\u774a\u774b\u774c\u774d\u774e\u774f\u7750\u7751\u7752\u7753\u7754\u7755\u7756\u7757\u7758\u7759\u775a\u775b\u775c\u775d\u775e\u775f\u7760\u7761\u7762\u7763\u7764\u7765\u7766\u7767\u7768\u7769\u776a\u776b\u776c\u776d\u776e\u776f\u7770\u7771\u7772\u7773\u7774\u7775\u7776\u7777\u7778\u7779\u777a\u777b\u777c\u777d\u777e\u777f\u7780\u7781\u7782\u7783\u7784\u7785\u7786\u7787\u7788\u7789\u778a\u778b\u778c\u778d\u778e\u778f\u7790\u7791\u7792\u7793\u7794\u7795\u7796\u7797\u7798\u7799\u779a\u779b\u779c\u779d\u779e\u779f\u77a0\u77a1\u77a2\u77a3\u77a4\u77a5\u77a6\u77a7\u77a8\u77a9\u77aa\u77ab\u77ac\u77ad\u77ae\u77af\u77b0\u77b1\u77b2\u77b3\u77b4\u77b5\u77b6\u77b7\u77b8\u77b9\u77ba\u77bb\u77bc\u77bd\u77be\u77bf\u77c0\u77c1\u77c2\u77c3\u77c4\u77c5\u77c6\u77c7\u77c8\u77c9\u77ca\u77cb\u77cc\u77cd\u77ce\u77cf\u77d0\u77d1\u77d2\u77d3\u77d4\u77d5\u77d6\u77d7\u77d8\u77d9\u77da\u77db\u77dc\u77dd\u77de\u77df\u77e0\u77e1\u77e2\u77e3\u77e4\u77e5\u77e6\u77e7\u77e8\u77e9\u77ea\u77eb\u77ec\u77ed\u77ee\u77ef\u77f0\u77f1\u77f2\u77f3\u77f4\u77f5\u77f6\u77f7\u77f8\u77f9\u77fa\u77fb\u77fc\u77fd\u77fe\u77ff\u7800\u7801\u7802\u7803\u7804\u7805\u7806\u7807\u7808\u7809\u780a\u780b\u780c\u780d\u780e\u780f\u7810\u7811\u7812\u7813\u7814\u7815\u7816\u7817\u7818\u7819\u781a\u781b\u781c\u781d\u781e\u781f\u7820\u7821\u7822\u7823\u7824\u7825\u7826\u7827\u7828\u7829\u782a\u782b\u782c\u782d\u782e\u782f\u7830\u7831\u7832\u7833\u7834\u7835\u7836\u7837\u7838\u7839\u783a\u783b\u783c\u783d\u783e\u783f\u7840\u7841\u7842\u7843\u7844\u7845\u7846\u7847\u7848\u7849\u784a\u784b\u784c\u784d\u784e\u784f\u7850\u7851\u7852\u7853\u7854\u7855\u7856\u7857\u7858\u7859\u785a\u785b\u785c\u785d\u785e\u785f\u7860\u7861\u7862\u7863\u7864\u7865\u7866\u7867\u7868\u7869\u786a\u786b\u786c\u786d\u786e\u786f\u7870\u7871\u7872\u7873\u7874\u7875\u7876\u7877\u7878\u7879\u787a\u787b\u787c\u787d\u787e\u787f\u7880\u7881\u7882\u7883\u7884\u7885\u7886\u7887\u7888\u7889\u788a\u788b\u788c\u788d\u788e\u788f\u7890\u7891\u7892\u7893\u7894\u7895\u7896\u7897\u7898\u7899\u789a\u789b\u789c\u789d\u789e\u789f\u78a0\u78a1\u78a2\u78a3\u78a4\u78a5\u78a6\u78a7\u78a8\u78a9\u78aa\u78ab\u78ac\u78ad\u78ae\u78af\u78b0\u78b1\u78b2\u78b3\u78b4\u78b5\u78b6\u78b7\u78b8\u78b9\u78ba\u78bb\u78bc\u78bd\u78be\u78bf\u78c0\u78c1\u78c2\u78c3\u78c4\u78c5\u78c6\u78c7\u78c8\u78c9\u78ca\u78cb\u78cc\u78cd\u78ce\u78cf\u78d0\u78d1\u78d2\u78d3\u78d4\u78d5\u78d6\u78d7\u78d8\u78d9\u78da\u78db\u78dc\u78dd\u78de\u78df\u78e0\u78e1\u78e2\u78e3\u78e4\u78e5\u78e6\u78e7\u78e8\u78e9\u78ea\u78eb\u78ec\u78ed\u78ee\u78ef\u78f0\u78f1\u78f2\u78f3\u78f4\u78f5\u78f6\u78f7\u78f8\u78f9\u78fa\u78fb\u78fc\u78fd\u78fe\u78ff\u7900\u7901\u7902\u7903\u7904\u7905\u7906\u7907\u7908\u7909\u790a\u790b\u790c\u790d\u790e\u790f\u7910\u7911\u7912\u7913\u7914\u7915\u7916\u7917\u7918\u7919\u791a\u791b\u791c\u791d\u791e\u791f\u7920\u7921\u7922\u7923\u7924\u7925\u7926\u7927\u7928\u7929\u792a\u792b\u792c\u792d\u792e\u792f\u7930\u7931\u7932\u7933\u7934\u7935\u7936\u7937\u7938\u7939\u793a\u793b\u793c\u793d\u793e\u793f\u7940\u7941\u7942\u7943\u7944\u7945\u7946\u7947\u7948\u7949\u794a\u794b\u794c\u794d\u794e\u794f\u7950\u7951\u7952\u7953\u7954\u7955\u7956\u7957\u7958\u7959\u795a\u795b\u795c\u795d\u795e\u795f\u7960\u7961\u7962\u7963\u7964\u7965\u7966\u7967\u7968\u7969\u796a\u796b\u796c\u796d\u796e\u796f\u7970\u7971\u7972\u7973\u7974\u7975\u7976\u7977\u7978\u7979\u797a\u797b\u797c\u797d\u797e\u797f\u7980\u7981\u7982\u7983\u7984\u7985\u7986\u7987\u7988\u7989\u798a\u798b\u798c\u798d\u798e\u798f\u7990\u7991\u7992\u7993\u7994\u7995\u7996\u7997\u7998\u7999\u799a\u799b\u799c\u799d\u799e\u799f\u79a0\u79a1\u79a2\u79a3\u79a4\u79a5\u79a6\u79a7\u79a8\u79a9\u79aa\u79ab\u79ac\u79ad\u79ae\u79af\u79b0\u79b1\u79b2\u79b3\u79b4\u79b5\u79b6\u79b7\u79b8\u79b9\u79ba\u79bb\u79bc\u79bd\u79be\u79bf\u79c0\u79c1\u79c2\u79c3\u79c4\u79c5\u79c6\u79c7\u79c8\u79c9\u79ca\u79cb\u79cc\u79cd\u79ce\u79cf\u79d0\u79d1\u79d2\u79d3\u79d4\u79d5\u79d6\u79d7\u79d8\u79d9\u79da\u79db\u79dc\u79dd\u79de\u79df\u79e0\u79e1\u79e2\u79e3\u79e4\u79e5\u79e6\u79e7\u79e8\u79e9\u79ea\u79eb\u79ec\u79ed\u79ee\u79ef\u79f0\u79f1\u79f2\u79f3\u79f4\u79f5\u79f6\u79f7\u79f8\u79f9\u79fa\u79fb\u79fc\u79fd\u79fe\u79ff\u7a00\u7a01\u7a02\u7a03\u7a04\u7a05\u7a06\u7a07\u7a08\u7a09\u7a0a\u7a0b\u7a0c\u7a0d\u7a0e\u7a0f\u7a10\u7a11\u7a12\u7a13\u7a14\u7a15\u7a16\u7a17\u7a18\u7a19\u7a1a\u7a1b\u7a1c\u7a1d\u7a1e\u7a1f\u7a20\u7a21\u7a22\u7a23\u7a24\u7a25\u7a26\u7a27\u7a28\u7a29\u7a2a\u7a2b\u7a2c\u7a2d\u7a2e\u7a2f\u7a30\u7a31\u7a32\u7a33\u7a34\u7a35\u7a36\u7a37\u7a38\u7a39\u7a3a\u7a3b\u7a3c\u7a3d\u7a3e\u7a3f\u7a40\u7a41\u7a42\u7a43\u7a44\u7a45\u7a46\u7a47\u7a48\u7a49\u7a4a\u7a4b\u7a4c\u7a4d\u7a4e\u7a4f\u7a50\u7a51\u7a52\u7a53\u7a54\u7a55\u7a56\u7a57\u7a58\u7a59\u7a5a\u7a5b\u7a5c\u7a5d\u7a5e\u7a5f\u7a60\u7a61\u7a62\u7a63\u7a64\u7a65\u7a66\u7a67\u7a68\u7a69\u7a6a\u7a6b\u7a6c\u7a6d\u7a6e\u7a6f\u7a70\u7a71\u7a72\u7a73\u7a74\u7a75\u7a76\u7a77\u7a78\u7a79\u7a7a\u7a7b\u7a7c\u7a7d\u7a7e\u7a7f\u7a80\u7a81\u7a82\u7a83\u7a84\u7a85\u7a86\u7a87\u7a88\u7a89\u7a8a\u7a8b\u7a8c\u7a8d\u7a8e\u7a8f\u7a90\u7a91\u7a92\u7a93\u7a94\u7a95\u7a96\u7a97\u7a98\u7a99\u7a9a\u7a9b\u7a9c\u7a9d\u7a9e\u7a9f\u7aa0\u7aa1\u7aa2\u7aa3\u7aa4\u7aa5\u7aa6\u7aa7\u7aa8\u7aa9\u7aaa\u7aab\u7aac\u7aad\u7aae\u7aaf\u7ab0\u7ab1\u7ab2\u7ab3\u7ab4\u7ab5\u7ab6\u7ab7\u7ab8\u7ab9\u7aba\u7abb\u7abc\u7abd\u7abe\u7abf\u7ac0\u7ac1\u7ac2\u7ac3\u7ac4\u7ac5\u7ac6\u7ac7\u7ac8\u7ac9\u7aca\u7acb\u7acc\u7acd\u7ace\u7acf\u7ad0\u7ad1\u7ad2\u7ad3\u7ad4\u7ad5\u7ad6\u7ad7\u7ad8\u7ad9\u7ada\u7adb\u7adc\u7add\u7ade\u7adf\u7ae0\u7ae1\u7ae2\u7ae3\u7ae4\u7ae5\u7ae6\u7ae7\u7ae8\u7ae9\u7aea\u7aeb\u7aec\u7aed\u7aee\u7aef\u7af0\u7af1\u7af2\u7af3\u7af4\u7af5\u7af6\u7af7\u7af8\u7af9\u7afa\u7afb\u7afc\u7afd\u7afe\u7aff\u7b00\u7b01\u7b02\u7b03\u7b04\u7b05\u7b06\u7b07\u7b08\u7b09\u7b0a\u7b0b\u7b0c\u7b0d\u7b0e\u7b0f\u7b10\u7b11\u7b12\u7b13\u7b14\u7b15\u7b16\u7b17\u7b18\u7b19\u7b1a\u7b1b\u7b1c\u7b1d\u7b1e\u7b1f\u7b20\u7b21\u7b22\u7b23\u7b24\u7b25\u7b26\u7b27\u7b28\u7b29\u7b2a\u7b2b\u7b2c\u7b2d\u7b2e\u7b2f\u7b30\u7b31\u7b32\u7b33\u7b34\u7b35\u7b36\u7b37\u7b38\u7b39\u7b3a\u7b3b\u7b3c\u7b3d\u7b3e\u7b3f\u7b40\u7b41\u7b42\u7b43\u7b44\u7b45\u7b46\u7b47\u7b48\u7b49\u7b4a\u7b4b\u7b4c\u7b4d\u7b4e\u7b4f\u7b50\u7b51\u7b52\u7b53\u7b54\u7b55\u7b56\u7b57\u7b58\u7b59\u7b5a\u7b5b\u7b5c\u7b5d\u7b5e\u7b5f\u7b60\u7b61\u7b62\u7b63\u7b64\u7b65\u7b66\u7b67\u7b68\u7b69\u7b6a\u7b6b\u7b6c\u7b6d\u7b6e\u7b6f\u7b70\u7b71\u7b72\u7b73\u7b74\u7b75\u7b76\u7b77\u7b78\u7b79\u7b7a\u7b7b\u7b7c\u7b7d\u7b7e\u7b7f\u7b80\u7b81\u7b82\u7b83\u7b84\u7b85\u7b86\u7b87\u7b88\u7b89\u7b8a\u7b8b\u7b8c\u7b8d\u7b8e\u7b8f\u7b90\u7b91\u7b92\u7b93\u7b94\u7b95\u7b96\u7b97\u7b98\u7b99\u7b9a\u7b9b\u7b9c\u7b9d\u7b9e\u7b9f\u7ba0\u7ba1\u7ba2\u7ba3\u7ba4\u7ba5\u7ba6\u7ba7\u7ba8\u7ba9\u7baa\u7bab\u7bac\u7bad\u7bae\u7baf\u7bb0\u7bb1\u7bb2\u7bb3\u7bb4\u7bb5\u7bb6\u7bb7\u7bb8\u7bb9\u7bba\u7bbb\u7bbc\u7bbd\u7bbe\u7bbf\u7bc0\u7bc1\u7bc2\u7bc3\u7bc4\u7bc5\u7bc6\u7bc7\u7bc8\u7bc9\u7bca\u7bcb\u7bcc\u7bcd\u7bce\u7bcf\u7bd0\u7bd1\u7bd2\u7bd3\u7bd4\u7bd5\u7bd6\u7bd7\u7bd8\u7bd9\u7bda\u7bdb\u7bdc\u7bdd\u7bde\u7bdf\u7be0\u7be1\u7be2\u7be3\u7be4\u7be5\u7be6\u7be7\u7be8\u7be9\u7bea\u7beb\u7bec\u7bed\u7bee\u7bef\u7bf0\u7bf1\u7bf2\u7bf3\u7bf4\u7bf5\u7bf6\u7bf7\u7bf8\u7bf9\u7bfa\u7bfb\u7bfc\u7bfd\u7bfe\u7bff\u7c00\u7c01\u7c02\u7c03\u7c04\u7c05\u7c06\u7c07\u7c08\u7c09\u7c0a\u7c0b\u7c0c\u7c0d\u7c0e\u7c0f\u7c10\u7c11\u7c12\u7c13\u7c14\u7c15\u7c16\u7c17\u7c18\u7c19\u7c1a\u7c1b\u7c1c\u7c1d\u7c1e\u7c1f\u7c20\u7c21\u7c22\u7c23\u7c24\u7c25\u7c26\u7c27\u7c28\u7c29\u7c2a\u7c2b\u7c2c\u7c2d\u7c2e\u7c2f\u7c30\u7c31\u7c32\u7c33\u7c34\u7c35\u7c36\u7c37\u7c38\u7c39\u7c3a\u7c3b\u7c3c\u7c3d\u7c3e\u7c3f\u7c40\u7c41\u7c42\u7c43\u7c44\u7c45\u7c46\u7c47\u7c48\u7c49\u7c4a\u7c4b\u7c4c\u7c4d\u7c4e\u7c4f\u7c50\u7c51\u7c52\u7c53\u7c54\u7c55\u7c56\u7c57\u7c58\u7c59\u7c5a\u7c5b\u7c5c\u7c5d\u7c5e\u7c5f\u7c60\u7c61\u7c62\u7c63\u7c64\u7c65\u7c66\u7c67\u7c68\u7c69\u7c6a\u7c6b\u7c6c\u7c6d\u7c6e\u7c6f\u7c70\u7c71\u7c72\u7c73\u7c74\u7c75\u7c76\u7c77\u7c78\u7c79\u7c7a\u7c7b\u7c7c\u7c7d\u7c7e\u7c7f\u7c80\u7c81\u7c82\u7c83\u7c84\u7c85\u7c86\u7c87\u7c88\u7c89\u7c8a\u7c8b\u7c8c\u7c8d\u7c8e\u7c8f\u7c90\u7c91\u7c92\u7c93\u7c94\u7c95\u7c96\u7c97\u7c98\u7c99\u7c9a\u7c9b\u7c9c\u7c9d\u7c9e\u7c9f\u7ca0\u7ca1\u7ca2\u7ca3\u7ca4\u7ca5\u7ca6\u7ca7\u7ca8\u7ca9\u7caa\u7cab\u7cac\u7cad\u7cae\u7caf\u7cb0\u7cb1\u7cb2\u7cb3\u7cb4\u7cb5\u7cb6\u7cb7\u7cb8\u7cb9\u7cba\u7cbb\u7cbc\u7cbd\u7cbe\u7cbf\u7cc0\u7cc1\u7cc2\u7cc3\u7cc4\u7cc5\u7cc6\u7cc7\u7cc8\u7cc9\u7cca\u7ccb\u7ccc\u7ccd\u7cce\u7ccf\u7cd0\u7cd1\u7cd2\u7cd3\u7cd4\u7cd5\u7cd6\u7cd7\u7cd8\u7cd9\u7cda\u7cdb\u7cdc\u7cdd\u7cde\u7cdf\u7ce0\u7ce1\u7ce2\u7ce3\u7ce4\u7ce5\u7ce6\u7ce7\u7ce8\u7ce9\u7cea\u7ceb\u7cec\u7ced\u7cee\u7cef\u7cf0\u7cf1\u7cf2\u7cf3\u7cf4\u7cf5\u7cf6\u7cf7\u7cf8\u7cf9\u7cfa\u7cfb\u7cfc\u7cfd\u7cfe\u7cff\u7d00\u7d01\u7d02\u7d03\u7d04\u7d05\u7d06\u7d07\u7d08\u7d09\u7d0a\u7d0b\u7d0c\u7d0d\u7d0e\u7d0f\u7d10\u7d11\u7d12\u7d13\u7d14\u7d15\u7d16\u7d17\u7d18\u7d19\u7d1a\u7d1b\u7d1c\u7d1d\u7d1e\u7d1f\u7d20\u7d21\u7d22\u7d23\u7d24\u7d25\u7d26\u7d27\u7d28\u7d29\u7d2a\u7d2b\u7d2c\u7d2d\u7d2e\u7d2f\u7d30\u7d31\u7d32\u7d33\u7d34\u7d35\u7d36\u7d37\u7d38\u7d39\u7d3a\u7d3b\u7d3c\u7d3d\u7d3e\u7d3f\u7d40\u7d41\u7d42\u7d43\u7d44\u7d45\u7d46\u7d47\u7d48\u7d49\u7d4a\u7d4b\u7d4c\u7d4d\u7d4e\u7d4f\u7d50\u7d51\u7d52\u7d53\u7d54\u7d55\u7d56\u7d57\u7d58\u7d59\u7d5a\u7d5b\u7d5c\u7d5d\u7d5e\u7d5f\u7d60\u7d61\u7d62\u7d63\u7d64\u7d65\u7d66\u7d67\u7d68\u7d69\u7d6a\u7d6b\u7d6c\u7d6d\u7d6e\u7d6f\u7d70\u7d71\u7d72\u7d73\u7d74\u7d75\u7d76\u7d77\u7d78\u7d79\u7d7a\u7d7b\u7d7c\u7d7d\u7d7e\u7d7f\u7d80\u7d81\u7d82\u7d83\u7d84\u7d85\u7d86\u7d87\u7d88\u7d89\u7d8a\u7d8b\u7d8c\u7d8d\u7d8e\u7d8f\u7d90\u7d91\u7d92\u7d93\u7d94\u7d95\u7d96\u7d97\u7d98\u7d99\u7d9a\u7d9b\u7d9c\u7d9d\u7d9e\u7d9f\u7da0\u7da1\u7da2\u7da3\u7da4\u7da5\u7da6\u7da7\u7da8\u7da9\u7daa\u7dab\u7dac\u7dad\u7dae\u7daf\u7db0\u7db1\u7db2\u7db3\u7db4\u7db5\u7db6\u7db7\u7db8\u7db9\u7dba\u7dbb\u7dbc\u7dbd\u7dbe\u7dbf\u7dc0\u7dc1\u7dc2\u7dc3\u7dc4\u7dc5\u7dc6\u7dc7\u7dc8\u7dc9\u7dca\u7dcb\u7dcc\u7dcd\u7dce\u7dcf\u7dd0\u7dd1\u7dd2\u7dd3\u7dd4\u7dd5\u7dd6\u7dd7\u7dd8\u7dd9\u7dda\u7ddb\u7ddc\u7ddd\u7dde\u7ddf\u7de0\u7de1\u7de2\u7de3\u7de4\u7de5\u7de6\u7de7\u7de8\u7de9\u7dea\u7deb\u7dec\u7ded\u7dee\u7def\u7df0\u7df1\u7df2\u7df3\u7df4\u7df5\u7df6\u7df7\u7df8\u7df9\u7dfa\u7dfb\u7dfc\u7dfd\u7dfe\u7dff\u7e00\u7e01\u7e02\u7e03\u7e04\u7e05\u7e06\u7e07\u7e08\u7e09\u7e0a\u7e0b\u7e0c\u7e0d\u7e0e\u7e0f\u7e10\u7e11\u7e12\u7e13\u7e14\u7e15\u7e16\u7e17\u7e18\u7e19\u7e1a\u7e1b\u7e1c\u7e1d\u7e1e\u7e1f\u7e20\u7e21\u7e22\u7e23\u7e24\u7e25\u7e26\u7e27\u7e28\u7e29\u7e2a\u7e2b\u7e2c\u7e2d\u7e2e\u7e2f\u7e30\u7e31\u7e32\u7e33\u7e34\u7e35\u7e36\u7e37\u7e38\u7e39\u7e3a\u7e3b\u7e3c\u7e3d\u7e3e\u7e3f\u7e40\u7e41\u7e42\u7e43\u7e44\u7e45\u7e46\u7e47\u7e48\u7e49\u7e4a\u7e4b\u7e4c\u7e4d\u7e4e\u7e4f\u7e50\u7e51\u7e52\u7e53\u7e54\u7e55\u7e56\u7e57\u7e58\u7e59\u7e5a\u7e5b\u7e5c\u7e5d\u7e5e\u7e5f\u7e60\u7e61\u7e62\u7e63\u7e64\u7e65\u7e66\u7e67\u7e68\u7e69\u7e6a\u7e6b\u7e6c\u7e6d\u7e6e\u7e6f\u7e70\u7e71\u7e72\u7e73\u7e74\u7e75\u7e76\u7e77\u7e78\u7e79\u7e7a\u7e7b\u7e7c\u7e7d\u7e7e\u7e7f\u7e80\u7e81\u7e82\u7e83\u7e84\u7e85\u7e86\u7e87\u7e88\u7e89\u7e8a\u7e8b\u7e8c\u7e8d\u7e8e\u7e8f\u7e90\u7e91\u7e92\u7e93\u7e94\u7e95\u7e96\u7e97\u7e98\u7e99\u7e9a\u7e9b\u7e9c\u7e9d\u7e9e\u7e9f\u7ea0\u7ea1\u7ea2\u7ea3\u7ea4\u7ea5\u7ea6\u7ea7\u7ea8\u7ea9\u7eaa\u7eab\u7eac\u7ead\u7eae\u7eaf\u7eb0\u7eb1\u7eb2\u7eb3\u7eb4\u7eb5\u7eb6\u7eb7\u7eb8\u7eb9\u7eba\u7ebb\u7ebc\u7ebd\u7ebe\u7ebf\u7ec0\u7ec1\u7ec2\u7ec3\u7ec4\u7ec5\u7ec6\u7ec7\u7ec8\u7ec9\u7eca\u7ecb\u7ecc\u7ecd\u7ece\u7ecf\u7ed0\u7ed1\u7ed2\u7ed3\u7ed4\u7ed5\u7ed6\u7ed7\u7ed8\u7ed9\u7eda\u7edb\u7edc\u7edd\u7ede\u7edf\u7ee0\u7ee1\u7ee2\u7ee3\u7ee4\u7ee5\u7ee6\u7ee7\u7ee8\u7ee9\u7eea\u7eeb\u7eec\u7eed\u7eee\u7eef\u7ef0\u7ef1\u7ef2\u7ef3\u7ef4\u7ef5\u7ef6\u7ef7\u7ef8\u7ef9\u7efa\u7efb\u7efc\u7efd\u7efe\u7eff\u7f00\u7f01\u7f02\u7f03\u7f04\u7f05\u7f06\u7f07\u7f08\u7f09\u7f0a\u7f0b\u7f0c\u7f0d\u7f0e\u7f0f\u7f10\u7f11\u7f12\u7f13\u7f14\u7f15\u7f16\u7f17\u7f18\u7f19\u7f1a\u7f1b\u7f1c\u7f1d\u7f1e\u7f1f\u7f20\u7f21\u7f22\u7f23\u7f24\u7f25\u7f26\u7f27\u7f28\u7f29\u7f2a\u7f2b\u7f2c\u7f2d\u7f2e\u7f2f\u7f30\u7f31\u7f32\u7f33\u7f34\u7f35\u7f36\u7f37\u7f38\u7f39\u7f3a\u7f3b\u7f3c\u7f3d\u7f3e\u7f3f\u7f40\u7f41\u7f42\u7f43\u7f44\u7f45\u7f46\u7f47\u7f48\u7f49\u7f4a\u7f4b\u7f4c\u7f4d\u7f4e\u7f4f\u7f50\u7f51\u7f52\u7f53\u7f54\u7f55\u7f56\u7f57\u7f58\u7f59\u7f5a\u7f5b\u7f5c\u7f5d\u7f5e\u7f5f\u7f60\u7f61\u7f62\u7f63\u7f64\u7f65\u7f66\u7f67\u7f68\u7f69\u7f6a\u7f6b\u7f6c\u7f6d\u7f6e\u7f6f\u7f70\u7f71\u7f72\u7f73\u7f74\u7f75\u7f76\u7f77\u7f78\u7f79\u7f7a\u7f7b\u7f7c\u7f7d\u7f7e\u7f7f\u7f80\u7f81\u7f82\u7f83\u7f84\u7f85\u7f86\u7f87\u7f88\u7f89\u7f8a\u7f8b\u7f8c\u7f8d\u7f8e\u7f8f\u7f90\u7f91\u7f92\u7f93\u7f94\u7f95\u7f96\u7f97\u7f98\u7f99\u7f9a\u7f9b\u7f9c\u7f9d\u7f9e\u7f9f\u7fa0\u7fa1\u7fa2\u7fa3\u7fa4\u7fa5\u7fa6\u7fa7\u7fa8\u7fa9\u7faa\u7fab\u7fac\u7fad\u7fae\u7faf\u7fb0\u7fb1\u7fb2\u7fb3\u7fb4\u7fb5\u7fb6\u7fb7\u7fb8\u7fb9\u7fba\u7fbb\u7fbc\u7fbd\u7fbe\u7fbf\u7fc0\u7fc1\u7fc2\u7fc3\u7fc4\u7fc5\u7fc6\u7fc7\u7fc8\u7fc9\u7fca\u7fcb\u7fcc\u7fcd\u7fce\u7fcf\u7fd0\u7fd1\u7fd2\u7fd3\u7fd4\u7fd5\u7fd6\u7fd7\u7fd8\u7fd9\u7fda\u7fdb\u7fdc\u7fdd\u7fde\u7fdf\u7fe0\u7fe1\u7fe2\u7fe3\u7fe4\u7fe5\u7fe6\u7fe7\u7fe8\u7fe9\u7fea\u7feb\u7fec\u7fed\u7fee\u7fef\u7ff0\u7ff1\u7ff2\u7ff3\u7ff4\u7ff5\u7ff6\u7ff7\u7ff8\u7ff9\u7ffa\u7ffb\u7ffc\u7ffd\u7ffe\u7fff\u8000\u8001\u8002\u8003\u8004\u8005\u8006\u8007\u8008\u8009\u800a\u800b\u800c\u800d\u800e\u800f\u8010\u8011\u8012\u8013\u8014\u8015\u8016\u8017\u8018\u8019\u801a\u801b\u801c\u801d\u801e\u801f\u8020\u8021\u8022\u8023\u8024\u8025\u8026\u8027\u8028\u8029\u802a\u802b\u802c\u802d\u802e\u802f\u8030\u8031\u8032\u8033\u8034\u8035\u8036\u8037\u8038\u8039\u803a\u803b\u803c\u803d\u803e\u803f\u8040\u8041\u8042\u8043\u8044\u8045\u8046\u8047\u8048\u8049\u804a\u804b\u804c\u804d\u804e\u804f\u8050\u8051\u8052\u8053\u8054\u8055\u8056\u8057\u8058\u8059\u805a\u805b\u805c\u805d\u805e\u805f\u8060\u8061\u8062\u8063\u8064\u8065\u8066\u8067\u8068\u8069\u806a\u806b\u806c\u806d\u806e\u806f\u8070\u8071\u8072\u8073\u8074\u8075\u8076\u8077\u8078\u8079\u807a\u807b\u807c\u807d\u807e\u807f\u8080\u8081\u8082\u8083\u8084\u8085\u8086\u8087\u8088\u8089\u808a\u808b\u808c\u808d\u808e\u808f\u8090\u8091\u8092\u8093\u8094\u8095\u8096\u8097\u8098\u8099\u809a\u809b\u809c\u809d\u809e\u809f\u80a0\u80a1\u80a2\u80a3\u80a4\u80a5\u80a6\u80a7\u80a8\u80a9\u80aa\u80ab\u80ac\u80ad\u80ae\u80af\u80b0\u80b1\u80b2\u80b3\u80b4\u80b5\u80b6\u80b7\u80b8\u80b9\u80ba\u80bb\u80bc\u80bd\u80be\u80bf\u80c0\u80c1\u80c2\u80c3\u80c4\u80c5\u80c6\u80c7\u80c8\u80c9\u80ca\u80cb\u80cc\u80cd\u80ce\u80cf\u80d0\u80d1\u80d2\u80d3\u80d4\u80d5\u80d6\u80d7\u80d8\u80d9\u80da\u80db\u80dc\u80dd\u80de\u80df\u80e0\u80e1\u80e2\u80e3\u80e4\u80e5\u80e6\u80e7\u80e8\u80e9\u80ea\u80eb\u80ec\u80ed\u80ee\u80ef\u80f0\u80f1\u80f2\u80f3\u80f4\u80f5\u80f6\u80f7\u80f8\u80f9\u80fa\u80fb\u80fc\u80fd\u80fe\u80ff\u8100\u8101\u8102\u8103\u8104\u8105\u8106\u8107\u8108\u8109\u810a\u810b\u810c\u810d\u810e\u810f\u8110\u8111\u8112\u8113\u8114\u8115\u8116\u8117\u8118\u8119\u811a\u811b\u811c\u811d\u811e\u811f\u8120\u8121\u8122\u8123\u8124\u8125\u8126\u8127\u8128\u8129\u812a\u812b\u812c\u812d\u812e\u812f\u8130\u8131\u8132\u8133\u8134\u8135\u8136\u8137\u8138\u8139\u813a\u813b\u813c\u813d\u813e\u813f\u8140\u8141\u8142\u8143\u8144\u8145\u8146\u8147\u8148\u8149\u814a\u814b\u814c\u814d\u814e\u814f\u8150\u8151\u8152\u8153\u8154\u8155\u8156\u8157\u8158\u8159\u815a\u815b\u815c\u815d\u815e\u815f\u8160\u8161\u8162\u8163\u8164\u8165\u8166\u8167\u8168\u8169\u816a\u816b\u816c\u816d\u816e\u816f\u8170\u8171\u8172\u8173\u8174\u8175\u8176\u8177\u8178\u8179\u817a\u817b\u817c\u817d\u817e\u817f\u8180\u8181\u8182\u8183\u8184\u8185\u8186\u8187\u8188\u8189\u818a\u818b\u818c\u818d\u818e\u818f\u8190\u8191\u8192\u8193\u8194\u8195\u8196\u8197\u8198\u8199\u819a\u819b\u819c\u819d\u819e\u819f\u81a0\u81a1\u81a2\u81a3\u81a4\u81a5\u81a6\u81a7\u81a8\u81a9\u81aa\u81ab\u81ac\u81ad\u81ae\u81af\u81b0\u81b1\u81b2\u81b3\u81b4\u81b5\u81b6\u81b7\u81b8\u81b9\u81ba\u81bb\u81bc\u81bd\u81be\u81bf\u81c0\u81c1\u81c2\u81c3\u81c4\u81c5\u81c6\u81c7\u81c8\u81c9\u81ca\u81cb\u81cc\u81cd\u81ce\u81cf\u81d0\u81d1\u81d2\u81d3\u81d4\u81d5\u81d6\u81d7\u81d8\u81d9\u81da\u81db\u81dc\u81dd\u81de\u81df\u81e0\u81e1\u81e2\u81e3\u81e4\u81e5\u81e6\u81e7\u81e8\u81e9\u81ea\u81eb\u81ec\u81ed\u81ee\u81ef\u81f0\u81f1\u81f2\u81f3\u81f4\u81f5\u81f6\u81f7\u81f8\u81f9\u81fa\u81fb\u81fc\u81fd\u81fe\u81ff\u8200\u8201\u8202\u8203\u8204\u8205\u8206\u8207\u8208\u8209\u820a\u820b\u820c\u820d\u820e\u820f\u8210\u8211\u8212\u8213\u8214\u8215\u8216\u8217\u8218\u8219\u821a\u821b\u821c\u821d\u821e\u821f\u8220\u8221\u8222\u8223\u8224\u8225\u8226\u8227\u8228\u8229\u822a\u822b\u822c\u822d\u822e\u822f\u8230\u8231\u8232\u8233\u8234\u8235\u8236\u8237\u8238\u8239\u823a\u823b\u823c\u823d\u823e\u823f\u8240\u8241\u8242\u8243\u8244\u8245\u8246\u8247\u8248\u8249\u824a\u824b\u824c\u824d\u824e\u824f\u8250\u8251\u8252\u8253\u8254\u8255\u8256\u8257\u8258\u8259\u825a\u825b\u825c\u825d\u825e\u825f\u8260\u8261\u8262\u8263\u8264\u8265\u8266\u8267\u8268\u8269\u826a\u826b\u826c\u826d\u826e\u826f\u8270\u8271\u8272\u8273\u8274\u8275\u8276\u8277\u8278\u8279\u827a\u827b\u827c\u827d\u827e\u827f\u8280\u8281\u8282\u8283\u8284\u8285\u8286\u8287\u8288\u8289\u828a\u828b\u828c\u828d\u828e\u828f\u8290\u8291\u8292\u8293\u8294\u8295\u8296\u8297\u8298\u8299\u829a\u829b\u829c\u829d\u829e\u829f\u82a0\u82a1\u82a2\u82a3\u82a4\u82a5\u82a6\u82a7\u82a8\u82a9\u82aa\u82ab\u82ac\u82ad\u82ae\u82af\u82b0\u82b1\u82b2\u82b3\u82b4\u82b5\u82b6\u82b7\u82b8\u82b9\u82ba\u82bb\u82bc\u82bd\u82be\u82bf\u82c0\u82c1\u82c2\u82c3\u82c4\u82c5\u82c6\u82c7\u82c8\u82c9\u82ca\u82cb\u82cc\u82cd\u82ce\u82cf\u82d0\u82d1\u82d2\u82d3\u82d4\u82d5\u82d6\u82d7\u82d8\u82d9\u82da\u82db\u82dc\u82dd\u82de\u82df\u82e0\u82e1\u82e2\u82e3\u82e4\u82e5\u82e6\u82e7\u82e8\u82e9\u82ea\u82eb\u82ec\u82ed\u82ee\u82ef\u82f0\u82f1\u82f2\u82f3\u82f4\u82f5\u82f6\u82f7\u82f8\u82f9\u82fa\u82fb\u82fc\u82fd\u82fe\u82ff\u8300\u8301\u8302\u8303\u8304\u8305\u8306\u8307\u8308\u8309\u830a\u830b\u830c\u830d\u830e\u830f\u8310\u8311\u8312\u8313\u8314\u8315\u8316\u8317\u8318\u8319\u831a\u831b\u831c\u831d\u831e\u831f\u8320\u8321\u8322\u8323\u8324\u8325\u8326\u8327\u8328\u8329\u832a\u832b\u832c\u832d\u832e\u832f\u8330\u8331\u8332\u8333\u8334\u8335\u8336\u8337\u8338\u8339\u833a\u833b\u833c\u833d\u833e\u833f\u8340\u8341\u8342\u8343\u8344\u8345\u8346\u8347\u8348\u8349\u834a\u834b\u834c\u834d\u834e\u834f\u8350\u8351\u8352\u8353\u8354\u8355\u8356\u8357\u8358\u8359\u835a\u835b\u835c\u835d\u835e\u835f\u8360\u8361\u8362\u8363\u8364\u8365\u8366\u8367\u8368\u8369\u836a\u836b\u836c\u836d\u836e\u836f\u8370\u8371\u8372\u8373\u8374\u8375\u8376\u8377\u8378\u8379\u837a\u837b\u837c\u837d\u837e\u837f\u8380\u8381\u8382\u8383\u8384\u8385\u8386\u8387\u8388\u8389\u838a\u838b\u838c\u838d\u838e\u838f\u8390\u8391\u8392\u8393\u8394\u8395\u8396\u8397\u8398\u8399\u839a\u839b\u839c\u839d\u839e\u839f\u83a0\u83a1\u83a2\u83a3\u83a4\u83a5\u83a6\u83a7\u83a8\u83a9\u83aa\u83ab\u83ac\u83ad\u83ae\u83af\u83b0\u83b1\u83b2\u83b3\u83b4\u83b5\u83b6\u83b7\u83b8\u83b9\u83ba\u83bb\u83bc\u83bd\u83be\u83bf\u83c0\u83c1\u83c2\u83c3\u83c4\u83c5\u83c6\u83c7\u83c8\u83c9\u83ca\u83cb\u83cc\u83cd\u83ce\u83cf\u83d0\u83d1\u83d2\u83d3\u83d4\u83d5\u83d6\u83d7\u83d8\u83d9\u83da\u83db\u83dc\u83dd\u83de\u83df\u83e0\u83e1\u83e2\u83e3\u83e4\u83e5\u83e6\u83e7\u83e8\u83e9\u83ea\u83eb\u83ec\u83ed\u83ee\u83ef\u83f0\u83f1\u83f2\u83f3\u83f4\u83f5\u83f6\u83f7\u83f8\u83f9\u83fa\u83fb\u83fc\u83fd\u83fe\u83ff\u8400\u8401\u8402\u8403\u8404\u8405\u8406\u8407\u8408\u8409\u840a\u840b\u840c\u840d\u840e\u840f\u8410\u8411\u8412\u8413\u8414\u8415\u8416\u8417\u8418\u8419\u841a\u841b\u841c\u841d\u841e\u841f\u8420\u8421\u8422\u8423\u8424\u8425\u8426\u8427\u8428\u8429\u842a\u842b\u842c\u842d\u842e\u842f\u8430\u8431\u8432\u8433\u8434\u8435\u8436\u8437\u8438\u8439\u843a\u843b\u843c\u843d\u843e\u843f\u8440\u8441\u8442\u8443\u8444\u8445\u8446\u8447\u8448\u8449\u844a\u844b\u844c\u844d\u844e\u844f\u8450\u8451\u8452\u8453\u8454\u8455\u8456\u8457\u8458\u8459\u845a\u845b\u845c\u845d\u845e\u845f\u8460\u8461\u8462\u8463\u8464\u8465\u8466\u8467\u8468\u8469\u846a\u846b\u846c\u846d\u846e\u846f\u8470\u8471\u8472\u8473\u8474\u8475\u8476\u8477\u8478\u8479\u847a\u847b\u847c\u847d\u847e\u847f\u8480\u8481\u8482\u8483\u8484\u8485\u8486\u8487\u8488\u8489\u848a\u848b\u848c\u848d\u848e\u848f\u8490\u8491\u8492\u8493\u8494\u8495\u8496\u8497\u8498\u8499\u849a\u849b\u849c\u849d\u849e\u849f\u84a0\u84a1\u84a2\u84a3\u84a4\u84a5\u84a6\u84a7\u84a8\u84a9\u84aa\u84ab\u84ac\u84ad\u84ae\u84af\u84b0\u84b1\u84b2\u84b3\u84b4\u84b5\u84b6\u84b7\u84b8\u84b9\u84ba\u84bb\u84bc\u84bd\u84be\u84bf\u84c0\u84c1\u84c2\u84c3\u84c4\u84c5\u84c6\u84c7\u84c8\u84c9\u84ca\u84cb\u84cc\u84cd\u84ce\u84cf\u84d0\u84d1\u84d2\u84d3\u84d4\u84d5\u84d6\u84d7\u84d8\u84d9\u84da\u84db\u84dc\u84dd\u84de\u84df\u84e0\u84e1\u84e2\u84e3\u84e4\u84e5\u84e6\u84e7\u84e8\u84e9\u84ea\u84eb\u84ec\u84ed\u84ee\u84ef\u84f0\u84f1\u84f2\u84f3\u84f4\u84f5\u84f6\u84f7\u84f8\u84f9\u84fa\u84fb\u84fc\u84fd\u84fe\u84ff\u8500\u8501\u8502\u8503\u8504\u8505\u8506\u8507\u8508\u8509\u850a\u850b\u850c\u850d\u850e\u850f\u8510\u8511\u8512\u8513\u8514\u8515\u8516\u8517\u8518\u8519\u851a\u851b\u851c\u851d\u851e\u851f\u8520\u8521\u8522\u8523\u8524\u8525\u8526\u8527\u8528\u8529\u852a\u852b\u852c\u852d\u852e\u852f\u8530\u8531\u8532\u8533\u8534\u8535\u8536\u8537\u8538\u8539\u853a\u853b\u853c\u853d\u853e\u853f\u8540\u8541\u8542\u8543\u8544\u8545\u8546\u8547\u8548\u8549\u854a\u854b\u854c\u854d\u854e\u854f\u8550\u8551\u8552\u8553\u8554\u8555\u8556\u8557\u8558\u8559\u855a\u855b\u855c\u855d\u855e\u855f\u8560\u8561\u8562\u8563\u8564\u8565\u8566\u8567\u8568\u8569\u856a\u856b\u856c\u856d\u856e\u856f\u8570\u8571\u8572\u8573\u8574\u8575\u8576\u8577\u8578\u8579\u857a\u857b\u857c\u857d\u857e\u857f\u8580\u8581\u8582\u8583\u8584\u8585\u8586\u8587\u8588\u8589\u858a\u858b\u858c\u858d\u858e\u858f\u8590\u8591\u8592\u8593\u8594\u8595\u8596\u8597\u8598\u8599\u859a\u859b\u859c\u859d\u859e\u859f\u85a0\u85a1\u85a2\u85a3\u85a4\u85a5\u85a6\u85a7\u85a8\u85a9\u85aa\u85ab\u85ac\u85ad\u85ae\u85af\u85b0\u85b1\u85b2\u85b3\u85b4\u85b5\u85b6\u85b7\u85b8\u85b9\u85ba\u85bb\u85bc\u85bd\u85be\u85bf\u85c0\u85c1\u85c2\u85c3\u85c4\u85c5\u85c6\u85c7\u85c8\u85c9\u85ca\u85cb\u85cc\u85cd\u85ce\u85cf\u85d0\u85d1\u85d2\u85d3\u85d4\u85d5\u85d6\u85d7\u85d8\u85d9\u85da\u85db\u85dc\u85dd\u85de\u85df\u85e0\u85e1\u85e2\u85e3\u85e4\u85e5\u85e6\u85e7\u85e8\u85e9\u85ea\u85eb\u85ec\u85ed\u85ee\u85ef\u85f0\u85f1\u85f2\u85f3\u85f4\u85f5\u85f6\u85f7\u85f8\u85f9\u85fa\u85fb\u85fc\u85fd\u85fe\u85ff\u8600\u8601\u8602\u8603\u8604\u8605\u8606\u8607\u8608\u8609\u860a\u860b\u860c\u860d\u860e\u860f\u8610\u8611\u8612\u8613\u8614\u8615\u8616\u8617\u8618\u8619\u861a\u861b\u861c\u861d\u861e\u861f\u8620\u8621\u8622\u8623\u8624\u8625\u8626\u8627\u8628\u8629\u862a\u862b\u862c\u862d\u862e\u862f\u8630\u8631\u8632\u8633\u8634\u8635\u8636\u8637\u8638\u8639\u863a\u863b\u863c\u863d\u863e\u863f\u8640\u8641\u8642\u8643\u8644\u8645\u8646\u8647\u8648\u8649\u864a\u864b\u864c\u864d\u864e\u864f\u8650\u8651\u8652\u8653\u8654\u8655\u8656\u8657\u8658\u8659\u865a\u865b\u865c\u865d\u865e\u865f\u8660\u8661\u8662\u8663\u8664\u8665\u8666\u8667\u8668\u8669\u866a\u866b\u866c\u866d\u866e\u866f\u8670\u8671\u8672\u8673\u8674\u8675\u8676\u8677\u8678\u8679\u867a\u867b\u867c\u867d\u867e\u867f\u8680\u8681\u8682\u8683\u8684\u8685\u8686\u8687\u8688\u8689\u868a\u868b\u868c\u868d\u868e\u868f\u8690\u8691\u8692\u8693\u8694\u8695\u8696\u8697\u8698\u8699\u869a\u869b\u869c\u869d\u869e\u869f\u86a0\u86a1\u86a2\u86a3\u86a4\u86a5\u86a6\u86a7\u86a8\u86a9\u86aa\u86ab\u86ac\u86ad\u86ae\u86af\u86b0\u86b1\u86b2\u86b3\u86b4\u86b5\u86b6\u86b7\u86b8\u86b9\u86ba\u86bb\u86bc\u86bd\u86be\u86bf\u86c0\u86c1\u86c2\u86c3\u86c4\u86c5\u86c6\u86c7\u86c8\u86c9\u86ca\u86cb\u86cc\u86cd\u86ce\u86cf\u86d0\u86d1\u86d2\u86d3\u86d4\u86d5\u86d6\u86d7\u86d8\u86d9\u86da\u86db\u86dc\u86dd\u86de\u86df\u86e0\u86e1\u86e2\u86e3\u86e4\u86e5\u86e6\u86e7\u86e8\u86e9\u86ea\u86eb\u86ec\u86ed\u86ee\u86ef\u86f0\u86f1\u86f2\u86f3\u86f4\u86f5\u86f6\u86f7\u86f8\u86f9\u86fa\u86fb\u86fc\u86fd\u86fe\u86ff\u8700\u8701\u8702\u8703\u8704\u8705\u8706\u8707\u8708\u8709\u870a\u870b\u870c\u870d\u870e\u870f\u8710\u8711\u8712\u8713\u8714\u8715\u8716\u8717\u8718\u8719\u871a\u871b\u871c\u871d\u871e\u871f\u8720\u8721\u8722\u8723\u8724\u8725\u8726\u8727\u8728\u8729\u872a\u872b\u872c\u872d\u872e\u872f\u8730\u8731\u8732\u8733\u8734\u8735\u8736\u8737\u8738\u8739\u873a\u873b\u873c\u873d\u873e\u873f\u8740\u8741\u8742\u8743\u8744\u8745\u8746\u8747\u8748\u8749\u874a\u874b\u874c\u874d\u874e\u874f\u8750\u8751\u8752\u8753\u8754\u8755\u8756\u8757\u8758\u8759\u875a\u875b\u875c\u875d\u875e\u875f\u8760\u8761\u8762\u8763\u8764\u8765\u8766\u8767\u8768\u8769\u876a\u876b\u876c\u876d\u876e\u876f\u8770\u8771\u8772\u8773\u8774\u8775\u8776\u8777\u8778\u8779\u877a\u877b\u877c\u877d\u877e\u877f\u8780\u8781\u8782\u8783\u8784\u8785\u8786\u8787\u8788\u8789\u878a\u878b\u878c\u878d\u878e\u878f\u8790\u8791\u8792\u8793\u8794\u8795\u8796\u8797\u8798\u8799\u879a\u879b\u879c\u879d\u879e\u879f\u87a0\u87a1\u87a2\u87a3\u87a4\u87a5\u87a6\u87a7\u87a8\u87a9\u87aa\u87ab\u87ac\u87ad\u87ae\u87af\u87b0\u87b1\u87b2\u87b3\u87b4\u87b5\u87b6\u87b7\u87b8\u87b9\u87ba\u87bb\u87bc\u87bd\u87be\u87bf\u87c0\u87c1\u87c2\u87c3\u87c4\u87c5\u87c6\u87c7\u87c8\u87c9\u87ca\u87cb\u87cc\u87cd\u87ce\u87cf\u87d0\u87d1\u87d2\u87d3\u87d4\u87d5\u87d6\u87d7\u87d8\u87d9\u87da\u87db\u87dc\u87dd\u87de\u87df\u87e0\u87e1\u87e2\u87e3\u87e4\u87e5\u87e6\u87e7\u87e8\u87e9\u87ea\u87eb\u87ec\u87ed\u87ee\u87ef\u87f0\u87f1\u87f2\u87f3\u87f4\u87f5\u87f6\u87f7\u87f8\u87f9\u87fa\u87fb\u87fc\u87fd\u87fe\u87ff\u8800\u8801\u8802\u8803\u8804\u8805\u8806\u8807\u8808\u8809\u880a\u880b\u880c\u880d\u880e\u880f\u8810\u8811\u8812\u8813\u8814\u8815\u8816\u8817\u8818\u8819\u881a\u881b\u881c\u881d\u881e\u881f\u8820\u8821\u8822\u8823\u8824\u8825\u8826\u8827\u8828\u8829\u882a\u882b\u882c\u882d\u882e\u882f\u8830\u8831\u8832\u8833\u8834\u8835\u8836\u8837\u8838\u8839\u883a\u883b\u883c\u883d\u883e\u883f\u8840\u8841\u8842\u8843\u8844\u8845\u8846\u8847\u8848\u8849\u884a\u884b\u884c\u884d\u884e\u884f\u8850\u8851\u8852\u8853\u8854\u8855\u8856\u8857\u8858\u8859\u885a\u885b\u885c\u885d\u885e\u885f\u8860\u8861\u8862\u8863\u8864\u8865\u8866\u8867\u8868\u8869\u886a\u886b\u886c\u886d\u886e\u886f\u8870\u8871\u8872\u8873\u8874\u8875\u8876\u8877\u8878\u8879\u887a\u887b\u887c\u887d\u887e\u887f\u8880\u8881\u8882\u8883\u8884\u8885\u8886\u8887\u8888\u8889\u888a\u888b\u888c\u888d\u888e\u888f\u8890\u8891\u8892\u8893\u8894\u8895\u8896\u8897\u8898\u8899\u889a\u889b\u889c\u889d\u889e\u889f\u88a0\u88a1\u88a2\u88a3\u88a4\u88a5\u88a6\u88a7\u88a8\u88a9\u88aa\u88ab\u88ac\u88ad\u88ae\u88af\u88b0\u88b1\u88b2\u88b3\u88b4\u88b5\u88b6\u88b7\u88b8\u88b9\u88ba\u88bb\u88bc\u88bd\u88be\u88bf\u88c0\u88c1\u88c2\u88c3\u88c4\u88c5\u88c6\u88c7\u88c8\u88c9\u88ca\u88cb\u88cc\u88cd\u88ce\u88cf\u88d0\u88d1\u88d2\u88d3\u88d4\u88d5\u88d6\u88d7\u88d8\u88d9\u88da\u88db\u88dc\u88dd\u88de\u88df\u88e0\u88e1\u88e2\u88e3\u88e4\u88e5\u88e6\u88e7\u88e8\u88e9\u88ea\u88eb\u88ec\u88ed\u88ee\u88ef\u88f0\u88f1\u88f2\u88f3\u88f4\u88f5\u88f6\u88f7\u88f8\u88f9\u88fa\u88fb\u88fc\u88fd\u88fe\u88ff\u8900\u8901\u8902\u8903\u8904\u8905\u8906\u8907\u8908\u8909\u890a\u890b\u890c\u890d\u890e\u890f\u8910\u8911\u8912\u8913\u8914\u8915\u8916\u8917\u8918\u8919\u891a\u891b\u891c\u891d\u891e\u891f\u8920\u8921\u8922\u8923\u8924\u8925\u8926\u8927\u8928\u8929\u892a\u892b\u892c\u892d\u892e\u892f\u8930\u8931\u8932\u8933\u8934\u8935\u8936\u8937\u8938\u8939\u893a\u893b\u893c\u893d\u893e\u893f\u8940\u8941\u8942\u8943\u8944\u8945\u8946\u8947\u8948\u8949\u894a\u894b\u894c\u894d\u894e\u894f\u8950\u8951\u8952\u8953\u8954\u8955\u8956\u8957\u8958\u8959\u895a\u895b\u895c\u895d\u895e\u895f\u8960\u8961\u8962\u8963\u8964\u8965\u8966\u8967\u8968\u8969\u896a\u896b\u896c\u896d\u896e\u896f\u8970\u8971\u8972\u8973\u8974\u8975\u8976\u8977\u8978\u8979\u897a\u897b\u897c\u897d\u897e\u897f\u8980\u8981\u8982\u8983\u8984\u8985\u8986\u8987\u8988\u8989\u898a\u898b\u898c\u898d\u898e\u898f\u8990\u8991\u8992\u8993\u8994\u8995\u8996\u8997\u8998\u8999\u899a\u899b\u899c\u899d\u899e\u899f\u89a0\u89a1\u89a2\u89a3\u89a4\u89a5\u89a6\u89a7\u89a8\u89a9\u89aa\u89ab\u89ac\u89ad\u89ae\u89af\u89b0\u89b1\u89b2\u89b3\u89b4\u89b5\u89b6\u89b7\u89b8\u89b9\u89ba\u89bb\u89bc\u89bd\u89be\u89bf\u89c0\u89c1\u89c2\u89c3\u89c4\u89c5\u89c6\u89c7\u89c8\u89c9\u89ca\u89cb\u89cc\u89cd\u89ce\u89cf\u89d0\u89d1\u89d2\u89d3\u89d4\u89d5\u89d6\u89d7\u89d8\u89d9\u89da\u89db\u89dc\u89dd\u89de\u89df\u89e0\u89e1\u89e2\u89e3\u89e4\u89e5\u89e6\u89e7\u89e8\u89e9\u89ea\u89eb\u89ec\u89ed\u89ee\u89ef\u89f0\u89f1\u89f2\u89f3\u89f4\u89f5\u89f6\u89f7\u89f8\u89f9\u89fa\u89fb\u89fc\u89fd\u89fe\u89ff\u8a00\u8a01\u8a02\u8a03\u8a04\u8a05\u8a06\u8a07\u8a08\u8a09\u8a0a\u8a0b\u8a0c\u8a0d\u8a0e\u8a0f\u8a10\u8a11\u8a12\u8a13\u8a14\u8a15\u8a16\u8a17\u8a18\u8a19\u8a1a\u8a1b\u8a1c\u8a1d\u8a1e\u8a1f\u8a20\u8a21\u8a22\u8a23\u8a24\u8a25\u8a26\u8a27\u8a28\u8a29\u8a2a\u8a2b\u8a2c\u8a2d\u8a2e\u8a2f\u8a30\u8a31\u8a32\u8a33\u8a34\u8a35\u8a36\u8a37\u8a38\u8a39\u8a3a\u8a3b\u8a3c\u8a3d\u8a3e\u8a3f\u8a40\u8a41\u8a42\u8a43\u8a44\u8a45\u8a46\u8a47\u8a48\u8a49\u8a4a\u8a4b\u8a4c\u8a4d\u8a4e\u8a4f\u8a50\u8a51\u8a52\u8a53\u8a54\u8a55\u8a56\u8a57\u8a58\u8a59\u8a5a\u8a5b\u8a5c\u8a5d\u8a5e\u8a5f\u8a60\u8a61\u8a62\u8a63\u8a64\u8a65\u8a66\u8a67\u8a68\u8a69\u8a6a\u8a6b\u8a6c\u8a6d\u8a6e\u8a6f\u8a70\u8a71\u8a72\u8a73\u8a74\u8a75\u8a76\u8a77\u8a78\u8a79\u8a7a\u8a7b\u8a7c\u8a7d\u8a7e\u8a7f\u8a80\u8a81\u8a82\u8a83\u8a84\u8a85\u8a86\u8a87\u8a88\u8a89\u8a8a\u8a8b\u8a8c\u8a8d\u8a8e\u8a8f\u8a90\u8a91\u8a92\u8a93\u8a94\u8a95\u8a96\u8a97\u8a98\u8a99\u8a9a\u8a9b\u8a9c\u8a9d\u8a9e\u8a9f\u8aa0\u8aa1\u8aa2\u8aa3\u8aa4\u8aa5\u8aa6\u8aa7\u8aa8\u8aa9\u8aaa\u8aab\u8aac\u8aad\u8aae\u8aaf\u8ab0\u8ab1\u8ab2\u8ab3\u8ab4\u8ab5\u8ab6\u8ab7\u8ab8\u8ab9\u8aba\u8abb\u8abc\u8abd\u8abe\u8abf\u8ac0\u8ac1\u8ac2\u8ac3\u8ac4\u8ac5\u8ac6\u8ac7\u8ac8\u8ac9\u8aca\u8acb\u8acc\u8acd\u8ace\u8acf\u8ad0\u8ad1\u8ad2\u8ad3\u8ad4\u8ad5\u8ad6\u8ad7\u8ad8\u8ad9\u8ada\u8adb\u8adc\u8add\u8ade\u8adf\u8ae0\u8ae1\u8ae2\u8ae3\u8ae4\u8ae5\u8ae6\u8ae7\u8ae8\u8ae9\u8aea\u8aeb\u8aec\u8aed\u8aee\u8aef\u8af0\u8af1\u8af2\u8af3\u8af4\u8af5\u8af6\u8af7\u8af8\u8af9\u8afa\u8afb\u8afc\u8afd\u8afe\u8aff\u8b00\u8b01\u8b02\u8b03\u8b04\u8b05\u8b06\u8b07\u8b08\u8b09\u8b0a\u8b0b\u8b0c\u8b0d\u8b0e\u8b0f\u8b10\u8b11\u8b12\u8b13\u8b14\u8b15\u8b16\u8b17\u8b18\u8b19\u8b1a\u8b1b\u8b1c\u8b1d\u8b1e\u8b1f\u8b20\u8b21\u8b22\u8b23\u8b24\u8b25\u8b26\u8b27\u8b28\u8b29\u8b2a\u8b2b\u8b2c\u8b2d\u8b2e\u8b2f\u8b30\u8b31\u8b32\u8b33\u8b34\u8b35\u8b36\u8b37\u8b38\u8b39\u8b3a\u8b3b\u8b3c\u8b3d\u8b3e\u8b3f\u8b40\u8b41\u8b42\u8b43\u8b44\u8b45\u8b46\u8b47\u8b48\u8b49\u8b4a\u8b4b\u8b4c\u8b4d\u8b4e\u8b4f\u8b50\u8b51\u8b52\u8b53\u8b54\u8b55\u8b56\u8b57\u8b58\u8b59\u8b5a\u8b5b\u8b5c\u8b5d\u8b5e\u8b5f\u8b60\u8b61\u8b62\u8b63\u8b64\u8b65\u8b66\u8b67\u8b68\u8b69\u8b6a\u8b6b\u8b6c\u8b6d\u8b6e\u8b6f\u8b70\u8b71\u8b72\u8b73\u8b74\u8b75\u8b76\u8b77\u8b78\u8b79\u8b7a\u8b7b\u8b7c\u8b7d\u8b7e\u8b7f\u8b80\u8b81\u8b82\u8b83\u8b84\u8b85\u8b86\u8b87\u8b88\u8b89\u8b8a\u8b8b\u8b8c\u8b8d\u8b8e\u8b8f\u8b90\u8b91\u8b92\u8b93\u8b94\u8b95\u8b96\u8b97\u8b98\u8b99\u8b9a\u8b9b\u8b9c\u8b9d\u8b9e\u8b9f\u8ba0\u8ba1\u8ba2\u8ba3\u8ba4\u8ba5\u8ba6\u8ba7\u8ba8\u8ba9\u8baa\u8bab\u8bac\u8bad\u8bae\u8baf\u8bb0\u8bb1\u8bb2\u8bb3\u8bb4\u8bb5\u8bb6\u8bb7\u8bb8\u8bb9\u8bba\u8bbb\u8bbc\u8bbd\u8bbe\u8bbf\u8bc0\u8bc1\u8bc2\u8bc3\u8bc4\u8bc5\u8bc6\u8bc7\u8bc8\u8bc9\u8bca\u8bcb\u8bcc\u8bcd\u8bce\u8bcf\u8bd0\u8bd1\u8bd2\u8bd3\u8bd4\u8bd5\u8bd6\u8bd7\u8bd8\u8bd9\u8bda\u8bdb\u8bdc\u8bdd\u8bde\u8bdf\u8be0\u8be1\u8be2\u8be3\u8be4\u8be5\u8be6\u8be7\u8be8\u8be9\u8bea\u8beb\u8bec\u8bed\u8bee\u8bef\u8bf0\u8bf1\u8bf2\u8bf3\u8bf4\u8bf5\u8bf6\u8bf7\u8bf8\u8bf9\u8bfa\u8bfb\u8bfc\u8bfd\u8bfe\u8bff\u8c00\u8c01\u8c02\u8c03\u8c04\u8c05\u8c06\u8c07\u8c08\u8c09\u8c0a\u8c0b\u8c0c\u8c0d\u8c0e\u8c0f\u8c10\u8c11\u8c12\u8c13\u8c14\u8c15\u8c16\u8c17\u8c18\u8c19\u8c1a\u8c1b\u8c1c\u8c1d\u8c1e\u8c1f\u8c20\u8c21\u8c22\u8c23\u8c24\u8c25\u8c26\u8c27\u8c28\u8c29\u8c2a\u8c2b\u8c2c\u8c2d\u8c2e\u8c2f\u8c30\u8c31\u8c32\u8c33\u8c34\u8c35\u8c36\u8c37\u8c38\u8c39\u8c3a\u8c3b\u8c3c\u8c3d\u8c3e\u8c3f\u8c40\u8c41\u8c42\u8c43\u8c44\u8c45\u8c46\u8c47\u8c48\u8c49\u8c4a\u8c4b\u8c4c\u8c4d\u8c4e\u8c4f\u8c50\u8c51\u8c52\u8c53\u8c54\u8c55\u8c56\u8c57\u8c58\u8c59\u8c5a\u8c5b\u8c5c\u8c5d\u8c5e\u8c5f\u8c60\u8c61\u8c62\u8c63\u8c64\u8c65\u8c66\u8c67\u8c68\u8c69\u8c6a\u8c6b\u8c6c\u8c6d\u8c6e\u8c6f\u8c70\u8c71\u8c72\u8c73\u8c74\u8c75\u8c76\u8c77\u8c78\u8c79\u8c7a\u8c7b\u8c7c\u8c7d\u8c7e\u8c7f\u8c80\u8c81\u8c82\u8c83\u8c84\u8c85\u8c86\u8c87\u8c88\u8c89\u8c8a\u8c8b\u8c8c\u8c8d\u8c8e\u8c8f\u8c90\u8c91\u8c92\u8c93\u8c94\u8c95\u8c96\u8c97\u8c98\u8c99\u8c9a\u8c9b\u8c9c\u8c9d\u8c9e\u8c9f\u8ca0\u8ca1\u8ca2\u8ca3\u8ca4\u8ca5\u8ca6\u8ca7\u8ca8\u8ca9\u8caa\u8cab\u8cac\u8cad\u8cae\u8caf\u8cb0\u8cb1\u8cb2\u8cb3\u8cb4\u8cb5\u8cb6\u8cb7\u8cb8\u8cb9\u8cba\u8cbb\u8cbc\u8cbd\u8cbe\u8cbf\u8cc0\u8cc1\u8cc2\u8cc3\u8cc4\u8cc5\u8cc6\u8cc7\u8cc8\u8cc9\u8cca\u8ccb\u8ccc\u8ccd\u8cce\u8ccf\u8cd0\u8cd1\u8cd2\u8cd3\u8cd4\u8cd5\u8cd6\u8cd7\u8cd8\u8cd9\u8cda\u8cdb\u8cdc\u8cdd\u8cde\u8cdf\u8ce0\u8ce1\u8ce2\u8ce3\u8ce4\u8ce5\u8ce6\u8ce7\u8ce8\u8ce9\u8cea\u8ceb\u8cec\u8ced\u8cee\u8cef\u8cf0\u8cf1\u8cf2\u8cf3\u8cf4\u8cf5\u8cf6\u8cf7\u8cf8\u8cf9\u8cfa\u8cfb\u8cfc\u8cfd\u8cfe\u8cff\u8d00\u8d01\u8d02\u8d03\u8d04\u8d05\u8d06\u8d07\u8d08\u8d09\u8d0a\u8d0b\u8d0c\u8d0d\u8d0e\u8d0f\u8d10\u8d11\u8d12\u8d13\u8d14\u8d15\u8d16\u8d17\u8d18\u8d19\u8d1a\u8d1b\u8d1c\u8d1d\u8d1e\u8d1f\u8d20\u8d21\u8d22\u8d23\u8d24\u8d25\u8d26\u8d27\u8d28\u8d29\u8d2a\u8d2b\u8d2c\u8d2d\u8d2e\u8d2f\u8d30\u8d31\u8d32\u8d33\u8d34\u8d35\u8d36\u8d37\u8d38\u8d39\u8d3a\u8d3b\u8d3c\u8d3d\u8d3e\u8d3f\u8d40\u8d41\u8d42\u8d43\u8d44\u8d45\u8d46\u8d47\u8d48\u8d49\u8d4a\u8d4b\u8d4c\u8d4d\u8d4e\u8d4f\u8d50\u8d51\u8d52\u8d53\u8d54\u8d55\u8d56\u8d57\u8d58\u8d59\u8d5a\u8d5b\u8d5c\u8d5d\u8d5e\u8d5f\u8d60\u8d61\u8d62\u8d63\u8d64\u8d65\u8d66\u8d67\u8d68\u8d69\u8d6a\u8d6b\u8d6c\u8d6d\u8d6e\u8d6f\u8d70\u8d71\u8d72\u8d73\u8d74\u8d75\u8d76\u8d77\u8d78\u8d79\u8d7a\u8d7b\u8d7c\u8d7d\u8d7e\u8d7f\u8d80\u8d81\u8d82\u8d83\u8d84\u8d85\u8d86\u8d87\u8d88\u8d89\u8d8a\u8d8b\u8d8c\u8d8d\u8d8e\u8d8f\u8d90\u8d91\u8d92\u8d93\u8d94\u8d95\u8d96\u8d97\u8d98\u8d99\u8d9a\u8d9b\u8d9c\u8d9d\u8d9e\u8d9f\u8da0\u8da1\u8da2\u8da3\u8da4\u8da5\u8da6\u8da7\u8da8\u8da9\u8daa\u8dab\u8dac\u8dad\u8dae\u8daf\u8db0\u8db1\u8db2\u8db3\u8db4\u8db5\u8db6\u8db7\u8db8\u8db9\u8dba\u8dbb\u8dbc\u8dbd\u8dbe\u8dbf\u8dc0\u8dc1\u8dc2\u8dc3\u8dc4\u8dc5\u8dc6\u8dc7\u8dc8\u8dc9\u8dca\u8dcb\u8dcc\u8dcd\u8dce\u8dcf\u8dd0\u8dd1\u8dd2\u8dd3\u8dd4\u8dd5\u8dd6\u8dd7\u8dd8\u8dd9\u8dda\u8ddb\u8ddc\u8ddd\u8dde\u8ddf\u8de0\u8de1\u8de2\u8de3\u8de4\u8de5\u8de6\u8de7\u8de8\u8de9\u8dea\u8deb\u8dec\u8ded\u8dee\u8def\u8df0\u8df1\u8df2\u8df3\u8df4\u8df5\u8df6\u8df7\u8df8\u8df9\u8dfa\u8dfb\u8dfc\u8dfd\u8dfe\u8dff\u8e00\u8e01\u8e02\u8e03\u8e04\u8e05\u8e06\u8e07\u8e08\u8e09\u8e0a\u8e0b\u8e0c\u8e0d\u8e0e\u8e0f\u8e10\u8e11\u8e12\u8e13\u8e14\u8e15\u8e16\u8e17\u8e18\u8e19\u8e1a\u8e1b\u8e1c\u8e1d\u8e1e\u8e1f\u8e20\u8e21\u8e22\u8e23\u8e24\u8e25\u8e26\u8e27\u8e28\u8e29\u8e2a\u8e2b\u8e2c\u8e2d\u8e2e\u8e2f\u8e30\u8e31\u8e32\u8e33\u8e34\u8e35\u8e36\u8e37\u8e38\u8e39\u8e3a\u8e3b\u8e3c\u8e3d\u8e3e\u8e3f\u8e40\u8e41\u8e42\u8e43\u8e44\u8e45\u8e46\u8e47\u8e48\u8e49\u8e4a\u8e4b\u8e4c\u8e4d\u8e4e\u8e4f\u8e50\u8e51\u8e52\u8e53\u8e54\u8e55\u8e56\u8e57\u8e58\u8e59\u8e5a\u8e5b\u8e5c\u8e5d\u8e5e\u8e5f\u8e60\u8e61\u8e62\u8e63\u8e64\u8e65\u8e66\u8e67\u8e68\u8e69\u8e6a\u8e6b\u8e6c\u8e6d\u8e6e\u8e6f\u8e70\u8e71\u8e72\u8e73\u8e74\u8e75\u8e76\u8e77\u8e78\u8e79\u8e7a\u8e7b\u8e7c\u8e7d\u8e7e\u8e7f\u8e80\u8e81\u8e82\u8e83\u8e84\u8e85\u8e86\u8e87\u8e88\u8e89\u8e8a\u8e8b\u8e8c\u8e8d\u8e8e\u8e8f\u8e90\u8e91\u8e92\u8e93\u8e94\u8e95\u8e96\u8e97\u8e98\u8e99\u8e9a\u8e9b\u8e9c\u8e9d\u8e9e\u8e9f\u8ea0\u8ea1\u8ea2\u8ea3\u8ea4\u8ea5\u8ea6\u8ea7\u8ea8\u8ea9\u8eaa\u8eab\u8eac\u8ead\u8eae\u8eaf\u8eb0\u8eb1\u8eb2\u8eb3\u8eb4\u8eb5\u8eb6\u8eb7\u8eb8\u8eb9\u8eba\u8ebb\u8ebc\u8ebd\u8ebe\u8ebf\u8ec0\u8ec1\u8ec2\u8ec3\u8ec4\u8ec5\u8ec6\u8ec7\u8ec8\u8ec9\u8eca\u8ecb\u8ecc\u8ecd\u8ece\u8ecf\u8ed0\u8ed1\u8ed2\u8ed3\u8ed4\u8ed5\u8ed6\u8ed7\u8ed8\u8ed9\u8eda\u8edb\u8edc\u8edd\u8ede\u8edf\u8ee0\u8ee1\u8ee2\u8ee3\u8ee4\u8ee5\u8ee6\u8ee7\u8ee8\u8ee9\u8eea\u8eeb\u8eec\u8eed\u8eee\u8eef\u8ef0\u8ef1\u8ef2\u8ef3\u8ef4\u8ef5\u8ef6\u8ef7\u8ef8\u8ef9\u8efa\u8efb\u8efc\u8efd\u8efe\u8eff\u8f00\u8f01\u8f02\u8f03\u8f04\u8f05\u8f06\u8f07\u8f08\u8f09\u8f0a\u8f0b\u8f0c\u8f0d\u8f0e\u8f0f\u8f10\u8f11\u8f12\u8f13\u8f14\u8f15\u8f16\u8f17\u8f18\u8f19\u8f1a\u8f1b\u8f1c\u8f1d\u8f1e\u8f1f\u8f20\u8f21\u8f22\u8f23\u8f24\u8f25\u8f26\u8f27\u8f28\u8f29\u8f2a\u8f2b\u8f2c\u8f2d\u8f2e\u8f2f\u8f30\u8f31\u8f32\u8f33\u8f34\u8f35\u8f36\u8f37\u8f38\u8f39\u8f3a\u8f3b\u8f3c\u8f3d\u8f3e\u8f3f\u8f40\u8f41\u8f42\u8f43\u8f44\u8f45\u8f46\u8f47\u8f48\u8f49\u8f4a\u8f4b\u8f4c\u8f4d\u8f4e\u8f4f\u8f50\u8f51\u8f52\u8f53\u8f54\u8f55\u8f56\u8f57\u8f58\u8f59\u8f5a\u8f5b\u8f5c\u8f5d\u8f5e\u8f5f\u8f60\u8f61\u8f62\u8f63\u8f64\u8f65\u8f66\u8f67\u8f68\u8f69\u8f6a\u8f6b\u8f6c\u8f6d\u8f6e\u8f6f\u8f70\u8f71\u8f72\u8f73\u8f74\u8f75\u8f76\u8f77\u8f78\u8f79\u8f7a\u8f7b\u8f7c\u8f7d\u8f7e\u8f7f\u8f80\u8f81\u8f82\u8f83\u8f84\u8f85\u8f86\u8f87\u8f88\u8f89\u8f8a\u8f8b\u8f8c\u8f8d\u8f8e\u8f8f\u8f90\u8f91\u8f92\u8f93\u8f94\u8f95\u8f96\u8f97\u8f98\u8f99\u8f9a\u8f9b\u8f9c\u8f9d\u8f9e\u8f9f\u8fa0\u8fa1\u8fa2\u8fa3\u8fa4\u8fa5\u8fa6\u8fa7\u8fa8\u8fa9\u8faa\u8fab\u8fac\u8fad\u8fae\u8faf\u8fb0\u8fb1\u8fb2\u8fb3\u8fb4\u8fb5\u8fb6\u8fb7\u8fb8\u8fb9\u8fba\u8fbb\u8fbc\u8fbd\u8fbe\u8fbf\u8fc0\u8fc1\u8fc2\u8fc3\u8fc4\u8fc5\u8fc6\u8fc7\u8fc8\u8fc9\u8fca\u8fcb\u8fcc\u8fcd\u8fce\u8fcf\u8fd0\u8fd1\u8fd2\u8fd3\u8fd4\u8fd5\u8fd6\u8fd7\u8fd8\u8fd9\u8fda\u8fdb\u8fdc\u8fdd\u8fde\u8fdf\u8fe0\u8fe1\u8fe2\u8fe3\u8fe4\u8fe5\u8fe6\u8fe7\u8fe8\u8fe9\u8fea\u8feb\u8fec\u8fed\u8fee\u8fef\u8ff0\u8ff1\u8ff2\u8ff3\u8ff4\u8ff5\u8ff6\u8ff7\u8ff8\u8ff9\u8ffa\u8ffb\u8ffc\u8ffd\u8ffe\u8fff\u9000\u9001\u9002\u9003\u9004\u9005\u9006\u9007\u9008\u9009\u900a\u900b\u900c\u900d\u900e\u900f\u9010\u9011\u9012\u9013\u9014\u9015\u9016\u9017\u9018\u9019\u901a\u901b\u901c\u901d\u901e\u901f\u9020\u9021\u9022\u9023\u9024\u9025\u9026\u9027\u9028\u9029\u902a\u902b\u902c\u902d\u902e\u902f\u9030\u9031\u9032\u9033\u9034\u9035\u9036\u9037\u9038\u9039\u903a\u903b\u903c\u903d\u903e\u903f\u9040\u9041\u9042\u9043\u9044\u9045\u9046\u9047\u9048\u9049\u904a\u904b\u904c\u904d\u904e\u904f\u9050\u9051\u9052\u9053\u9054\u9055\u9056\u9057\u9058\u9059\u905a\u905b\u905c\u905d\u905e\u905f\u9060\u9061\u9062\u9063\u9064\u9065\u9066\u9067\u9068\u9069\u906a\u906b\u906c\u906d\u906e\u906f\u9070\u9071\u9072\u9073\u9074\u9075\u9076\u9077\u9078\u9079\u907a\u907b\u907c\u907d\u907e\u907f\u9080\u9081\u9082\u9083\u9084\u9085\u9086\u9087\u9088\u9089\u908a\u908b\u908c\u908d\u908e\u908f\u9090\u9091\u9092\u9093\u9094\u9095\u9096\u9097\u9098\u9099\u909a\u909b\u909c\u909d\u909e\u909f\u90a0\u90a1\u90a2\u90a3\u90a4\u90a5\u90a6\u90a7\u90a8\u90a9\u90aa\u90ab\u90ac\u90ad\u90ae\u90af\u90b0\u90b1\u90b2\u90b3\u90b4\u90b5\u90b6\u90b7\u90b8\u90b9\u90ba\u90bb\u90bc\u90bd\u90be\u90bf\u90c0\u90c1\u90c2\u90c3\u90c4\u90c5\u90c6\u90c7\u90c8\u90c9\u90ca\u90cb\u90cc\u90cd\u90ce\u90cf\u90d0\u90d1\u90d2\u90d3\u90d4\u90d5\u90d6\u90d7\u90d8\u90d9\u90da\u90db\u90dc\u90dd\u90de\u90df\u90e0\u90e1\u90e2\u90e3\u90e4\u90e5\u90e6\u90e7\u90e8\u90e9\u90ea\u90eb\u90ec\u90ed\u90ee\u90ef\u90f0\u90f1\u90f2\u90f3\u90f4\u90f5\u90f6\u90f7\u90f8\u90f9\u90fa\u90fb\u90fc\u90fd\u90fe\u90ff\u9100\u9101\u9102\u9103\u9104\u9105\u9106\u9107\u9108\u9109\u910a\u910b\u910c\u910d\u910e\u910f\u9110\u9111\u9112\u9113\u9114\u9115\u9116\u9117\u9118\u9119\u911a\u911b\u911c\u911d\u911e\u911f\u9120\u9121\u9122\u9123\u9124\u9125\u9126\u9127\u9128\u9129\u912a\u912b\u912c\u912d\u912e\u912f\u9130\u9131\u9132\u9133\u9134\u9135\u9136\u9137\u9138\u9139\u913a\u913b\u913c\u913d\u913e\u913f\u9140\u9141\u9142\u9143\u9144\u9145\u9146\u9147\u9148\u9149\u914a\u914b\u914c\u914d\u914e\u914f\u9150\u9151\u9152\u9153\u9154\u9155\u9156\u9157\u9158\u9159\u915a\u915b\u915c\u915d\u915e\u915f\u9160\u9161\u9162\u9163\u9164\u9165\u9166\u9167\u9168\u9169\u916a\u916b\u916c\u916d\u916e\u916f\u9170\u9171\u9172\u9173\u9174\u9175\u9176\u9177\u9178\u9179\u917a\u917b\u917c\u917d\u917e\u917f\u9180\u9181\u9182\u9183\u9184\u9185\u9186\u9187\u9188\u9189\u918a\u918b\u918c\u918d\u918e\u918f\u9190\u9191\u9192\u9193\u9194\u9195\u9196\u9197\u9198\u9199\u919a\u919b\u919c\u919d\u919e\u919f\u91a0\u91a1\u91a2\u91a3\u91a4\u91a5\u91a6\u91a7\u91a8\u91a9\u91aa\u91ab\u91ac\u91ad\u91ae\u91af\u91b0\u91b1\u91b2\u91b3\u91b4\u91b5\u91b6\u91b7\u91b8\u91b9\u91ba\u91bb\u91bc\u91bd\u91be\u91bf\u91c0\u91c1\u91c2\u91c3\u91c4\u91c5\u91c6\u91c7\u91c8\u91c9\u91ca\u91cb\u91cc\u91cd\u91ce\u91cf\u91d0\u91d1\u91d2\u91d3\u91d4\u91d5\u91d6\u91d7\u91d8\u91d9\u91da\u91db\u91dc\u91dd\u91de\u91df\u91e0\u91e1\u91e2\u91e3\u91e4\u91e5\u91e6\u91e7\u91e8\u91e9\u91ea\u91eb\u91ec\u91ed\u91ee\u91ef\u91f0\u91f1\u91f2\u91f3\u91f4\u91f5\u91f6\u91f7\u91f8\u91f9\u91fa\u91fb\u91fc\u91fd\u91fe\u91ff\u9200\u9201\u9202\u9203\u9204\u9205\u9206\u9207\u9208\u9209\u920a\u920b\u920c\u920d\u920e\u920f\u9210\u9211\u9212\u9213\u9214\u9215\u9216\u9217\u9218\u9219\u921a\u921b\u921c\u921d\u921e\u921f\u9220\u9221\u9222\u9223\u9224\u9225\u9226\u9227\u9228\u9229\u922a\u922b\u922c\u922d\u922e\u922f\u9230\u9231\u9232\u9233\u9234\u9235\u9236\u9237\u9238\u9239\u923a\u923b\u923c\u923d\u923e\u923f\u9240\u9241\u9242\u9243\u9244\u9245\u9246\u9247\u9248\u9249\u924a\u924b\u924c\u924d\u924e\u924f\u9250\u9251\u9252\u9253\u9254\u9255\u9256\u9257\u9258\u9259\u925a\u925b\u925c\u925d\u925e\u925f\u9260\u9261\u9262\u9263\u9264\u9265\u9266\u9267\u9268\u9269\u926a\u926b\u926c\u926d\u926e\u926f\u9270\u9271\u9272\u9273\u9274\u9275\u9276\u9277\u9278\u9279\u927a\u927b\u927c\u927d\u927e\u927f\u9280\u9281\u9282\u9283\u9284\u9285\u9286\u9287\u9288\u9289\u928a\u928b\u928c\u928d\u928e\u928f\u9290\u9291\u9292\u9293\u9294\u9295\u9296\u9297\u9298\u9299\u929a\u929b\u929c\u929d\u929e\u929f\u92a0\u92a1\u92a2\u92a3\u92a4\u92a5\u92a6\u92a7\u92a8\u92a9\u92aa\u92ab\u92ac\u92ad\u92ae\u92af\u92b0\u92b1\u92b2\u92b3\u92b4\u92b5\u92b6\u92b7\u92b8\u92b9\u92ba\u92bb\u92bc\u92bd\u92be\u92bf\u92c0\u92c1\u92c2\u92c3\u92c4\u92c5\u92c6\u92c7\u92c8\u92c9\u92ca\u92cb\u92cc\u92cd\u92ce\u92cf\u92d0\u92d1\u92d2\u92d3\u92d4\u92d5\u92d6\u92d7\u92d8\u92d9\u92da\u92db\u92dc\u92dd\u92de\u92df\u92e0\u92e1\u92e2\u92e3\u92e4\u92e5\u92e6\u92e7\u92e8\u92e9\u92ea\u92eb\u92ec\u92ed\u92ee\u92ef\u92f0\u92f1\u92f2\u92f3\u92f4\u92f5\u92f6\u92f7\u92f8\u92f9\u92fa\u92fb\u92fc\u92fd\u92fe\u92ff\u9300\u9301\u9302\u9303\u9304\u9305\u9306\u9307\u9308\u9309\u930a\u930b\u930c\u930d\u930e\u930f\u9310\u9311\u9312\u9313\u9314\u9315\u9316\u9317\u9318\u9319\u931a\u931b\u931c\u931d\u931e\u931f\u9320\u9321\u9322\u9323\u9324\u9325\u9326\u9327\u9328\u9329\u932a\u932b\u932c\u932d\u932e\u932f\u9330\u9331\u9332\u9333\u9334\u9335\u9336\u9337\u9338\u9339\u933a\u933b\u933c\u933d\u933e\u933f\u9340\u9341\u9342\u9343\u9344\u9345\u9346\u9347\u9348\u9349\u934a\u934b\u934c\u934d\u934e\u934f\u9350\u9351\u9352\u9353\u9354\u9355\u9356\u9357\u9358\u9359\u935a\u935b\u935c\u935d\u935e\u935f\u9360\u9361\u9362\u9363\u9364\u9365\u9366\u9367\u9368\u9369\u936a\u936b\u936c\u936d\u936e\u936f\u9370\u9371\u9372\u9373\u9374\u9375\u9376\u9377\u9378\u9379\u937a\u937b\u937c\u937d\u937e\u937f\u9380\u9381\u9382\u9383\u9384\u9385\u9386\u9387\u9388\u9389\u938a\u938b\u938c\u938d\u938e\u938f\u9390\u9391\u9392\u9393\u9394\u9395\u9396\u9397\u9398\u9399\u939a\u939b\u939c\u939d\u939e\u939f\u93a0\u93a1\u93a2\u93a3\u93a4\u93a5\u93a6\u93a7\u93a8\u93a9\u93aa\u93ab\u93ac\u93ad\u93ae\u93af\u93b0\u93b1\u93b2\u93b3\u93b4\u93b5\u93b6\u93b7\u93b8\u93b9\u93ba\u93bb\u93bc\u93bd\u93be\u93bf\u93c0\u93c1\u93c2\u93c3\u93c4\u93c5\u93c6\u93c7\u93c8\u93c9\u93ca\u93cb\u93cc\u93cd\u93ce\u93cf\u93d0\u93d1\u93d2\u93d3\u93d4\u93d5\u93d6\u93d7\u93d8\u93d9\u93da\u93db\u93dc\u93dd\u93de\u93df\u93e0\u93e1\u93e2\u93e3\u93e4\u93e5\u93e6\u93e7\u93e8\u93e9\u93ea\u93eb\u93ec\u93ed\u93ee\u93ef\u93f0\u93f1\u93f2\u93f3\u93f4\u93f5\u93f6\u93f7\u93f8\u93f9\u93fa\u93fb\u93fc\u93fd\u93fe\u93ff\u9400\u9401\u9402\u9403\u9404\u9405\u9406\u9407\u9408\u9409\u940a\u940b\u940c\u940d\u940e\u940f\u9410\u9411\u9412\u9413\u9414\u9415\u9416\u9417\u9418\u9419\u941a\u941b\u941c\u941d\u941e\u941f\u9420\u9421\u9422\u9423\u9424\u9425\u9426\u9427\u9428\u9429\u942a\u942b\u942c\u942d\u942e\u942f\u9430\u9431\u9432\u9433\u9434\u9435\u9436\u9437\u9438\u9439\u943a\u943b\u943c\u943d\u943e\u943f\u9440\u9441\u9442\u9443\u9444\u9445\u9446\u9447\u9448\u9449\u944a\u944b\u944c\u944d\u944e\u944f\u9450\u9451\u9452\u9453\u9454\u9455\u9456\u9457\u9458\u9459\u945a\u945b\u945c\u945d\u945e\u945f\u9460\u9461\u9462\u9463\u9464\u9465\u9466\u9467\u9468\u9469\u946a\u946b\u946c\u946d\u946e\u946f\u9470\u9471\u9472\u9473\u9474\u9475\u9476\u9477\u9478\u9479\u947a\u947b\u947c\u947d\u947e\u947f\u9480\u9481\u9482\u9483\u9484\u9485\u9486\u9487\u9488\u9489\u948a\u948b\u948c\u948d\u948e\u948f\u9490\u9491\u9492\u9493\u9494\u9495\u9496\u9497\u9498\u9499\u949a\u949b\u949c\u949d\u949e\u949f\u94a0\u94a1\u94a2\u94a3\u94a4\u94a5\u94a6\u94a7\u94a8\u94a9\u94aa\u94ab\u94ac\u94ad\u94ae\u94af\u94b0\u94b1\u94b2\u94b3\u94b4\u94b5\u94b6\u94b7\u94b8\u94b9\u94ba\u94bb\u94bc\u94bd\u94be\u94bf\u94c0\u94c1\u94c2\u94c3\u94c4\u94c5\u94c6\u94c7\u94c8\u94c9\u94ca\u94cb\u94cc\u94cd\u94ce\u94cf\u94d0\u94d1\u94d2\u94d3\u94d4\u94d5\u94d6\u94d7\u94d8\u94d9\u94da\u94db\u94dc\u94dd\u94de\u94df\u94e0\u94e1\u94e2\u94e3\u94e4\u94e5\u94e6\u94e7\u94e8\u94e9\u94ea\u94eb\u94ec\u94ed\u94ee\u94ef\u94f0\u94f1\u94f2\u94f3\u94f4\u94f5\u94f6\u94f7\u94f8\u94f9\u94fa\u94fb\u94fc\u94fd\u94fe\u94ff\u9500\u9501\u9502\u9503\u9504\u9505\u9506\u9507\u9508\u9509\u950a\u950b\u950c\u950d\u950e\u950f\u9510\u9511\u9512\u9513\u9514\u9515\u9516\u9517\u9518\u9519\u951a\u951b\u951c\u951d\u951e\u951f\u9520\u9521\u9522\u9523\u9524\u9525\u9526\u9527\u9528\u9529\u952a\u952b\u952c\u952d\u952e\u952f\u9530\u9531\u9532\u9533\u9534\u9535\u9536\u9537\u9538\u9539\u953a\u953b\u953c\u953d\u953e\u953f\u9540\u9541\u9542\u9543\u9544\u9545\u9546\u9547\u9548\u9549\u954a\u954b\u954c\u954d\u954e\u954f\u9550\u9551\u9552\u9553\u9554\u9555\u9556\u9557\u9558\u9559\u955a\u955b\u955c\u955d\u955e\u955f\u9560\u9561\u9562\u9563\u9564\u9565\u9566\u9567\u9568\u9569\u956a\u956b\u956c\u956d\u956e\u956f\u9570\u9571\u9572\u9573\u9574\u9575\u9576\u9577\u9578\u9579\u957a\u957b\u957c\u957d\u957e\u957f\u9580\u9581\u9582\u9583\u9584\u9585\u9586\u9587\u9588\u9589\u958a\u958b\u958c\u958d\u958e\u958f\u9590\u9591\u9592\u9593\u9594\u9595\u9596\u9597\u9598\u9599\u959a\u959b\u959c\u959d\u959e\u959f\u95a0\u95a1\u95a2\u95a3\u95a4\u95a5\u95a6\u95a7\u95a8\u95a9\u95aa\u95ab\u95ac\u95ad\u95ae\u95af\u95b0\u95b1\u95b2\u95b3\u95b4\u95b5\u95b6\u95b7\u95b8\u95b9\u95ba\u95bb\u95bc\u95bd\u95be\u95bf\u95c0\u95c1\u95c2\u95c3\u95c4\u95c5\u95c6\u95c7\u95c8\u95c9\u95ca\u95cb\u95cc\u95cd\u95ce\u95cf\u95d0\u95d1\u95d2\u95d3\u95d4\u95d5\u95d6\u95d7\u95d8\u95d9\u95da\u95db\u95dc\u95dd\u95de\u95df\u95e0\u95e1\u95e2\u95e3\u95e4\u95e5\u95e6\u95e7\u95e8\u95e9\u95ea\u95eb\u95ec\u95ed\u95ee\u95ef\u95f0\u95f1\u95f2\u95f3\u95f4\u95f5\u95f6\u95f7\u95f8\u95f9\u95fa\u95fb\u95fc\u95fd\u95fe\u95ff\u9600\u9601\u9602\u9603\u9604\u9605\u9606\u9607\u9608\u9609\u960a\u960b\u960c\u960d\u960e\u960f\u9610\u9611\u9612\u9613\u9614\u9615\u9616\u9617\u9618\u9619\u961a\u961b\u961c\u961d\u961e\u961f\u9620\u9621\u9622\u9623\u9624\u9625\u9626\u9627\u9628\u9629\u962a\u962b\u962c\u962d\u962e\u962f\u9630\u9631\u9632\u9633\u9634\u9635\u9636\u9637\u9638\u9639\u963a\u963b\u963c\u963d\u963e\u963f\u9640\u9641\u9642\u9643\u9644\u9645\u9646\u9647\u9648\u9649\u964a\u964b\u964c\u964d\u964e\u964f\u9650\u9651\u9652\u9653\u9654\u9655\u9656\u9657\u9658\u9659\u965a\u965b\u965c\u965d\u965e\u965f\u9660\u9661\u9662\u9663\u9664\u9665\u9666\u9667\u9668\u9669\u966a\u966b\u966c\u966d\u966e\u966f\u9670\u9671\u9672\u9673\u9674\u9675\u9676\u9677\u9678\u9679\u967a\u967b\u967c\u967d\u967e\u967f\u9680\u9681\u9682\u9683\u9684\u9685\u9686\u9687\u9688\u9689\u968a\u968b\u968c\u968d\u968e\u968f\u9690\u9691\u9692\u9693\u9694\u9695\u9696\u9697\u9698\u9699\u969a\u969b\u969c\u969d\u969e\u969f\u96a0\u96a1\u96a2\u96a3\u96a4\u96a5\u96a6\u96a7\u96a8\u96a9\u96aa\u96ab\u96ac\u96ad\u96ae\u96af\u96b0\u96b1\u96b2\u96b3\u96b4\u96b5\u96b6\u96b7\u96b8\u96b9\u96ba\u96bb\u96bc\u96bd\u96be\u96bf\u96c0\u96c1\u96c2\u96c3\u96c4\u96c5\u96c6\u96c7\u96c8\u96c9\u96ca\u96cb\u96cc\u96cd\u96ce\u96cf\u96d0\u96d1\u96d2\u96d3\u96d4\u96d5\u96d6\u96d7\u96d8\u96d9\u96da\u96db\u96dc\u96dd\u96de\u96df\u96e0\u96e1\u96e2\u96e3\u96e4\u96e5\u96e6\u96e7\u96e8\u96e9\u96ea\u96eb\u96ec\u96ed\u96ee\u96ef\u96f0\u96f1\u96f2\u96f3\u96f4\u96f5\u96f6\u96f7\u96f8\u96f9\u96fa\u96fb\u96fc\u96fd\u96fe\u96ff\u9700\u9701\u9702\u9703\u9704\u9705\u9706\u9707\u9708\u9709\u970a\u970b\u970c\u970d\u970e\u970f\u9710\u9711\u9712\u9713\u9714\u9715\u9716\u9717\u9718\u9719\u971a\u971b\u971c\u971d\u971e\u971f\u9720\u9721\u9722\u9723\u9724\u9725\u9726\u9727\u9728\u9729\u972a\u972b\u972c\u972d\u972e\u972f\u9730\u9731\u9732\u9733\u9734\u9735\u9736\u9737\u9738\u9739\u973a\u973b\u973c\u973d\u973e\u973f\u9740\u9741\u9742\u9743\u9744\u9745\u9746\u9747\u9748\u9749\u974a\u974b\u974c\u974d\u974e\u974f\u9750\u9751\u9752\u9753\u9754\u9755\u9756\u9757\u9758\u9759\u975a\u975b\u975c\u975d\u975e\u975f\u9760\u9761\u9762\u9763\u9764\u9765\u9766\u9767\u9768\u9769\u976a\u976b\u976c\u976d\u976e\u976f\u9770\u9771\u9772\u9773\u9774\u9775\u9776\u9777\u9778\u9779\u977a\u977b\u977c\u977d\u977e\u977f\u9780\u9781\u9782\u9783\u9784\u9785\u9786\u9787\u9788\u9789\u978a\u978b\u978c\u978d\u978e\u978f\u9790\u9791\u9792\u9793\u9794\u9795\u9796\u9797\u9798\u9799\u979a\u979b\u979c\u979d\u979e\u979f\u97a0\u97a1\u97a2\u97a3\u97a4\u97a5\u97a6\u97a7\u97a8\u97a9\u97aa\u97ab\u97ac\u97ad\u97ae\u97af\u97b0\u97b1\u97b2\u97b3\u97b4\u97b5\u97b6\u97b7\u97b8\u97b9\u97ba\u97bb\u97bc\u97bd\u97be\u97bf\u97c0\u97c1\u97c2\u97c3\u97c4\u97c5\u97c6\u97c7\u97c8\u97c9\u97ca\u97cb\u97cc\u97cd\u97ce\u97cf\u97d0\u97d1\u97d2\u97d3\u97d4\u97d5\u97d6\u97d7\u97d8\u97d9\u97da\u97db\u97dc\u97dd\u97de\u97df\u97e0\u97e1\u97e2\u97e3\u97e4\u97e5\u97e6\u97e7\u97e8\u97e9\u97ea\u97eb\u97ec\u97ed\u97ee\u97ef\u97f0\u97f1\u97f2\u97f3\u97f4\u97f5\u97f6\u97f7\u97f8\u97f9\u97fa\u97fb\u97fc\u97fd\u97fe\u97ff\u9800\u9801\u9802\u9803\u9804\u9805\u9806\u9807\u9808\u9809\u980a\u980b\u980c\u980d\u980e\u980f\u9810\u9811\u9812\u9813\u9814\u9815\u9816\u9817\u9818\u9819\u981a\u981b\u981c\u981d\u981e\u981f\u9820\u9821\u9822\u9823\u9824\u9825\u9826\u9827\u9828\u9829\u982a\u982b\u982c\u982d\u982e\u982f\u9830\u9831\u9832\u9833\u9834\u9835\u9836\u9837\u9838\u9839\u983a\u983b\u983c\u983d\u983e\u983f\u9840\u9841\u9842\u9843\u9844\u9845\u9846\u9847\u9848\u9849\u984a\u984b\u984c\u984d\u984e\u984f\u9850\u9851\u9852\u9853\u9854\u9855\u9856\u9857\u9858\u9859\u985a\u985b\u985c\u985d\u985e\u985f\u9860\u9861\u9862\u9863\u9864\u9865\u9866\u9867\u9868\u9869\u986a\u986b\u986c\u986d\u986e\u986f\u9870\u9871\u9872\u9873\u9874\u9875\u9876\u9877\u9878\u9879\u987a\u987b\u987c\u987d\u987e\u987f\u9880\u9881\u9882\u9883\u9884\u9885\u9886\u9887\u9888\u9889\u988a\u988b\u988c\u988d\u988e\u988f\u9890\u9891\u9892\u9893\u9894\u9895\u9896\u9897\u9898\u9899\u989a\u989b\u989c\u989d\u989e\u989f\u98a0\u98a1\u98a2\u98a3\u98a4\u98a5\u98a6\u98a7\u98a8\u98a9\u98aa\u98ab\u98ac\u98ad\u98ae\u98af\u98b0\u98b1\u98b2\u98b3\u98b4\u98b5\u98b6\u98b7\u98b8\u98b9\u98ba\u98bb\u98bc\u98bd\u98be\u98bf\u98c0\u98c1\u98c2\u98c3\u98c4\u98c5\u98c6\u98c7\u98c8\u98c9\u98ca\u98cb\u98cc\u98cd\u98ce\u98cf\u98d0\u98d1\u98d2\u98d3\u98d4\u98d5\u98d6\u98d7\u98d8\u98d9\u98da\u98db\u98dc\u98dd\u98de\u98df\u98e0\u98e1\u98e2\u98e3\u98e4\u98e5\u98e6\u98e7\u98e8\u98e9\u98ea\u98eb\u98ec\u98ed\u98ee\u98ef\u98f0\u98f1\u98f2\u98f3\u98f4\u98f5\u98f6\u98f7\u98f8\u98f9\u98fa\u98fb\u98fc\u98fd\u98fe\u98ff\u9900\u9901\u9902\u9903\u9904\u9905\u9906\u9907\u9908\u9909\u990a\u990b\u990c\u990d\u990e\u990f\u9910\u9911\u9912\u9913\u9914\u9915\u9916\u9917\u9918\u9919\u991a\u991b\u991c\u991d\u991e\u991f\u9920\u9921\u9922\u9923\u9924\u9925\u9926\u9927\u9928\u9929\u992a\u992b\u992c\u992d\u992e\u992f\u9930\u9931\u9932\u9933\u9934\u9935\u9936\u9937\u9938\u9939\u993a\u993b\u993c\u993d\u993e\u993f\u9940\u9941\u9942\u9943\u9944\u9945\u9946\u9947\u9948\u9949\u994a\u994b\u994c\u994d\u994e\u994f\u9950\u9951\u9952\u9953\u9954\u9955\u9956\u9957\u9958\u9959\u995a\u995b\u995c\u995d\u995e\u995f\u9960\u9961\u9962\u9963\u9964\u9965\u9966\u9967\u9968\u9969\u996a\u996b\u996c\u996d\u996e\u996f\u9970\u9971\u9972\u9973\u9974\u9975\u9976\u9977\u9978\u9979\u997a\u997b\u997c\u997d\u997e\u997f\u9980\u9981\u9982\u9983\u9984\u9985\u9986\u9987\u9988\u9989\u998a\u998b\u998c\u998d\u998e\u998f\u9990\u9991\u9992\u9993\u9994\u9995\u9996\u9997\u9998\u9999\u999a\u999b\u999c\u999d\u999e\u999f\u99a0\u99a1\u99a2\u99a3\u99a4\u99a5\u99a6\u99a7\u99a8\u99a9\u99aa\u99ab\u99ac\u99ad\u99ae\u99af\u99b0\u99b1\u99b2\u99b3\u99b4\u99b5\u99b6\u99b7\u99b8\u99b9\u99ba\u99bb\u99bc\u99bd\u99be\u99bf\u99c0\u99c1\u99c2\u99c3\u99c4\u99c5\u99c6\u99c7\u99c8\u99c9\u99ca\u99cb\u99cc\u99cd\u99ce\u99cf\u99d0\u99d1\u99d2\u99d3\u99d4\u99d5\u99d6\u99d7\u99d8\u99d9\u99da\u99db\u99dc\u99dd\u99de\u99df\u99e0\u99e1\u99e2\u99e3\u99e4\u99e5\u99e6\u99e7\u99e8\u99e9\u99ea\u99eb\u99ec\u99ed\u99ee\u99ef\u99f0\u99f1\u99f2\u99f3\u99f4\u99f5\u99f6\u99f7\u99f8\u99f9\u99fa\u99fb\u99fc\u99fd\u99fe\u99ff\u9a00\u9a01\u9a02\u9a03\u9a04\u9a05\u9a06\u9a07\u9a08\u9a09\u9a0a\u9a0b\u9a0c\u9a0d\u9a0e\u9a0f\u9a10\u9a11\u9a12\u9a13\u9a14\u9a15\u9a16\u9a17\u9a18\u9a19\u9a1a\u9a1b\u9a1c\u9a1d\u9a1e\u9a1f\u9a20\u9a21\u9a22\u9a23\u9a24\u9a25\u9a26\u9a27\u9a28\u9a29\u9a2a\u9a2b\u9a2c\u9a2d\u9a2e\u9a2f\u9a30\u9a31\u9a32\u9a33\u9a34\u9a35\u9a36\u9a37\u9a38\u9a39\u9a3a\u9a3b\u9a3c\u9a3d\u9a3e\u9a3f\u9a40\u9a41\u9a42\u9a43\u9a44\u9a45\u9a46\u9a47\u9a48\u9a49\u9a4a\u9a4b\u9a4c\u9a4d\u9a4e\u9a4f\u9a50\u9a51\u9a52\u9a53\u9a54\u9a55\u9a56\u9a57\u9a58\u9a59\u9a5a\u9a5b\u9a5c\u9a5d\u9a5e\u9a5f\u9a60\u9a61\u9a62\u9a63\u9a64\u9a65\u9a66\u9a67\u9a68\u9a69\u9a6a\u9a6b\u9a6c\u9a6d\u9a6e\u9a6f\u9a70\u9a71\u9a72\u9a73\u9a74\u9a75\u9a76\u9a77\u9a78\u9a79\u9a7a\u9a7b\u9a7c\u9a7d\u9a7e\u9a7f\u9a80\u9a81\u9a82\u9a83\u9a84\u9a85\u9a86\u9a87\u9a88\u9a89\u9a8a\u9a8b\u9a8c\u9a8d\u9a8e\u9a8f\u9a90\u9a91\u9a92\u9a93\u9a94\u9a95\u9a96\u9a97\u9a98\u9a99\u9a9a\u9a9b\u9a9c\u9a9d\u9a9e\u9a9f\u9aa0\u9aa1\u9aa2\u9aa3\u9aa4\u9aa5\u9aa6\u9aa7\u9aa8\u9aa9\u9aaa\u9aab\u9aac\u9aad\u9aae\u9aaf\u9ab0\u9ab1\u9ab2\u9ab3\u9ab4\u9ab5\u9ab6\u9ab7\u9ab8\u9ab9\u9aba\u9abb\u9abc\u9abd\u9abe\u9abf\u9ac0\u9ac1\u9ac2\u9ac3\u9ac4\u9ac5\u9ac6\u9ac7\u9ac8\u9ac9\u9aca\u9acb\u9acc\u9acd\u9ace\u9acf\u9ad0\u9ad1\u9ad2\u9ad3\u9ad4\u9ad5\u9ad6\u9ad7\u9ad8\u9ad9\u9ada\u9adb\u9adc\u9add\u9ade\u9adf\u9ae0\u9ae1\u9ae2\u9ae3\u9ae4\u9ae5\u9ae6\u9ae7\u9ae8\u9ae9\u9aea\u9aeb\u9aec\u9aed\u9aee\u9aef\u9af0\u9af1\u9af2\u9af3\u9af4\u9af5\u9af6\u9af7\u9af8\u9af9\u9afa\u9afb\u9afc\u9afd\u9afe\u9aff\u9b00\u9b01\u9b02\u9b03\u9b04\u9b05\u9b06\u9b07\u9b08\u9b09\u9b0a\u9b0b\u9b0c\u9b0d\u9b0e\u9b0f\u9b10\u9b11\u9b12\u9b13\u9b14\u9b15\u9b16\u9b17\u9b18\u9b19\u9b1a\u9b1b\u9b1c\u9b1d\u9b1e\u9b1f\u9b20\u9b21\u9b22\u9b23\u9b24\u9b25\u9b26\u9b27\u9b28\u9b29\u9b2a\u9b2b\u9b2c\u9b2d\u9b2e\u9b2f\u9b30\u9b31\u9b32\u9b33\u9b34\u9b35\u9b36\u9b37\u9b38\u9b39\u9b3a\u9b3b\u9b3c\u9b3d\u9b3e\u9b3f\u9b40\u9b41\u9b42\u9b43\u9b44\u9b45\u9b46\u9b47\u9b48\u9b49\u9b4a\u9b4b\u9b4c\u9b4d\u9b4e\u9b4f\u9b50\u9b51\u9b52\u9b53\u9b54\u9b55\u9b56\u9b57\u9b58\u9b59\u9b5a\u9b5b\u9b5c\u9b5d\u9b5e\u9b5f\u9b60\u9b61\u9b62\u9b63\u9b64\u9b65\u9b66\u9b67\u9b68\u9b69\u9b6a\u9b6b\u9b6c\u9b6d\u9b6e\u9b6f\u9b70\u9b71\u9b72\u9b73\u9b74\u9b75\u9b76\u9b77\u9b78\u9b79\u9b7a\u9b7b\u9b7c\u9b7d\u9b7e\u9b7f\u9b80\u9b81\u9b82\u9b83\u9b84\u9b85\u9b86\u9b87\u9b88\u9b89\u9b8a\u9b8b\u9b8c\u9b8d\u9b8e\u9b8f\u9b90\u9b91\u9b92\u9b93\u9b94\u9b95\u9b96\u9b97\u9b98\u9b99\u9b9a\u9b9b\u9b9c\u9b9d\u9b9e\u9b9f\u9ba0\u9ba1\u9ba2\u9ba3\u9ba4\u9ba5\u9ba6\u9ba7\u9ba8\u9ba9\u9baa\u9bab\u9bac\u9bad\u9bae\u9baf\u9bb0\u9bb1\u9bb2\u9bb3\u9bb4\u9bb5\u9bb6\u9bb7\u9bb8\u9bb9\u9bba\u9bbb\u9bbc\u9bbd\u9bbe\u9bbf\u9bc0\u9bc1\u9bc2\u9bc3\u9bc4\u9bc5\u9bc6\u9bc7\u9bc8\u9bc9\u9bca\u9bcb\u9bcc\u9bcd\u9bce\u9bcf\u9bd0\u9bd1\u9bd2\u9bd3\u9bd4\u9bd5\u9bd6\u9bd7\u9bd8\u9bd9\u9bda\u9bdb\u9bdc\u9bdd\u9bde\u9bdf\u9be0\u9be1\u9be2\u9be3\u9be4\u9be5\u9be6\u9be7\u9be8\u9be9\u9bea\u9beb\u9bec\u9bed\u9bee\u9bef\u9bf0\u9bf1\u9bf2\u9bf3\u9bf4\u9bf5\u9bf6\u9bf7\u9bf8\u9bf9\u9bfa\u9bfb\u9bfc\u9bfd\u9bfe\u9bff\u9c00\u9c01\u9c02\u9c03\u9c04\u9c05\u9c06\u9c07\u9c08\u9c09\u9c0a\u9c0b\u9c0c\u9c0d\u9c0e\u9c0f\u9c10\u9c11\u9c12\u9c13\u9c14\u9c15\u9c16\u9c17\u9c18\u9c19\u9c1a\u9c1b\u9c1c\u9c1d\u9c1e\u9c1f\u9c20\u9c21\u9c22\u9c23\u9c24\u9c25\u9c26\u9c27\u9c28\u9c29\u9c2a\u9c2b\u9c2c\u9c2d\u9c2e\u9c2f\u9c30\u9c31\u9c32\u9c33\u9c34\u9c35\u9c36\u9c37\u9c38\u9c39\u9c3a\u9c3b\u9c3c\u9c3d\u9c3e\u9c3f\u9c40\u9c41\u9c42\u9c43\u9c44\u9c45\u9c46\u9c47\u9c48\u9c49\u9c4a\u9c4b\u9c4c\u9c4d\u9c4e\u9c4f\u9c50\u9c51\u9c52\u9c53\u9c54\u9c55\u9c56\u9c57\u9c58\u9c59\u9c5a\u9c5b\u9c5c\u9c5d\u9c5e\u9c5f\u9c60\u9c61\u9c62\u9c63\u9c64\u9c65\u9c66\u9c67\u9c68\u9c69\u9c6a\u9c6b\u9c6c\u9c6d\u9c6e\u9c6f\u9c70\u9c71\u9c72\u9c73\u9c74\u9c75\u9c76\u9c77\u9c78\u9c79\u9c7a\u9c7b\u9c7c\u9c7d\u9c7e\u9c7f\u9c80\u9c81\u9c82\u9c83\u9c84\u9c85\u9c86\u9c87\u9c88\u9c89\u9c8a\u9c8b\u9c8c\u9c8d\u9c8e\u9c8f\u9c90\u9c91\u9c92\u9c93\u9c94\u9c95\u9c96\u9c97\u9c98\u9c99\u9c9a\u9c9b\u9c9c\u9c9d\u9c9e\u9c9f\u9ca0\u9ca1\u9ca2\u9ca3\u9ca4\u9ca5\u9ca6\u9ca7\u9ca8\u9ca9\u9caa\u9cab\u9cac\u9cad\u9cae\u9caf\u9cb0\u9cb1\u9cb2\u9cb3\u9cb4\u9cb5\u9cb6\u9cb7\u9cb8\u9cb9\u9cba\u9cbb\u9cbc\u9cbd\u9cbe\u9cbf\u9cc0\u9cc1\u9cc2\u9cc3\u9cc4\u9cc5\u9cc6\u9cc7\u9cc8\u9cc9\u9cca\u9ccb\u9ccc\u9ccd\u9cce\u9ccf\u9cd0\u9cd1\u9cd2\u9cd3\u9cd4\u9cd5\u9cd6\u9cd7\u9cd8\u9cd9\u9cda\u9cdb\u9cdc\u9cdd\u9cde\u9cdf\u9ce0\u9ce1\u9ce2\u9ce3\u9ce4\u9ce5\u9ce6\u9ce7\u9ce8\u9ce9\u9cea\u9ceb\u9cec\u9ced\u9cee\u9cef\u9cf0\u9cf1\u9cf2\u9cf3\u9cf4\u9cf5\u9cf6\u9cf7\u9cf8\u9cf9\u9cfa\u9cfb\u9cfc\u9cfd\u9cfe\u9cff\u9d00\u9d01\u9d02\u9d03\u9d04\u9d05\u9d06\u9d07\u9d08\u9d09\u9d0a\u9d0b\u9d0c\u9d0d\u9d0e\u9d0f\u9d10\u9d11\u9d12\u9d13\u9d14\u9d15\u9d16\u9d17\u9d18\u9d19\u9d1a\u9d1b\u9d1c\u9d1d\u9d1e\u9d1f\u9d20\u9d21\u9d22\u9d23\u9d24\u9d25\u9d26\u9d27\u9d28\u9d29\u9d2a\u9d2b\u9d2c\u9d2d\u9d2e\u9d2f\u9d30\u9d31\u9d32\u9d33\u9d34\u9d35\u9d36\u9d37\u9d38\u9d39\u9d3a\u9d3b\u9d3c\u9d3d\u9d3e\u9d3f\u9d40\u9d41\u9d42\u9d43\u9d44\u9d45\u9d46\u9d47\u9d48\u9d49\u9d4a\u9d4b\u9d4c\u9d4d\u9d4e\u9d4f\u9d50\u9d51\u9d52\u9d53\u9d54\u9d55\u9d56\u9d57\u9d58\u9d59\u9d5a\u9d5b\u9d5c\u9d5d\u9d5e\u9d5f\u9d60\u9d61\u9d62\u9d63\u9d64\u9d65\u9d66\u9d67\u9d68\u9d69\u9d6a\u9d6b\u9d6c\u9d6d\u9d6e\u9d6f\u9d70\u9d71\u9d72\u9d73\u9d74\u9d75\u9d76\u9d77\u9d78\u9d79\u9d7a\u9d7b\u9d7c\u9d7d\u9d7e\u9d7f\u9d80\u9d81\u9d82\u9d83\u9d84\u9d85\u9d86\u9d87\u9d88\u9d89\u9d8a\u9d8b\u9d8c\u9d8d\u9d8e\u9d8f\u9d90\u9d91\u9d92\u9d93\u9d94\u9d95\u9d96\u9d97\u9d98\u9d99\u9d9a\u9d9b\u9d9c\u9d9d\u9d9e\u9d9f\u9da0\u9da1\u9da2\u9da3\u9da4\u9da5\u9da6\u9da7\u9da8\u9da9\u9daa\u9dab\u9dac\u9dad\u9dae\u9daf\u9db0\u9db1\u9db2\u9db3\u9db4\u9db5\u9db6\u9db7\u9db8\u9db9\u9dba\u9dbb\u9dbc\u9dbd\u9dbe\u9dbf\u9dc0\u9dc1\u9dc2\u9dc3\u9dc4\u9dc5\u9dc6\u9dc7\u9dc8\u9dc9\u9dca\u9dcb\u9dcc\u9dcd\u9dce\u9dcf\u9dd0\u9dd1\u9dd2\u9dd3\u9dd4\u9dd5\u9dd6\u9dd7\u9dd8\u9dd9\u9dda\u9ddb\u9ddc\u9ddd\u9dde\u9ddf\u9de0\u9de1\u9de2\u9de3\u9de4\u9de5\u9de6\u9de7\u9de8\u9de9\u9dea\u9deb\u9dec\u9ded\u9dee\u9def\u9df0\u9df1\u9df2\u9df3\u9df4\u9df5\u9df6\u9df7\u9df8\u9df9\u9dfa\u9dfb\u9dfc\u9dfd\u9dfe\u9dff\u9e00\u9e01\u9e02\u9e03\u9e04\u9e05\u9e06\u9e07\u9e08\u9e09\u9e0a\u9e0b\u9e0c\u9e0d\u9e0e\u9e0f\u9e10\u9e11\u9e12\u9e13\u9e14\u9e15\u9e16\u9e17\u9e18\u9e19\u9e1a\u9e1b\u9e1c\u9e1d\u9e1e\u9e1f\u9e20\u9e21\u9e22\u9e23\u9e24\u9e25\u9e26\u9e27\u9e28\u9e29\u9e2a\u9e2b\u9e2c\u9e2d\u9e2e\u9e2f\u9e30\u9e31\u9e32\u9e33\u9e34\u9e35\u9e36\u9e37\u9e38\u9e39\u9e3a\u9e3b\u9e3c\u9e3d\u9e3e\u9e3f\u9e40\u9e41\u9e42\u9e43\u9e44\u9e45\u9e46\u9e47\u9e48\u9e49\u9e4a\u9e4b\u9e4c\u9e4d\u9e4e\u9e4f\u9e50\u9e51\u9e52\u9e53\u9e54\u9e55\u9e56\u9e57\u9e58\u9e59\u9e5a\u9e5b\u9e5c\u9e5d\u9e5e\u9e5f\u9e60\u9e61\u9e62\u9e63\u9e64\u9e65\u9e66\u9e67\u9e68\u9e69\u9e6a\u9e6b\u9e6c\u9e6d\u9e6e\u9e6f\u9e70\u9e71\u9e72\u9e73\u9e74\u9e75\u9e76\u9e77\u9e78\u9e79\u9e7a\u9e7b\u9e7c\u9e7d\u9e7e\u9e7f\u9e80\u9e81\u9e82\u9e83\u9e84\u9e85\u9e86\u9e87\u9e88\u9e89\u9e8a\u9e8b\u9e8c\u9e8d\u9e8e\u9e8f\u9e90\u9e91\u9e92\u9e93\u9e94\u9e95\u9e96\u9e97\u9e98\u9e99\u9e9a\u9e9b\u9e9c\u9e9d\u9e9e\u9e9f\u9ea0\u9ea1\u9ea2\u9ea3\u9ea4\u9ea5\u9ea6\u9ea7\u9ea8\u9ea9\u9eaa\u9eab\u9eac\u9ead\u9eae\u9eaf\u9eb0\u9eb1\u9eb2\u9eb3\u9eb4\u9eb5\u9eb6\u9eb7\u9eb8\u9eb9\u9eba\u9ebb\u9ebc\u9ebd\u9ebe\u9ebf\u9ec0\u9ec1\u9ec2\u9ec3\u9ec4\u9ec5\u9ec6\u9ec7\u9ec8\u9ec9\u9eca\u9ecb\u9ecc\u9ecd\u9ece\u9ecf\u9ed0\u9ed1\u9ed2\u9ed3\u9ed4\u9ed5\u9ed6\u9ed7\u9ed8\u9ed9\u9eda\u9edb\u9edc\u9edd\u9ede\u9edf\u9ee0\u9ee1\u9ee2\u9ee3\u9ee4\u9ee5\u9ee6\u9ee7\u9ee8\u9ee9\u9eea\u9eeb\u9eec\u9eed\u9eee\u9eef\u9ef0\u9ef1\u9ef2\u9ef3\u9ef4\u9ef5\u9ef6\u9ef7\u9ef8\u9ef9\u9efa\u9efb\u9efc\u9efd\u9efe\u9eff\u9f00\u9f01\u9f02\u9f03\u9f04\u9f05\u9f06\u9f07\u9f08\u9f09\u9f0a\u9f0b\u9f0c\u9f0d\u9f0e\u9f0f\u9f10\u9f11\u9f12\u9f13\u9f14\u9f15\u9f16\u9f17\u9f18\u9f19\u9f1a\u9f1b\u9f1c\u9f1d\u9f1e\u9f1f\u9f20\u9f21\u9f22\u9f23\u9f24\u9f25\u9f26\u9f27\u9f28\u9f29\u9f2a\u9f2b\u9f2c\u9f2d\u9f2e\u9f2f\u9f30\u9f31\u9f32\u9f33\u9f34\u9f35\u9f36\u9f37\u9f38\u9f39\u9f3a\u9f3b\u9f3c\u9f3d\u9f3e\u9f3f\u9f40\u9f41\u9f42\u9f43\u9f44\u9f45\u9f46\u9f47\u9f48\u9f49\u9f4a\u9f4b\u9f4c\u9f4d\u9f4e\u9f4f\u9f50\u9f51\u9f52\u9f53\u9f54\u9f55\u9f56\u9f57\u9f58\u9f59\u9f5a\u9f5b\u9f5c\u9f5d\u9f5e\u9f5f\u9f60\u9f61\u9f62\u9f63\u9f64\u9f65\u9f66\u9f67\u9f68\u9f69\u9f6a\u9f6b\u9f6c\u9f6d\u9f6e\u9f6f\u9f70\u9f71\u9f72\u9f73\u9f74\u9f75\u9f76\u9f77\u9f78\u9f79\u9f7a\u9f7b\u9f7c\u9f7d\u9f7e\u9f7f\u9f80\u9f81\u9f82\u9f83\u9f84\u9f85\u9f86\u9f87\u9f88\u9f89\u9f8a\u9f8b\u9f8c\u9f8d\u9f8e\u9f8f\u9f90\u9f91\u9f92\u9f93\u9f94\u9f95\u9f96\u9f97\u9f98\u9f99\u9f9a\u9f9b\u9f9c\u9f9d\u9f9e\u9f9f\u9fa0\u9fa1\u9fa2\u9fa3\u9fa4\u9fa5\u9fa6\u9fa7\u9fa8\u9fa9\u9faa\u9fab\u9fac\u9fad\u9fae\u9faf\u9fb0\u9fb1\u9fb2\u9fb3\u9fb4\u9fb5\u9fb6\u9fb7\u9fb8\u9fb9\u9fba\u9fbb\u9fbc\u9fbd\u9fbe\u9fbf\u9fc0\u9fc1\u9fc2\u9fc3\u9fc4\u9fc5\u9fc6\u9fc7\u9fc8\u9fc9\u9fca\u9fcb\u9fcc\u9fcd\u9fce\u9fcf\u9fd0\u9fd1\u9fd2\u9fd3\u9fd4\u9fd5\ua000\ua001\ua002\ua003\ua004\ua005\ua006\ua007\ua008\ua009\ua00a\ua00b\ua00c\ua00d\ua00e\ua00f\ua010\ua011\ua012\ua013\ua014\ua015\ua016\ua017\ua018\ua019\ua01a\ua01b\ua01c\ua01d\ua01e\ua01f\ua020\ua021\ua022\ua023\ua024\ua025\ua026\ua027\ua028\ua029\ua02a\ua02b\ua02c\ua02d\ua02e\ua02f\ua030\ua031\ua032\ua033\ua034\ua035\ua036\ua037\ua038\ua039\ua03a\ua03b\ua03c\ua03d\ua03e\ua03f\ua040\ua041\ua042\ua043\ua044\ua045\ua046\ua047\ua048\ua049\ua04a\ua04b\ua04c\ua04d\ua04e\ua04f\ua050\ua051\ua052\ua053\ua054\ua055\ua056\ua057\ua058\ua059\ua05a\ua05b\ua05c\ua05d\ua05e\ua05f\ua060\ua061\ua062\ua063\ua064\ua065\ua066\ua067\ua068\ua069\ua06a\ua06b\ua06c\ua06d\ua06e\ua06f\ua070\ua071\ua072\ua073\ua074\ua075\ua076\ua077\ua078\ua079\ua07a\ua07b\ua07c\ua07d\ua07e\ua07f\ua080\ua081\ua082\ua083\ua084\ua085\ua086\ua087\ua088\ua089\ua08a\ua08b\ua08c\ua08d\ua08e\ua08f\ua090\ua091\ua092\ua093\ua094\ua095\ua096\ua097\ua098\ua099\ua09a\ua09b\ua09c\ua09d\ua09e\ua09f\ua0a0\ua0a1\ua0a2\ua0a3\ua0a4\ua0a5\ua0a6\ua0a7\ua0a8\ua0a9\ua0aa\ua0ab\ua0ac\ua0ad\ua0ae\ua0af\ua0b0\ua0b1\ua0b2\ua0b3\ua0b4\ua0b5\ua0b6\ua0b7\ua0b8\ua0b9\ua0ba\ua0bb\ua0bc\ua0bd\ua0be\ua0bf\ua0c0\ua0c1\ua0c2\ua0c3\ua0c4\ua0c5\ua0c6\ua0c7\ua0c8\ua0c9\ua0ca\ua0cb\ua0cc\ua0cd\ua0ce\ua0cf\ua0d0\ua0d1\ua0d2\ua0d3\ua0d4\ua0d5\ua0d6\ua0d7\ua0d8\ua0d9\ua0da\ua0db\ua0dc\ua0dd\ua0de\ua0df\ua0e0\ua0e1\ua0e2\ua0e3\ua0e4\ua0e5\ua0e6\ua0e7\ua0e8\ua0e9\ua0ea\ua0eb\ua0ec\ua0ed\ua0ee\ua0ef\ua0f0\ua0f1\ua0f2\ua0f3\ua0f4\ua0f5\ua0f6\ua0f7\ua0f8\ua0f9\ua0fa\ua0fb\ua0fc\ua0fd\ua0fe\ua0ff\ua100\ua101\ua102\ua103\ua104\ua105\ua106\ua107\ua108\ua109\ua10a\ua10b\ua10c\ua10d\ua10e\ua10f\ua110\ua111\ua112\ua113\ua114\ua115\ua116\ua117\ua118\ua119\ua11a\ua11b\ua11c\ua11d\ua11e\ua11f\ua120\ua121\ua122\ua123\ua124\ua125\ua126\ua127\ua128\ua129\ua12a\ua12b\ua12c\ua12d\ua12e\ua12f\ua130\ua131\ua132\ua133\ua134\ua135\ua136\ua137\ua138\ua139\ua13a\ua13b\ua13c\ua13d\ua13e\ua13f\ua140\ua141\ua142\ua143\ua144\ua145\ua146\ua147\ua148\ua149\ua14a\ua14b\ua14c\ua14d\ua14e\ua14f\ua150\ua151\ua152\ua153\ua154\ua155\ua156\ua157\ua158\ua159\ua15a\ua15b\ua15c\ua15d\ua15e\ua15f\ua160\ua161\ua162\ua163\ua164\ua165\ua166\ua167\ua168\ua169\ua16a\ua16b\ua16c\ua16d\ua16e\ua16f\ua170\ua171\ua172\ua173\ua174\ua175\ua176\ua177\ua178\ua179\ua17a\ua17b\ua17c\ua17d\ua17e\ua17f\ua180\ua181\ua182\ua183\ua184\ua185\ua186\ua187\ua188\ua189\ua18a\ua18b\ua18c\ua18d\ua18e\ua18f\ua190\ua191\ua192\ua193\ua194\ua195\ua196\ua197\ua198\ua199\ua19a\ua19b\ua19c\ua19d\ua19e\ua19f\ua1a0\ua1a1\ua1a2\ua1a3\ua1a4\ua1a5\ua1a6\ua1a7\ua1a8\ua1a9\ua1aa\ua1ab\ua1ac\ua1ad\ua1ae\ua1af\ua1b0\ua1b1\ua1b2\ua1b3\ua1b4\ua1b5\ua1b6\ua1b7\ua1b8\ua1b9\ua1ba\ua1bb\ua1bc\ua1bd\ua1be\ua1bf\ua1c0\ua1c1\ua1c2\ua1c3\ua1c4\ua1c5\ua1c6\ua1c7\ua1c8\ua1c9\ua1ca\ua1cb\ua1cc\ua1cd\ua1ce\ua1cf\ua1d0\ua1d1\ua1d2\ua1d3\ua1d4\ua1d5\ua1d6\ua1d7\ua1d8\ua1d9\ua1da\ua1db\ua1dc\ua1dd\ua1de\ua1df\ua1e0\ua1e1\ua1e2\ua1e3\ua1e4\ua1e5\ua1e6\ua1e7\ua1e8\ua1e9\ua1ea\ua1eb\ua1ec\ua1ed\ua1ee\ua1ef\ua1f0\ua1f1\ua1f2\ua1f3\ua1f4\ua1f5\ua1f6\ua1f7\ua1f8\ua1f9\ua1fa\ua1fb\ua1fc\ua1fd\ua1fe\ua1ff\ua200\ua201\ua202\ua203\ua204\ua205\ua206\ua207\ua208\ua209\ua20a\ua20b\ua20c\ua20d\ua20e\ua20f\ua210\ua211\ua212\ua213\ua214\ua215\ua216\ua217\ua218\ua219\ua21a\ua21b\ua21c\ua21d\ua21e\ua21f\ua220\ua221\ua222\ua223\ua224\ua225\ua226\ua227\ua228\ua229\ua22a\ua22b\ua22c\ua22d\ua22e\ua22f\ua230\ua231\ua232\ua233\ua234\ua235\ua236\ua237\ua238\ua239\ua23a\ua23b\ua23c\ua23d\ua23e\ua23f\ua240\ua241\ua242\ua243\ua244\ua245\ua246\ua247\ua248\ua249\ua24a\ua24b\ua24c\ua24d\ua24e\ua24f\ua250\ua251\ua252\ua253\ua254\ua255\ua256\ua257\ua258\ua259\ua25a\ua25b\ua25c\ua25d\ua25e\ua25f\ua260\ua261\ua262\ua263\ua264\ua265\ua266\ua267\ua268\ua269\ua26a\ua26b\ua26c\ua26d\ua26e\ua26f\ua270\ua271\ua272\ua273\ua274\ua275\ua276\ua277\ua278\ua279\ua27a\ua27b\ua27c\ua27d\ua27e\ua27f\ua280\ua281\ua282\ua283\ua284\ua285\ua286\ua287\ua288\ua289\ua28a\ua28b\ua28c\ua28d\ua28e\ua28f\ua290\ua291\ua292\ua293\ua294\ua295\ua296\ua297\ua298\ua299\ua29a\ua29b\ua29c\ua29d\ua29e\ua29f\ua2a0\ua2a1\ua2a2\ua2a3\ua2a4\ua2a5\ua2a6\ua2a7\ua2a8\ua2a9\ua2aa\ua2ab\ua2ac\ua2ad\ua2ae\ua2af\ua2b0\ua2b1\ua2b2\ua2b3\ua2b4\ua2b5\ua2b6\ua2b7\ua2b8\ua2b9\ua2ba\ua2bb\ua2bc\ua2bd\ua2be\ua2bf\ua2c0\ua2c1\ua2c2\ua2c3\ua2c4\ua2c5\ua2c6\ua2c7\ua2c8\ua2c9\ua2ca\ua2cb\ua2cc\ua2cd\ua2ce\ua2cf\ua2d0\ua2d1\ua2d2\ua2d3\ua2d4\ua2d5\ua2d6\ua2d7\ua2d8\ua2d9\ua2da\ua2db\ua2dc\ua2dd\ua2de\ua2df\ua2e0\ua2e1\ua2e2\ua2e3\ua2e4\ua2e5\ua2e6\ua2e7\ua2e8\ua2e9\ua2ea\ua2eb\ua2ec\ua2ed\ua2ee\ua2ef\ua2f0\ua2f1\ua2f2\ua2f3\ua2f4\ua2f5\ua2f6\ua2f7\ua2f8\ua2f9\ua2fa\ua2fb\ua2fc\ua2fd\ua2fe\ua2ff\ua300\ua301\ua302\ua303\ua304\ua305\ua306\ua307\ua308\ua309\ua30a\ua30b\ua30c\ua30d\ua30e\ua30f\ua310\ua311\ua312\ua313\ua314\ua315\ua316\ua317\ua318\ua319\ua31a\ua31b\ua31c\ua31d\ua31e\ua31f\ua320\ua321\ua322\ua323\ua324\ua325\ua326\ua327\ua328\ua329\ua32a\ua32b\ua32c\ua32d\ua32e\ua32f\ua330\ua331\ua332\ua333\ua334\ua335\ua336\ua337\ua338\ua339\ua33a\ua33b\ua33c\ua33d\ua33e\ua33f\ua340\ua341\ua342\ua343\ua344\ua345\ua346\ua347\ua348\ua349\ua34a\ua34b\ua34c\ua34d\ua34e\ua34f\ua350\ua351\ua352\ua353\ua354\ua355\ua356\ua357\ua358\ua359\ua35a\ua35b\ua35c\ua35d\ua35e\ua35f\ua360\ua361\ua362\ua363\ua364\ua365\ua366\ua367\ua368\ua369\ua36a\ua36b\ua36c\ua36d\ua36e\ua36f\ua370\ua371\ua372\ua373\ua374\ua375\ua376\ua377\ua378\ua379\ua37a\ua37b\ua37c\ua37d\ua37e\ua37f\ua380\ua381\ua382\ua383\ua384\ua385\ua386\ua387\ua388\ua389\ua38a\ua38b\ua38c\ua38d\ua38e\ua38f\ua390\ua391\ua392\ua393\ua394\ua395\ua396\ua397\ua398\ua399\ua39a\ua39b\ua39c\ua39d\ua39e\ua39f\ua3a0\ua3a1\ua3a2\ua3a3\ua3a4\ua3a5\ua3a6\ua3a7\ua3a8\ua3a9\ua3aa\ua3ab\ua3ac\ua3ad\ua3ae\ua3af\ua3b0\ua3b1\ua3b2\ua3b3\ua3b4\ua3b5\ua3b6\ua3b7\ua3b8\ua3b9\ua3ba\ua3bb\ua3bc\ua3bd\ua3be\ua3bf\ua3c0\ua3c1\ua3c2\ua3c3\ua3c4\ua3c5\ua3c6\ua3c7\ua3c8\ua3c9\ua3ca\ua3cb\ua3cc\ua3cd\ua3ce\ua3cf\ua3d0\ua3d1\ua3d2\ua3d3\ua3d4\ua3d5\ua3d6\ua3d7\ua3d8\ua3d9\ua3da\ua3db\ua3dc\ua3dd\ua3de\ua3df\ua3e0\ua3e1\ua3e2\ua3e3\ua3e4\ua3e5\ua3e6\ua3e7\ua3e8\ua3e9\ua3ea\ua3eb\ua3ec\ua3ed\ua3ee\ua3ef\ua3f0\ua3f1\ua3f2\ua3f3\ua3f4\ua3f5\ua3f6\ua3f7\ua3f8\ua3f9\ua3fa\ua3fb\ua3fc\ua3fd\ua3fe\ua3ff\ua400\ua401\ua402\ua403\ua404\ua405\ua406\ua407\ua408\ua409\ua40a\ua40b\ua40c\ua40d\ua40e\ua40f\ua410\ua411\ua412\ua413\ua414\ua415\ua416\ua417\ua418\ua419\ua41a\ua41b\ua41c\ua41d\ua41e\ua41f\ua420\ua421\ua422\ua423\ua424\ua425\ua426\ua427\ua428\ua429\ua42a\ua42b\ua42c\ua42d\ua42e\ua42f\ua430\ua431\ua432\ua433\ua434\ua435\ua436\ua437\ua438\ua439\ua43a\ua43b\ua43c\ua43d\ua43e\ua43f\ua440\ua441\ua442\ua443\ua444\ua445\ua446\ua447\ua448\ua449\ua44a\ua44b\ua44c\ua44d\ua44e\ua44f\ua450\ua451\ua452\ua453\ua454\ua455\ua456\ua457\ua458\ua459\ua45a\ua45b\ua45c\ua45d\ua45e\ua45f\ua460\ua461\ua462\ua463\ua464\ua465\ua466\ua467\ua468\ua469\ua46a\ua46b\ua46c\ua46d\ua46e\ua46f\ua470\ua471\ua472\ua473\ua474\ua475\ua476\ua477\ua478\ua479\ua47a\ua47b\ua47c\ua47d\ua47e\ua47f\ua480\ua481\ua482\ua483\ua484\ua485\ua486\ua487\ua488\ua489\ua48a\ua48b\ua48c\ua4d0\ua4d1\ua4d2\ua4d3\ua4d4\ua4d5\ua4d6\ua4d7\ua4d8\ua4d9\ua4da\ua4db\ua4dc\ua4dd\ua4de\ua4df\ua4e0\ua4e1\ua4e2\ua4e3\ua4e4\ua4e5\ua4e6\ua4e7\ua4e8\ua4e9\ua4ea\ua4eb\ua4ec\ua4ed\ua4ee\ua4ef\ua4f0\ua4f1\ua4f2\ua4f3\ua4f4\ua4f5\ua4f6\ua4f7\ua4f8\ua4f9\ua4fa\ua4fb\ua4fc\ua4fd\ua500\ua501\ua502\ua503\ua504\ua505\ua506\ua507\ua508\ua509\ua50a\ua50b\ua50c\ua50d\ua50e\ua50f\ua510\ua511\ua512\ua513\ua514\ua515\ua516\ua517\ua518\ua519\ua51a\ua51b\ua51c\ua51d\ua51e\ua51f\ua520\ua521\ua522\ua523\ua524\ua525\ua526\ua527\ua528\ua529\ua52a\ua52b\ua52c\ua52d\ua52e\ua52f\ua530\ua531\ua532\ua533\ua534\ua535\ua536\ua537\ua538\ua539\ua53a\ua53b\ua53c\ua53d\ua53e\ua53f\ua540\ua541\ua542\ua543\ua544\ua545\ua546\ua547\ua548\ua549\ua54a\ua54b\ua54c\ua54d\ua54e\ua54f\ua550\ua551\ua552\ua553\ua554\ua555\ua556\ua557\ua558\ua559\ua55a\ua55b\ua55c\ua55d\ua55e\ua55f\ua560\ua561\ua562\ua563\ua564\ua565\ua566\ua567\ua568\ua569\ua56a\ua56b\ua56c\ua56d\ua56e\ua56f\ua570\ua571\ua572\ua573\ua574\ua575\ua576\ua577\ua578\ua579\ua57a\ua57b\ua57c\ua57d\ua57e\ua57f\ua580\ua581\ua582\ua583\ua584\ua585\ua586\ua587\ua588\ua589\ua58a\ua58b\ua58c\ua58d\ua58e\ua58f\ua590\ua591\ua592\ua593\ua594\ua595\ua596\ua597\ua598\ua599\ua59a\ua59b\ua59c\ua59d\ua59e\ua59f\ua5a0\ua5a1\ua5a2\ua5a3\ua5a4\ua5a5\ua5a6\ua5a7\ua5a8\ua5a9\ua5aa\ua5ab\ua5ac\ua5ad\ua5ae\ua5af\ua5b0\ua5b1\ua5b2\ua5b3\ua5b4\ua5b5\ua5b6\ua5b7\ua5b8\ua5b9\ua5ba\ua5bb\ua5bc\ua5bd\ua5be\ua5bf\ua5c0\ua5c1\ua5c2\ua5c3\ua5c4\ua5c5\ua5c6\ua5c7\ua5c8\ua5c9\ua5ca\ua5cb\ua5cc\ua5cd\ua5ce\ua5cf\ua5d0\ua5d1\ua5d2\ua5d3\ua5d4\ua5d5\ua5d6\ua5d7\ua5d8\ua5d9\ua5da\ua5db\ua5dc\ua5dd\ua5de\ua5df\ua5e0\ua5e1\ua5e2\ua5e3\ua5e4\ua5e5\ua5e6\ua5e7\ua5e8\ua5e9\ua5ea\ua5eb\ua5ec\ua5ed\ua5ee\ua5ef\ua5f0\ua5f1\ua5f2\ua5f3\ua5f4\ua5f5\ua5f6\ua5f7\ua5f8\ua5f9\ua5fa\ua5fb\ua5fc\ua5fd\ua5fe\ua5ff\ua600\ua601\ua602\ua603\ua604\ua605\ua606\ua607\ua608\ua609\ua60a\ua60b\ua60c\ua610\ua611\ua612\ua613\ua614\ua615\ua616\ua617\ua618\ua619\ua61a\ua61b\ua61c\ua61d\ua61e\ua61f\ua620\ua621\ua622\ua623\ua624\ua625\ua626\ua627\ua628\ua629\ua62a\ua62b\ua640\ua641\ua642\ua643\ua644\ua645\ua646\ua647\ua648\ua649\ua64a\ua64b\ua64c\ua64d\ua64e\ua64f\ua650\ua651\ua652\ua653\ua654\ua655\ua656\ua657\ua658\ua659\ua65a\ua65b\ua65c\ua65d\ua65e\ua65f\ua660\ua661\ua662\ua663\ua664\ua665\ua666\ua667\ua668\ua669\ua66a\ua66b\ua66c\ua66d\ua66e\ua66f\ua674\ua675\ua676\ua677\ua678\ua679\ua67a\ua67b\ua67c\ua67d\ua67f\ua680\ua681\ua682\ua683\ua684\ua685\ua686\ua687\ua688\ua689\ua68a\ua68b\ua68c\ua68d\ua68e\ua68f\ua690\ua691\ua692\ua693\ua694\ua695\ua696\ua697\ua698\ua699\ua69a\ua69b\ua69c\ua69d\ua69e\ua69f\ua6a0\ua6a1\ua6a2\ua6a3\ua6a4\ua6a5\ua6a6\ua6a7\ua6a8\ua6a9\ua6aa\ua6ab\ua6ac\ua6ad\ua6ae\ua6af\ua6b0\ua6b1\ua6b2\ua6b3\ua6b4\ua6b5\ua6b6\ua6b7\ua6b8\ua6b9\ua6ba\ua6bb\ua6bc\ua6bd\ua6be\ua6bf\ua6c0\ua6c1\ua6c2\ua6c3\ua6c4\ua6c5\ua6c6\ua6c7\ua6c8\ua6c9\ua6ca\ua6cb\ua6cc\ua6cd\ua6ce\ua6cf\ua6d0\ua6d1\ua6d2\ua6d3\ua6d4\ua6d5\ua6d6\ua6d7\ua6d8\ua6d9\ua6da\ua6db\ua6dc\ua6dd\ua6de\ua6df\ua6e0\ua6e1\ua6e2\ua6e3\ua6e4\ua6e5\ua6e6\ua6e7\ua6e8\ua6e9\ua6ea\ua6eb\ua6ec\ua6ed\ua6ee\ua6ef\ua6f0\ua6f1\ua717\ua718\ua719\ua71a\ua71b\ua71c\ua71d\ua71e\ua71f\ua722\ua723\ua724\ua725\ua726\ua727\ua728\ua729\ua72a\ua72b\ua72c\ua72d\ua72e\ua72f\ua730\ua731\ua732\ua733\ua734\ua735\ua736\ua737\ua738\ua739\ua73a\ua73b\ua73c\ua73d\ua73e\ua73f\ua740\ua741\ua742\ua743\ua744\ua745\ua746\ua747\ua748\ua749\ua74a\ua74b\ua74c\ua74d\ua74e\ua74f\ua750\ua751\ua752\ua753\ua754\ua755\ua756\ua757\ua758\ua759\ua75a\ua75b\ua75c\ua75d\ua75e\ua75f\ua760\ua761\ua762\ua763\ua764\ua765\ua766\ua767\ua768\ua769\ua76a\ua76b\ua76c\ua76d\ua76e\ua76f\ua770\ua771\ua772\ua773\ua774\ua775\ua776\ua777\ua778\ua779\ua77a\ua77b\ua77c\ua77d\ua77e\ua77f\ua780\ua781\ua782\ua783\ua784\ua785\ua786\ua787\ua788\ua78b\ua78c\ua78d\ua78e\ua78f\ua790\ua791\ua792\ua793\ua794\ua795\ua796\ua797\ua798\ua799\ua79a\ua79b\ua79c\ua79d\ua79e\ua79f\ua7a0\ua7a1\ua7a2\ua7a3\ua7a4\ua7a5\ua7a6\ua7a7\ua7a8\ua7a9\ua7aa\ua7ab\ua7ac\ua7ad\ua7ae\ua7b0\ua7b1\ua7b2\ua7b3\ua7b4\ua7b5\ua7b6\ua7b7\ua7f7\ua7f8\ua7f9\ua7fa\ua7fb\ua7fc\ua7fd\ua7fe\ua7ff\ua800\ua801\ua802\ua803\ua804\ua805\ua806\ua807\ua808\ua809\ua80a\ua80b\ua80c\ua80d\ua80e\ua80f\ua810\ua811\ua812\ua813\ua814\ua815\ua816\ua817\ua818\ua819\ua81a\ua81b\ua81c\ua81d\ua81e\ua81f\ua820\ua821\ua822\ua823\ua824\ua825\ua826\ua827\ua840\ua841\ua842\ua843\ua844\ua845\ua846\ua847\ua848\ua849\ua84a\ua84b\ua84c\ua84d\ua84e\ua84f\ua850\ua851\ua852\ua853\ua854\ua855\ua856\ua857\ua858\ua859\ua85a\ua85b\ua85c\ua85d\ua85e\ua85f\ua860\ua861\ua862\ua863\ua864\ua865\ua866\ua867\ua868\ua869\ua86a\ua86b\ua86c\ua86d\ua86e\ua86f\ua870\ua871\ua872\ua873\ua880\ua881\ua882\ua883\ua884\ua885\ua886\ua887\ua888\ua889\ua88a\ua88b\ua88c\ua88d\ua88e\ua88f\ua890\ua891\ua892\ua893\ua894\ua895\ua896\ua897\ua898\ua899\ua89a\ua89b\ua89c\ua89d\ua89e\ua89f\ua8a0\ua8a1\ua8a2\ua8a3\ua8a4\ua8a5\ua8a6\ua8a7\ua8a8\ua8a9\ua8aa\ua8ab\ua8ac\ua8ad\ua8ae\ua8af\ua8b0\ua8b1\ua8b2\ua8b3\ua8b4\ua8b5\ua8b6\ua8b7\ua8b8\ua8b9\ua8ba\ua8bb\ua8bc\ua8bd\ua8be\ua8bf\ua8c0\ua8c1\ua8c2\ua8c3\ua8c4\ua8c5\ua8d0\ua8d1\ua8d2\ua8d3\ua8d4\ua8d5\ua8d6\ua8d7\ua8d8\ua8d9\ua8e0\ua8e1\ua8e2\ua8e3\ua8e4\ua8e5\ua8e6\ua8e7\ua8e8\ua8e9\ua8ea\ua8eb\ua8ec\ua8ed\ua8ee\ua8ef\ua8f0\ua8f1\ua8f2\ua8f3\ua8f4\ua8f5\ua8f6\ua8f7\ua8fb\ua8fd\ua900\ua901\ua902\ua903\ua904\ua905\ua906\ua907\ua908\ua909\ua90a\ua90b\ua90c\ua90d\ua90e\ua90f\ua910\ua911\ua912\ua913\ua914\ua915\ua916\ua917\ua918\ua919\ua91a\ua91b\ua91c\ua91d\ua91e\ua91f\ua920\ua921\ua922\ua923\ua924\ua925\ua926\ua927\ua928\ua929\ua92a\ua92b\ua92c\ua92d\ua930\ua931\ua932\ua933\ua934\ua935\ua936\ua937\ua938\ua939\ua93a\ua93b\ua93c\ua93d\ua93e\ua93f\ua940\ua941\ua942\ua943\ua944\ua945\ua946\ua947\ua948\ua949\ua94a\ua94b\ua94c\ua94d\ua94e\ua94f\ua950\ua951\ua952\ua953\ua960\ua961\ua962\ua963\ua964\ua965\ua966\ua967\ua968\ua969\ua96a\ua96b\ua96c\ua96d\ua96e\ua96f\ua970\ua971\ua972\ua973\ua974\ua975\ua976\ua977\ua978\ua979\ua97a\ua97b\ua97c\ua980\ua981\ua982\ua983\ua984\ua985\ua986\ua987\ua988\ua989\ua98a\ua98b\ua98c\ua98d\ua98e\ua98f\ua990\ua991\ua992\ua993\ua994\ua995\ua996\ua997\ua998\ua999\ua99a\ua99b\ua99c\ua99d\ua99e\ua99f\ua9a0\ua9a1\ua9a2\ua9a3\ua9a4\ua9a5\ua9a6\ua9a7\ua9a8\ua9a9\ua9aa\ua9ab\ua9ac\ua9ad\ua9ae\ua9af\ua9b0\ua9b1\ua9b2\ua9b3\ua9b4\ua9b5\ua9b6\ua9b7\ua9b8\ua9b9\ua9ba\ua9bb\ua9bc\ua9bd\ua9be\ua9bf\ua9c0\ua9cf\ua9d0\ua9d1\ua9d2\ua9d3\ua9d4\ua9d5\ua9d6\ua9d7\ua9d8\ua9d9\ua9e0\ua9e1\ua9e2\ua9e3\ua9e4\ua9e5\ua9e6\ua9e7\ua9e8\ua9e9\ua9ea\ua9eb\ua9ec\ua9ed\ua9ee\ua9ef\ua9f0\ua9f1\ua9f2\ua9f3\ua9f4\ua9f5\ua9f6\ua9f7\ua9f8\ua9f9\ua9fa\ua9fb\ua9fc\ua9fd\ua9fe\uaa00\uaa01\uaa02\uaa03\uaa04\uaa05\uaa06\uaa07\uaa08\uaa09\uaa0a\uaa0b\uaa0c\uaa0d\uaa0e\uaa0f\uaa10\uaa11\uaa12\uaa13\uaa14\uaa15\uaa16\uaa17\uaa18\uaa19\uaa1a\uaa1b\uaa1c\uaa1d\uaa1e\uaa1f\uaa20\uaa21\uaa22\uaa23\uaa24\uaa25\uaa26\uaa27\uaa28\uaa29\uaa2a\uaa2b\uaa2c\uaa2d\uaa2e\uaa2f\uaa30\uaa31\uaa32\uaa33\uaa34\uaa35\uaa36\uaa40\uaa41\uaa42\uaa43\uaa44\uaa45\uaa46\uaa47\uaa48\uaa49\uaa4a\uaa4b\uaa4c\uaa4d\uaa50\uaa51\uaa52\uaa53\uaa54\uaa55\uaa56\uaa57\uaa58\uaa59\uaa60\uaa61\uaa62\uaa63\uaa64\uaa65\uaa66\uaa67\uaa68\uaa69\uaa6a\uaa6b\uaa6c\uaa6d\uaa6e\uaa6f\uaa70\uaa71\uaa72\uaa73\uaa74\uaa75\uaa76\uaa7a\uaa7b\uaa7c\uaa7d\uaa7e\uaa7f\uaa80\uaa81\uaa82\uaa83\uaa84\uaa85\uaa86\uaa87\uaa88\uaa89\uaa8a\uaa8b\uaa8c\uaa8d\uaa8e\uaa8f\uaa90\uaa91\uaa92\uaa93\uaa94\uaa95\uaa96\uaa97\uaa98\uaa99\uaa9a\uaa9b\uaa9c\uaa9d\uaa9e\uaa9f\uaaa0\uaaa1\uaaa2\uaaa3\uaaa4\uaaa5\uaaa6\uaaa7\uaaa8\uaaa9\uaaaa\uaaab\uaaac\uaaad\uaaae\uaaaf\uaab0\uaab1\uaab2\uaab3\uaab4\uaab5\uaab6\uaab7\uaab8\uaab9\uaaba\uaabb\uaabc\uaabd\uaabe\uaabf\uaac0\uaac1\uaac2\uaadb\uaadc\uaadd\uaae0\uaae1\uaae2\uaae3\uaae4\uaae5\uaae6\uaae7\uaae8\uaae9\uaaea\uaaeb\uaaec\uaaed\uaaee\uaaef\uaaf2\uaaf3\uaaf4\uaaf5\uaaf6\uab01\uab02\uab03\uab04\uab05\uab06\uab09\uab0a\uab0b\uab0c\uab0d\uab0e\uab11\uab12\uab13\uab14\uab15\uab16\uab20\uab21\uab22\uab23\uab24\uab25\uab26\uab28\uab29\uab2a\uab2b\uab2c\uab2d\uab2e\uab30\uab31\uab32\uab33\uab34\uab35\uab36\uab37\uab38\uab39\uab3a\uab3b\uab3c\uab3d\uab3e\uab3f\uab40\uab41\uab42\uab43\uab44\uab45\uab46\uab47\uab48\uab49\uab4a\uab4b\uab4c\uab4d\uab4e\uab4f\uab50\uab51\uab52\uab53\uab54\uab55\uab56\uab57\uab58\uab59\uab5a\uab5c\uab5d\uab5e\uab5f\uab60\uab61\uab62\uab63\uab64\uab65\uab70\uab71\uab72\uab73\uab74\uab75\uab76\uab77\uab78\uab79\uab7a\uab7b\uab7c\uab7d\uab7e\uab7f\uab80\uab81\uab82\uab83\uab84\uab85\uab86\uab87\uab88\uab89\uab8a\uab8b\uab8c\uab8d\uab8e\uab8f\uab90\uab91\uab92\uab93\uab94\uab95\uab96\uab97\uab98\uab99\uab9a\uab9b\uab9c\uab9d\uab9e\uab9f\uaba0\uaba1\uaba2\uaba3\uaba4\uaba5\uaba6\uaba7\uaba8\uaba9\uabaa\uabab\uabac\uabad\uabae\uabaf\uabb0\uabb1\uabb2\uabb3\uabb4\uabb5\uabb6\uabb7\uabb8\uabb9\uabba\uabbb\uabbc\uabbd\uabbe\uabbf\uabc0\uabc1\uabc2\uabc3\uabc4\uabc5\uabc6\uabc7\uabc8\uabc9\uabca\uabcb\uabcc\uabcd\uabce\uabcf\uabd0\uabd1\uabd2\uabd3\uabd4\uabd5\uabd6\uabd7\uabd8\uabd9\uabda\uabdb\uabdc\uabdd\uabde\uabdf\uabe0\uabe1\uabe2\uabe3\uabe4\uabe5\uabe6\uabe7\uabe8\uabe9\uabea\uabec\uabed\uabf0\uabf1\uabf2\uabf3\uabf4\uabf5\uabf6\uabf7\uabf8\uabf9\uac00\uac01\uac02\uac03\uac04\uac05\uac06\uac07\uac08\uac09\uac0a\uac0b\uac0c\uac0d\uac0e\uac0f\uac10\uac11\uac12\uac13\uac14\uac15\uac16\uac17\uac18\uac19\uac1a\uac1b\uac1c\uac1d\uac1e\uac1f\uac20\uac21\uac22\uac23\uac24\uac25\uac26\uac27\uac28\uac29\uac2a\uac2b\uac2c\uac2d\uac2e\uac2f\uac30\uac31\uac32\uac33\uac34\uac35\uac36\uac37\uac38\uac39\uac3a\uac3b\uac3c\uac3d\uac3e\uac3f\uac40\uac41\uac42\uac43\uac44\uac45\uac46\uac47\uac48\uac49\uac4a\uac4b\uac4c\uac4d\uac4e\uac4f\uac50\uac51\uac52\uac53\uac54\uac55\uac56\uac57\uac58\uac59\uac5a\uac5b\uac5c\uac5d\uac5e\uac5f\uac60\uac61\uac62\uac63\uac64\uac65\uac66\uac67\uac68\uac69\uac6a\uac6b\uac6c\uac6d\uac6e\uac6f\uac70\uac71\uac72\uac73\uac74\uac75\uac76\uac77\uac78\uac79\uac7a\uac7b\uac7c\uac7d\uac7e\uac7f\uac80\uac81\uac82\uac83\uac84\uac85\uac86\uac87\uac88\uac89\uac8a\uac8b\uac8c\uac8d\uac8e\uac8f\uac90\uac91\uac92\uac93\uac94\uac95\uac96\uac97\uac98\uac99\uac9a\uac9b\uac9c\uac9d\uac9e\uac9f\uaca0\uaca1\uaca2\uaca3\uaca4\uaca5\uaca6\uaca7\uaca8\uaca9\uacaa\uacab\uacac\uacad\uacae\uacaf\uacb0\uacb1\uacb2\uacb3\uacb4\uacb5\uacb6\uacb7\uacb8\uacb9\uacba\uacbb\uacbc\uacbd\uacbe\uacbf\uacc0\uacc1\uacc2\uacc3\uacc4\uacc5\uacc6\uacc7\uacc8\uacc9\uacca\uaccb\uaccc\uaccd\uacce\uaccf\uacd0\uacd1\uacd2\uacd3\uacd4\uacd5\uacd6\uacd7\uacd8\uacd9\uacda\uacdb\uacdc\uacdd\uacde\uacdf\uace0\uace1\uace2\uace3\uace4\uace5\uace6\uace7\uace8\uace9\uacea\uaceb\uacec\uaced\uacee\uacef\uacf0\uacf1\uacf2\uacf3\uacf4\uacf5\uacf6\uacf7\uacf8\uacf9\uacfa\uacfb\uacfc\uacfd\uacfe\uacff\uad00\uad01\uad02\uad03\uad04\uad05\uad06\uad07\uad08\uad09\uad0a\uad0b\uad0c\uad0d\uad0e\uad0f\uad10\uad11\uad12\uad13\uad14\uad15\uad16\uad17\uad18\uad19\uad1a\uad1b\uad1c\uad1d\uad1e\uad1f\uad20\uad21\uad22\uad23\uad24\uad25\uad26\uad27\uad28\uad29\uad2a\uad2b\uad2c\uad2d\uad2e\uad2f\uad30\uad31\uad32\uad33\uad34\uad35\uad36\uad37\uad38\uad39\uad3a\uad3b\uad3c\uad3d\uad3e\uad3f\uad40\uad41\uad42\uad43\uad44\uad45\uad46\uad47\uad48\uad49\uad4a\uad4b\uad4c\uad4d\uad4e\uad4f\uad50\uad51\uad52\uad53\uad54\uad55\uad56\uad57\uad58\uad59\uad5a\uad5b\uad5c\uad5d\uad5e\uad5f\uad60\uad61\uad62\uad63\uad64\uad65\uad66\uad67\uad68\uad69\uad6a\uad6b\uad6c\uad6d\uad6e\uad6f\uad70\uad71\uad72\uad73\uad74\uad75\uad76\uad77\uad78\uad79\uad7a\uad7b\uad7c\uad7d\uad7e\uad7f\uad80\uad81\uad82\uad83\uad84\uad85\uad86\uad87\uad88\uad89\uad8a\uad8b\uad8c\uad8d\uad8e\uad8f\uad90\uad91\uad92\uad93\uad94\uad95\uad96\uad97\uad98\uad99\uad9a\uad9b\uad9c\uad9d\uad9e\uad9f\uada0\uada1\uada2\uada3\uada4\uada5\uada6\uada7\uada8\uada9\uadaa\uadab\uadac\uadad\uadae\uadaf\uadb0\uadb1\uadb2\uadb3\uadb4\uadb5\uadb6\uadb7\uadb8\uadb9\uadba\uadbb\uadbc\uadbd\uadbe\uadbf\uadc0\uadc1\uadc2\uadc3\uadc4\uadc5\uadc6\uadc7\uadc8\uadc9\uadca\uadcb\uadcc\uadcd\uadce\uadcf\uadd0\uadd1\uadd2\uadd3\uadd4\uadd5\uadd6\uadd7\uadd8\uadd9\uadda\uaddb\uaddc\uaddd\uadde\uaddf\uade0\uade1\uade2\uade3\uade4\uade5\uade6\uade7\uade8\uade9\uadea\uadeb\uadec\uaded\uadee\uadef\uadf0\uadf1\uadf2\uadf3\uadf4\uadf5\uadf6\uadf7\uadf8\uadf9\uadfa\uadfb\uadfc\uadfd\uadfe\uadff\uae00\uae01\uae02\uae03\uae04\uae05\uae06\uae07\uae08\uae09\uae0a\uae0b\uae0c\uae0d\uae0e\uae0f\uae10\uae11\uae12\uae13\uae14\uae15\uae16\uae17\uae18\uae19\uae1a\uae1b\uae1c\uae1d\uae1e\uae1f\uae20\uae21\uae22\uae23\uae24\uae25\uae26\uae27\uae28\uae29\uae2a\uae2b\uae2c\uae2d\uae2e\uae2f\uae30\uae31\uae32\uae33\uae34\uae35\uae36\uae37\uae38\uae39\uae3a\uae3b\uae3c\uae3d\uae3e\uae3f\uae40\uae41\uae42\uae43\uae44\uae45\uae46\uae47\uae48\uae49\uae4a\uae4b\uae4c\uae4d\uae4e\uae4f\uae50\uae51\uae52\uae53\uae54\uae55\uae56\uae57\uae58\uae59\uae5a\uae5b\uae5c\uae5d\uae5e\uae5f\uae60\uae61\uae62\uae63\uae64\uae65\uae66\uae67\uae68\uae69\uae6a\uae6b\uae6c\uae6d\uae6e\uae6f\uae70\uae71\uae72\uae73\uae74\uae75\uae76\uae77\uae78\uae79\uae7a\uae7b\uae7c\uae7d\uae7e\uae7f\uae80\uae81\uae82\uae83\uae84\uae85\uae86\uae87\uae88\uae89\uae8a\uae8b\uae8c\uae8d\uae8e\uae8f\uae90\uae91\uae92\uae93\uae94\uae95\uae96\uae97\uae98\uae99\uae9a\uae9b\uae9c\uae9d\uae9e\uae9f\uaea0\uaea1\uaea2\uaea3\uaea4\uaea5\uaea6\uaea7\uaea8\uaea9\uaeaa\uaeab\uaeac\uaead\uaeae\uaeaf\uaeb0\uaeb1\uaeb2\uaeb3\uaeb4\uaeb5\uaeb6\uaeb7\uaeb8\uaeb9\uaeba\uaebb\uaebc\uaebd\uaebe\uaebf\uaec0\uaec1\uaec2\uaec3\uaec4\uaec5\uaec6\uaec7\uaec8\uaec9\uaeca\uaecb\uaecc\uaecd\uaece\uaecf\uaed0\uaed1\uaed2\uaed3\uaed4\uaed5\uaed6\uaed7\uaed8\uaed9\uaeda\uaedb\uaedc\uaedd\uaede\uaedf\uaee0\uaee1\uaee2\uaee3\uaee4\uaee5\uaee6\uaee7\uaee8\uaee9\uaeea\uaeeb\uaeec\uaeed\uaeee\uaeef\uaef0\uaef1\uaef2\uaef3\uaef4\uaef5\uaef6\uaef7\uaef8\uaef9\uaefa\uaefb\uaefc\uaefd\uaefe\uaeff\uaf00\uaf01\uaf02\uaf03\uaf04\uaf05\uaf06\uaf07\uaf08\uaf09\uaf0a\uaf0b\uaf0c\uaf0d\uaf0e\uaf0f\uaf10\uaf11\uaf12\uaf13\uaf14\uaf15\uaf16\uaf17\uaf18\uaf19\uaf1a\uaf1b\uaf1c\uaf1d\uaf1e\uaf1f\uaf20\uaf21\uaf22\uaf23\uaf24\uaf25\uaf26\uaf27\uaf28\uaf29\uaf2a\uaf2b\uaf2c\uaf2d\uaf2e\uaf2f\uaf30\uaf31\uaf32\uaf33\uaf34\uaf35\uaf36\uaf37\uaf38\uaf39\uaf3a\uaf3b\uaf3c\uaf3d\uaf3e\uaf3f\uaf40\uaf41\uaf42\uaf43\uaf44\uaf45\uaf46\uaf47\uaf48\uaf49\uaf4a\uaf4b\uaf4c\uaf4d\uaf4e\uaf4f\uaf50\uaf51\uaf52\uaf53\uaf54\uaf55\uaf56\uaf57\uaf58\uaf59\uaf5a\uaf5b\uaf5c\uaf5d\uaf5e\uaf5f\uaf60\uaf61\uaf62\uaf63\uaf64\uaf65\uaf66\uaf67\uaf68\uaf69\uaf6a\uaf6b\uaf6c\uaf6d\uaf6e\uaf6f\uaf70\uaf71\uaf72\uaf73\uaf74\uaf75\uaf76\uaf77\uaf78\uaf79\uaf7a\uaf7b\uaf7c\uaf7d\uaf7e\uaf7f\uaf80\uaf81\uaf82\uaf83\uaf84\uaf85\uaf86\uaf87\uaf88\uaf89\uaf8a\uaf8b\uaf8c\uaf8d\uaf8e\uaf8f\uaf90\uaf91\uaf92\uaf93\uaf94\uaf95\uaf96\uaf97\uaf98\uaf99\uaf9a\uaf9b\uaf9c\uaf9d\uaf9e\uaf9f\uafa0\uafa1\uafa2\uafa3\uafa4\uafa5\uafa6\uafa7\uafa8\uafa9\uafaa\uafab\uafac\uafad\uafae\uafaf\uafb0\uafb1\uafb2\uafb3\uafb4\uafb5\uafb6\uafb7\uafb8\uafb9\uafba\uafbb\uafbc\uafbd\uafbe\uafbf\uafc0\uafc1\uafc2\uafc3\uafc4\uafc5\uafc6\uafc7\uafc8\uafc9\uafca\uafcb\uafcc\uafcd\uafce\uafcf\uafd0\uafd1\uafd2\uafd3\uafd4\uafd5\uafd6\uafd7\uafd8\uafd9\uafda\uafdb\uafdc\uafdd\uafde\uafdf\uafe0\uafe1\uafe2\uafe3\uafe4\uafe5\uafe6\uafe7\uafe8\uafe9\uafea\uafeb\uafec\uafed\uafee\uafef\uaff0\uaff1\uaff2\uaff3\uaff4\uaff5\uaff6\uaff7\uaff8\uaff9\uaffa\uaffb\uaffc\uaffd\uaffe\uafff\ub000\ub001\ub002\ub003\ub004\ub005\ub006\ub007\ub008\ub009\ub00a\ub00b\ub00c\ub00d\ub00e\ub00f\ub010\ub011\ub012\ub013\ub014\ub015\ub016\ub017\ub018\ub019\ub01a\ub01b\ub01c\ub01d\ub01e\ub01f\ub020\ub021\ub022\ub023\ub024\ub025\ub026\ub027\ub028\ub029\ub02a\ub02b\ub02c\ub02d\ub02e\ub02f\ub030\ub031\ub032\ub033\ub034\ub035\ub036\ub037\ub038\ub039\ub03a\ub03b\ub03c\ub03d\ub03e\ub03f\ub040\ub041\ub042\ub043\ub044\ub045\ub046\ub047\ub048\ub049\ub04a\ub04b\ub04c\ub04d\ub04e\ub04f\ub050\ub051\ub052\ub053\ub054\ub055\ub056\ub057\ub058\ub059\ub05a\ub05b\ub05c\ub05d\ub05e\ub05f\ub060\ub061\ub062\ub063\ub064\ub065\ub066\ub067\ub068\ub069\ub06a\ub06b\ub06c\ub06d\ub06e\ub06f\ub070\ub071\ub072\ub073\ub074\ub075\ub076\ub077\ub078\ub079\ub07a\ub07b\ub07c\ub07d\ub07e\ub07f\ub080\ub081\ub082\ub083\ub084\ub085\ub086\ub087\ub088\ub089\ub08a\ub08b\ub08c\ub08d\ub08e\ub08f\ub090\ub091\ub092\ub093\ub094\ub095\ub096\ub097\ub098\ub099\ub09a\ub09b\ub09c\ub09d\ub09e\ub09f\ub0a0\ub0a1\ub0a2\ub0a3\ub0a4\ub0a5\ub0a6\ub0a7\ub0a8\ub0a9\ub0aa\ub0ab\ub0ac\ub0ad\ub0ae\ub0af\ub0b0\ub0b1\ub0b2\ub0b3\ub0b4\ub0b5\ub0b6\ub0b7\ub0b8\ub0b9\ub0ba\ub0bb\ub0bc\ub0bd\ub0be\ub0bf\ub0c0\ub0c1\ub0c2\ub0c3\ub0c4\ub0c5\ub0c6\ub0c7\ub0c8\ub0c9\ub0ca\ub0cb\ub0cc\ub0cd\ub0ce\ub0cf\ub0d0\ub0d1\ub0d2\ub0d3\ub0d4\ub0d5\ub0d6\ub0d7\ub0d8\ub0d9\ub0da\ub0db\ub0dc\ub0dd\ub0de\ub0df\ub0e0\ub0e1\ub0e2\ub0e3\ub0e4\ub0e5\ub0e6\ub0e7\ub0e8\ub0e9\ub0ea\ub0eb\ub0ec\ub0ed\ub0ee\ub0ef\ub0f0\ub0f1\ub0f2\ub0f3\ub0f4\ub0f5\ub0f6\ub0f7\ub0f8\ub0f9\ub0fa\ub0fb\ub0fc\ub0fd\ub0fe\ub0ff\ub100\ub101\ub102\ub103\ub104\ub105\ub106\ub107\ub108\ub109\ub10a\ub10b\ub10c\ub10d\ub10e\ub10f\ub110\ub111\ub112\ub113\ub114\ub115\ub116\ub117\ub118\ub119\ub11a\ub11b\ub11c\ub11d\ub11e\ub11f\ub120\ub121\ub122\ub123\ub124\ub125\ub126\ub127\ub128\ub129\ub12a\ub12b\ub12c\ub12d\ub12e\ub12f\ub130\ub131\ub132\ub133\ub134\ub135\ub136\ub137\ub138\ub139\ub13a\ub13b\ub13c\ub13d\ub13e\ub13f\ub140\ub141\ub142\ub143\ub144\ub145\ub146\ub147\ub148\ub149\ub14a\ub14b\ub14c\ub14d\ub14e\ub14f\ub150\ub151\ub152\ub153\ub154\ub155\ub156\ub157\ub158\ub159\ub15a\ub15b\ub15c\ub15d\ub15e\ub15f\ub160\ub161\ub162\ub163\ub164\ub165\ub166\ub167\ub168\ub169\ub16a\ub16b\ub16c\ub16d\ub16e\ub16f\ub170\ub171\ub172\ub173\ub174\ub175\ub176\ub177\ub178\ub179\ub17a\ub17b\ub17c\ub17d\ub17e\ub17f\ub180\ub181\ub182\ub183\ub184\ub185\ub186\ub187\ub188\ub189\ub18a\ub18b\ub18c\ub18d\ub18e\ub18f\ub190\ub191\ub192\ub193\ub194\ub195\ub196\ub197\ub198\ub199\ub19a\ub19b\ub19c\ub19d\ub19e\ub19f\ub1a0\ub1a1\ub1a2\ub1a3\ub1a4\ub1a5\ub1a6\ub1a7\ub1a8\ub1a9\ub1aa\ub1ab\ub1ac\ub1ad\ub1ae\ub1af\ub1b0\ub1b1\ub1b2\ub1b3\ub1b4\ub1b5\ub1b6\ub1b7\ub1b8\ub1b9\ub1ba\ub1bb\ub1bc\ub1bd\ub1be\ub1bf\ub1c0\ub1c1\ub1c2\ub1c3\ub1c4\ub1c5\ub1c6\ub1c7\ub1c8\ub1c9\ub1ca\ub1cb\ub1cc\ub1cd\ub1ce\ub1cf\ub1d0\ub1d1\ub1d2\ub1d3\ub1d4\ub1d5\ub1d6\ub1d7\ub1d8\ub1d9\ub1da\ub1db\ub1dc\ub1dd\ub1de\ub1df\ub1e0\ub1e1\ub1e2\ub1e3\ub1e4\ub1e5\ub1e6\ub1e7\ub1e8\ub1e9\ub1ea\ub1eb\ub1ec\ub1ed\ub1ee\ub1ef\ub1f0\ub1f1\ub1f2\ub1f3\ub1f4\ub1f5\ub1f6\ub1f7\ub1f8\ub1f9\ub1fa\ub1fb\ub1fc\ub1fd\ub1fe\ub1ff\ub200\ub201\ub202\ub203\ub204\ub205\ub206\ub207\ub208\ub209\ub20a\ub20b\ub20c\ub20d\ub20e\ub20f\ub210\ub211\ub212\ub213\ub214\ub215\ub216\ub217\ub218\ub219\ub21a\ub21b\ub21c\ub21d\ub21e\ub21f\ub220\ub221\ub222\ub223\ub224\ub225\ub226\ub227\ub228\ub229\ub22a\ub22b\ub22c\ub22d\ub22e\ub22f\ub230\ub231\ub232\ub233\ub234\ub235\ub236\ub237\ub238\ub239\ub23a\ub23b\ub23c\ub23d\ub23e\ub23f\ub240\ub241\ub242\ub243\ub244\ub245\ub246\ub247\ub248\ub249\ub24a\ub24b\ub24c\ub24d\ub24e\ub24f\ub250\ub251\ub252\ub253\ub254\ub255\ub256\ub257\ub258\ub259\ub25a\ub25b\ub25c\ub25d\ub25e\ub25f\ub260\ub261\ub262\ub263\ub264\ub265\ub266\ub267\ub268\ub269\ub26a\ub26b\ub26c\ub26d\ub26e\ub26f\ub270\ub271\ub272\ub273\ub274\ub275\ub276\ub277\ub278\ub279\ub27a\ub27b\ub27c\ub27d\ub27e\ub27f\ub280\ub281\ub282\ub283\ub284\ub285\ub286\ub287\ub288\ub289\ub28a\ub28b\ub28c\ub28d\ub28e\ub28f\ub290\ub291\ub292\ub293\ub294\ub295\ub296\ub297\ub298\ub299\ub29a\ub29b\ub29c\ub29d\ub29e\ub29f\ub2a0\ub2a1\ub2a2\ub2a3\ub2a4\ub2a5\ub2a6\ub2a7\ub2a8\ub2a9\ub2aa\ub2ab\ub2ac\ub2ad\ub2ae\ub2af\ub2b0\ub2b1\ub2b2\ub2b3\ub2b4\ub2b5\ub2b6\ub2b7\ub2b8\ub2b9\ub2ba\ub2bb\ub2bc\ub2bd\ub2be\ub2bf\ub2c0\ub2c1\ub2c2\ub2c3\ub2c4\ub2c5\ub2c6\ub2c7\ub2c8\ub2c9\ub2ca\ub2cb\ub2cc\ub2cd\ub2ce\ub2cf\ub2d0\ub2d1\ub2d2\ub2d3\ub2d4\ub2d5\ub2d6\ub2d7\ub2d8\ub2d9\ub2da\ub2db\ub2dc\ub2dd\ub2de\ub2df\ub2e0\ub2e1\ub2e2\ub2e3\ub2e4\ub2e5\ub2e6\ub2e7\ub2e8\ub2e9\ub2ea\ub2eb\ub2ec\ub2ed\ub2ee\ub2ef\ub2f0\ub2f1\ub2f2\ub2f3\ub2f4\ub2f5\ub2f6\ub2f7\ub2f8\ub2f9\ub2fa\ub2fb\ub2fc\ub2fd\ub2fe\ub2ff\ub300\ub301\ub302\ub303\ub304\ub305\ub306\ub307\ub308\ub309\ub30a\ub30b\ub30c\ub30d\ub30e\ub30f\ub310\ub311\ub312\ub313\ub314\ub315\ub316\ub317\ub318\ub319\ub31a\ub31b\ub31c\ub31d\ub31e\ub31f\ub320\ub321\ub322\ub323\ub324\ub325\ub326\ub327\ub328\ub329\ub32a\ub32b\ub32c\ub32d\ub32e\ub32f\ub330\ub331\ub332\ub333\ub334\ub335\ub336\ub337\ub338\ub339\ub33a\ub33b\ub33c\ub33d\ub33e\ub33f\ub340\ub341\ub342\ub343\ub344\ub345\ub346\ub347\ub348\ub349\ub34a\ub34b\ub34c\ub34d\ub34e\ub34f\ub350\ub351\ub352\ub353\ub354\ub355\ub356\ub357\ub358\ub359\ub35a\ub35b\ub35c\ub35d\ub35e\ub35f\ub360\ub361\ub362\ub363\ub364\ub365\ub366\ub367\ub368\ub369\ub36a\ub36b\ub36c\ub36d\ub36e\ub36f\ub370\ub371\ub372\ub373\ub374\ub375\ub376\ub377\ub378\ub379\ub37a\ub37b\ub37c\ub37d\ub37e\ub37f\ub380\ub381\ub382\ub383\ub384\ub385\ub386\ub387\ub388\ub389\ub38a\ub38b\ub38c\ub38d\ub38e\ub38f\ub390\ub391\ub392\ub393\ub394\ub395\ub396\ub397\ub398\ub399\ub39a\ub39b\ub39c\ub39d\ub39e\ub39f\ub3a0\ub3a1\ub3a2\ub3a3\ub3a4\ub3a5\ub3a6\ub3a7\ub3a8\ub3a9\ub3aa\ub3ab\ub3ac\ub3ad\ub3ae\ub3af\ub3b0\ub3b1\ub3b2\ub3b3\ub3b4\ub3b5\ub3b6\ub3b7\ub3b8\ub3b9\ub3ba\ub3bb\ub3bc\ub3bd\ub3be\ub3bf\ub3c0\ub3c1\ub3c2\ub3c3\ub3c4\ub3c5\ub3c6\ub3c7\ub3c8\ub3c9\ub3ca\ub3cb\ub3cc\ub3cd\ub3ce\ub3cf\ub3d0\ub3d1\ub3d2\ub3d3\ub3d4\ub3d5\ub3d6\ub3d7\ub3d8\ub3d9\ub3da\ub3db\ub3dc\ub3dd\ub3de\ub3df\ub3e0\ub3e1\ub3e2\ub3e3\ub3e4\ub3e5\ub3e6\ub3e7\ub3e8\ub3e9\ub3ea\ub3eb\ub3ec\ub3ed\ub3ee\ub3ef\ub3f0\ub3f1\ub3f2\ub3f3\ub3f4\ub3f5\ub3f6\ub3f7\ub3f8\ub3f9\ub3fa\ub3fb\ub3fc\ub3fd\ub3fe\ub3ff\ub400\ub401\ub402\ub403\ub404\ub405\ub406\ub407\ub408\ub409\ub40a\ub40b\ub40c\ub40d\ub40e\ub40f\ub410\ub411\ub412\ub413\ub414\ub415\ub416\ub417\ub418\ub419\ub41a\ub41b\ub41c\ub41d\ub41e\ub41f\ub420\ub421\ub422\ub423\ub424\ub425\ub426\ub427\ub428\ub429\ub42a\ub42b\ub42c\ub42d\ub42e\ub42f\ub430\ub431\ub432\ub433\ub434\ub435\ub436\ub437\ub438\ub439\ub43a\ub43b\ub43c\ub43d\ub43e\ub43f\ub440\ub441\ub442\ub443\ub444\ub445\ub446\ub447\ub448\ub449\ub44a\ub44b\ub44c\ub44d\ub44e\ub44f\ub450\ub451\ub452\ub453\ub454\ub455\ub456\ub457\ub458\ub459\ub45a\ub45b\ub45c\ub45d\ub45e\ub45f\ub460\ub461\ub462\ub463\ub464\ub465\ub466\ub467\ub468\ub469\ub46a\ub46b\ub46c\ub46d\ub46e\ub46f\ub470\ub471\ub472\ub473\ub474\ub475\ub476\ub477\ub478\ub479\ub47a\ub47b\ub47c\ub47d\ub47e\ub47f\ub480\ub481\ub482\ub483\ub484\ub485\ub486\ub487\ub488\ub489\ub48a\ub48b\ub48c\ub48d\ub48e\ub48f\ub490\ub491\ub492\ub493\ub494\ub495\ub496\ub497\ub498\ub499\ub49a\ub49b\ub49c\ub49d\ub49e\ub49f\ub4a0\ub4a1\ub4a2\ub4a3\ub4a4\ub4a5\ub4a6\ub4a7\ub4a8\ub4a9\ub4aa\ub4ab\ub4ac\ub4ad\ub4ae\ub4af\ub4b0\ub4b1\ub4b2\ub4b3\ub4b4\ub4b5\ub4b6\ub4b7\ub4b8\ub4b9\ub4ba\ub4bb\ub4bc\ub4bd\ub4be\ub4bf\ub4c0\ub4c1\ub4c2\ub4c3\ub4c4\ub4c5\ub4c6\ub4c7\ub4c8\ub4c9\ub4ca\ub4cb\ub4cc\ub4cd\ub4ce\ub4cf\ub4d0\ub4d1\ub4d2\ub4d3\ub4d4\ub4d5\ub4d6\ub4d7\ub4d8\ub4d9\ub4da\ub4db\ub4dc\ub4dd\ub4de\ub4df\ub4e0\ub4e1\ub4e2\ub4e3\ub4e4\ub4e5\ub4e6\ub4e7\ub4e8\ub4e9\ub4ea\ub4eb\ub4ec\ub4ed\ub4ee\ub4ef\ub4f0\ub4f1\ub4f2\ub4f3\ub4f4\ub4f5\ub4f6\ub4f7\ub4f8\ub4f9\ub4fa\ub4fb\ub4fc\ub4fd\ub4fe\ub4ff\ub500\ub501\ub502\ub503\ub504\ub505\ub506\ub507\ub508\ub509\ub50a\ub50b\ub50c\ub50d\ub50e\ub50f\ub510\ub511\ub512\ub513\ub514\ub515\ub516\ub517\ub518\ub519\ub51a\ub51b\ub51c\ub51d\ub51e\ub51f\ub520\ub521\ub522\ub523\ub524\ub525\ub526\ub527\ub528\ub529\ub52a\ub52b\ub52c\ub52d\ub52e\ub52f\ub530\ub531\ub532\ub533\ub534\ub535\ub536\ub537\ub538\ub539\ub53a\ub53b\ub53c\ub53d\ub53e\ub53f\ub540\ub541\ub542\ub543\ub544\ub545\ub546\ub547\ub548\ub549\ub54a\ub54b\ub54c\ub54d\ub54e\ub54f\ub550\ub551\ub552\ub553\ub554\ub555\ub556\ub557\ub558\ub559\ub55a\ub55b\ub55c\ub55d\ub55e\ub55f\ub560\ub561\ub562\ub563\ub564\ub565\ub566\ub567\ub568\ub569\ub56a\ub56b\ub56c\ub56d\ub56e\ub56f\ub570\ub571\ub572\ub573\ub574\ub575\ub576\ub577\ub578\ub579\ub57a\ub57b\ub57c\ub57d\ub57e\ub57f\ub580\ub581\ub582\ub583\ub584\ub585\ub586\ub587\ub588\ub589\ub58a\ub58b\ub58c\ub58d\ub58e\ub58f\ub590\ub591\ub592\ub593\ub594\ub595\ub596\ub597\ub598\ub599\ub59a\ub59b\ub59c\ub59d\ub59e\ub59f\ub5a0\ub5a1\ub5a2\ub5a3\ub5a4\ub5a5\ub5a6\ub5a7\ub5a8\ub5a9\ub5aa\ub5ab\ub5ac\ub5ad\ub5ae\ub5af\ub5b0\ub5b1\ub5b2\ub5b3\ub5b4\ub5b5\ub5b6\ub5b7\ub5b8\ub5b9\ub5ba\ub5bb\ub5bc\ub5bd\ub5be\ub5bf\ub5c0\ub5c1\ub5c2\ub5c3\ub5c4\ub5c5\ub5c6\ub5c7\ub5c8\ub5c9\ub5ca\ub5cb\ub5cc\ub5cd\ub5ce\ub5cf\ub5d0\ub5d1\ub5d2\ub5d3\ub5d4\ub5d5\ub5d6\ub5d7\ub5d8\ub5d9\ub5da\ub5db\ub5dc\ub5dd\ub5de\ub5df\ub5e0\ub5e1\ub5e2\ub5e3\ub5e4\ub5e5\ub5e6\ub5e7\ub5e8\ub5e9\ub5ea\ub5eb\ub5ec\ub5ed\ub5ee\ub5ef\ub5f0\ub5f1\ub5f2\ub5f3\ub5f4\ub5f5\ub5f6\ub5f7\ub5f8\ub5f9\ub5fa\ub5fb\ub5fc\ub5fd\ub5fe\ub5ff\ub600\ub601\ub602\ub603\ub604\ub605\ub606\ub607\ub608\ub609\ub60a\ub60b\ub60c\ub60d\ub60e\ub60f\ub610\ub611\ub612\ub613\ub614\ub615\ub616\ub617\ub618\ub619\ub61a\ub61b\ub61c\ub61d\ub61e\ub61f\ub620\ub621\ub622\ub623\ub624\ub625\ub626\ub627\ub628\ub629\ub62a\ub62b\ub62c\ub62d\ub62e\ub62f\ub630\ub631\ub632\ub633\ub634\ub635\ub636\ub637\ub638\ub639\ub63a\ub63b\ub63c\ub63d\ub63e\ub63f\ub640\ub641\ub642\ub643\ub644\ub645\ub646\ub647\ub648\ub649\ub64a\ub64b\ub64c\ub64d\ub64e\ub64f\ub650\ub651\ub652\ub653\ub654\ub655\ub656\ub657\ub658\ub659\ub65a\ub65b\ub65c\ub65d\ub65e\ub65f\ub660\ub661\ub662\ub663\ub664\ub665\ub666\ub667\ub668\ub669\ub66a\ub66b\ub66c\ub66d\ub66e\ub66f\ub670\ub671\ub672\ub673\ub674\ub675\ub676\ub677\ub678\ub679\ub67a\ub67b\ub67c\ub67d\ub67e\ub67f\ub680\ub681\ub682\ub683\ub684\ub685\ub686\ub687\ub688\ub689\ub68a\ub68b\ub68c\ub68d\ub68e\ub68f\ub690\ub691\ub692\ub693\ub694\ub695\ub696\ub697\ub698\ub699\ub69a\ub69b\ub69c\ub69d\ub69e\ub69f\ub6a0\ub6a1\ub6a2\ub6a3\ub6a4\ub6a5\ub6a6\ub6a7\ub6a8\ub6a9\ub6aa\ub6ab\ub6ac\ub6ad\ub6ae\ub6af\ub6b0\ub6b1\ub6b2\ub6b3\ub6b4\ub6b5\ub6b6\ub6b7\ub6b8\ub6b9\ub6ba\ub6bb\ub6bc\ub6bd\ub6be\ub6bf\ub6c0\ub6c1\ub6c2\ub6c3\ub6c4\ub6c5\ub6c6\ub6c7\ub6c8\ub6c9\ub6ca\ub6cb\ub6cc\ub6cd\ub6ce\ub6cf\ub6d0\ub6d1\ub6d2\ub6d3\ub6d4\ub6d5\ub6d6\ub6d7\ub6d8\ub6d9\ub6da\ub6db\ub6dc\ub6dd\ub6de\ub6df\ub6e0\ub6e1\ub6e2\ub6e3\ub6e4\ub6e5\ub6e6\ub6e7\ub6e8\ub6e9\ub6ea\ub6eb\ub6ec\ub6ed\ub6ee\ub6ef\ub6f0\ub6f1\ub6f2\ub6f3\ub6f4\ub6f5\ub6f6\ub6f7\ub6f8\ub6f9\ub6fa\ub6fb\ub6fc\ub6fd\ub6fe\ub6ff\ub700\ub701\ub702\ub703\ub704\ub705\ub706\ub707\ub708\ub709\ub70a\ub70b\ub70c\ub70d\ub70e\ub70f\ub710\ub711\ub712\ub713\ub714\ub715\ub716\ub717\ub718\ub719\ub71a\ub71b\ub71c\ub71d\ub71e\ub71f\ub720\ub721\ub722\ub723\ub724\ub725\ub726\ub727\ub728\ub729\ub72a\ub72b\ub72c\ub72d\ub72e\ub72f\ub730\ub731\ub732\ub733\ub734\ub735\ub736\ub737\ub738\ub739\ub73a\ub73b\ub73c\ub73d\ub73e\ub73f\ub740\ub741\ub742\ub743\ub744\ub745\ub746\ub747\ub748\ub749\ub74a\ub74b\ub74c\ub74d\ub74e\ub74f\ub750\ub751\ub752\ub753\ub754\ub755\ub756\ub757\ub758\ub759\ub75a\ub75b\ub75c\ub75d\ub75e\ub75f\ub760\ub761\ub762\ub763\ub764\ub765\ub766\ub767\ub768\ub769\ub76a\ub76b\ub76c\ub76d\ub76e\ub76f\ub770\ub771\ub772\ub773\ub774\ub775\ub776\ub777\ub778\ub779\ub77a\ub77b\ub77c\ub77d\ub77e\ub77f\ub780\ub781\ub782\ub783\ub784\ub785\ub786\ub787\ub788\ub789\ub78a\ub78b\ub78c\ub78d\ub78e\ub78f\ub790\ub791\ub792\ub793\ub794\ub795\ub796\ub797\ub798\ub799\ub79a\ub79b\ub79c\ub79d\ub79e\ub79f\ub7a0\ub7a1\ub7a2\ub7a3\ub7a4\ub7a5\ub7a6\ub7a7\ub7a8\ub7a9\ub7aa\ub7ab\ub7ac\ub7ad\ub7ae\ub7af\ub7b0\ub7b1\ub7b2\ub7b3\ub7b4\ub7b5\ub7b6\ub7b7\ub7b8\ub7b9\ub7ba\ub7bb\ub7bc\ub7bd\ub7be\ub7bf\ub7c0\ub7c1\ub7c2\ub7c3\ub7c4\ub7c5\ub7c6\ub7c7\ub7c8\ub7c9\ub7ca\ub7cb\ub7cc\ub7cd\ub7ce\ub7cf\ub7d0\ub7d1\ub7d2\ub7d3\ub7d4\ub7d5\ub7d6\ub7d7\ub7d8\ub7d9\ub7da\ub7db\ub7dc\ub7dd\ub7de\ub7df\ub7e0\ub7e1\ub7e2\ub7e3\ub7e4\ub7e5\ub7e6\ub7e7\ub7e8\ub7e9\ub7ea\ub7eb\ub7ec\ub7ed\ub7ee\ub7ef\ub7f0\ub7f1\ub7f2\ub7f3\ub7f4\ub7f5\ub7f6\ub7f7\ub7f8\ub7f9\ub7fa\ub7fb\ub7fc\ub7fd\ub7fe\ub7ff\ub800\ub801\ub802\ub803\ub804\ub805\ub806\ub807\ub808\ub809\ub80a\ub80b\ub80c\ub80d\ub80e\ub80f\ub810\ub811\ub812\ub813\ub814\ub815\ub816\ub817\ub818\ub819\ub81a\ub81b\ub81c\ub81d\ub81e\ub81f\ub820\ub821\ub822\ub823\ub824\ub825\ub826\ub827\ub828\ub829\ub82a\ub82b\ub82c\ub82d\ub82e\ub82f\ub830\ub831\ub832\ub833\ub834\ub835\ub836\ub837\ub838\ub839\ub83a\ub83b\ub83c\ub83d\ub83e\ub83f\ub840\ub841\ub842\ub843\ub844\ub845\ub846\ub847\ub848\ub849\ub84a\ub84b\ub84c\ub84d\ub84e\ub84f\ub850\ub851\ub852\ub853\ub854\ub855\ub856\ub857\ub858\ub859\ub85a\ub85b\ub85c\ub85d\ub85e\ub85f\ub860\ub861\ub862\ub863\ub864\ub865\ub866\ub867\ub868\ub869\ub86a\ub86b\ub86c\ub86d\ub86e\ub86f\ub870\ub871\ub872\ub873\ub874\ub875\ub876\ub877\ub878\ub879\ub87a\ub87b\ub87c\ub87d\ub87e\ub87f\ub880\ub881\ub882\ub883\ub884\ub885\ub886\ub887\ub888\ub889\ub88a\ub88b\ub88c\ub88d\ub88e\ub88f\ub890\ub891\ub892\ub893\ub894\ub895\ub896\ub897\ub898\ub899\ub89a\ub89b\ub89c\ub89d\ub89e\ub89f\ub8a0\ub8a1\ub8a2\ub8a3\ub8a4\ub8a5\ub8a6\ub8a7\ub8a8\ub8a9\ub8aa\ub8ab\ub8ac\ub8ad\ub8ae\ub8af\ub8b0\ub8b1\ub8b2\ub8b3\ub8b4\ub8b5\ub8b6\ub8b7\ub8b8\ub8b9\ub8ba\ub8bb\ub8bc\ub8bd\ub8be\ub8bf\ub8c0\ub8c1\ub8c2\ub8c3\ub8c4\ub8c5\ub8c6\ub8c7\ub8c8\ub8c9\ub8ca\ub8cb\ub8cc\ub8cd\ub8ce\ub8cf\ub8d0\ub8d1\ub8d2\ub8d3\ub8d4\ub8d5\ub8d6\ub8d7\ub8d8\ub8d9\ub8da\ub8db\ub8dc\ub8dd\ub8de\ub8df\ub8e0\ub8e1\ub8e2\ub8e3\ub8e4\ub8e5\ub8e6\ub8e7\ub8e8\ub8e9\ub8ea\ub8eb\ub8ec\ub8ed\ub8ee\ub8ef\ub8f0\ub8f1\ub8f2\ub8f3\ub8f4\ub8f5\ub8f6\ub8f7\ub8f8\ub8f9\ub8fa\ub8fb\ub8fc\ub8fd\ub8fe\ub8ff\ub900\ub901\ub902\ub903\ub904\ub905\ub906\ub907\ub908\ub909\ub90a\ub90b\ub90c\ub90d\ub90e\ub90f\ub910\ub911\ub912\ub913\ub914\ub915\ub916\ub917\ub918\ub919\ub91a\ub91b\ub91c\ub91d\ub91e\ub91f\ub920\ub921\ub922\ub923\ub924\ub925\ub926\ub927\ub928\ub929\ub92a\ub92b\ub92c\ub92d\ub92e\ub92f\ub930\ub931\ub932\ub933\ub934\ub935\ub936\ub937\ub938\ub939\ub93a\ub93b\ub93c\ub93d\ub93e\ub93f\ub940\ub941\ub942\ub943\ub944\ub945\ub946\ub947\ub948\ub949\ub94a\ub94b\ub94c\ub94d\ub94e\ub94f\ub950\ub951\ub952\ub953\ub954\ub955\ub956\ub957\ub958\ub959\ub95a\ub95b\ub95c\ub95d\ub95e\ub95f\ub960\ub961\ub962\ub963\ub964\ub965\ub966\ub967\ub968\ub969\ub96a\ub96b\ub96c\ub96d\ub96e\ub96f\ub970\ub971\ub972\ub973\ub974\ub975\ub976\ub977\ub978\ub979\ub97a\ub97b\ub97c\ub97d\ub97e\ub97f\ub980\ub981\ub982\ub983\ub984\ub985\ub986\ub987\ub988\ub989\ub98a\ub98b\ub98c\ub98d\ub98e\ub98f\ub990\ub991\ub992\ub993\ub994\ub995\ub996\ub997\ub998\ub999\ub99a\ub99b\ub99c\ub99d\ub99e\ub99f\ub9a0\ub9a1\ub9a2\ub9a3\ub9a4\ub9a5\ub9a6\ub9a7\ub9a8\ub9a9\ub9aa\ub9ab\ub9ac\ub9ad\ub9ae\ub9af\ub9b0\ub9b1\ub9b2\ub9b3\ub9b4\ub9b5\ub9b6\ub9b7\ub9b8\ub9b9\ub9ba\ub9bb\ub9bc\ub9bd\ub9be\ub9bf\ub9c0\ub9c1\ub9c2\ub9c3\ub9c4\ub9c5\ub9c6\ub9c7\ub9c8\ub9c9\ub9ca\ub9cb\ub9cc\ub9cd\ub9ce\ub9cf\ub9d0\ub9d1\ub9d2\ub9d3\ub9d4\ub9d5\ub9d6\ub9d7\ub9d8\ub9d9\ub9da\ub9db\ub9dc\ub9dd\ub9de\ub9df\ub9e0\ub9e1\ub9e2\ub9e3\ub9e4\ub9e5\ub9e6\ub9e7\ub9e8\ub9e9\ub9ea\ub9eb\ub9ec\ub9ed\ub9ee\ub9ef\ub9f0\ub9f1\ub9f2\ub9f3\ub9f4\ub9f5\ub9f6\ub9f7\ub9f8\ub9f9\ub9fa\ub9fb\ub9fc\ub9fd\ub9fe\ub9ff\uba00\uba01\uba02\uba03\uba04\uba05\uba06\uba07\uba08\uba09\uba0a\uba0b\uba0c\uba0d\uba0e\uba0f\uba10\uba11\uba12\uba13\uba14\uba15\uba16\uba17\uba18\uba19\uba1a\uba1b\uba1c\uba1d\uba1e\uba1f\uba20\uba21\uba22\uba23\uba24\uba25\uba26\uba27\uba28\uba29\uba2a\uba2b\uba2c\uba2d\uba2e\uba2f\uba30\uba31\uba32\uba33\uba34\uba35\uba36\uba37\uba38\uba39\uba3a\uba3b\uba3c\uba3d\uba3e\uba3f\uba40\uba41\uba42\uba43\uba44\uba45\uba46\uba47\uba48\uba49\uba4a\uba4b\uba4c\uba4d\uba4e\uba4f\uba50\uba51\uba52\uba53\uba54\uba55\uba56\uba57\uba58\uba59\uba5a\uba5b\uba5c\uba5d\uba5e\uba5f\uba60\uba61\uba62\uba63\uba64\uba65\uba66\uba67\uba68\uba69\uba6a\uba6b\uba6c\uba6d\uba6e\uba6f\uba70\uba71\uba72\uba73\uba74\uba75\uba76\uba77\uba78\uba79\uba7a\uba7b\uba7c\uba7d\uba7e\uba7f\uba80\uba81\uba82\uba83\uba84\uba85\uba86\uba87\uba88\uba89\uba8a\uba8b\uba8c\uba8d\uba8e\uba8f\uba90\uba91\uba92\uba93\uba94\uba95\uba96\uba97\uba98\uba99\uba9a\uba9b\uba9c\uba9d\uba9e\uba9f\ubaa0\ubaa1\ubaa2\ubaa3\ubaa4\ubaa5\ubaa6\ubaa7\ubaa8\ubaa9\ubaaa\ubaab\ubaac\ubaad\ubaae\ubaaf\ubab0\ubab1\ubab2\ubab3\ubab4\ubab5\ubab6\ubab7\ubab8\ubab9\ubaba\ubabb\ubabc\ubabd\ubabe\ubabf\ubac0\ubac1\ubac2\ubac3\ubac4\ubac5\ubac6\ubac7\ubac8\ubac9\ubaca\ubacb\ubacc\ubacd\ubace\ubacf\ubad0\ubad1\ubad2\ubad3\ubad4\ubad5\ubad6\ubad7\ubad8\ubad9\ubada\ubadb\ubadc\ubadd\ubade\ubadf\ubae0\ubae1\ubae2\ubae3\ubae4\ubae5\ubae6\ubae7\ubae8\ubae9\ubaea\ubaeb\ubaec\ubaed\ubaee\ubaef\ubaf0\ubaf1\ubaf2\ubaf3\ubaf4\ubaf5\ubaf6\ubaf7\ubaf8\ubaf9\ubafa\ubafb\ubafc\ubafd\ubafe\ubaff\ubb00\ubb01\ubb02\ubb03\ubb04\ubb05\ubb06\ubb07\ubb08\ubb09\ubb0a\ubb0b\ubb0c\ubb0d\ubb0e\ubb0f\ubb10\ubb11\ubb12\ubb13\ubb14\ubb15\ubb16\ubb17\ubb18\ubb19\ubb1a\ubb1b\ubb1c\ubb1d\ubb1e\ubb1f\ubb20\ubb21\ubb22\ubb23\ubb24\ubb25\ubb26\ubb27\ubb28\ubb29\ubb2a\ubb2b\ubb2c\ubb2d\ubb2e\ubb2f\ubb30\ubb31\ubb32\ubb33\ubb34\ubb35\ubb36\ubb37\ubb38\ubb39\ubb3a\ubb3b\ubb3c\ubb3d\ubb3e\ubb3f\ubb40\ubb41\ubb42\ubb43\ubb44\ubb45\ubb46\ubb47\ubb48\ubb49\ubb4a\ubb4b\ubb4c\ubb4d\ubb4e\ubb4f\ubb50\ubb51\ubb52\ubb53\ubb54\ubb55\ubb56\ubb57\ubb58\ubb59\ubb5a\ubb5b\ubb5c\ubb5d\ubb5e\ubb5f\ubb60\ubb61\ubb62\ubb63\ubb64\ubb65\ubb66\ubb67\ubb68\ubb69\ubb6a\ubb6b\ubb6c\ubb6d\ubb6e\ubb6f\ubb70\ubb71\ubb72\ubb73\ubb74\ubb75\ubb76\ubb77\ubb78\ubb79\ubb7a\ubb7b\ubb7c\ubb7d\ubb7e\ubb7f\ubb80\ubb81\ubb82\ubb83\ubb84\ubb85\ubb86\ubb87\ubb88\ubb89\ubb8a\ubb8b\ubb8c\ubb8d\ubb8e\ubb8f\ubb90\ubb91\ubb92\ubb93\ubb94\ubb95\ubb96\ubb97\ubb98\ubb99\ubb9a\ubb9b\ubb9c\ubb9d\ubb9e\ubb9f\ubba0\ubba1\ubba2\ubba3\ubba4\ubba5\ubba6\ubba7\ubba8\ubba9\ubbaa\ubbab\ubbac\ubbad\ubbae\ubbaf\ubbb0\ubbb1\ubbb2\ubbb3\ubbb4\ubbb5\ubbb6\ubbb7\ubbb8\ubbb9\ubbba\ubbbb\ubbbc\ubbbd\ubbbe\ubbbf\ubbc0\ubbc1\ubbc2\ubbc3\ubbc4\ubbc5\ubbc6\ubbc7\ubbc8\ubbc9\ubbca\ubbcb\ubbcc\ubbcd\ubbce\ubbcf\ubbd0\ubbd1\ubbd2\ubbd3\ubbd4\ubbd5\ubbd6\ubbd7\ubbd8\ubbd9\ubbda\ubbdb\ubbdc\ubbdd\ubbde\ubbdf\ubbe0\ubbe1\ubbe2\ubbe3\ubbe4\ubbe5\ubbe6\ubbe7\ubbe8\ubbe9\ubbea\ubbeb\ubbec\ubbed\ubbee\ubbef\ubbf0\ubbf1\ubbf2\ubbf3\ubbf4\ubbf5\ubbf6\ubbf7\ubbf8\ubbf9\ubbfa\ubbfb\ubbfc\ubbfd\ubbfe\ubbff\ubc00\ubc01\ubc02\ubc03\ubc04\ubc05\ubc06\ubc07\ubc08\ubc09\ubc0a\ubc0b\ubc0c\ubc0d\ubc0e\ubc0f\ubc10\ubc11\ubc12\ubc13\ubc14\ubc15\ubc16\ubc17\ubc18\ubc19\ubc1a\ubc1b\ubc1c\ubc1d\ubc1e\ubc1f\ubc20\ubc21\ubc22\ubc23\ubc24\ubc25\ubc26\ubc27\ubc28\ubc29\ubc2a\ubc2b\ubc2c\ubc2d\ubc2e\ubc2f\ubc30\ubc31\ubc32\ubc33\ubc34\ubc35\ubc36\ubc37\ubc38\ubc39\ubc3a\ubc3b\ubc3c\ubc3d\ubc3e\ubc3f\ubc40\ubc41\ubc42\ubc43\ubc44\ubc45\ubc46\ubc47\ubc48\ubc49\ubc4a\ubc4b\ubc4c\ubc4d\ubc4e\ubc4f\ubc50\ubc51\ubc52\ubc53\ubc54\ubc55\ubc56\ubc57\ubc58\ubc59\ubc5a\ubc5b\ubc5c\ubc5d\ubc5e\ubc5f\ubc60\ubc61\ubc62\ubc63\ubc64\ubc65\ubc66\ubc67\ubc68\ubc69\ubc6a\ubc6b\ubc6c\ubc6d\ubc6e\ubc6f\ubc70\ubc71\ubc72\ubc73\ubc74\ubc75\ubc76\ubc77\ubc78\ubc79\ubc7a\ubc7b\ubc7c\ubc7d\ubc7e\ubc7f\ubc80\ubc81\ubc82\ubc83\ubc84\ubc85\ubc86\ubc87\ubc88\ubc89\ubc8a\ubc8b\ubc8c\ubc8d\ubc8e\ubc8f\ubc90\ubc91\ubc92\ubc93\ubc94\ubc95\ubc96\ubc97\ubc98\ubc99\ubc9a\ubc9b\ubc9c\ubc9d\ubc9e\ubc9f\ubca0\ubca1\ubca2\ubca3\ubca4\ubca5\ubca6\ubca7\ubca8\ubca9\ubcaa\ubcab\ubcac\ubcad\ubcae\ubcaf\ubcb0\ubcb1\ubcb2\ubcb3\ubcb4\ubcb5\ubcb6\ubcb7\ubcb8\ubcb9\ubcba\ubcbb\ubcbc\ubcbd\ubcbe\ubcbf\ubcc0\ubcc1\ubcc2\ubcc3\ubcc4\ubcc5\ubcc6\ubcc7\ubcc8\ubcc9\ubcca\ubccb\ubccc\ubccd\ubcce\ubccf\ubcd0\ubcd1\ubcd2\ubcd3\ubcd4\ubcd5\ubcd6\ubcd7\ubcd8\ubcd9\ubcda\ubcdb\ubcdc\ubcdd\ubcde\ubcdf\ubce0\ubce1\ubce2\ubce3\ubce4\ubce5\ubce6\ubce7\ubce8\ubce9\ubcea\ubceb\ubcec\ubced\ubcee\ubcef\ubcf0\ubcf1\ubcf2\ubcf3\ubcf4\ubcf5\ubcf6\ubcf7\ubcf8\ubcf9\ubcfa\ubcfb\ubcfc\ubcfd\ubcfe\ubcff\ubd00\ubd01\ubd02\ubd03\ubd04\ubd05\ubd06\ubd07\ubd08\ubd09\ubd0a\ubd0b\ubd0c\ubd0d\ubd0e\ubd0f\ubd10\ubd11\ubd12\ubd13\ubd14\ubd15\ubd16\ubd17\ubd18\ubd19\ubd1a\ubd1b\ubd1c\ubd1d\ubd1e\ubd1f\ubd20\ubd21\ubd22\ubd23\ubd24\ubd25\ubd26\ubd27\ubd28\ubd29\ubd2a\ubd2b\ubd2c\ubd2d\ubd2e\ubd2f\ubd30\ubd31\ubd32\ubd33\ubd34\ubd35\ubd36\ubd37\ubd38\ubd39\ubd3a\ubd3b\ubd3c\ubd3d\ubd3e\ubd3f\ubd40\ubd41\ubd42\ubd43\ubd44\ubd45\ubd46\ubd47\ubd48\ubd49\ubd4a\ubd4b\ubd4c\ubd4d\ubd4e\ubd4f\ubd50\ubd51\ubd52\ubd53\ubd54\ubd55\ubd56\ubd57\ubd58\ubd59\ubd5a\ubd5b\ubd5c\ubd5d\ubd5e\ubd5f\ubd60\ubd61\ubd62\ubd63\ubd64\ubd65\ubd66\ubd67\ubd68\ubd69\ubd6a\ubd6b\ubd6c\ubd6d\ubd6e\ubd6f\ubd70\ubd71\ubd72\ubd73\ubd74\ubd75\ubd76\ubd77\ubd78\ubd79\ubd7a\ubd7b\ubd7c\ubd7d\ubd7e\ubd7f\ubd80\ubd81\ubd82\ubd83\ubd84\ubd85\ubd86\ubd87\ubd88\ubd89\ubd8a\ubd8b\ubd8c\ubd8d\ubd8e\ubd8f\ubd90\ubd91\ubd92\ubd93\ubd94\ubd95\ubd96\ubd97\ubd98\ubd99\ubd9a\ubd9b\ubd9c\ubd9d\ubd9e\ubd9f\ubda0\ubda1\ubda2\ubda3\ubda4\ubda5\ubda6\ubda7\ubda8\ubda9\ubdaa\ubdab\ubdac\ubdad\ubdae\ubdaf\ubdb0\ubdb1\ubdb2\ubdb3\ubdb4\ubdb5\ubdb6\ubdb7\ubdb8\ubdb9\ubdba\ubdbb\ubdbc\ubdbd\ubdbe\ubdbf\ubdc0\ubdc1\ubdc2\ubdc3\ubdc4\ubdc5\ubdc6\ubdc7\ubdc8\ubdc9\ubdca\ubdcb\ubdcc\ubdcd\ubdce\ubdcf\ubdd0\ubdd1\ubdd2\ubdd3\ubdd4\ubdd5\ubdd6\ubdd7\ubdd8\ubdd9\ubdda\ubddb\ubddc\ubddd\ubdde\ubddf\ubde0\ubde1\ubde2\ubde3\ubde4\ubde5\ubde6\ubde7\ubde8\ubde9\ubdea\ubdeb\ubdec\ubded\ubdee\ubdef\ubdf0\ubdf1\ubdf2\ubdf3\ubdf4\ubdf5\ubdf6\ubdf7\ubdf8\ubdf9\ubdfa\ubdfb\ubdfc\ubdfd\ubdfe\ubdff\ube00\ube01\ube02\ube03\ube04\ube05\ube06\ube07\ube08\ube09\ube0a\ube0b\ube0c\ube0d\ube0e\ube0f\ube10\ube11\ube12\ube13\ube14\ube15\ube16\ube17\ube18\ube19\ube1a\ube1b\ube1c\ube1d\ube1e\ube1f\ube20\ube21\ube22\ube23\ube24\ube25\ube26\ube27\ube28\ube29\ube2a\ube2b\ube2c\ube2d\ube2e\ube2f\ube30\ube31\ube32\ube33\ube34\ube35\ube36\ube37\ube38\ube39\ube3a\ube3b\ube3c\ube3d\ube3e\ube3f\ube40\ube41\ube42\ube43\ube44\ube45\ube46\ube47\ube48\ube49\ube4a\ube4b\ube4c\ube4d\ube4e\ube4f\ube50\ube51\ube52\ube53\ube54\ube55\ube56\ube57\ube58\ube59\ube5a\ube5b\ube5c\ube5d\ube5e\ube5f\ube60\ube61\ube62\ube63\ube64\ube65\ube66\ube67\ube68\ube69\ube6a\ube6b\ube6c\ube6d\ube6e\ube6f\ube70\ube71\ube72\ube73\ube74\ube75\ube76\ube77\ube78\ube79\ube7a\ube7b\ube7c\ube7d\ube7e\ube7f\ube80\ube81\ube82\ube83\ube84\ube85\ube86\ube87\ube88\ube89\ube8a\ube8b\ube8c\ube8d\ube8e\ube8f\ube90\ube91\ube92\ube93\ube94\ube95\ube96\ube97\ube98\ube99\ube9a\ube9b\ube9c\ube9d\ube9e\ube9f\ubea0\ubea1\ubea2\ubea3\ubea4\ubea5\ubea6\ubea7\ubea8\ubea9\ubeaa\ubeab\ubeac\ubead\ubeae\ubeaf\ubeb0\ubeb1\ubeb2\ubeb3\ubeb4\ubeb5\ubeb6\ubeb7\ubeb8\ubeb9\ubeba\ubebb\ubebc\ubebd\ubebe\ubebf\ubec0\ubec1\ubec2\ubec3\ubec4\ubec5\ubec6\ubec7\ubec8\ubec9\ubeca\ubecb\ubecc\ubecd\ubece\ubecf\ubed0\ubed1\ubed2\ubed3\ubed4\ubed5\ubed6\ubed7\ubed8\ubed9\ubeda\ubedb\ubedc\ubedd\ubede\ubedf\ubee0\ubee1\ubee2\ubee3\ubee4\ubee5\ubee6\ubee7\ubee8\ubee9\ubeea\ubeeb\ubeec\ubeed\ubeee\ubeef\ubef0\ubef1\ubef2\ubef3\ubef4\ubef5\ubef6\ubef7\ubef8\ubef9\ubefa\ubefb\ubefc\ubefd\ubefe\ubeff\ubf00\ubf01\ubf02\ubf03\ubf04\ubf05\ubf06\ubf07\ubf08\ubf09\ubf0a\ubf0b\ubf0c\ubf0d\ubf0e\ubf0f\ubf10\ubf11\ubf12\ubf13\ubf14\ubf15\ubf16\ubf17\ubf18\ubf19\ubf1a\ubf1b\ubf1c\ubf1d\ubf1e\ubf1f\ubf20\ubf21\ubf22\ubf23\ubf24\ubf25\ubf26\ubf27\ubf28\ubf29\ubf2a\ubf2b\ubf2c\ubf2d\ubf2e\ubf2f\ubf30\ubf31\ubf32\ubf33\ubf34\ubf35\ubf36\ubf37\ubf38\ubf39\ubf3a\ubf3b\ubf3c\ubf3d\ubf3e\ubf3f\ubf40\ubf41\ubf42\ubf43\ubf44\ubf45\ubf46\ubf47\ubf48\ubf49\ubf4a\ubf4b\ubf4c\ubf4d\ubf4e\ubf4f\ubf50\ubf51\ubf52\ubf53\ubf54\ubf55\ubf56\ubf57\ubf58\ubf59\ubf5a\ubf5b\ubf5c\ubf5d\ubf5e\ubf5f\ubf60\ubf61\ubf62\ubf63\ubf64\ubf65\ubf66\ubf67\ubf68\ubf69\ubf6a\ubf6b\ubf6c\ubf6d\ubf6e\ubf6f\ubf70\ubf71\ubf72\ubf73\ubf74\ubf75\ubf76\ubf77\ubf78\ubf79\ubf7a\ubf7b\ubf7c\ubf7d\ubf7e\ubf7f\ubf80\ubf81\ubf82\ubf83\ubf84\ubf85\ubf86\ubf87\ubf88\ubf89\ubf8a\ubf8b\ubf8c\ubf8d\ubf8e\ubf8f\ubf90\ubf91\ubf92\ubf93\ubf94\ubf95\ubf96\ubf97\ubf98\ubf99\ubf9a\ubf9b\ubf9c\ubf9d\ubf9e\ubf9f\ubfa0\ubfa1\ubfa2\ubfa3\ubfa4\ubfa5\ubfa6\ubfa7\ubfa8\ubfa9\ubfaa\ubfab\ubfac\ubfad\ubfae\ubfaf\ubfb0\ubfb1\ubfb2\ubfb3\ubfb4\ubfb5\ubfb6\ubfb7\ubfb8\ubfb9\ubfba\ubfbb\ubfbc\ubfbd\ubfbe\ubfbf\ubfc0\ubfc1\ubfc2\ubfc3\ubfc4\ubfc5\ubfc6\ubfc7\ubfc8\ubfc9\ubfca\ubfcb\ubfcc\ubfcd\ubfce\ubfcf\ubfd0\ubfd1\ubfd2\ubfd3\ubfd4\ubfd5\ubfd6\ubfd7\ubfd8\ubfd9\ubfda\ubfdb\ubfdc\ubfdd\ubfde\ubfdf\ubfe0\ubfe1\ubfe2\ubfe3\ubfe4\ubfe5\ubfe6\ubfe7\ubfe8\ubfe9\ubfea\ubfeb\ubfec\ubfed\ubfee\ubfef\ubff0\ubff1\ubff2\ubff3\ubff4\ubff5\ubff6\ubff7\ubff8\ubff9\ubffa\ubffb\ubffc\ubffd\ubffe\ubfff\uc000\uc001\uc002\uc003\uc004\uc005\uc006\uc007\uc008\uc009\uc00a\uc00b\uc00c\uc00d\uc00e\uc00f\uc010\uc011\uc012\uc013\uc014\uc015\uc016\uc017\uc018\uc019\uc01a\uc01b\uc01c\uc01d\uc01e\uc01f\uc020\uc021\uc022\uc023\uc024\uc025\uc026\uc027\uc028\uc029\uc02a\uc02b\uc02c\uc02d\uc02e\uc02f\uc030\uc031\uc032\uc033\uc034\uc035\uc036\uc037\uc038\uc039\uc03a\uc03b\uc03c\uc03d\uc03e\uc03f\uc040\uc041\uc042\uc043\uc044\uc045\uc046\uc047\uc048\uc049\uc04a\uc04b\uc04c\uc04d\uc04e\uc04f\uc050\uc051\uc052\uc053\uc054\uc055\uc056\uc057\uc058\uc059\uc05a\uc05b\uc05c\uc05d\uc05e\uc05f\uc060\uc061\uc062\uc063\uc064\uc065\uc066\uc067\uc068\uc069\uc06a\uc06b\uc06c\uc06d\uc06e\uc06f\uc070\uc071\uc072\uc073\uc074\uc075\uc076\uc077\uc078\uc079\uc07a\uc07b\uc07c\uc07d\uc07e\uc07f\uc080\uc081\uc082\uc083\uc084\uc085\uc086\uc087\uc088\uc089\uc08a\uc08b\uc08c\uc08d\uc08e\uc08f\uc090\uc091\uc092\uc093\uc094\uc095\uc096\uc097\uc098\uc099\uc09a\uc09b\uc09c\uc09d\uc09e\uc09f\uc0a0\uc0a1\uc0a2\uc0a3\uc0a4\uc0a5\uc0a6\uc0a7\uc0a8\uc0a9\uc0aa\uc0ab\uc0ac\uc0ad\uc0ae\uc0af\uc0b0\uc0b1\uc0b2\uc0b3\uc0b4\uc0b5\uc0b6\uc0b7\uc0b8\uc0b9\uc0ba\uc0bb\uc0bc\uc0bd\uc0be\uc0bf\uc0c0\uc0c1\uc0c2\uc0c3\uc0c4\uc0c5\uc0c6\uc0c7\uc0c8\uc0c9\uc0ca\uc0cb\uc0cc\uc0cd\uc0ce\uc0cf\uc0d0\uc0d1\uc0d2\uc0d3\uc0d4\uc0d5\uc0d6\uc0d7\uc0d8\uc0d9\uc0da\uc0db\uc0dc\uc0dd\uc0de\uc0df\uc0e0\uc0e1\uc0e2\uc0e3\uc0e4\uc0e5\uc0e6\uc0e7\uc0e8\uc0e9\uc0ea\uc0eb\uc0ec\uc0ed\uc0ee\uc0ef\uc0f0\uc0f1\uc0f2\uc0f3\uc0f4\uc0f5\uc0f6\uc0f7\uc0f8\uc0f9\uc0fa\uc0fb\uc0fc\uc0fd\uc0fe\uc0ff\uc100\uc101\uc102\uc103\uc104\uc105\uc106\uc107\uc108\uc109\uc10a\uc10b\uc10c\uc10d\uc10e\uc10f\uc110\uc111\uc112\uc113\uc114\uc115\uc116\uc117\uc118\uc119\uc11a\uc11b\uc11c\uc11d\uc11e\uc11f\uc120\uc121\uc122\uc123\uc124\uc125\uc126\uc127\uc128\uc129\uc12a\uc12b\uc12c\uc12d\uc12e\uc12f\uc130\uc131\uc132\uc133\uc134\uc135\uc136\uc137\uc138\uc139\uc13a\uc13b\uc13c\uc13d\uc13e\uc13f\uc140\uc141\uc142\uc143\uc144\uc145\uc146\uc147\uc148\uc149\uc14a\uc14b\uc14c\uc14d\uc14e\uc14f\uc150\uc151\uc152\uc153\uc154\uc155\uc156\uc157\uc158\uc159\uc15a\uc15b\uc15c\uc15d\uc15e\uc15f\uc160\uc161\uc162\uc163\uc164\uc165\uc166\uc167\uc168\uc169\uc16a\uc16b\uc16c\uc16d\uc16e\uc16f\uc170\uc171\uc172\uc173\uc174\uc175\uc176\uc177\uc178\uc179\uc17a\uc17b\uc17c\uc17d\uc17e\uc17f\uc180\uc181\uc182\uc183\uc184\uc185\uc186\uc187\uc188\uc189\uc18a\uc18b\uc18c\uc18d\uc18e\uc18f\uc190\uc191\uc192\uc193\uc194\uc195\uc196\uc197\uc198\uc199\uc19a\uc19b\uc19c\uc19d\uc19e\uc19f\uc1a0\uc1a1\uc1a2\uc1a3\uc1a4\uc1a5\uc1a6\uc1a7\uc1a8\uc1a9\uc1aa\uc1ab\uc1ac\uc1ad\uc1ae\uc1af\uc1b0\uc1b1\uc1b2\uc1b3\uc1b4\uc1b5\uc1b6\uc1b7\uc1b8\uc1b9\uc1ba\uc1bb\uc1bc\uc1bd\uc1be\uc1bf\uc1c0\uc1c1\uc1c2\uc1c3\uc1c4\uc1c5\uc1c6\uc1c7\uc1c8\uc1c9\uc1ca\uc1cb\uc1cc\uc1cd\uc1ce\uc1cf\uc1d0\uc1d1\uc1d2\uc1d3\uc1d4\uc1d5\uc1d6\uc1d7\uc1d8\uc1d9\uc1da\uc1db\uc1dc\uc1dd\uc1de\uc1df\uc1e0\uc1e1\uc1e2\uc1e3\uc1e4\uc1e5\uc1e6\uc1e7\uc1e8\uc1e9\uc1ea\uc1eb\uc1ec\uc1ed\uc1ee\uc1ef\uc1f0\uc1f1\uc1f2\uc1f3\uc1f4\uc1f5\uc1f6\uc1f7\uc1f8\uc1f9\uc1fa\uc1fb\uc1fc\uc1fd\uc1fe\uc1ff\uc200\uc201\uc202\uc203\uc204\uc205\uc206\uc207\uc208\uc209\uc20a\uc20b\uc20c\uc20d\uc20e\uc20f\uc210\uc211\uc212\uc213\uc214\uc215\uc216\uc217\uc218\uc219\uc21a\uc21b\uc21c\uc21d\uc21e\uc21f\uc220\uc221\uc222\uc223\uc224\uc225\uc226\uc227\uc228\uc229\uc22a\uc22b\uc22c\uc22d\uc22e\uc22f\uc230\uc231\uc232\uc233\uc234\uc235\uc236\uc237\uc238\uc239\uc23a\uc23b\uc23c\uc23d\uc23e\uc23f\uc240\uc241\uc242\uc243\uc244\uc245\uc246\uc247\uc248\uc249\uc24a\uc24b\uc24c\uc24d\uc24e\uc24f\uc250\uc251\uc252\uc253\uc254\uc255\uc256\uc257\uc258\uc259\uc25a\uc25b\uc25c\uc25d\uc25e\uc25f\uc260\uc261\uc262\uc263\uc264\uc265\uc266\uc267\uc268\uc269\uc26a\uc26b\uc26c\uc26d\uc26e\uc26f\uc270\uc271\uc272\uc273\uc274\uc275\uc276\uc277\uc278\uc279\uc27a\uc27b\uc27c\uc27d\uc27e\uc27f\uc280\uc281\uc282\uc283\uc284\uc285\uc286\uc287\uc288\uc289\uc28a\uc28b\uc28c\uc28d\uc28e\uc28f\uc290\uc291\uc292\uc293\uc294\uc295\uc296\uc297\uc298\uc299\uc29a\uc29b\uc29c\uc29d\uc29e\uc29f\uc2a0\uc2a1\uc2a2\uc2a3\uc2a4\uc2a5\uc2a6\uc2a7\uc2a8\uc2a9\uc2aa\uc2ab\uc2ac\uc2ad\uc2ae\uc2af\uc2b0\uc2b1\uc2b2\uc2b3\uc2b4\uc2b5\uc2b6\uc2b7\uc2b8\uc2b9\uc2ba\uc2bb\uc2bc\uc2bd\uc2be\uc2bf\uc2c0\uc2c1\uc2c2\uc2c3\uc2c4\uc2c5\uc2c6\uc2c7\uc2c8\uc2c9\uc2ca\uc2cb\uc2cc\uc2cd\uc2ce\uc2cf\uc2d0\uc2d1\uc2d2\uc2d3\uc2d4\uc2d5\uc2d6\uc2d7\uc2d8\uc2d9\uc2da\uc2db\uc2dc\uc2dd\uc2de\uc2df\uc2e0\uc2e1\uc2e2\uc2e3\uc2e4\uc2e5\uc2e6\uc2e7\uc2e8\uc2e9\uc2ea\uc2eb\uc2ec\uc2ed\uc2ee\uc2ef\uc2f0\uc2f1\uc2f2\uc2f3\uc2f4\uc2f5\uc2f6\uc2f7\uc2f8\uc2f9\uc2fa\uc2fb\uc2fc\uc2fd\uc2fe\uc2ff\uc300\uc301\uc302\uc303\uc304\uc305\uc306\uc307\uc308\uc309\uc30a\uc30b\uc30c\uc30d\uc30e\uc30f\uc310\uc311\uc312\uc313\uc314\uc315\uc316\uc317\uc318\uc319\uc31a\uc31b\uc31c\uc31d\uc31e\uc31f\uc320\uc321\uc322\uc323\uc324\uc325\uc326\uc327\uc328\uc329\uc32a\uc32b\uc32c\uc32d\uc32e\uc32f\uc330\uc331\uc332\uc333\uc334\uc335\uc336\uc337\uc338\uc339\uc33a\uc33b\uc33c\uc33d\uc33e\uc33f\uc340\uc341\uc342\uc343\uc344\uc345\uc346\uc347\uc348\uc349\uc34a\uc34b\uc34c\uc34d\uc34e\uc34f\uc350\uc351\uc352\uc353\uc354\uc355\uc356\uc357\uc358\uc359\uc35a\uc35b\uc35c\uc35d\uc35e\uc35f\uc360\uc361\uc362\uc363\uc364\uc365\uc366\uc367\uc368\uc369\uc36a\uc36b\uc36c\uc36d\uc36e\uc36f\uc370\uc371\uc372\uc373\uc374\uc375\uc376\uc377\uc378\uc379\uc37a\uc37b\uc37c\uc37d\uc37e\uc37f\uc380\uc381\uc382\uc383\uc384\uc385\uc386\uc387\uc388\uc389\uc38a\uc38b\uc38c\uc38d\uc38e\uc38f\uc390\uc391\uc392\uc393\uc394\uc395\uc396\uc397\uc398\uc399\uc39a\uc39b\uc39c\uc39d\uc39e\uc39f\uc3a0\uc3a1\uc3a2\uc3a3\uc3a4\uc3a5\uc3a6\uc3a7\uc3a8\uc3a9\uc3aa\uc3ab\uc3ac\uc3ad\uc3ae\uc3af\uc3b0\uc3b1\uc3b2\uc3b3\uc3b4\uc3b5\uc3b6\uc3b7\uc3b8\uc3b9\uc3ba\uc3bb\uc3bc\uc3bd\uc3be\uc3bf\uc3c0\uc3c1\uc3c2\uc3c3\uc3c4\uc3c5\uc3c6\uc3c7\uc3c8\uc3c9\uc3ca\uc3cb\uc3cc\uc3cd\uc3ce\uc3cf\uc3d0\uc3d1\uc3d2\uc3d3\uc3d4\uc3d5\uc3d6\uc3d7\uc3d8\uc3d9\uc3da\uc3db\uc3dc\uc3dd\uc3de\uc3df\uc3e0\uc3e1\uc3e2\uc3e3\uc3e4\uc3e5\uc3e6\uc3e7\uc3e8\uc3e9\uc3ea\uc3eb\uc3ec\uc3ed\uc3ee\uc3ef\uc3f0\uc3f1\uc3f2\uc3f3\uc3f4\uc3f5\uc3f6\uc3f7\uc3f8\uc3f9\uc3fa\uc3fb\uc3fc\uc3fd\uc3fe\uc3ff\uc400\uc401\uc402\uc403\uc404\uc405\uc406\uc407\uc408\uc409\uc40a\uc40b\uc40c\uc40d\uc40e\uc40f\uc410\uc411\uc412\uc413\uc414\uc415\uc416\uc417\uc418\uc419\uc41a\uc41b\uc41c\uc41d\uc41e\uc41f\uc420\uc421\uc422\uc423\uc424\uc425\uc426\uc427\uc428\uc429\uc42a\uc42b\uc42c\uc42d\uc42e\uc42f\uc430\uc431\uc432\uc433\uc434\uc435\uc436\uc437\uc438\uc439\uc43a\uc43b\uc43c\uc43d\uc43e\uc43f\uc440\uc441\uc442\uc443\uc444\uc445\uc446\uc447\uc448\uc449\uc44a\uc44b\uc44c\uc44d\uc44e\uc44f\uc450\uc451\uc452\uc453\uc454\uc455\uc456\uc457\uc458\uc459\uc45a\uc45b\uc45c\uc45d\uc45e\uc45f\uc460\uc461\uc462\uc463\uc464\uc465\uc466\uc467\uc468\uc469\uc46a\uc46b\uc46c\uc46d\uc46e\uc46f\uc470\uc471\uc472\uc473\uc474\uc475\uc476\uc477\uc478\uc479\uc47a\uc47b\uc47c\uc47d\uc47e\uc47f\uc480\uc481\uc482\uc483\uc484\uc485\uc486\uc487\uc488\uc489\uc48a\uc48b\uc48c\uc48d\uc48e\uc48f\uc490\uc491\uc492\uc493\uc494\uc495\uc496\uc497\uc498\uc499\uc49a\uc49b\uc49c\uc49d\uc49e\uc49f\uc4a0\uc4a1\uc4a2\uc4a3\uc4a4\uc4a5\uc4a6\uc4a7\uc4a8\uc4a9\uc4aa\uc4ab\uc4ac\uc4ad\uc4ae\uc4af\uc4b0\uc4b1\uc4b2\uc4b3\uc4b4\uc4b5\uc4b6\uc4b7\uc4b8\uc4b9\uc4ba\uc4bb\uc4bc\uc4bd\uc4be\uc4bf\uc4c0\uc4c1\uc4c2\uc4c3\uc4c4\uc4c5\uc4c6\uc4c7\uc4c8\uc4c9\uc4ca\uc4cb\uc4cc\uc4cd\uc4ce\uc4cf\uc4d0\uc4d1\uc4d2\uc4d3\uc4d4\uc4d5\uc4d6\uc4d7\uc4d8\uc4d9\uc4da\uc4db\uc4dc\uc4dd\uc4de\uc4df\uc4e0\uc4e1\uc4e2\uc4e3\uc4e4\uc4e5\uc4e6\uc4e7\uc4e8\uc4e9\uc4ea\uc4eb\uc4ec\uc4ed\uc4ee\uc4ef\uc4f0\uc4f1\uc4f2\uc4f3\uc4f4\uc4f5\uc4f6\uc4f7\uc4f8\uc4f9\uc4fa\uc4fb\uc4fc\uc4fd\uc4fe\uc4ff\uc500\uc501\uc502\uc503\uc504\uc505\uc506\uc507\uc508\uc509\uc50a\uc50b\uc50c\uc50d\uc50e\uc50f\uc510\uc511\uc512\uc513\uc514\uc515\uc516\uc517\uc518\uc519\uc51a\uc51b\uc51c\uc51d\uc51e\uc51f\uc520\uc521\uc522\uc523\uc524\uc525\uc526\uc527\uc528\uc529\uc52a\uc52b\uc52c\uc52d\uc52e\uc52f\uc530\uc531\uc532\uc533\uc534\uc535\uc536\uc537\uc538\uc539\uc53a\uc53b\uc53c\uc53d\uc53e\uc53f\uc540\uc541\uc542\uc543\uc544\uc545\uc546\uc547\uc548\uc549\uc54a\uc54b\uc54c\uc54d\uc54e\uc54f\uc550\uc551\uc552\uc553\uc554\uc555\uc556\uc557\uc558\uc559\uc55a\uc55b\uc55c\uc55d\uc55e\uc55f\uc560\uc561\uc562\uc563\uc564\uc565\uc566\uc567\uc568\uc569\uc56a\uc56b\uc56c\uc56d\uc56e\uc56f\uc570\uc571\uc572\uc573\uc574\uc575\uc576\uc577\uc578\uc579\uc57a\uc57b\uc57c\uc57d\uc57e\uc57f\uc580\uc581\uc582\uc583\uc584\uc585\uc586\uc587\uc588\uc589\uc58a\uc58b\uc58c\uc58d\uc58e\uc58f\uc590\uc591\uc592\uc593\uc594\uc595\uc596\uc597\uc598\uc599\uc59a\uc59b\uc59c\uc59d\uc59e\uc59f\uc5a0\uc5a1\uc5a2\uc5a3\uc5a4\uc5a5\uc5a6\uc5a7\uc5a8\uc5a9\uc5aa\uc5ab\uc5ac\uc5ad\uc5ae\uc5af\uc5b0\uc5b1\uc5b2\uc5b3\uc5b4\uc5b5\uc5b6\uc5b7\uc5b8\uc5b9\uc5ba\uc5bb\uc5bc\uc5bd\uc5be\uc5bf\uc5c0\uc5c1\uc5c2\uc5c3\uc5c4\uc5c5\uc5c6\uc5c7\uc5c8\uc5c9\uc5ca\uc5cb\uc5cc\uc5cd\uc5ce\uc5cf\uc5d0\uc5d1\uc5d2\uc5d3\uc5d4\uc5d5\uc5d6\uc5d7\uc5d8\uc5d9\uc5da\uc5db\uc5dc\uc5dd\uc5de\uc5df\uc5e0\uc5e1\uc5e2\uc5e3\uc5e4\uc5e5\uc5e6\uc5e7\uc5e8\uc5e9\uc5ea\uc5eb\uc5ec\uc5ed\uc5ee\uc5ef\uc5f0\uc5f1\uc5f2\uc5f3\uc5f4\uc5f5\uc5f6\uc5f7\uc5f8\uc5f9\uc5fa\uc5fb\uc5fc\uc5fd\uc5fe\uc5ff\uc600\uc601\uc602\uc603\uc604\uc605\uc606\uc607\uc608\uc609\uc60a\uc60b\uc60c\uc60d\uc60e\uc60f\uc610\uc611\uc612\uc613\uc614\uc615\uc616\uc617\uc618\uc619\uc61a\uc61b\uc61c\uc61d\uc61e\uc61f\uc620\uc621\uc622\uc623\uc624\uc625\uc626\uc627\uc628\uc629\uc62a\uc62b\uc62c\uc62d\uc62e\uc62f\uc630\uc631\uc632\uc633\uc634\uc635\uc636\uc637\uc638\uc639\uc63a\uc63b\uc63c\uc63d\uc63e\uc63f\uc640\uc641\uc642\uc643\uc644\uc645\uc646\uc647\uc648\uc649\uc64a\uc64b\uc64c\uc64d\uc64e\uc64f\uc650\uc651\uc652\uc653\uc654\uc655\uc656\uc657\uc658\uc659\uc65a\uc65b\uc65c\uc65d\uc65e\uc65f\uc660\uc661\uc662\uc663\uc664\uc665\uc666\uc667\uc668\uc669\uc66a\uc66b\uc66c\uc66d\uc66e\uc66f\uc670\uc671\uc672\uc673\uc674\uc675\uc676\uc677\uc678\uc679\uc67a\uc67b\uc67c\uc67d\uc67e\uc67f\uc680\uc681\uc682\uc683\uc684\uc685\uc686\uc687\uc688\uc689\uc68a\uc68b\uc68c\uc68d\uc68e\uc68f\uc690\uc691\uc692\uc693\uc694\uc695\uc696\uc697\uc698\uc699\uc69a\uc69b\uc69c\uc69d\uc69e\uc69f\uc6a0\uc6a1\uc6a2\uc6a3\uc6a4\uc6a5\uc6a6\uc6a7\uc6a8\uc6a9\uc6aa\uc6ab\uc6ac\uc6ad\uc6ae\uc6af\uc6b0\uc6b1\uc6b2\uc6b3\uc6b4\uc6b5\uc6b6\uc6b7\uc6b8\uc6b9\uc6ba\uc6bb\uc6bc\uc6bd\uc6be\uc6bf\uc6c0\uc6c1\uc6c2\uc6c3\uc6c4\uc6c5\uc6c6\uc6c7\uc6c8\uc6c9\uc6ca\uc6cb\uc6cc\uc6cd\uc6ce\uc6cf\uc6d0\uc6d1\uc6d2\uc6d3\uc6d4\uc6d5\uc6d6\uc6d7\uc6d8\uc6d9\uc6da\uc6db\uc6dc\uc6dd\uc6de\uc6df\uc6e0\uc6e1\uc6e2\uc6e3\uc6e4\uc6e5\uc6e6\uc6e7\uc6e8\uc6e9\uc6ea\uc6eb\uc6ec\uc6ed\uc6ee\uc6ef\uc6f0\uc6f1\uc6f2\uc6f3\uc6f4\uc6f5\uc6f6\uc6f7\uc6f8\uc6f9\uc6fa\uc6fb\uc6fc\uc6fd\uc6fe\uc6ff\uc700\uc701\uc702\uc703\uc704\uc705\uc706\uc707\uc708\uc709\uc70a\uc70b\uc70c\uc70d\uc70e\uc70f\uc710\uc711\uc712\uc713\uc714\uc715\uc716\uc717\uc718\uc719\uc71a\uc71b\uc71c\uc71d\uc71e\uc71f\uc720\uc721\uc722\uc723\uc724\uc725\uc726\uc727\uc728\uc729\uc72a\uc72b\uc72c\uc72d\uc72e\uc72f\uc730\uc731\uc732\uc733\uc734\uc735\uc736\uc737\uc738\uc739\uc73a\uc73b\uc73c\uc73d\uc73e\uc73f\uc740\uc741\uc742\uc743\uc744\uc745\uc746\uc747\uc748\uc749\uc74a\uc74b\uc74c\uc74d\uc74e\uc74f\uc750\uc751\uc752\uc753\uc754\uc755\uc756\uc757\uc758\uc759\uc75a\uc75b\uc75c\uc75d\uc75e\uc75f\uc760\uc761\uc762\uc763\uc764\uc765\uc766\uc767\uc768\uc769\uc76a\uc76b\uc76c\uc76d\uc76e\uc76f\uc770\uc771\uc772\uc773\uc774\uc775\uc776\uc777\uc778\uc779\uc77a\uc77b\uc77c\uc77d\uc77e\uc77f\uc780\uc781\uc782\uc783\uc784\uc785\uc786\uc787\uc788\uc789\uc78a\uc78b\uc78c\uc78d\uc78e\uc78f\uc790\uc791\uc792\uc793\uc794\uc795\uc796\uc797\uc798\uc799\uc79a\uc79b\uc79c\uc79d\uc79e\uc79f\uc7a0\uc7a1\uc7a2\uc7a3\uc7a4\uc7a5\uc7a6\uc7a7\uc7a8\uc7a9\uc7aa\uc7ab\uc7ac\uc7ad\uc7ae\uc7af\uc7b0\uc7b1\uc7b2\uc7b3\uc7b4\uc7b5\uc7b6\uc7b7\uc7b8\uc7b9\uc7ba\uc7bb\uc7bc\uc7bd\uc7be\uc7bf\uc7c0\uc7c1\uc7c2\uc7c3\uc7c4\uc7c5\uc7c6\uc7c7\uc7c8\uc7c9\uc7ca\uc7cb\uc7cc\uc7cd\uc7ce\uc7cf\uc7d0\uc7d1\uc7d2\uc7d3\uc7d4\uc7d5\uc7d6\uc7d7\uc7d8\uc7d9\uc7da\uc7db\uc7dc\uc7dd\uc7de\uc7df\uc7e0\uc7e1\uc7e2\uc7e3\uc7e4\uc7e5\uc7e6\uc7e7\uc7e8\uc7e9\uc7ea\uc7eb\uc7ec\uc7ed\uc7ee\uc7ef\uc7f0\uc7f1\uc7f2\uc7f3\uc7f4\uc7f5\uc7f6\uc7f7\uc7f8\uc7f9\uc7fa\uc7fb\uc7fc\uc7fd\uc7fe\uc7ff\uc800\uc801\uc802\uc803\uc804\uc805\uc806\uc807\uc808\uc809\uc80a\uc80b\uc80c\uc80d\uc80e\uc80f\uc810\uc811\uc812\uc813\uc814\uc815\uc816\uc817\uc818\uc819\uc81a\uc81b\uc81c\uc81d\uc81e\uc81f\uc820\uc821\uc822\uc823\uc824\uc825\uc826\uc827\uc828\uc829\uc82a\uc82b\uc82c\uc82d\uc82e\uc82f\uc830\uc831\uc832\uc833\uc834\uc835\uc836\uc837\uc838\uc839\uc83a\uc83b\uc83c\uc83d\uc83e\uc83f\uc840\uc841\uc842\uc843\uc844\uc845\uc846\uc847\uc848\uc849\uc84a\uc84b\uc84c\uc84d\uc84e\uc84f\uc850\uc851\uc852\uc853\uc854\uc855\uc856\uc857\uc858\uc859\uc85a\uc85b\uc85c\uc85d\uc85e\uc85f\uc860\uc861\uc862\uc863\uc864\uc865\uc866\uc867\uc868\uc869\uc86a\uc86b\uc86c\uc86d\uc86e\uc86f\uc870\uc871\uc872\uc873\uc874\uc875\uc876\uc877\uc878\uc879\uc87a\uc87b\uc87c\uc87d\uc87e\uc87f\uc880\uc881\uc882\uc883\uc884\uc885\uc886\uc887\uc888\uc889\uc88a\uc88b\uc88c\uc88d\uc88e\uc88f\uc890\uc891\uc892\uc893\uc894\uc895\uc896\uc897\uc898\uc899\uc89a\uc89b\uc89c\uc89d\uc89e\uc89f\uc8a0\uc8a1\uc8a2\uc8a3\uc8a4\uc8a5\uc8a6\uc8a7\uc8a8\uc8a9\uc8aa\uc8ab\uc8ac\uc8ad\uc8ae\uc8af\uc8b0\uc8b1\uc8b2\uc8b3\uc8b4\uc8b5\uc8b6\uc8b7\uc8b8\uc8b9\uc8ba\uc8bb\uc8bc\uc8bd\uc8be\uc8bf\uc8c0\uc8c1\uc8c2\uc8c3\uc8c4\uc8c5\uc8c6\uc8c7\uc8c8\uc8c9\uc8ca\uc8cb\uc8cc\uc8cd\uc8ce\uc8cf\uc8d0\uc8d1\uc8d2\uc8d3\uc8d4\uc8d5\uc8d6\uc8d7\uc8d8\uc8d9\uc8da\uc8db\uc8dc\uc8dd\uc8de\uc8df\uc8e0\uc8e1\uc8e2\uc8e3\uc8e4\uc8e5\uc8e6\uc8e7\uc8e8\uc8e9\uc8ea\uc8eb\uc8ec\uc8ed\uc8ee\uc8ef\uc8f0\uc8f1\uc8f2\uc8f3\uc8f4\uc8f5\uc8f6\uc8f7\uc8f8\uc8f9\uc8fa\uc8fb\uc8fc\uc8fd\uc8fe\uc8ff\uc900\uc901\uc902\uc903\uc904\uc905\uc906\uc907\uc908\uc909\uc90a\uc90b\uc90c\uc90d\uc90e\uc90f\uc910\uc911\uc912\uc913\uc914\uc915\uc916\uc917\uc918\uc919\uc91a\uc91b\uc91c\uc91d\uc91e\uc91f\uc920\uc921\uc922\uc923\uc924\uc925\uc926\uc927\uc928\uc929\uc92a\uc92b\uc92c\uc92d\uc92e\uc92f\uc930\uc931\uc932\uc933\uc934\uc935\uc936\uc937\uc938\uc939\uc93a\uc93b\uc93c\uc93d\uc93e\uc93f\uc940\uc941\uc942\uc943\uc944\uc945\uc946\uc947\uc948\uc949\uc94a\uc94b\uc94c\uc94d\uc94e\uc94f\uc950\uc951\uc952\uc953\uc954\uc955\uc956\uc957\uc958\uc959\uc95a\uc95b\uc95c\uc95d\uc95e\uc95f\uc960\uc961\uc962\uc963\uc964\uc965\uc966\uc967\uc968\uc969\uc96a\uc96b\uc96c\uc96d\uc96e\uc96f\uc970\uc971\uc972\uc973\uc974\uc975\uc976\uc977\uc978\uc979\uc97a\uc97b\uc97c\uc97d\uc97e\uc97f\uc980\uc981\uc982\uc983\uc984\uc985\uc986\uc987\uc988\uc989\uc98a\uc98b\uc98c\uc98d\uc98e\uc98f\uc990\uc991\uc992\uc993\uc994\uc995\uc996\uc997\uc998\uc999\uc99a\uc99b\uc99c\uc99d\uc99e\uc99f\uc9a0\uc9a1\uc9a2\uc9a3\uc9a4\uc9a5\uc9a6\uc9a7\uc9a8\uc9a9\uc9aa\uc9ab\uc9ac\uc9ad\uc9ae\uc9af\uc9b0\uc9b1\uc9b2\uc9b3\uc9b4\uc9b5\uc9b6\uc9b7\uc9b8\uc9b9\uc9ba\uc9bb\uc9bc\uc9bd\uc9be\uc9bf\uc9c0\uc9c1\uc9c2\uc9c3\uc9c4\uc9c5\uc9c6\uc9c7\uc9c8\uc9c9\uc9ca\uc9cb\uc9cc\uc9cd\uc9ce\uc9cf\uc9d0\uc9d1\uc9d2\uc9d3\uc9d4\uc9d5\uc9d6\uc9d7\uc9d8\uc9d9\uc9da\uc9db\uc9dc\uc9dd\uc9de\uc9df\uc9e0\uc9e1\uc9e2\uc9e3\uc9e4\uc9e5\uc9e6\uc9e7\uc9e8\uc9e9\uc9ea\uc9eb\uc9ec\uc9ed\uc9ee\uc9ef\uc9f0\uc9f1\uc9f2\uc9f3\uc9f4\uc9f5\uc9f6\uc9f7\uc9f8\uc9f9\uc9fa\uc9fb\uc9fc\uc9fd\uc9fe\uc9ff\uca00\uca01\uca02\uca03\uca04\uca05\uca06\uca07\uca08\uca09\uca0a\uca0b\uca0c\uca0d\uca0e\uca0f\uca10\uca11\uca12\uca13\uca14\uca15\uca16\uca17\uca18\uca19\uca1a\uca1b\uca1c\uca1d\uca1e\uca1f\uca20\uca21\uca22\uca23\uca24\uca25\uca26\uca27\uca28\uca29\uca2a\uca2b\uca2c\uca2d\uca2e\uca2f\uca30\uca31\uca32\uca33\uca34\uca35\uca36\uca37\uca38\uca39\uca3a\uca3b\uca3c\uca3d\uca3e\uca3f\uca40\uca41\uca42\uca43\uca44\uca45\uca46\uca47\uca48\uca49\uca4a\uca4b\uca4c\uca4d\uca4e\uca4f\uca50\uca51\uca52\uca53\uca54\uca55\uca56\uca57\uca58\uca59\uca5a\uca5b\uca5c\uca5d\uca5e\uca5f\uca60\uca61\uca62\uca63\uca64\uca65\uca66\uca67\uca68\uca69\uca6a\uca6b\uca6c\uca6d\uca6e\uca6f\uca70\uca71\uca72\uca73\uca74\uca75\uca76\uca77\uca78\uca79\uca7a\uca7b\uca7c\uca7d\uca7e\uca7f\uca80\uca81\uca82\uca83\uca84\uca85\uca86\uca87\uca88\uca89\uca8a\uca8b\uca8c\uca8d\uca8e\uca8f\uca90\uca91\uca92\uca93\uca94\uca95\uca96\uca97\uca98\uca99\uca9a\uca9b\uca9c\uca9d\uca9e\uca9f\ucaa0\ucaa1\ucaa2\ucaa3\ucaa4\ucaa5\ucaa6\ucaa7\ucaa8\ucaa9\ucaaa\ucaab\ucaac\ucaad\ucaae\ucaaf\ucab0\ucab1\ucab2\ucab3\ucab4\ucab5\ucab6\ucab7\ucab8\ucab9\ucaba\ucabb\ucabc\ucabd\ucabe\ucabf\ucac0\ucac1\ucac2\ucac3\ucac4\ucac5\ucac6\ucac7\ucac8\ucac9\ucaca\ucacb\ucacc\ucacd\ucace\ucacf\ucad0\ucad1\ucad2\ucad3\ucad4\ucad5\ucad6\ucad7\ucad8\ucad9\ucada\ucadb\ucadc\ucadd\ucade\ucadf\ucae0\ucae1\ucae2\ucae3\ucae4\ucae5\ucae6\ucae7\ucae8\ucae9\ucaea\ucaeb\ucaec\ucaed\ucaee\ucaef\ucaf0\ucaf1\ucaf2\ucaf3\ucaf4\ucaf5\ucaf6\ucaf7\ucaf8\ucaf9\ucafa\ucafb\ucafc\ucafd\ucafe\ucaff\ucb00\ucb01\ucb02\ucb03\ucb04\ucb05\ucb06\ucb07\ucb08\ucb09\ucb0a\ucb0b\ucb0c\ucb0d\ucb0e\ucb0f\ucb10\ucb11\ucb12\ucb13\ucb14\ucb15\ucb16\ucb17\ucb18\ucb19\ucb1a\ucb1b\ucb1c\ucb1d\ucb1e\ucb1f\ucb20\ucb21\ucb22\ucb23\ucb24\ucb25\ucb26\ucb27\ucb28\ucb29\ucb2a\ucb2b\ucb2c\ucb2d\ucb2e\ucb2f\ucb30\ucb31\ucb32\ucb33\ucb34\ucb35\ucb36\ucb37\ucb38\ucb39\ucb3a\ucb3b\ucb3c\ucb3d\ucb3e\ucb3f\ucb40\ucb41\ucb42\ucb43\ucb44\ucb45\ucb46\ucb47\ucb48\ucb49\ucb4a\ucb4b\ucb4c\ucb4d\ucb4e\ucb4f\ucb50\ucb51\ucb52\ucb53\ucb54\ucb55\ucb56\ucb57\ucb58\ucb59\ucb5a\ucb5b\ucb5c\ucb5d\ucb5e\ucb5f\ucb60\ucb61\ucb62\ucb63\ucb64\ucb65\ucb66\ucb67\ucb68\ucb69\ucb6a\ucb6b\ucb6c\ucb6d\ucb6e\ucb6f\ucb70\ucb71\ucb72\ucb73\ucb74\ucb75\ucb76\ucb77\ucb78\ucb79\ucb7a\ucb7b\ucb7c\ucb7d\ucb7e\ucb7f\ucb80\ucb81\ucb82\ucb83\ucb84\ucb85\ucb86\ucb87\ucb88\ucb89\ucb8a\ucb8b\ucb8c\ucb8d\ucb8e\ucb8f\ucb90\ucb91\ucb92\ucb93\ucb94\ucb95\ucb96\ucb97\ucb98\ucb99\ucb9a\ucb9b\ucb9c\ucb9d\ucb9e\ucb9f\ucba0\ucba1\ucba2\ucba3\ucba4\ucba5\ucba6\ucba7\ucba8\ucba9\ucbaa\ucbab\ucbac\ucbad\ucbae\ucbaf\ucbb0\ucbb1\ucbb2\ucbb3\ucbb4\ucbb5\ucbb6\ucbb7\ucbb8\ucbb9\ucbba\ucbbb\ucbbc\ucbbd\ucbbe\ucbbf\ucbc0\ucbc1\ucbc2\ucbc3\ucbc4\ucbc5\ucbc6\ucbc7\ucbc8\ucbc9\ucbca\ucbcb\ucbcc\ucbcd\ucbce\ucbcf\ucbd0\ucbd1\ucbd2\ucbd3\ucbd4\ucbd5\ucbd6\ucbd7\ucbd8\ucbd9\ucbda\ucbdb\ucbdc\ucbdd\ucbde\ucbdf\ucbe0\ucbe1\ucbe2\ucbe3\ucbe4\ucbe5\ucbe6\ucbe7\ucbe8\ucbe9\ucbea\ucbeb\ucbec\ucbed\ucbee\ucbef\ucbf0\ucbf1\ucbf2\ucbf3\ucbf4\ucbf5\ucbf6\ucbf7\ucbf8\ucbf9\ucbfa\ucbfb\ucbfc\ucbfd\ucbfe\ucbff\ucc00\ucc01\ucc02\ucc03\ucc04\ucc05\ucc06\ucc07\ucc08\ucc09\ucc0a\ucc0b\ucc0c\ucc0d\ucc0e\ucc0f\ucc10\ucc11\ucc12\ucc13\ucc14\ucc15\ucc16\ucc17\ucc18\ucc19\ucc1a\ucc1b\ucc1c\ucc1d\ucc1e\ucc1f\ucc20\ucc21\ucc22\ucc23\ucc24\ucc25\ucc26\ucc27\ucc28\ucc29\ucc2a\ucc2b\ucc2c\ucc2d\ucc2e\ucc2f\ucc30\ucc31\ucc32\ucc33\ucc34\ucc35\ucc36\ucc37\ucc38\ucc39\ucc3a\ucc3b\ucc3c\ucc3d\ucc3e\ucc3f\ucc40\ucc41\ucc42\ucc43\ucc44\ucc45\ucc46\ucc47\ucc48\ucc49\ucc4a\ucc4b\ucc4c\ucc4d\ucc4e\ucc4f\ucc50\ucc51\ucc52\ucc53\ucc54\ucc55\ucc56\ucc57\ucc58\ucc59\ucc5a\ucc5b\ucc5c\ucc5d\ucc5e\ucc5f\ucc60\ucc61\ucc62\ucc63\ucc64\ucc65\ucc66\ucc67\ucc68\ucc69\ucc6a\ucc6b\ucc6c\ucc6d\ucc6e\ucc6f\ucc70\ucc71\ucc72\ucc73\ucc74\ucc75\ucc76\ucc77\ucc78\ucc79\ucc7a\ucc7b\ucc7c\ucc7d\ucc7e\ucc7f\ucc80\ucc81\ucc82\ucc83\ucc84\ucc85\ucc86\ucc87\ucc88\ucc89\ucc8a\ucc8b\ucc8c\ucc8d\ucc8e\ucc8f\ucc90\ucc91\ucc92\ucc93\ucc94\ucc95\ucc96\ucc97\ucc98\ucc99\ucc9a\ucc9b\ucc9c\ucc9d\ucc9e\ucc9f\ucca0\ucca1\ucca2\ucca3\ucca4\ucca5\ucca6\ucca7\ucca8\ucca9\uccaa\uccab\uccac\uccad\uccae\uccaf\uccb0\uccb1\uccb2\uccb3\uccb4\uccb5\uccb6\uccb7\uccb8\uccb9\uccba\uccbb\uccbc\uccbd\uccbe\uccbf\uccc0\uccc1\uccc2\uccc3\uccc4\uccc5\uccc6\uccc7\uccc8\uccc9\uccca\ucccb\ucccc\ucccd\uccce\ucccf\uccd0\uccd1\uccd2\uccd3\uccd4\uccd5\uccd6\uccd7\uccd8\uccd9\uccda\uccdb\uccdc\uccdd\uccde\uccdf\ucce0\ucce1\ucce2\ucce3\ucce4\ucce5\ucce6\ucce7\ucce8\ucce9\uccea\ucceb\uccec\ucced\uccee\uccef\uccf0\uccf1\uccf2\uccf3\uccf4\uccf5\uccf6\uccf7\uccf8\uccf9\uccfa\uccfb\uccfc\uccfd\uccfe\uccff\ucd00\ucd01\ucd02\ucd03\ucd04\ucd05\ucd06\ucd07\ucd08\ucd09\ucd0a\ucd0b\ucd0c\ucd0d\ucd0e\ucd0f\ucd10\ucd11\ucd12\ucd13\ucd14\ucd15\ucd16\ucd17\ucd18\ucd19\ucd1a\ucd1b\ucd1c\ucd1d\ucd1e\ucd1f\ucd20\ucd21\ucd22\ucd23\ucd24\ucd25\ucd26\ucd27\ucd28\ucd29\ucd2a\ucd2b\ucd2c\ucd2d\ucd2e\ucd2f\ucd30\ucd31\ucd32\ucd33\ucd34\ucd35\ucd36\ucd37\ucd38\ucd39\ucd3a\ucd3b\ucd3c\ucd3d\ucd3e\ucd3f\ucd40\ucd41\ucd42\ucd43\ucd44\ucd45\ucd46\ucd47\ucd48\ucd49\ucd4a\ucd4b\ucd4c\ucd4d\ucd4e\ucd4f\ucd50\ucd51\ucd52\ucd53\ucd54\ucd55\ucd56\ucd57\ucd58\ucd59\ucd5a\ucd5b\ucd5c\ucd5d\ucd5e\ucd5f\ucd60\ucd61\ucd62\ucd63\ucd64\ucd65\ucd66\ucd67\ucd68\ucd69\ucd6a\ucd6b\ucd6c\ucd6d\ucd6e\ucd6f\ucd70\ucd71\ucd72\ucd73\ucd74\ucd75\ucd76\ucd77\ucd78\ucd79\ucd7a\ucd7b\ucd7c\ucd7d\ucd7e\ucd7f\ucd80\ucd81\ucd82\ucd83\ucd84\ucd85\ucd86\ucd87\ucd88\ucd89\ucd8a\ucd8b\ucd8c\ucd8d\ucd8e\ucd8f\ucd90\ucd91\ucd92\ucd93\ucd94\ucd95\ucd96\ucd97\ucd98\ucd99\ucd9a\ucd9b\ucd9c\ucd9d\ucd9e\ucd9f\ucda0\ucda1\ucda2\ucda3\ucda4\ucda5\ucda6\ucda7\ucda8\ucda9\ucdaa\ucdab\ucdac\ucdad\ucdae\ucdaf\ucdb0\ucdb1\ucdb2\ucdb3\ucdb4\ucdb5\ucdb6\ucdb7\ucdb8\ucdb9\ucdba\ucdbb\ucdbc\ucdbd\ucdbe\ucdbf\ucdc0\ucdc1\ucdc2\ucdc3\ucdc4\ucdc5\ucdc6\ucdc7\ucdc8\ucdc9\ucdca\ucdcb\ucdcc\ucdcd\ucdce\ucdcf\ucdd0\ucdd1\ucdd2\ucdd3\ucdd4\ucdd5\ucdd6\ucdd7\ucdd8\ucdd9\ucdda\ucddb\ucddc\ucddd\ucdde\ucddf\ucde0\ucde1\ucde2\ucde3\ucde4\ucde5\ucde6\ucde7\ucde8\ucde9\ucdea\ucdeb\ucdec\ucded\ucdee\ucdef\ucdf0\ucdf1\ucdf2\ucdf3\ucdf4\ucdf5\ucdf6\ucdf7\ucdf8\ucdf9\ucdfa\ucdfb\ucdfc\ucdfd\ucdfe\ucdff\uce00\uce01\uce02\uce03\uce04\uce05\uce06\uce07\uce08\uce09\uce0a\uce0b\uce0c\uce0d\uce0e\uce0f\uce10\uce11\uce12\uce13\uce14\uce15\uce16\uce17\uce18\uce19\uce1a\uce1b\uce1c\uce1d\uce1e\uce1f\uce20\uce21\uce22\uce23\uce24\uce25\uce26\uce27\uce28\uce29\uce2a\uce2b\uce2c\uce2d\uce2e\uce2f\uce30\uce31\uce32\uce33\uce34\uce35\uce36\uce37\uce38\uce39\uce3a\uce3b\uce3c\uce3d\uce3e\uce3f\uce40\uce41\uce42\uce43\uce44\uce45\uce46\uce47\uce48\uce49\uce4a\uce4b\uce4c\uce4d\uce4e\uce4f\uce50\uce51\uce52\uce53\uce54\uce55\uce56\uce57\uce58\uce59\uce5a\uce5b\uce5c\uce5d\uce5e\uce5f\uce60\uce61\uce62\uce63\uce64\uce65\uce66\uce67\uce68\uce69\uce6a\uce6b\uce6c\uce6d\uce6e\uce6f\uce70\uce71\uce72\uce73\uce74\uce75\uce76\uce77\uce78\uce79\uce7a\uce7b\uce7c\uce7d\uce7e\uce7f\uce80\uce81\uce82\uce83\uce84\uce85\uce86\uce87\uce88\uce89\uce8a\uce8b\uce8c\uce8d\uce8e\uce8f\uce90\uce91\uce92\uce93\uce94\uce95\uce96\uce97\uce98\uce99\uce9a\uce9b\uce9c\uce9d\uce9e\uce9f\ucea0\ucea1\ucea2\ucea3\ucea4\ucea5\ucea6\ucea7\ucea8\ucea9\uceaa\uceab\uceac\ucead\uceae\uceaf\uceb0\uceb1\uceb2\uceb3\uceb4\uceb5\uceb6\uceb7\uceb8\uceb9\uceba\ucebb\ucebc\ucebd\ucebe\ucebf\ucec0\ucec1\ucec2\ucec3\ucec4\ucec5\ucec6\ucec7\ucec8\ucec9\uceca\ucecb\ucecc\ucecd\ucece\ucecf\uced0\uced1\uced2\uced3\uced4\uced5\uced6\uced7\uced8\uced9\uceda\ucedb\ucedc\ucedd\ucede\ucedf\ucee0\ucee1\ucee2\ucee3\ucee4\ucee5\ucee6\ucee7\ucee8\ucee9\uceea\uceeb\uceec\uceed\uceee\uceef\ucef0\ucef1\ucef2\ucef3\ucef4\ucef5\ucef6\ucef7\ucef8\ucef9\ucefa\ucefb\ucefc\ucefd\ucefe\uceff\ucf00\ucf01\ucf02\ucf03\ucf04\ucf05\ucf06\ucf07\ucf08\ucf09\ucf0a\ucf0b\ucf0c\ucf0d\ucf0e\ucf0f\ucf10\ucf11\ucf12\ucf13\ucf14\ucf15\ucf16\ucf17\ucf18\ucf19\ucf1a\ucf1b\ucf1c\ucf1d\ucf1e\ucf1f\ucf20\ucf21\ucf22\ucf23\ucf24\ucf25\ucf26\ucf27\ucf28\ucf29\ucf2a\ucf2b\ucf2c\ucf2d\ucf2e\ucf2f\ucf30\ucf31\ucf32\ucf33\ucf34\ucf35\ucf36\ucf37\ucf38\ucf39\ucf3a\ucf3b\ucf3c\ucf3d\ucf3e\ucf3f\ucf40\ucf41\ucf42\ucf43\ucf44\ucf45\ucf46\ucf47\ucf48\ucf49\ucf4a\ucf4b\ucf4c\ucf4d\ucf4e\ucf4f\ucf50\ucf51\ucf52\ucf53\ucf54\ucf55\ucf56\ucf57\ucf58\ucf59\ucf5a\ucf5b\ucf5c\ucf5d\ucf5e\ucf5f\ucf60\ucf61\ucf62\ucf63\ucf64\ucf65\ucf66\ucf67\ucf68\ucf69\ucf6a\ucf6b\ucf6c\ucf6d\ucf6e\ucf6f\ucf70\ucf71\ucf72\ucf73\ucf74\ucf75\ucf76\ucf77\ucf78\ucf79\ucf7a\ucf7b\ucf7c\ucf7d\ucf7e\ucf7f\ucf80\ucf81\ucf82\ucf83\ucf84\ucf85\ucf86\ucf87\ucf88\ucf89\ucf8a\ucf8b\ucf8c\ucf8d\ucf8e\ucf8f\ucf90\ucf91\ucf92\ucf93\ucf94\ucf95\ucf96\ucf97\ucf98\ucf99\ucf9a\ucf9b\ucf9c\ucf9d\ucf9e\ucf9f\ucfa0\ucfa1\ucfa2\ucfa3\ucfa4\ucfa5\ucfa6\ucfa7\ucfa8\ucfa9\ucfaa\ucfab\ucfac\ucfad\ucfae\ucfaf\ucfb0\ucfb1\ucfb2\ucfb3\ucfb4\ucfb5\ucfb6\ucfb7\ucfb8\ucfb9\ucfba\ucfbb\ucfbc\ucfbd\ucfbe\ucfbf\ucfc0\ucfc1\ucfc2\ucfc3\ucfc4\ucfc5\ucfc6\ucfc7\ucfc8\ucfc9\ucfca\ucfcb\ucfcc\ucfcd\ucfce\ucfcf\ucfd0\ucfd1\ucfd2\ucfd3\ucfd4\ucfd5\ucfd6\ucfd7\ucfd8\ucfd9\ucfda\ucfdb\ucfdc\ucfdd\ucfde\ucfdf\ucfe0\ucfe1\ucfe2\ucfe3\ucfe4\ucfe5\ucfe6\ucfe7\ucfe8\ucfe9\ucfea\ucfeb\ucfec\ucfed\ucfee\ucfef\ucff0\ucff1\ucff2\ucff3\ucff4\ucff5\ucff6\ucff7\ucff8\ucff9\ucffa\ucffb\ucffc\ucffd\ucffe\ucfff\ud000\ud001\ud002\ud003\ud004\ud005\ud006\ud007\ud008\ud009\ud00a\ud00b\ud00c\ud00d\ud00e\ud00f\ud010\ud011\ud012\ud013\ud014\ud015\ud016\ud017\ud018\ud019\ud01a\ud01b\ud01c\ud01d\ud01e\ud01f\ud020\ud021\ud022\ud023\ud024\ud025\ud026\ud027\ud028\ud029\ud02a\ud02b\ud02c\ud02d\ud02e\ud02f\ud030\ud031\ud032\ud033\ud034\ud035\ud036\ud037\ud038\ud039\ud03a\ud03b\ud03c\ud03d\ud03e\ud03f\ud040\ud041\ud042\ud043\ud044\ud045\ud046\ud047\ud048\ud049\ud04a\ud04b\ud04c\ud04d\ud04e\ud04f\ud050\ud051\ud052\ud053\ud054\ud055\ud056\ud057\ud058\ud059\ud05a\ud05b\ud05c\ud05d\ud05e\ud05f\ud060\ud061\ud062\ud063\ud064\ud065\ud066\ud067\ud068\ud069\ud06a\ud06b\ud06c\ud06d\ud06e\ud06f\ud070\ud071\ud072\ud073\ud074\ud075\ud076\ud077\ud078\ud079\ud07a\ud07b\ud07c\ud07d\ud07e\ud07f\ud080\ud081\ud082\ud083\ud084\ud085\ud086\ud087\ud088\ud089\ud08a\ud08b\ud08c\ud08d\ud08e\ud08f\ud090\ud091\ud092\ud093\ud094\ud095\ud096\ud097\ud098\ud099\ud09a\ud09b\ud09c\ud09d\ud09e\ud09f\ud0a0\ud0a1\ud0a2\ud0a3\ud0a4\ud0a5\ud0a6\ud0a7\ud0a8\ud0a9\ud0aa\ud0ab\ud0ac\ud0ad\ud0ae\ud0af\ud0b0\ud0b1\ud0b2\ud0b3\ud0b4\ud0b5\ud0b6\ud0b7\ud0b8\ud0b9\ud0ba\ud0bb\ud0bc\ud0bd\ud0be\ud0bf\ud0c0\ud0c1\ud0c2\ud0c3\ud0c4\ud0c5\ud0c6\ud0c7\ud0c8\ud0c9\ud0ca\ud0cb\ud0cc\ud0cd\ud0ce\ud0cf\ud0d0\ud0d1\ud0d2\ud0d3\ud0d4\ud0d5\ud0d6\ud0d7\ud0d8\ud0d9\ud0da\ud0db\ud0dc\ud0dd\ud0de\ud0df\ud0e0\ud0e1\ud0e2\ud0e3\ud0e4\ud0e5\ud0e6\ud0e7\ud0e8\ud0e9\ud0ea\ud0eb\ud0ec\ud0ed\ud0ee\ud0ef\ud0f0\ud0f1\ud0f2\ud0f3\ud0f4\ud0f5\ud0f6\ud0f7\ud0f8\ud0f9\ud0fa\ud0fb\ud0fc\ud0fd\ud0fe\ud0ff\ud100\ud101\ud102\ud103\ud104\ud105\ud106\ud107\ud108\ud109\ud10a\ud10b\ud10c\ud10d\ud10e\ud10f\ud110\ud111\ud112\ud113\ud114\ud115\ud116\ud117\ud118\ud119\ud11a\ud11b\ud11c\ud11d\ud11e\ud11f\ud120\ud121\ud122\ud123\ud124\ud125\ud126\ud127\ud128\ud129\ud12a\ud12b\ud12c\ud12d\ud12e\ud12f\ud130\ud131\ud132\ud133\ud134\ud135\ud136\ud137\ud138\ud139\ud13a\ud13b\ud13c\ud13d\ud13e\ud13f\ud140\ud141\ud142\ud143\ud144\ud145\ud146\ud147\ud148\ud149\ud14a\ud14b\ud14c\ud14d\ud14e\ud14f\ud150\ud151\ud152\ud153\ud154\ud155\ud156\ud157\ud158\ud159\ud15a\ud15b\ud15c\ud15d\ud15e\ud15f\ud160\ud161\ud162\ud163\ud164\ud165\ud166\ud167\ud168\ud169\ud16a\ud16b\ud16c\ud16d\ud16e\ud16f\ud170\ud171\ud172\ud173\ud174\ud175\ud176\ud177\ud178\ud179\ud17a\ud17b\ud17c\ud17d\ud17e\ud17f\ud180\ud181\ud182\ud183\ud184\ud185\ud186\ud187\ud188\ud189\ud18a\ud18b\ud18c\ud18d\ud18e\ud18f\ud190\ud191\ud192\ud193\ud194\ud195\ud196\ud197\ud198\ud199\ud19a\ud19b\ud19c\ud19d\ud19e\ud19f\ud1a0\ud1a1\ud1a2\ud1a3\ud1a4\ud1a5\ud1a6\ud1a7\ud1a8\ud1a9\ud1aa\ud1ab\ud1ac\ud1ad\ud1ae\ud1af\ud1b0\ud1b1\ud1b2\ud1b3\ud1b4\ud1b5\ud1b6\ud1b7\ud1b8\ud1b9\ud1ba\ud1bb\ud1bc\ud1bd\ud1be\ud1bf\ud1c0\ud1c1\ud1c2\ud1c3\ud1c4\ud1c5\ud1c6\ud1c7\ud1c8\ud1c9\ud1ca\ud1cb\ud1cc\ud1cd\ud1ce\ud1cf\ud1d0\ud1d1\ud1d2\ud1d3\ud1d4\ud1d5\ud1d6\ud1d7\ud1d8\ud1d9\ud1da\ud1db\ud1dc\ud1dd\ud1de\ud1df\ud1e0\ud1e1\ud1e2\ud1e3\ud1e4\ud1e5\ud1e6\ud1e7\ud1e8\ud1e9\ud1ea\ud1eb\ud1ec\ud1ed\ud1ee\ud1ef\ud1f0\ud1f1\ud1f2\ud1f3\ud1f4\ud1f5\ud1f6\ud1f7\ud1f8\ud1f9\ud1fa\ud1fb\ud1fc\ud1fd\ud1fe\ud1ff\ud200\ud201\ud202\ud203\ud204\ud205\ud206\ud207\ud208\ud209\ud20a\ud20b\ud20c\ud20d\ud20e\ud20f\ud210\ud211\ud212\ud213\ud214\ud215\ud216\ud217\ud218\ud219\ud21a\ud21b\ud21c\ud21d\ud21e\ud21f\ud220\ud221\ud222\ud223\ud224\ud225\ud226\ud227\ud228\ud229\ud22a\ud22b\ud22c\ud22d\ud22e\ud22f\ud230\ud231\ud232\ud233\ud234\ud235\ud236\ud237\ud238\ud239\ud23a\ud23b\ud23c\ud23d\ud23e\ud23f\ud240\ud241\ud242\ud243\ud244\ud245\ud246\ud247\ud248\ud249\ud24a\ud24b\ud24c\ud24d\ud24e\ud24f\ud250\ud251\ud252\ud253\ud254\ud255\ud256\ud257\ud258\ud259\ud25a\ud25b\ud25c\ud25d\ud25e\ud25f\ud260\ud261\ud262\ud263\ud264\ud265\ud266\ud267\ud268\ud269\ud26a\ud26b\ud26c\ud26d\ud26e\ud26f\ud270\ud271\ud272\ud273\ud274\ud275\ud276\ud277\ud278\ud279\ud27a\ud27b\ud27c\ud27d\ud27e\ud27f\ud280\ud281\ud282\ud283\ud284\ud285\ud286\ud287\ud288\ud289\ud28a\ud28b\ud28c\ud28d\ud28e\ud28f\ud290\ud291\ud292\ud293\ud294\ud295\ud296\ud297\ud298\ud299\ud29a\ud29b\ud29c\ud29d\ud29e\ud29f\ud2a0\ud2a1\ud2a2\ud2a3\ud2a4\ud2a5\ud2a6\ud2a7\ud2a8\ud2a9\ud2aa\ud2ab\ud2ac\ud2ad\ud2ae\ud2af\ud2b0\ud2b1\ud2b2\ud2b3\ud2b4\ud2b5\ud2b6\ud2b7\ud2b8\ud2b9\ud2ba\ud2bb\ud2bc\ud2bd\ud2be\ud2bf\ud2c0\ud2c1\ud2c2\ud2c3\ud2c4\ud2c5\ud2c6\ud2c7\ud2c8\ud2c9\ud2ca\ud2cb\ud2cc\ud2cd\ud2ce\ud2cf\ud2d0\ud2d1\ud2d2\ud2d3\ud2d4\ud2d5\ud2d6\ud2d7\ud2d8\ud2d9\ud2da\ud2db\ud2dc\ud2dd\ud2de\ud2df\ud2e0\ud2e1\ud2e2\ud2e3\ud2e4\ud2e5\ud2e6\ud2e7\ud2e8\ud2e9\ud2ea\ud2eb\ud2ec\ud2ed\ud2ee\ud2ef\ud2f0\ud2f1\ud2f2\ud2f3\ud2f4\ud2f5\ud2f6\ud2f7\ud2f8\ud2f9\ud2fa\ud2fb\ud2fc\ud2fd\ud2fe\ud2ff\ud300\ud301\ud302\ud303\ud304\ud305\ud306\ud307\ud308\ud309\ud30a\ud30b\ud30c\ud30d\ud30e\ud30f\ud310\ud311\ud312\ud313\ud314\ud315\ud316\ud317\ud318\ud319\ud31a\ud31b\ud31c\ud31d\ud31e\ud31f\ud320\ud321\ud322\ud323\ud324\ud325\ud326\ud327\ud328\ud329\ud32a\ud32b\ud32c\ud32d\ud32e\ud32f\ud330\ud331\ud332\ud333\ud334\ud335\ud336\ud337\ud338\ud339\ud33a\ud33b\ud33c\ud33d\ud33e\ud33f\ud340\ud341\ud342\ud343\ud344\ud345\ud346\ud347\ud348\ud349\ud34a\ud34b\ud34c\ud34d\ud34e\ud34f\ud350\ud351\ud352\ud353\ud354\ud355\ud356\ud357\ud358\ud359\ud35a\ud35b\ud35c\ud35d\ud35e\ud35f\ud360\ud361\ud362\ud363\ud364\ud365\ud366\ud367\ud368\ud369\ud36a\ud36b\ud36c\ud36d\ud36e\ud36f\ud370\ud371\ud372\ud373\ud374\ud375\ud376\ud377\ud378\ud379\ud37a\ud37b\ud37c\ud37d\ud37e\ud37f\ud380\ud381\ud382\ud383\ud384\ud385\ud386\ud387\ud388\ud389\ud38a\ud38b\ud38c\ud38d\ud38e\ud38f\ud390\ud391\ud392\ud393\ud394\ud395\ud396\ud397\ud398\ud399\ud39a\ud39b\ud39c\ud39d\ud39e\ud39f\ud3a0\ud3a1\ud3a2\ud3a3\ud3a4\ud3a5\ud3a6\ud3a7\ud3a8\ud3a9\ud3aa\ud3ab\ud3ac\ud3ad\ud3ae\ud3af\ud3b0\ud3b1\ud3b2\ud3b3\ud3b4\ud3b5\ud3b6\ud3b7\ud3b8\ud3b9\ud3ba\ud3bb\ud3bc\ud3bd\ud3be\ud3bf\ud3c0\ud3c1\ud3c2\ud3c3\ud3c4\ud3c5\ud3c6\ud3c7\ud3c8\ud3c9\ud3ca\ud3cb\ud3cc\ud3cd\ud3ce\ud3cf\ud3d0\ud3d1\ud3d2\ud3d3\ud3d4\ud3d5\ud3d6\ud3d7\ud3d8\ud3d9\ud3da\ud3db\ud3dc\ud3dd\ud3de\ud3df\ud3e0\ud3e1\ud3e2\ud3e3\ud3e4\ud3e5\ud3e6\ud3e7\ud3e8\ud3e9\ud3ea\ud3eb\ud3ec\ud3ed\ud3ee\ud3ef\ud3f0\ud3f1\ud3f2\ud3f3\ud3f4\ud3f5\ud3f6\ud3f7\ud3f8\ud3f9\ud3fa\ud3fb\ud3fc\ud3fd\ud3fe\ud3ff\ud400\ud401\ud402\ud403\ud404\ud405\ud406\ud407\ud408\ud409\ud40a\ud40b\ud40c\ud40d\ud40e\ud40f\ud410\ud411\ud412\ud413\ud414\ud415\ud416\ud417\ud418\ud419\ud41a\ud41b\ud41c\ud41d\ud41e\ud41f\ud420\ud421\ud422\ud423\ud424\ud425\ud426\ud427\ud428\ud429\ud42a\ud42b\ud42c\ud42d\ud42e\ud42f\ud430\ud431\ud432\ud433\ud434\ud435\ud436\ud437\ud438\ud439\ud43a\ud43b\ud43c\ud43d\ud43e\ud43f\ud440\ud441\ud442\ud443\ud444\ud445\ud446\ud447\ud448\ud449\ud44a\ud44b\ud44c\ud44d\ud44e\ud44f\ud450\ud451\ud452\ud453\ud454\ud455\ud456\ud457\ud458\ud459\ud45a\ud45b\ud45c\ud45d\ud45e\ud45f\ud460\ud461\ud462\ud463\ud464\ud465\ud466\ud467\ud468\ud469\ud46a\ud46b\ud46c\ud46d\ud46e\ud46f\ud470\ud471\ud472\ud473\ud474\ud475\ud476\ud477\ud478\ud479\ud47a\ud47b\ud47c\ud47d\ud47e\ud47f\ud480\ud481\ud482\ud483\ud484\ud485\ud486\ud487\ud488\ud489\ud48a\ud48b\ud48c\ud48d\ud48e\ud48f\ud490\ud491\ud492\ud493\ud494\ud495\ud496\ud497\ud498\ud499\ud49a\ud49b\ud49c\ud49d\ud49e\ud49f\ud4a0\ud4a1\ud4a2\ud4a3\ud4a4\ud4a5\ud4a6\ud4a7\ud4a8\ud4a9\ud4aa\ud4ab\ud4ac\ud4ad\ud4ae\ud4af\ud4b0\ud4b1\ud4b2\ud4b3\ud4b4\ud4b5\ud4b6\ud4b7\ud4b8\ud4b9\ud4ba\ud4bb\ud4bc\ud4bd\ud4be\ud4bf\ud4c0\ud4c1\ud4c2\ud4c3\ud4c4\ud4c5\ud4c6\ud4c7\ud4c8\ud4c9\ud4ca\ud4cb\ud4cc\ud4cd\ud4ce\ud4cf\ud4d0\ud4d1\ud4d2\ud4d3\ud4d4\ud4d5\ud4d6\ud4d7\ud4d8\ud4d9\ud4da\ud4db\ud4dc\ud4dd\ud4de\ud4df\ud4e0\ud4e1\ud4e2\ud4e3\ud4e4\ud4e5\ud4e6\ud4e7\ud4e8\ud4e9\ud4ea\ud4eb\ud4ec\ud4ed\ud4ee\ud4ef\ud4f0\ud4f1\ud4f2\ud4f3\ud4f4\ud4f5\ud4f6\ud4f7\ud4f8\ud4f9\ud4fa\ud4fb\ud4fc\ud4fd\ud4fe\ud4ff\ud500\ud501\ud502\ud503\ud504\ud505\ud506\ud507\ud508\ud509\ud50a\ud50b\ud50c\ud50d\ud50e\ud50f\ud510\ud511\ud512\ud513\ud514\ud515\ud516\ud517\ud518\ud519\ud51a\ud51b\ud51c\ud51d\ud51e\ud51f\ud520\ud521\ud522\ud523\ud524\ud525\ud526\ud527\ud528\ud529\ud52a\ud52b\ud52c\ud52d\ud52e\ud52f\ud530\ud531\ud532\ud533\ud534\ud535\ud536\ud537\ud538\ud539\ud53a\ud53b\ud53c\ud53d\ud53e\ud53f\ud540\ud541\ud542\ud543\ud544\ud545\ud546\ud547\ud548\ud549\ud54a\ud54b\ud54c\ud54d\ud54e\ud54f\ud550\ud551\ud552\ud553\ud554\ud555\ud556\ud557\ud558\ud559\ud55a\ud55b\ud55c\ud55d\ud55e\ud55f\ud560\ud561\ud562\ud563\ud564\ud565\ud566\ud567\ud568\ud569\ud56a\ud56b\ud56c\ud56d\ud56e\ud56f\ud570\ud571\ud572\ud573\ud574\ud575\ud576\ud577\ud578\ud579\ud57a\ud57b\ud57c\ud57d\ud57e\ud57f\ud580\ud581\ud582\ud583\ud584\ud585\ud586\ud587\ud588\ud589\ud58a\ud58b\ud58c\ud58d\ud58e\ud58f\ud590\ud591\ud592\ud593\ud594\ud595\ud596\ud597\ud598\ud599\ud59a\ud59b\ud59c\ud59d\ud59e\ud59f\ud5a0\ud5a1\ud5a2\ud5a3\ud5a4\ud5a5\ud5a6\ud5a7\ud5a8\ud5a9\ud5aa\ud5ab\ud5ac\ud5ad\ud5ae\ud5af\ud5b0\ud5b1\ud5b2\ud5b3\ud5b4\ud5b5\ud5b6\ud5b7\ud5b8\ud5b9\ud5ba\ud5bb\ud5bc\ud5bd\ud5be\ud5bf\ud5c0\ud5c1\ud5c2\ud5c3\ud5c4\ud5c5\ud5c6\ud5c7\ud5c8\ud5c9\ud5ca\ud5cb\ud5cc\ud5cd\ud5ce\ud5cf\ud5d0\ud5d1\ud5d2\ud5d3\ud5d4\ud5d5\ud5d6\ud5d7\ud5d8\ud5d9\ud5da\ud5db\ud5dc\ud5dd\ud5de\ud5df\ud5e0\ud5e1\ud5e2\ud5e3\ud5e4\ud5e5\ud5e6\ud5e7\ud5e8\ud5e9\ud5ea\ud5eb\ud5ec\ud5ed\ud5ee\ud5ef\ud5f0\ud5f1\ud5f2\ud5f3\ud5f4\ud5f5\ud5f6\ud5f7\ud5f8\ud5f9\ud5fa\ud5fb\ud5fc\ud5fd\ud5fe\ud5ff\ud600\ud601\ud602\ud603\ud604\ud605\ud606\ud607\ud608\ud609\ud60a\ud60b\ud60c\ud60d\ud60e\ud60f\ud610\ud611\ud612\ud613\ud614\ud615\ud616\ud617\ud618\ud619\ud61a\ud61b\ud61c\ud61d\ud61e\ud61f\ud620\ud621\ud622\ud623\ud624\ud625\ud626\ud627\ud628\ud629\ud62a\ud62b\ud62c\ud62d\ud62e\ud62f\ud630\ud631\ud632\ud633\ud634\ud635\ud636\ud637\ud638\ud639\ud63a\ud63b\ud63c\ud63d\ud63e\ud63f\ud640\ud641\ud642\ud643\ud644\ud645\ud646\ud647\ud648\ud649\ud64a\ud64b\ud64c\ud64d\ud64e\ud64f\ud650\ud651\ud652\ud653\ud654\ud655\ud656\ud657\ud658\ud659\ud65a\ud65b\ud65c\ud65d\ud65e\ud65f\ud660\ud661\ud662\ud663\ud664\ud665\ud666\ud667\ud668\ud669\ud66a\ud66b\ud66c\ud66d\ud66e\ud66f\ud670\ud671\ud672\ud673\ud674\ud675\ud676\ud677\ud678\ud679\ud67a\ud67b\ud67c\ud67d\ud67e\ud67f\ud680\ud681\ud682\ud683\ud684\ud685\ud686\ud687\ud688\ud689\ud68a\ud68b\ud68c\ud68d\ud68e\ud68f\ud690\ud691\ud692\ud693\ud694\ud695\ud696\ud697\ud698\ud699\ud69a\ud69b\ud69c\ud69d\ud69e\ud69f\ud6a0\ud6a1\ud6a2\ud6a3\ud6a4\ud6a5\ud6a6\ud6a7\ud6a8\ud6a9\ud6aa\ud6ab\ud6ac\ud6ad\ud6ae\ud6af\ud6b0\ud6b1\ud6b2\ud6b3\ud6b4\ud6b5\ud6b6\ud6b7\ud6b8\ud6b9\ud6ba\ud6bb\ud6bc\ud6bd\ud6be\ud6bf\ud6c0\ud6c1\ud6c2\ud6c3\ud6c4\ud6c5\ud6c6\ud6c7\ud6c8\ud6c9\ud6ca\ud6cb\ud6cc\ud6cd\ud6ce\ud6cf\ud6d0\ud6d1\ud6d2\ud6d3\ud6d4\ud6d5\ud6d6\ud6d7\ud6d8\ud6d9\ud6da\ud6db\ud6dc\ud6dd\ud6de\ud6df\ud6e0\ud6e1\ud6e2\ud6e3\ud6e4\ud6e5\ud6e6\ud6e7\ud6e8\ud6e9\ud6ea\ud6eb\ud6ec\ud6ed\ud6ee\ud6ef\ud6f0\ud6f1\ud6f2\ud6f3\ud6f4\ud6f5\ud6f6\ud6f7\ud6f8\ud6f9\ud6fa\ud6fb\ud6fc\ud6fd\ud6fe\ud6ff\ud700\ud701\ud702\ud703\ud704\ud705\ud706\ud707\ud708\ud709\ud70a\ud70b\ud70c\ud70d\ud70e\ud70f\ud710\ud711\ud712\ud713\ud714\ud715\ud716\ud717\ud718\ud719\ud71a\ud71b\ud71c\ud71d\ud71e\ud71f\ud720\ud721\ud722\ud723\ud724\ud725\ud726\ud727\ud728\ud729\ud72a\ud72b\ud72c\ud72d\ud72e\ud72f\ud730\ud731\ud732\ud733\ud734\ud735\ud736\ud737\ud738\ud739\ud73a\ud73b\ud73c\ud73d\ud73e\ud73f\ud740\ud741\ud742\ud743\ud744\ud745\ud746\ud747\ud748\ud749\ud74a\ud74b\ud74c\ud74d\ud74e\ud74f\ud750\ud751\ud752\ud753\ud754\ud755\ud756\ud757\ud758\ud759\ud75a\ud75b\ud75c\ud75d\ud75e\ud75f\ud760\ud761\ud762\ud763\ud764\ud765\ud766\ud767\ud768\ud769\ud76a\ud76b\ud76c\ud76d\ud76e\ud76f\ud770\ud771\ud772\ud773\ud774\ud775\ud776\ud777\ud778\ud779\ud77a\ud77b\ud77c\ud77d\ud77e\ud77f\ud780\ud781\ud782\ud783\ud784\ud785\ud786\ud787\ud788\ud789\ud78a\ud78b\ud78c\ud78d\ud78e\ud78f\ud790\ud791\ud792\ud793\ud794\ud795\ud796\ud797\ud798\ud799\ud79a\ud79b\ud79c\ud79d\ud79e\ud79f\ud7a0\ud7a1\ud7a2\ud7a3\ud7b0\ud7b1\ud7b2\ud7b3\ud7b4\ud7b5\ud7b6\ud7b7\ud7b8\ud7b9\ud7ba\ud7bb\ud7bc\ud7bd\ud7be\ud7bf\ud7c0\ud7c1\ud7c2\ud7c3\ud7c4\ud7c5\ud7c6\ud7cb\ud7cc\ud7cd\ud7ce\ud7cf\ud7d0\ud7d1\ud7d2\ud7d3\ud7d4\ud7d5\ud7d6\ud7d7\ud7d8\ud7d9\ud7da\ud7db\ud7dc\ud7dd\ud7de\ud7df\ud7e0\ud7e1\ud7e2\ud7e3\ud7e4\ud7e5\ud7e6\ud7e7\ud7e8\ud7e9\ud7ea\ud7eb\ud7ec\ud7ed\ud7ee\ud7ef\ud7f0\ud7f1\ud7f2\ud7f3\ud7f4\ud7f5\ud7f6\ud7f7\ud7f8\ud7f9\ud7fa\ud7fb\uf900\uf901\uf902\uf903\uf904\uf905\uf906\uf907\uf908\uf909\uf90a\uf90b\uf90c\uf90d\uf90e\uf90f\uf910\uf911\uf912\uf913\uf914\uf915\uf916\uf917\uf918\uf919\uf91a\uf91b\uf91c\uf91d\uf91e\uf91f\uf920\uf921\uf922\uf923\uf924\uf925\uf926\uf927\uf928\uf929\uf92a\uf92b\uf92c\uf92d\uf92e\uf92f\uf930\uf931\uf932\uf933\uf934\uf935\uf936\uf937\uf938\uf939\uf93a\uf93b\uf93c\uf93d\uf93e\uf93f\uf940\uf941\uf942\uf943\uf944\uf945\uf946\uf947\uf948\uf949\uf94a\uf94b\uf94c\uf94d\uf94e\uf94f\uf950\uf951\uf952\uf953\uf954\uf955\uf956\uf957\uf958\uf959\uf95a\uf95b\uf95c\uf95d\uf95e\uf95f\uf960\uf961\uf962\uf963\uf964\uf965\uf966\uf967\uf968\uf969\uf96a\uf96b\uf96c\uf96d\uf96e\uf96f\uf970\uf971\uf972\uf973\uf974\uf975\uf976\uf977\uf978\uf979\uf97a\uf97b\uf97c\uf97d\uf97e\uf97f\uf980\uf981\uf982\uf983\uf984\uf985\uf986\uf987\uf988\uf989\uf98a\uf98b\uf98c\uf98d\uf98e\uf98f\uf990\uf991\uf992\uf993\uf994\uf995\uf996\uf997\uf998\uf999\uf99a\uf99b\uf99c\uf99d\uf99e\uf99f\uf9a0\uf9a1\uf9a2\uf9a3\uf9a4\uf9a5\uf9a6\uf9a7\uf9a8\uf9a9\uf9aa\uf9ab\uf9ac\uf9ad\uf9ae\uf9af\uf9b0\uf9b1\uf9b2\uf9b3\uf9b4\uf9b5\uf9b6\uf9b7\uf9b8\uf9b9\uf9ba\uf9bb\uf9bc\uf9bd\uf9be\uf9bf\uf9c0\uf9c1\uf9c2\uf9c3\uf9c4\uf9c5\uf9c6\uf9c7\uf9c8\uf9c9\uf9ca\uf9cb\uf9cc\uf9cd\uf9ce\uf9cf\uf9d0\uf9d1\uf9d2\uf9d3\uf9d4\uf9d5\uf9d6\uf9d7\uf9d8\uf9d9\uf9da\uf9db\uf9dc\uf9dd\uf9de\uf9df\uf9e0\uf9e1\uf9e2\uf9e3\uf9e4\uf9e5\uf9e6\uf9e7\uf9e8\uf9e9\uf9ea\uf9eb\uf9ec\uf9ed\uf9ee\uf9ef\uf9f0\uf9f1\uf9f2\uf9f3\uf9f4\uf9f5\uf9f6\uf9f7\uf9f8\uf9f9\uf9fa\uf9fb\uf9fc\uf9fd\uf9fe\uf9ff\ufa00\ufa01\ufa02\ufa03\ufa04\ufa05\ufa06\ufa07\ufa08\ufa09\ufa0a\ufa0b\ufa0c\ufa0d\ufa0e\ufa0f\ufa10\ufa11\ufa12\ufa13\ufa14\ufa15\ufa16\ufa17\ufa18\ufa19\ufa1a\ufa1b\ufa1c\ufa1d\ufa1e\ufa1f\ufa20\ufa21\ufa22\ufa23\ufa24\ufa25\ufa26\ufa27\ufa28\ufa29\ufa2a\ufa2b\ufa2c\ufa2d\ufa2e\ufa2f\ufa30\ufa31\ufa32\ufa33\ufa34\ufa35\ufa36\ufa37\ufa38\ufa39\ufa3a\ufa3b\ufa3c\ufa3d\ufa3e\ufa3f\ufa40\ufa41\ufa42\ufa43\ufa44\ufa45\ufa46\ufa47\ufa48\ufa49\ufa4a\ufa4b\ufa4c\ufa4d\ufa4e\ufa4f\ufa50\ufa51\ufa52\ufa53\ufa54\ufa55\ufa56\ufa57\ufa58\ufa59\ufa5a\ufa5b\ufa5c\ufa5d\ufa5e\ufa5f\ufa60\ufa61\ufa62\ufa63\ufa64\ufa65\ufa66\ufa67\ufa68\ufa69\ufa6a\ufa6b\ufa6d\ufa70\ufa71\ufa72\ufa73\ufa74\ufa75\ufa76\ufa77\ufa78\ufa79\ufa7a\ufa7b\ufa7c\ufa7d\ufa7e\ufa7f\ufa80\ufa81\ufa82\ufa83\ufa84\ufa85\ufa86\ufa87\ufa88\ufa89\ufa8a\ufa8b\ufa8c\ufa8d\ufa8e\ufa8f\ufa90\ufa91\ufa92\ufa93\ufa94\ufa95\ufa96\ufa97\ufa98\ufa99\ufa9a\ufa9b\ufa9c\ufa9d\ufa9e\ufa9f\ufaa0\ufaa1\ufaa2\ufaa3\ufaa4\ufaa5\ufaa6\ufaa7\ufaa8\ufaa9\ufaaa\ufaab\ufaac\ufaad\ufaae\ufaaf\ufab0\ufab1\ufab2\ufab3\ufab4\ufab5\ufab6\ufab7\ufab8\ufab9\ufaba\ufabb\ufabc\ufabd\ufabe\ufabf\ufac0\ufac1\ufac2\ufac3\ufac4\ufac5\ufac6\ufac7\ufac8\ufac9\ufaca\ufacb\ufacc\ufacd\uface\ufad2\ufad3\ufad4\ufad8\ufad9\ufb1e\ufb20\ufb21\ufb22\ufb23\ufb24\ufb25\ufb26\ufb27\ufb28\ufb50\ufb51\ufb52\ufb53\ufb54\ufb55\ufb56\ufb57\ufb58\ufb59\ufb5a\ufb5b\ufb5c\ufb5d\ufb5e\ufb5f\ufb60\ufb61\ufb62\ufb63\ufb64\ufb65\ufb66\ufb67\ufb68\ufb69\ufb6a\ufb6b\ufb6c\ufb6d\ufb6e\ufb6f\ufb70\ufb71\ufb72\ufb73\ufb74\ufb75\ufb76\ufb77\ufb78\ufb79\ufb7a\ufb7b\ufb7c\ufb7d\ufb7e\ufb7f\ufb80\ufb81\ufb82\ufb83\ufb84\ufb85\ufb86\ufb87\ufb88\ufb89\ufb8a\ufb8b\ufb8c\ufb8d\ufb8e\ufb8f\ufb90\ufb91\ufb92\ufb93\ufb94\ufb95\ufb96\ufb97\ufb98\ufb99\ufb9a\ufb9b\ufb9c\ufb9d\ufb9e\ufb9f\ufba0\ufba1\ufba2\ufba3\ufba4\ufba5\ufba6\ufba7\ufba8\ufba9\ufbaa\ufbab\ufbac\ufbad\ufbae\ufbaf\ufbb0\ufbb1\ufbd3\ufbd4\ufbd5\ufbd6\ufbd7\ufbd8\ufbd9\ufbda\ufbdb\ufbdc\ufbde\ufbdf\ufbe0\ufbe1\ufbe2\ufbe3\ufbe4\ufbe5\ufbe6\ufbe7\ufbe8\ufbe9\ufbfc\ufbfd\ufbfe\ufbff\ufe00\ufe01\ufe02\ufe03\ufe04\ufe05\ufe06\ufe07\ufe08\ufe09\ufe0a\ufe0b\ufe0c\ufe0d\ufe0e\ufe0f\ufe20\ufe21\ufe22\ufe23\ufe24\ufe25\ufe26\ufe27\ufe28\ufe29\ufe2a\ufe2b\ufe2c\ufe2d\ufe2e\ufe2f\ufe33\ufe34\ufe4d\ufe4e\ufe4f\ufe73\ufe80\ufe81\ufe82\ufe83\ufe84\ufe85\ufe86\ufe87\ufe88\ufe89\ufe8a\ufe8b\ufe8c\ufe8d\ufe8e\ufe8f\ufe90\ufe91\ufe92\ufe93\ufe94\ufe95\ufe96\ufe97\ufe98\ufe99\ufe9a\ufe9b\ufe9c\ufe9d\ufe9e\ufe9f\ufea0\ufea1\ufea2\ufea3\ufea4\ufea5\ufea6\ufea7\ufea8\ufea9\ufeaa\ufeab\ufeac\ufead\ufeae\ufeaf\ufeb0\ufeb1\ufeb2\ufeb3\ufeb4\ufeb5\ufeb6\ufeb7\ufeb8\ufeb9\ufeba\ufebb\ufebc\ufebd\ufebe\ufebf\ufec0\ufec1\ufec2\ufec3\ufec4\ufec5\ufec6\ufec7\ufec8\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed2\ufed3\ufed4\ufed5\ufed6\ufed7\ufed8\ufed9\ufeda\ufedb\ufedc\ufedd\ufede\ufedf\ufee0\ufee1\ufee2\ufee3\ufee4\ufee5\ufee6\ufee7\ufee8\ufee9\ufeea\ufeeb\ufeec\ufeed\ufeee\ufeef\ufef0\ufef1\ufef2\ufef3\ufef4\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19\uff21\uff22\uff23\uff24\uff25\uff26\uff27\uff28\uff29\uff2a\uff2b\uff2c\uff2d\uff2e\uff2f\uff30\uff31\uff32\uff33\uff34\uff35\uff36\uff37\uff38\uff39\uff3a\uff3f\uff41\uff42\uff43\uff44\uff45\uff46\uff47\uff48\uff49\uff4a\uff4b\uff4c\uff4d\uff4e\uff4f\uff50\uff51\uff52\uff53\uff54\uff55\uff56\uff57\uff58\uff59\uff5a\uff66\uff67\uff68\uff69\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff7a\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82\uff83\uff84\uff85\uff86\uff87\uff88\uff89\uff8a\uff8b\uff8c\uff8d\uff8e\uff8f\uff90\uff91\uff92\uff93\uff94\uff95\uff96\uff97\uff98\uff99\uff9a\uff9b\uff9c\uff9d\uff9e\uff9f\uffa0\uffa1\uffa2\uffa3\uffa4\uffa5\uffa6\uffa7\uffa8\uffa9\uffaa\uffab\uffac\uffad\uffae\uffaf\uffb0\uffb1\uffb2\uffb3\uffb4\uffb5\uffb6\uffb7\uffb8\uffb9\uffba\uffbb\uffbc\uffbd\uffbe\uffc2\uffc3\uffc4\uffc5\uffc6\uffc7\uffca\uffcb\uffcc\uffcd\uffce\uffcf\uffd2\uffd3\uffd4\uffd5\uffd6\uffd7\uffda\uffdb\uffdc'
-# Generated code end
-
-if __name__ == '__main__':
- import sys
- import unicodedata
-
- if sys.version_info[0] < 3:
- raise RuntimeError('This needs to run on python 3')
-
- categories = {}
-
- f = open(__file__.rstrip('co'))
- try:
- content = f.read()
- finally:
- f.close()
-
- start = '# Generated code start\n'
- header = content[:content.find(start) + len(start)] + '\n'
- footer = content[content.find("# Generated code end\n"):]
-
- for code in range(65535):
- c = chr(code)
- cat = unicodedata.category(c)
- categories.setdefault(cat, []).append(c)
-
- # from 8.0.0 PropList (Other_ID_Start) + underscore
- id_start = set(u'_\u2118\u212E\u309B\u309C')
- for cat in 'Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl':
- id_start.update(categories[cat])
-
- # from 8.0.0 PropList (Other_ID_Continue)
- id_continue = set(id_start)
- id_continue.update(u'\u00B7\u0387\u1369\u1370\u1371\u19DA')
- for cat in 'Mn', 'Mc', 'Nd', 'Pc':
- id_continue.update(categories[cat])
-
- xid_start = u''.join(sorted(c for c in id_continue if
- unicodedata.normalize('NFKC', c)
- in id_start))
- xid_continue = u''.join(sorted(c for c in id_continue if
- unicodedata.normalize('NFKC', c) in
- id_continue))
-
- f = open(__file__, 'w')
- f.write(header)
-
- f.write('xid_start = %s\nxid_continue = %s\n' % (ascii(xid_start),
- ascii(xid_continue)))
-
- f.write(footer)
- f.close()
diff --git a/lib/spack/external/jinja2/asyncsupport.py b/lib/spack/external/jinja2/asyncsupport.py
index f4f264ad8c..b1e7b5ce9a 100644
--- a/lib/spack/external/jinja2/asyncsupport.py
+++ b/lib/spack/external/jinja2/asyncsupport.py
@@ -189,9 +189,9 @@ async def auto_aiter(iterable):
class AsyncLoopContext(LoopContextBase):
- def __init__(self, async_iterator, after, length, recurse=None,
+ def __init__(self, async_iterator, undefined, after, length, recurse=None,
depth0=0):
- LoopContextBase.__init__(self, recurse, depth0)
+ LoopContextBase.__init__(self, undefined, recurse, depth0)
self._async_iterator = async_iterator
self._after = after
self._length = length
@@ -221,15 +221,16 @@ class AsyncLoopContextIterator(object):
ctx.index0 += 1
if ctx._after is _last_iteration:
raise StopAsyncIteration()
- next_elem = ctx._after
+ ctx._before = ctx._current
+ ctx._current = ctx._after
try:
ctx._after = await ctx._async_iterator.__anext__()
except StopAsyncIteration:
ctx._after = _last_iteration
- return next_elem, ctx
+ return ctx._current, ctx
-async def make_async_loop_context(iterable, recurse=None, depth0=0):
+async def make_async_loop_context(iterable, undefined, recurse=None, depth0=0):
# Length is more complicated and less efficient in async mode. The
# reason for this is that we cannot know if length will be used
# upfront but because length is a property we cannot lazily execute it
@@ -251,4 +252,5 @@ async def make_async_loop_context(iterable, recurse=None, depth0=0):
after = await async_iterator.__anext__()
except StopAsyncIteration:
after = _last_iteration
- return AsyncLoopContext(async_iterator, after, length, recurse, depth0)
+ return AsyncLoopContext(async_iterator, undefined, after, length, recurse,
+ depth0)
diff --git a/lib/spack/external/jinja2/bccache.py b/lib/spack/external/jinja2/bccache.py
index d687d036fb..080e527cab 100644
--- a/lib/spack/external/jinja2/bccache.py
+++ b/lib/spack/external/jinja2/bccache.py
@@ -297,7 +297,7 @@ class MemcachedBytecodeCache(BytecodeCache):
Libraries compatible with this class:
- `werkzeug <http://werkzeug.pocoo.org/>`_.contrib.cache
- - `python-memcached <http://www.tummy.com/Community/software/python-memcached/>`_
+ - `python-memcached <https://www.tummy.com/Community/software/python-memcached/>`_
- `cmemcache <http://gijsbert.org/cmemcache/>`_
(Unfortunately the django cache interface is not compatible because it
diff --git a/lib/spack/external/jinja2/compiler.py b/lib/spack/external/jinja2/compiler.py
index b2ab6fe6a8..d534a82739 100644
--- a/lib/spack/external/jinja2/compiler.py
+++ b/lib/spack/external/jinja2/compiler.py
@@ -130,9 +130,10 @@ class MacroRef(object):
class Frame(object):
"""Holds compile time information for us."""
- def __init__(self, eval_ctx, parent=None):
+ def __init__(self, eval_ctx, parent=None, level=None):
self.eval_ctx = eval_ctx
- self.symbols = Symbols(parent and parent.symbols or None)
+ self.symbols = Symbols(parent and parent.symbols or None,
+ level=level)
# a toplevel frame is the root + soft frames such as if conditions.
self.toplevel = False
@@ -168,8 +169,10 @@ class Frame(object):
rv.symbols = self.symbols.copy()
return rv
- def inner(self):
+ def inner(self, isolated=False):
"""Return an inner frame."""
+ if isolated:
+ return Frame(self.eval_ctx, level=self.symbols.level + 1)
return Frame(self.eval_ctx, self)
def soft(self):
@@ -302,6 +305,9 @@ class CodeGenerator(NodeVisitor):
# Tracks parameter definition blocks
self._param_def_block = []
+ # Tracks the current context.
+ self._context_reference_stack = ['context']
+
# -- Various compilation helpers
def fail(self, msg, lineno):
@@ -472,8 +478,8 @@ class CodeGenerator(NodeVisitor):
if action == VAR_LOAD_PARAMETER:
pass
elif action == VAR_LOAD_RESOLVE:
- self.writeline('%s = resolve(%r)' %
- (target, param))
+ self.writeline('%s = %s(%r)' %
+ (target, self.get_resolve_func(), param))
elif action == VAR_LOAD_ALIAS:
self.writeline('%s = %s' % (target, param))
elif action == VAR_LOAD_UNDEFINED:
@@ -625,6 +631,27 @@ class CodeGenerator(NodeVisitor):
if self._param_def_block:
self._param_def_block[-1].discard(target)
+ def push_context_reference(self, target):
+ self._context_reference_stack.append(target)
+
+ def pop_context_reference(self):
+ self._context_reference_stack.pop()
+
+ def get_context_ref(self):
+ return self._context_reference_stack[-1]
+
+ def get_resolve_func(self):
+ target = self._context_reference_stack[-1]
+ if target == 'context':
+ return 'resolve'
+ return '%s.resolve' % target
+
+ def derive_context(self, frame):
+ return '%s.derived(%s)' % (
+ self.get_context_ref(),
+ self.dump_local_context(frame),
+ )
+
def parameter_is_undeclared(self, target):
"""Checks if a given target is an undeclared parameter."""
if not self._param_def_block:
@@ -793,8 +820,11 @@ class CodeGenerator(NodeVisitor):
self.writeline('if parent_template is None:')
self.indent()
level += 1
- context = node.scoped and (
- 'context.derived(%s)' % self.dump_local_context(frame)) or 'context'
+
+ if node.scoped:
+ context = self.derive_context(frame)
+ else:
+ context = self.get_context_ref()
if supports_yield_from and not self.environment.is_async and \
frame.buffer is None:
@@ -1082,9 +1112,9 @@ class CodeGenerator(NodeVisitor):
self.write(')')
if node.recursive:
- self.write(', loop_render_func, depth):')
+ self.write(', undefined, loop_render_func, depth):')
else:
- self.write(extended_loop and '):' or ':')
+ self.write(extended_loop and ', undefined):' or ':')
self.indent()
self.enter_frame(loop_frame)
@@ -1129,6 +1159,13 @@ class CodeGenerator(NodeVisitor):
self.indent()
self.blockvisit(node.body, if_frame)
self.outdent()
+ for elif_ in node.elif_:
+ self.writeline('elif ', elif_)
+ self.visit(elif_.test, if_frame)
+ self.write(':')
+ self.indent()
+ self.blockvisit(elif_.body, if_frame)
+ self.outdent()
if node.else_:
self.writeline('else:')
self.indent()
@@ -1348,7 +1385,12 @@ class CodeGenerator(NodeVisitor):
self.newline(node)
self.visit(node.target, frame)
self.write(' = (Markup if context.eval_ctx.autoescape '
- 'else identity)(concat(%s))' % block_frame.buffer)
+ 'else identity)(')
+ if node.filter is not None:
+ self.visit_Filter(node.filter, block_frame)
+ else:
+ self.write('concat(%s)' % block_frame.buffer)
+ self.write(')')
self.pop_assign_tracking(frame)
self.leave_frame(block_frame)
@@ -1373,6 +1415,18 @@ class CodeGenerator(NodeVisitor):
self.write(ref)
+ def visit_NSRef(self, node, frame):
+ # NSRefs can only be used to store values; since they use the normal
+ # `foo.bar` notation they will be parsed as a normal attribute access
+ # when used anywhere but in a `set` context
+ ref = frame.symbols.ref(node.name)
+ self.writeline('if not isinstance(%s, Namespace):' % ref)
+ self.indent()
+ self.writeline('raise TemplateRuntimeError(%r)' %
+ 'cannot assign attribute on non-namespace object')
+ self.outdent()
+ self.writeline('%s[%r]' % (ref, node.attr))
+
def visit_Const(self, node, frame):
val = node.as_const(frame.eval_ctx)
if isinstance(val, float):
@@ -1631,6 +1685,20 @@ class CodeGenerator(NodeVisitor):
self.blockvisit(node.body, scope_frame)
self.leave_frame(scope_frame)
+ def visit_OverlayScope(self, node, frame):
+ ctx = self.temporary_identifier()
+ self.writeline('%s = %s' % (ctx, self.derive_context(frame)))
+ self.writeline('%s.vars = ' % ctx)
+ self.visit(node.context, frame)
+ self.push_context_reference(ctx)
+
+ scope_frame = frame.inner(isolated=True)
+ scope_frame.symbols.analyze_node(node)
+ self.enter_frame(scope_frame)
+ self.blockvisit(node.body, scope_frame)
+ self.leave_frame(scope_frame)
+ self.pop_context_reference()
+
def visit_EvalContextModifier(self, node, frame):
for keyword in node.options:
self.writeline('context.eval_ctx.%s = ' % keyword.key)
diff --git a/lib/spack/external/jinja2/debug.py b/lib/spack/external/jinja2/debug.py
index 07c21f1a8b..b61139f0cd 100644
--- a/lib/spack/external/jinja2/debug.py
+++ b/lib/spack/external/jinja2/debug.py
@@ -198,7 +198,7 @@ def translate_exception(exc_info, initial_skip=0):
def get_jinja_locals(real_locals):
ctx = real_locals.get('context')
if ctx:
- locals = ctx.get_all()
+ locals = ctx.get_all().copy()
else:
locals = {}
diff --git a/lib/spack/external/jinja2/defaults.py b/lib/spack/external/jinja2/defaults.py
index 35903883cd..7c93dec0ae 100644
--- a/lib/spack/external/jinja2/defaults.py
+++ b/lib/spack/external/jinja2/defaults.py
@@ -9,7 +9,7 @@
:license: BSD, see LICENSE for more details.
"""
from jinja2._compat import range_type
-from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner
+from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner, Namespace
# defaults for the parser / lexer
@@ -35,7 +35,8 @@ DEFAULT_NAMESPACE = {
'dict': dict,
'lipsum': generate_lorem_ipsum,
'cycler': Cycler,
- 'joiner': Joiner
+ 'joiner': Joiner,
+ 'namespace': Namespace
}
@@ -47,6 +48,7 @@ DEFAULT_POLICIES = {
'truncate.leeway': 5,
'json.dumps_function': None,
'json.dumps_kwargs': {'sort_keys': True},
+ 'ext.i18n.trimmed': False,
}
diff --git a/lib/spack/external/jinja2/environment.py b/lib/spack/external/jinja2/environment.py
index 2a4d3d7da9..549d9afab4 100644
--- a/lib/spack/external/jinja2/environment.py
+++ b/lib/spack/external/jinja2/environment.py
@@ -809,7 +809,7 @@ class Environment(object):
@internalcode
def get_template(self, name, parent=None, globals=None):
"""Load a template from the loader. If a loader is configured this
- method ask the loader for the template and returns a :class:`Template`.
+ method asks the loader for the template and returns a :class:`Template`.
If the `parent` parameter is not `None`, :meth:`join_path` is called
to get the real template name before loading.
diff --git a/lib/spack/external/jinja2/ext.py b/lib/spack/external/jinja2/ext.py
index 75e1f3b625..0734a84f73 100644
--- a/lib/spack/external/jinja2/ext.py
+++ b/lib/spack/external/jinja2/ext.py
@@ -10,6 +10,8 @@
:copyright: (c) 2017 by the Jinja Team.
:license: BSD.
"""
+import re
+
from jinja2 import nodes
from jinja2.defaults import BLOCK_START_STRING, \
BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
@@ -223,6 +225,7 @@ class InternationalizationExtension(Extension):
plural_expr = None
plural_expr_assignment = None
variables = {}
+ trimmed = None
while parser.stream.current.type != 'block_end':
if variables:
parser.stream.expect('comma')
@@ -241,6 +244,9 @@ class InternationalizationExtension(Extension):
if parser.stream.current.type == 'assign':
next(parser.stream)
variables[name.value] = var = parser.parse_expression()
+ elif trimmed is None and name.value in ('trimmed', 'notrimmed'):
+ trimmed = name.value == 'trimmed'
+ continue
else:
variables[name.value] = var = nodes.Name(name.value, 'load')
@@ -256,7 +262,7 @@ class InternationalizationExtension(Extension):
parser.stream.expect('block_end')
- plural = plural_names = None
+ plural = None
have_plural = False
referenced = set()
@@ -297,6 +303,13 @@ class InternationalizationExtension(Extension):
elif plural_expr is None:
parser.fail('pluralize without variables', lineno)
+ if trimmed is None:
+ trimmed = self.environment.policies['ext.i18n.trimmed']
+ if trimmed:
+ singular = self._trim_whitespace(singular)
+ if plural:
+ plural = self._trim_whitespace(plural)
+
node = self._make_node(singular, plural, variables, plural_expr,
bool(referenced),
num_called_num and have_plural)
@@ -306,6 +319,9 @@ class InternationalizationExtension(Extension):
else:
return node
+ def _trim_whitespace(self, string, _ws_re=re.compile(r'\s*\n\s*')):
+ return _ws_re.sub(' ', string.strip())
+
def _parse_block(self, parser, allow_pluralize):
"""Parse until the next block tag with a given name."""
referenced = []
@@ -583,6 +599,8 @@ def babel_extract(fileobj, keywords, comment_tags, options):
auto_reload=False
)
+ if getbool(options, 'trimmed'):
+ environment.policies['ext.i18n.trimmed'] = True
if getbool(options, 'newstyle_gettext'):
environment.newstyle_gettext = True
diff --git a/lib/spack/external/jinja2/filters.py b/lib/spack/external/jinja2/filters.py
index 76e04db665..267ddddaa0 100644
--- a/lib/spack/external/jinja2/filters.py
+++ b/lib/spack/external/jinja2/filters.py
@@ -10,9 +10,10 @@
"""
import re
import math
+import random
+import warnings
-from random import choice
-from itertools import groupby
+from itertools import groupby, chain
from collections import namedtuple
from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
unicode_urlencode, htmlsafe_json_dumps
@@ -52,22 +53,34 @@ def environmentfilter(f):
return f
-def make_attrgetter(environment, attribute):
+def ignore_case(value):
+ """For use as a postprocessor for :func:`make_attrgetter`. Converts strings
+ to lowercase and returns other types as-is."""
+ return value.lower() if isinstance(value, string_types) else value
+
+
+def make_attrgetter(environment, attribute, postprocess=None):
"""Returns a callable that looks up the given attribute from a
passed object with the rules of the environment. Dots are allowed
to access attributes of attributes. Integer parts in paths are
looked up as integers.
"""
- if not isinstance(attribute, string_types) \
- or ('.' not in attribute and not attribute.isdigit()):
- return lambda x: environment.getitem(x, attribute)
- attribute = attribute.split('.')
+ if attribute is None:
+ attribute = []
+ elif isinstance(attribute, string_types):
+ attribute = [int(x) if x.isdigit() else x for x in attribute.split('.')]
+ else:
+ attribute = [attribute]
+
def attrgetter(item):
for part in attribute:
- if part.isdigit():
- part = int(part)
item = environment.getitem(item, part)
+
+ if postprocess is not None:
+ item = postprocess(item)
+
return item
+
return attrgetter
@@ -190,7 +203,7 @@ def do_title(s):
if item])
-def do_dictsort(value, case_sensitive=False, by='key'):
+def do_dictsort(value, case_sensitive=False, by='key', reverse=False):
"""Sort a dict and yield (key, value) pairs. Because python dicts are
unsorted you may want to use this function to order them by either
key or value:
@@ -200,6 +213,9 @@ def do_dictsort(value, case_sensitive=False, by='key'):
{% for item in mydict|dictsort %}
sort the dict by key, case insensitive
+ {% for item in mydict|dictsort(reverse=true) %}
+ sort the dict by key, case insensitive, reverse order
+
{% for item in mydict|dictsort(true) %}
sort the dict by key, case sensitive
@@ -211,20 +227,25 @@ def do_dictsort(value, case_sensitive=False, by='key'):
elif by == 'value':
pos = 1
else:
- raise FilterArgumentError('You can only sort by either '
- '"key" or "value"')
+ raise FilterArgumentError(
+ 'You can only sort by either "key" or "value"'
+ )
+
def sort_func(item):
value = item[pos]
- if isinstance(value, string_types) and not case_sensitive:
- value = value.lower()
+
+ if not case_sensitive:
+ value = ignore_case(value)
+
return value
- return sorted(value.items(), key=sort_func)
+ return sorted(value.items(), key=sort_func, reverse=reverse)
@environmentfilter
-def do_sort(environment, value, reverse=False, case_sensitive=False,
- attribute=None):
+def do_sort(
+ environment, value, reverse=False, case_sensitive=False, attribute=None
+):
"""Sort an iterable. Per default it sorts ascending, if you pass it
true as first argument it will reverse the sorting.
@@ -250,18 +271,85 @@ def do_sort(environment, value, reverse=False, case_sensitive=False,
.. versionchanged:: 2.6
The `attribute` parameter was added.
"""
- if not case_sensitive:
- def sort_func(item):
- if isinstance(item, string_types):
- item = item.lower()
- return item
- else:
- sort_func = None
- if attribute is not None:
- getter = make_attrgetter(environment, attribute)
- def sort_func(item, processor=sort_func or (lambda x: x)):
- return processor(getter(item))
- return sorted(value, key=sort_func, reverse=reverse)
+ key_func = make_attrgetter(
+ environment, attribute,
+ postprocess=ignore_case if not case_sensitive else None
+ )
+ return sorted(value, key=key_func, reverse=reverse)
+
+
+@environmentfilter
+def do_unique(environment, value, case_sensitive=False, attribute=None):
+ """Returns a list of unique items from the the given iterable.
+
+ .. sourcecode:: jinja
+
+ {{ ['foo', 'bar', 'foobar', 'FooBar']|unique }}
+ -> ['foo', 'bar', 'foobar']
+
+ The unique items are yielded in the same order as their first occurrence in
+ the iterable passed to the filter.
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Filter objects with unique values for this attribute.
+ """
+ getter = make_attrgetter(
+ environment, attribute,
+ postprocess=ignore_case if not case_sensitive else None
+ )
+ seen = set()
+
+ for item in value:
+ key = getter(item)
+
+ if key not in seen:
+ seen.add(key)
+ yield item
+
+
+def _min_or_max(environment, value, func, case_sensitive, attribute):
+ it = iter(value)
+
+ try:
+ first = next(it)
+ except StopIteration:
+ return environment.undefined('No aggregated item, sequence was empty.')
+
+ key_func = make_attrgetter(
+ environment, attribute,
+ ignore_case if not case_sensitive else None
+ )
+ return func(chain([first], it), key=key_func)
+
+
+@environmentfilter
+def do_min(environment, value, case_sensitive=False, attribute=None):
+ """Return the smallest item from the sequence.
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|min }}
+ -> 1
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Get the object with the max value of this attribute.
+ """
+ return _min_or_max(environment, value, min, case_sensitive, attribute)
+
+
+@environmentfilter
+def do_max(environment, value, case_sensitive=False, attribute=None):
+ """Return the largest item from the sequence.
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|max }}
+ -> 3
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Get the object with the max value of this attribute.
+ """
+ return _min_or_max(environment, value, max, case_sensitive, attribute)
def do_default(value, default_value=u'', boolean=False):
@@ -359,13 +447,13 @@ def do_last(environment, seq):
return environment.undefined('No last item, sequence was empty.')
-@environmentfilter
-def do_random(environment, seq):
+@contextfilter
+def do_random(context, seq):
"""Return a random item from the sequence."""
try:
- return choice(seq)
+ return random.choice(seq)
except IndexError:
- return environment.undefined('No random item, sequence was empty.')
+ return context.environment.undefined('No random item, sequence was empty.')
def do_filesizeformat(value, binary=False):
@@ -445,21 +533,44 @@ def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False,
return rv
-def do_indent(s, width=4, indentfirst=False):
- """Return a copy of the passed string, each line indented by
- 4 spaces. The first line is not indented. If you want to
- change the number of spaces or indent the first line too
- you can pass additional parameters to the filter:
+def do_indent(
+ s, width=4, first=False, blank=False, indentfirst=None
+):
+ """Return a copy of the string with each line indented by 4 spaces. The
+ first line and blank lines are not indented by default.
- .. sourcecode:: jinja
+ :param width: Number of spaces to indent by.
+ :param first: Don't skip indenting the first line.
+ :param blank: Don't skip indenting empty lines.
- {{ mytext|indent(2, true) }}
- indent by two spaces and indent the first line too.
+ .. versionchanged:: 2.10
+ Blank lines are not indented by default.
+
+ Rename the ``indentfirst`` argument to ``first``.
"""
+ if indentfirst is not None:
+ warnings.warn(DeprecationWarning(
+ 'The "indentfirst" argument is renamed to "first".'
+ ), stacklevel=2)
+ first = indentfirst
+
+ s += u'\n' # this quirk is necessary for splitlines method
indention = u' ' * width
- rv = (u'\n' + indention).join(s.splitlines())
- if indentfirst:
+
+ if blank:
+ rv = (u'\n' + indention).join(s.splitlines())
+ else:
+ lines = s.splitlines()
+ rv = lines.pop(0)
+
+ if lines:
+ rv += u'\n' + u'\n'.join(
+ indention + line if line else line for line in lines
+ )
+
+ if first:
rv = indention + rv
+
return rv
@@ -865,6 +976,9 @@ def do_select(*args, **kwargs):
{{ numbers|select("odd") }}
{{ numbers|select("odd") }}
+ {{ numbers|select("divisibleby", 3) }}
+ {{ numbers|select("lessthan", 42) }}
+ {{ strings|select("equalto", "mystring") }}
.. versionadded:: 2.7
"""
@@ -1045,6 +1159,8 @@ FILTERS = {
'list': do_list,
'lower': do_lower,
'map': do_map,
+ 'min': do_min,
+ 'max': do_max,
'pprint': do_pprint,
'random': do_random,
'reject': do_reject,
@@ -1063,6 +1179,7 @@ FILTERS = {
'title': do_title,
'trim': do_trim,
'truncate': do_truncate,
+ 'unique': do_unique,
'upper': do_upper,
'urlencode': do_urlencode,
'urlize': do_urlize,
diff --git a/lib/spack/external/jinja2/idtracking.py b/lib/spack/external/jinja2/idtracking.py
index 8479b72c23..491bfe0836 100644
--- a/lib/spack/external/jinja2/idtracking.py
+++ b/lib/spack/external/jinja2/idtracking.py
@@ -24,11 +24,13 @@ def symbols_for_node(node, parent_symbols=None):
class Symbols(object):
- def __init__(self, parent=None):
- if parent is None:
- self.level = 0
- else:
- self.level = parent.level + 1
+ def __init__(self, parent=None, level=None):
+ if level is None:
+ if parent is None:
+ level = 0
+ else:
+ level = parent.level + 1
+ self.level = level
self.parent = parent
self.refs = {}
self.loads = {}
@@ -167,6 +169,10 @@ class RootVisitor(NodeVisitor):
for child in node.iter_child_nodes(exclude=('call',)):
self.sym_visitor.visit(child)
+ def visit_OverlayScope(self, node, **kwargs):
+ for child in node.body:
+ self.sym_visitor.visit(child)
+
def visit_For(self, node, for_branch='body', **kwargs):
if for_branch == 'body':
self.sym_visitor.visit(node.target, store_as_param=True)
@@ -209,6 +215,9 @@ class FrameSymbolVisitor(NodeVisitor):
elif node.ctx == 'load':
self.symbols.load(node.name)
+ def visit_NSRef(self, node, **kwargs):
+ self.symbols.load(node.name)
+
def visit_If(self, node, **kwargs):
self.visit(node.test, **kwargs)
@@ -222,9 +231,10 @@ class FrameSymbolVisitor(NodeVisitor):
return rv
body_symbols = inner_visit(node.body)
+ elif_symbols = inner_visit(node.elif_)
else_symbols = inner_visit(node.else_ or ())
- self.symbols.branch_update([body_symbols, else_symbols])
+ self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])
def visit_Macro(self, node, **kwargs):
self.symbols.store(node.name)
@@ -271,3 +281,6 @@ class FrameSymbolVisitor(NodeVisitor):
def visit_Block(self, node, **kwargs):
"""Stop visiting at blocks."""
+
+ def visit_OverlayScope(self, node, **kwargs):
+ """Do not visit into overlay scopes."""
diff --git a/lib/spack/external/jinja2/lexer.py b/lib/spack/external/jinja2/lexer.py
index 30e82fb019..6fd135dd5b 100644
--- a/lib/spack/external/jinja2/lexer.py
+++ b/lib/spack/external/jinja2/lexer.py
@@ -15,14 +15,12 @@
:license: BSD, see LICENSE for more details.
"""
import re
-import sys
-
-from operator import itemgetter
from collections import deque
+from operator import itemgetter
+
+from jinja2._compat import implements_iterator, intern, iteritems, text_type
from jinja2.exceptions import TemplateSyntaxError
from jinja2.utils import LRUCache
-from jinja2._compat import iteritems, implements_iterator, text_type, intern
-
# cache for the lexers. Exists in order to be able to have multiple
# environments with the same lexer
@@ -34,28 +32,25 @@ string_re = re.compile(r"('([^'\\]*(?:\\.[^'\\]*)*)'"
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
integer_re = re.compile(r'\d+')
-def _make_name_re():
- try:
- compile('föö', '<unknown>', 'eval')
- except SyntaxError:
- return re.compile(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b')
-
+try:
+ # check if this Python supports Unicode identifiers
+ compile('föö', '<unknown>', 'eval')
+except SyntaxError:
+ # no Unicode support, use ASCII identifiers
+ name_re = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')
+ check_ident = False
+else:
+ # Unicode support, build a pattern to match valid characters, and set flag
+ # to use str.isidentifier to validate during lexing
+ from jinja2 import _identifier
+ name_re = re.compile(r'[\w{0}]+'.format(_identifier.pattern))
+ check_ident = True
+ # remove the pattern from memory after building the regex
+ import sys
+ del sys.modules['jinja2._identifier']
import jinja2
- from jinja2 import _stringdefs
- name_re = re.compile(r'[%s][%s]*' % (_stringdefs.xid_start,
- _stringdefs.xid_continue))
-
- # Save some memory here
- sys.modules.pop('jinja2._stringdefs')
- del _stringdefs
- del jinja2._stringdefs
-
- return name_re
-
-# we use the unicode identifier rule if this python version is able
-# to handle unicode identifiers, otherwise the standard ASCII one.
-name_re = _make_name_re()
-del _make_name_re
+ del jinja2._identifier
+ del _identifier
float_re = re.compile(r'(?<!\.)\d+\.\d+')
newline_re = re.compile(r'(\r\n|\r|\n)')
@@ -352,7 +347,10 @@ class TokenStream(object):
return self.next_if(expr) is not None
def __next__(self):
- """Go one token ahead and return the old one"""
+ """Go one token ahead and return the old one.
+
+ Use the built-in :func:`next` instead of calling this directly.
+ """
rv = self.current
if self._pushed:
self.current = self._pushed.popleft()
@@ -577,6 +575,10 @@ class Lexer(object):
token = value
elif token == 'name':
value = str(value)
+ if check_ident and not value.isidentifier():
+ raise TemplateSyntaxError(
+ 'Invalid character in identifier',
+ lineno, name, filename)
elif token == 'string':
# try to unescape string
try:
diff --git a/lib/spack/external/jinja2/nativetypes.py b/lib/spack/external/jinja2/nativetypes.py
new file mode 100644
index 0000000000..fe17e4138d
--- /dev/null
+++ b/lib/spack/external/jinja2/nativetypes.py
@@ -0,0 +1,220 @@
+import sys
+from ast import literal_eval
+from itertools import islice, chain
+from jinja2 import nodes
+from jinja2._compat import text_type
+from jinja2.compiler import CodeGenerator, has_safe_repr
+from jinja2.environment import Environment, Template
+from jinja2.utils import concat, escape
+
+
+def native_concat(nodes):
+ """Return a native Python type from the list of compiled nodes. If the
+ result is a single node, its value is returned. Otherwise, the nodes are
+ concatenated as strings. If the result can be parsed with
+ :func:`ast.literal_eval`, the parsed value is returned. Otherwise, the
+ string is returned.
+ """
+ head = list(islice(nodes, 2))
+
+ if not head:
+ return None
+
+ if len(head) == 1:
+ out = head[0]
+ else:
+ out = u''.join([text_type(v) for v in chain(head, nodes)])
+
+ try:
+ return literal_eval(out)
+ except (ValueError, SyntaxError, MemoryError):
+ return out
+
+
+class NativeCodeGenerator(CodeGenerator):
+ """A code generator which avoids injecting ``to_string()`` calls around the
+ internal code Jinja uses to render templates.
+ """
+
+ def visit_Output(self, node, frame):
+ """Same as :meth:`CodeGenerator.visit_Output`, but do not call
+ ``to_string`` on output nodes in generated code.
+ """
+ if self.has_known_extends and frame.require_output_check:
+ return
+
+ finalize = self.environment.finalize
+ finalize_context = getattr(finalize, 'contextfunction', False)
+ finalize_eval = getattr(finalize, 'evalcontextfunction', False)
+ finalize_env = getattr(finalize, 'environmentfunction', False)
+
+ if finalize is not None:
+ if finalize_context or finalize_eval:
+ const_finalize = None
+ elif finalize_env:
+ def const_finalize(x):
+ return finalize(self.environment, x)
+ else:
+ const_finalize = finalize
+ else:
+ def const_finalize(x):
+ return x
+
+ # If we are inside a frame that requires output checking, we do so.
+ outdent_later = False
+
+ if frame.require_output_check:
+ self.writeline('if parent_template is None:')
+ self.indent()
+ outdent_later = True
+
+ # Try to evaluate as many chunks as possible into a static string at
+ # compile time.
+ body = []
+
+ for child in node.nodes:
+ try:
+ if const_finalize is None:
+ raise nodes.Impossible()
+
+ const = child.as_const(frame.eval_ctx)
+ if not has_safe_repr(const):
+ raise nodes.Impossible()
+ except nodes.Impossible:
+ body.append(child)
+ continue
+
+ # the frame can't be volatile here, because otherwise the as_const
+ # function would raise an Impossible exception at that point
+ try:
+ if frame.eval_ctx.autoescape:
+ if hasattr(const, '__html__'):
+ const = const.__html__()
+ else:
+ const = escape(const)
+
+ const = const_finalize(const)
+ except Exception:
+ # if something goes wrong here we evaluate the node at runtime
+ # for easier debugging
+ body.append(child)
+ continue
+
+ if body and isinstance(body[-1], list):
+ body[-1].append(const)
+ else:
+ body.append([const])
+
+ # if we have less than 3 nodes or a buffer we yield or extend/append
+ if len(body) < 3 or frame.buffer is not None:
+ if frame.buffer is not None:
+ # for one item we append, for more we extend
+ if len(body) == 1:
+ self.writeline('%s.append(' % frame.buffer)
+ else:
+ self.writeline('%s.extend((' % frame.buffer)
+
+ self.indent()
+
+ for item in body:
+ if isinstance(item, list):
+ val = repr(native_concat(item))
+
+ if frame.buffer is None:
+ self.writeline('yield ' + val)
+ else:
+ self.writeline(val + ',')
+ else:
+ if frame.buffer is None:
+ self.writeline('yield ', item)
+ else:
+ self.newline(item)
+
+ close = 0
+
+ if finalize is not None:
+ self.write('environment.finalize(')
+
+ if finalize_context:
+ self.write('context, ')
+
+ close += 1
+
+ self.visit(item, frame)
+
+ if close > 0:
+ self.write(')' * close)
+
+ if frame.buffer is not None:
+ self.write(',')
+
+ if frame.buffer is not None:
+ # close the open parentheses
+ self.outdent()
+ self.writeline(len(body) == 1 and ')' or '))')
+
+ # otherwise we create a format string as this is faster in that case
+ else:
+ format = []
+ arguments = []
+
+ for item in body:
+ if isinstance(item, list):
+ format.append(native_concat(item).replace('%', '%%'))
+ else:
+ format.append('%s')
+ arguments.append(item)
+
+ self.writeline('yield ')
+ self.write(repr(concat(format)) + ' % (')
+ self.indent()
+
+ for argument in arguments:
+ self.newline(argument)
+ close = 0
+
+ if finalize is not None:
+ self.write('environment.finalize(')
+
+ if finalize_context:
+ self.write('context, ')
+ elif finalize_eval:
+ self.write('context.eval_ctx, ')
+ elif finalize_env:
+ self.write('environment, ')
+
+ close += 1
+
+ self.visit(argument, frame)
+ self.write(')' * close + ', ')
+
+ self.outdent()
+ self.writeline(')')
+
+ if outdent_later:
+ self.outdent()
+
+
+class NativeTemplate(Template):
+ def render(self, *args, **kwargs):
+ """Render the template to produce a native Python type. If the result
+ is a single node, its value is returned. Otherwise, the nodes are
+ concatenated as strings. If the result can be parsed with
+ :func:`ast.literal_eval`, the parsed value is returned. Otherwise, the
+ string is returned.
+ """
+ vars = dict(*args, **kwargs)
+
+ try:
+ return native_concat(self.root_render_func(self.new_context(vars)))
+ except Exception:
+ exc_info = sys.exc_info()
+
+ return self.environment.handle_exception(exc_info, True)
+
+
+class NativeEnvironment(Environment):
+ """An environment that renders templates to native Python types."""
+
+ code_generator_class = NativeCodeGenerator
+ template_class = NativeTemplate
diff --git a/lib/spack/external/jinja2/nodes.py b/lib/spack/external/jinja2/nodes.py
index aa4df72380..4d9a01ad8b 100644
--- a/lib/spack/external/jinja2/nodes.py
+++ b/lib/spack/external/jinja2/nodes.py
@@ -314,7 +314,7 @@ class For(Stmt):
class If(Stmt):
"""If `test` is true, `body` is rendered, else `else_`."""
- fields = ('test', 'body', 'else_')
+ fields = ('test', 'body', 'elif_', 'else_')
class Macro(Stmt):
@@ -387,7 +387,7 @@ class Assign(Stmt):
class AssignBlock(Stmt):
"""Assigns a block to a target."""
- fields = ('target', 'body')
+ fields = ('target', 'filter', 'body')
class Expr(Node):
@@ -465,6 +465,18 @@ class Name(Expr):
'True', 'False', 'None')
+class NSRef(Expr):
+ """Reference to a namespace value assignment"""
+ fields = ('name', 'attr')
+
+ def can_assign(self):
+ # We don't need any special checks here; NSRef assignments have a
+ # runtime check to ensure the target is a namespace object which will
+ # have been checked already as it is created using a normal assignment
+ # which goes through a `Name` node.
+ return True
+
+
class Literal(Expr):
"""Baseclass for literals."""
abstract = True
@@ -587,6 +599,25 @@ class CondExpr(Expr):
return self.expr2.as_const(eval_ctx)
+def args_as_const(node, eval_ctx):
+ args = [x.as_const(eval_ctx) for x in node.args]
+ kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
+
+ if node.dyn_args is not None:
+ try:
+ args.extend(node.dyn_args.as_const(eval_ctx))
+ except Exception:
+ raise Impossible()
+
+ if node.dyn_kwargs is not None:
+ try:
+ kwargs.update(node.dyn_kwargs.as_const(eval_ctx))
+ except Exception:
+ raise Impossible()
+
+ return args, kwargs
+
+
class Filter(Expr):
"""This node applies a filter on an expression. `name` is the name of
the filter, the rest of the fields are the same as for :class:`Call`.
@@ -594,44 +625,41 @@ class Filter(Expr):
If the `node` of a filter is `None` the contents of the last buffer are
filtered. Buffers are created by macros and filter blocks.
"""
+
fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
+
if eval_ctx.volatile or self.node is None:
raise Impossible()
+
# we have to be careful here because we call filter_ below.
# if this variable would be called filter, 2to3 would wrap the
# call in a list beause it is assuming we are talking about the
# builtin filter function here which no longer returns a list in
# python 3. because of that, do not rename filter_ to filter!
filter_ = self.environment.filters.get(self.name)
+
if filter_ is None or getattr(filter_, 'contextfilter', False):
raise Impossible()
# We cannot constant handle async filters, so we need to make sure
# to not go down this path.
- if eval_ctx.environment.is_async and \
- getattr(filter_, 'asyncfiltervariant', False):
+ if (
+ eval_ctx.environment.is_async
+ and getattr(filter_, 'asyncfiltervariant', False)
+ ):
raise Impossible()
- obj = self.node.as_const(eval_ctx)
- args = [obj] + [x.as_const(eval_ctx) for x in self.args]
+ args, kwargs = args_as_const(self, eval_ctx)
+ args.insert(0, self.node.as_const(eval_ctx))
+
if getattr(filter_, 'evalcontextfilter', False):
args.insert(0, eval_ctx)
elif getattr(filter_, 'environmentfilter', False):
args.insert(0, self.environment)
- kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
- if self.dyn_args is not None:
- try:
- args.extend(self.dyn_args.as_const(eval_ctx))
- except Exception:
- raise Impossible()
- if self.dyn_kwargs is not None:
- try:
- kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
- except Exception:
- raise Impossible()
+
try:
return filter_(*args, **kwargs)
except Exception:
@@ -642,8 +670,24 @@ class Test(Expr):
"""Applies a test on an expression. `name` is the name of the test, the
rest of the fields are the same as for :class:`Call`.
"""
+
fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+ def as_const(self, eval_ctx=None):
+ test = self.environment.tests.get(self.name)
+
+ if test is None:
+ raise Impossible()
+
+ eval_ctx = get_eval_context(self, eval_ctx)
+ args, kwargs = args_as_const(self, eval_ctx)
+ args.insert(0, self.node.as_const(eval_ctx))
+
+ try:
+ return test(*args, **kwargs)
+ except Exception:
+ raise Impossible()
+
class Call(Expr):
"""Calls an expression. `args` is a list of arguments, `kwargs` a list
@@ -914,6 +958,22 @@ class Scope(Stmt):
fields = ('body',)
+class OverlayScope(Stmt):
+ """An overlay scope for extensions. This is a largely unoptimized scope
+ that however can be used to introduce completely arbitrary variables into
+ a sub scope from a dictionary or dictionary like object. The `context`
+ field has to evaluate to a dictionary object.
+
+ Example usage::
+
+ OverlayScope(context=self.call_method('get_context'),
+ body=[...])
+
+ .. versionadded:: 2.10
+ """
+ fields = ('context', 'body')
+
+
class EvalContextModifier(Stmt):
"""Modifies the eval context. For each option that should be modified,
a :class:`Keyword` has to be added to the :attr:`options` list.
diff --git a/lib/spack/external/jinja2/parser.py b/lib/spack/external/jinja2/parser.py
index 0bf74c9459..ed00d9708e 100644
--- a/lib/spack/external/jinja2/parser.py
+++ b/lib/spack/external/jinja2/parser.py
@@ -176,13 +176,14 @@ class Parser(object):
def parse_set(self):
"""Parse an assign statement."""
lineno = next(self.stream).lineno
- target = self.parse_assign_target()
+ target = self.parse_assign_target(with_namespace=True)
if self.stream.skip_if('assign'):
expr = self.parse_tuple()
return nodes.Assign(target, expr, lineno=lineno)
+ filter_node = self.parse_filter(None)
body = self.parse_statements(('name:endset',),
drop_needle=True)
- return nodes.AssignBlock(target, body, lineno=lineno)
+ return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
def parse_for(self):
"""Parse a for loop."""
@@ -210,17 +211,16 @@ class Parser(object):
node.test = self.parse_tuple(with_condexpr=False)
node.body = self.parse_statements(('name:elif', 'name:else',
'name:endif'))
+ node.elif_ = []
+ node.else_ = []
token = next(self.stream)
if token.test('name:elif'):
- new_node = nodes.If(lineno=self.stream.current.lineno)
- node.else_ = [new_node]
- node = new_node
+ node = nodes.If(lineno=self.stream.current.lineno)
+ result.elif_.append(node)
continue
elif token.test('name:else'):
- node.else_ = self.parse_statements(('name:endif',),
- drop_needle=True)
- else:
- node.else_ = []
+ result.else_ = self.parse_statements(('name:endif',),
+ drop_needle=True)
break
return result
@@ -334,10 +334,9 @@ class Parser(object):
if parse_context() or self.stream.current.type != 'comma':
break
else:
- break
+ self.stream.expect('name')
if not hasattr(node, 'with_context'):
node.with_context = False
- self.stream.skip_if('comma')
return node
def parse_signature(self, node):
@@ -395,15 +394,21 @@ class Parser(object):
return node
def parse_assign_target(self, with_tuple=True, name_only=False,
- extra_end_rules=None):
+ extra_end_rules=None, with_namespace=False):
"""Parse an assignment target. As Jinja2 allows assignments to
tuples, this function can parse all allowed assignment targets. Per
default assignments to tuples are parsed, that can be disable however
by setting `with_tuple` to `False`. If only assignments to names are
wanted `name_only` can be set to `True`. The `extra_end_rules`
- parameter is forwarded to the tuple parsing function.
+ parameter is forwarded to the tuple parsing function. If
+ `with_namespace` is enabled, a namespace assignment may be parsed.
"""
- if name_only:
+ if with_namespace and self.stream.look().type == 'dot':
+ token = self.stream.expect('name')
+ next(self.stream) # dot
+ attr = self.stream.expect('name')
+ target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
+ elif name_only:
token = self.stream.expect('name')
target = nodes.Name(token.value, 'store', lineno=token.lineno)
else:
diff --git a/lib/spack/external/jinja2/runtime.py b/lib/spack/external/jinja2/runtime.py
index 00d5f03ca6..f9d7a6806c 100644
--- a/lib/spack/external/jinja2/runtime.py
+++ b/lib/spack/external/jinja2/runtime.py
@@ -15,7 +15,7 @@ from types import MethodType
from jinja2.nodes import EvalContext, _context_function_types
from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
- internalcode, object_type_repr, evalcontextfunction
+ internalcode, object_type_repr, evalcontextfunction, Namespace
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
TemplateNotFound
from jinja2._compat import imap, text_type, iteritems, \
@@ -27,7 +27,7 @@ from jinja2._compat import imap, text_type, iteritems, \
__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
'TemplateRuntimeError', 'missing', 'concat', 'escape',
'markup_join', 'unicode_join', 'to_string', 'identity',
- 'TemplateNotFound']
+ 'TemplateNotFound', 'Namespace']
#: the name of the function that is used to convert something into
#: a string. We can just use the text type here.
@@ -36,6 +36,7 @@ to_string = text_type
#: the identity function. Useful for certain things in the environment
identity = lambda x: x
+_first_iteration = object()
_last_iteration = object()
@@ -241,13 +242,14 @@ class Context(with_metaclass(ContextMeta)):
__traceback_hide__ = True # noqa
# Allow callable classes to take a context
- fn = __obj.__call__
- for fn_type in ('contextfunction',
- 'evalcontextfunction',
- 'environmentfunction'):
- if hasattr(fn, fn_type):
- __obj = fn
- break
+ if hasattr(__obj, '__call__'):
+ fn = __obj.__call__
+ for fn_type in ('contextfunction',
+ 'evalcontextfunction',
+ 'environmentfunction'):
+ if hasattr(fn, fn_type):
+ __obj = fn
+ break
if isinstance(__obj, _context_function_types):
if getattr(__obj, 'contextfunction', 0):
@@ -349,13 +351,17 @@ class BlockReference(object):
class LoopContextBase(object):
"""A loop context for dynamic iteration."""
+ _before = _first_iteration
+ _current = _first_iteration
_after = _last_iteration
_length = None
- def __init__(self, recurse=None, depth0=0):
+ def __init__(self, undefined, recurse=None, depth0=0):
+ self._undefined = undefined
self._recurse = recurse
self.index0 = -1
self.depth0 = depth0
+ self._last_checked_value = missing
def cycle(self, *args):
"""Cycles among the arguments with the current loop index."""
@@ -363,6 +369,13 @@ class LoopContextBase(object):
raise TypeError('no items for cycling given')
return args[self.index0 % len(args)]
+ def changed(self, *value):
+ """Checks whether the value has changed since the last call."""
+ if self._last_checked_value != value:
+ self._last_checked_value = value
+ return True
+ return False
+
first = property(lambda x: x.index0 == 0)
last = property(lambda x: x._after is _last_iteration)
index = property(lambda x: x.index0 + 1)
@@ -370,6 +383,18 @@ class LoopContextBase(object):
revindex0 = property(lambda x: x.length - x.index)
depth = property(lambda x: x.depth0 + 1)
+ @property
+ def previtem(self):
+ if self._before is _first_iteration:
+ return self._undefined('there is no previous item')
+ return self._before
+
+ @property
+ def nextitem(self):
+ if self._after is _last_iteration:
+ return self._undefined('there is no next item')
+ return self._after
+
def __len__(self):
return self.length
@@ -395,8 +420,8 @@ class LoopContextBase(object):
class LoopContext(LoopContextBase):
- def __init__(self, iterable, recurse=None, depth0=0):
- LoopContextBase.__init__(self, recurse, depth0)
+ def __init__(self, iterable, undefined, recurse=None, depth0=0):
+ LoopContextBase.__init__(self, undefined, recurse, depth0)
self._iterator = iter(iterable)
# try to get the length of the iterable early. This must be done
@@ -448,9 +473,10 @@ class LoopContextIterator(object):
ctx.index0 += 1
if ctx._after is _last_iteration:
raise StopIteration()
- next_elem = ctx._after
+ ctx._before = ctx._current
+ ctx._current = ctx._after
ctx._after = ctx._safe_next()
- return next_elem, ctx
+ return ctx._current, ctx
class Macro(object):
diff --git a/lib/spack/external/jinja2/sandbox.py b/lib/spack/external/jinja2/sandbox.py
index 32e2435010..93fb9d45f3 100644
--- a/lib/spack/external/jinja2/sandbox.py
+++ b/lib/spack/external/jinja2/sandbox.py
@@ -107,7 +107,7 @@ class _MagicFormatMapping(Mapping):
"""This class implements a dummy wrapper to fix a bug in the Python
standard library for string formatting.
- See http://bugs.python.org/issue13598 for information about why
+ See https://bugs.python.org/issue13598 for information about why
this is necessary.
"""
diff --git a/lib/spack/external/jinja2/tests.py b/lib/spack/external/jinja2/tests.py
index bd843b77bc..0adc3d4dbc 100644
--- a/lib/spack/external/jinja2/tests.py
+++ b/lib/spack/external/jinja2/tests.py
@@ -8,6 +8,7 @@
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
+import operator
import re
from collections import Mapping
from jinja2.runtime import Undefined
@@ -103,28 +104,6 @@ def test_sequence(value):
return True
-def test_equalto(value, other):
- """Check if an object has the same value as another object:
-
- .. sourcecode:: jinja
-
- {% if foo.expression is equalto 42 %}
- the foo attribute evaluates to the constant 42
- {% endif %}
-
- This appears to be a useless test as it does exactly the same as the
- ``==`` operator, but it can be useful when used together with the
- `selectattr` function:
-
- .. sourcecode:: jinja
-
- {{ users|selectattr("email", "equalto", "foo@bar.invalid") }}
-
- .. versionadded:: 2.8
- """
- return value == other
-
-
def test_sameas(value, other):
"""Check if an object points to the same memory address than another
object:
@@ -152,14 +131,12 @@ def test_escaped(value):
return hasattr(value, '__html__')
-def test_greaterthan(value, other):
- """Check if value is greater than other."""
- return value > other
-
+def test_in(value, seq):
+ """Check if value is in seq.
-def test_lessthan(value, other):
- """Check if value is less than other."""
- return value < other
+ .. versionadded:: 2.10
+ """
+ return value in seq
TESTS = {
@@ -178,8 +155,21 @@ TESTS = {
'iterable': test_iterable,
'callable': test_callable,
'sameas': test_sameas,
- 'equalto': test_equalto,
'escaped': test_escaped,
- 'greaterthan': test_greaterthan,
- 'lessthan': test_lessthan
+ 'in': test_in,
+ '==': operator.eq,
+ 'eq': operator.eq,
+ 'equalto': operator.eq,
+ '!=': operator.ne,
+ 'ne': operator.ne,
+ '>': operator.gt,
+ 'gt': operator.gt,
+ 'greaterthan': operator.gt,
+ 'ge': operator.ge,
+ '>=': operator.ge,
+ '<': operator.lt,
+ 'lt': operator.lt,
+ 'lessthan': operator.lt,
+ '<=': operator.le,
+ 'le': operator.le,
}
diff --git a/lib/spack/external/jinja2/utils.py b/lib/spack/external/jinja2/utils.py
index b96d309546..502a311c08 100644
--- a/lib/spack/external/jinja2/utils.py
+++ b/lib/spack/external/jinja2/utils.py
@@ -567,7 +567,7 @@ def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
.replace(u'>', u'\\u003e') \
.replace(u'&', u'\\u0026') \
.replace(u"'", u'\\u0027')
- return rv
+ return Markup(rv)
@implements_iterator
@@ -612,6 +612,29 @@ class Joiner(object):
return self.sep
+class Namespace(object):
+ """A namespace object that can hold arbitrary attributes. It may be
+ initialized from a dictionary or with keyword argments."""
+
+ def __init__(*args, **kwargs):
+ self, args = args[0], args[1:]
+ self.__attrs = dict(*args, **kwargs)
+
+ def __getattribute__(self, name):
+ if name == '_Namespace__attrs':
+ return object.__getattribute__(self, name)
+ try:
+ return self.__attrs[name]
+ except KeyError:
+ raise AttributeError(name)
+
+ def __setitem__(self, name, value):
+ self.__attrs[name] = value
+
+ def __repr__(self):
+ return '<Namespace %r>' % self.__attrs
+
+
# does this python version support async for in and async generators?
try:
exec('async def _():\n async for _ in ():\n yield _')
diff --git a/lib/spack/external/ordereddict_backport.py b/lib/spack/external/ordereddict_backport.py
index 154e5d1872..9bb788f093 100644
--- a/lib/spack/external/ordereddict_backport.py
+++ b/lib/spack/external/ordereddict_backport.py
@@ -1,268 +1,22 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
-# Passes Python2.7's test suite and incorporates all the latest updates.
-#
-# From http://code.activestate.com/recipes/576693-ordered-dictionary-for-py24/
-# This file is in the public domain, and has no particular license.
-#
-try:
- from thread import get_ident as _get_ident
-except ImportError:
- try:
- from dummy_thread import get_ident as _get_ident
- except ImportError:
- try:
- from _dummy_thread import get_ident as _get_ident
- except ImportError:
- from threading import get_ident as _get_ident # nopyqver
-
-try:
- from _abcoll import KeysView, ValuesView, ItemsView
-except ImportError:
- pass
-
-
-class OrderedDict(dict):
- 'Dictionary that remembers insertion order'
- # An inherited dict maps keys to values.
- # The inherited dict provides __getitem__, __len__, __contains__, and get.
- # The remaining methods are order-aware.
- # Big-O running times for all methods are the same as for regular dictionaries.
-
- # The internal self.__map dictionary maps keys to links in a doubly linked list.
- # The circular doubly linked list starts and ends with a sentinel element.
- # The sentinel element never gets deleted (this simplifies the algorithm).
- # Each link is stored as a list of length three: [PREV, NEXT, KEY].
-
- def __init__(self, *args, **kwds):
- '''Initialize an ordered dictionary. Signature is the same as for
- regular dictionaries, but keyword arguments are not recommended
- because their insertion order is arbitrary.
-
- '''
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
- try:
- self.__root
- except AttributeError:
- self.__root = root = [] # sentinel node
- root[:] = [root, root, None]
- self.__map = {}
- self.__update(*args, **kwds)
-
- def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
- 'od.__setitem__(i, y) <==> od[i]=y'
- # Setting a new item creates a new link which goes at the end of the linked
- # list, and the inherited dictionary is updated with the new key/value pair.
- if key not in self:
- root = self.__root
- last = root[0]
- last[1] = root[0] = self.__map[key] = [last, root, key]
- dict_setitem(self, key, value)
-
- def __delitem__(self, key, dict_delitem=dict.__delitem__):
- 'od.__delitem__(y) <==> del od[y]'
- # Deleting an existing item uses self.__map to find the link which is
- # then removed by updating the links in the predecessor and successor nodes.
- dict_delitem(self, key)
- link_prev, link_next, key = self.__map.pop(key)
- link_prev[1] = link_next
- link_next[0] = link_prev
-
- def __iter__(self):
- 'od.__iter__() <==> iter(od)'
- root = self.__root
- curr = root[1]
- while curr is not root:
- yield curr[2]
- curr = curr[1]
-
- def __reversed__(self):
- 'od.__reversed__() <==> reversed(od)'
- root = self.__root
- curr = root[0]
- while curr is not root:
- yield curr[2]
- curr = curr[0]
-
- def clear(self):
- 'od.clear() -> None. Remove all items from od.'
- try:
- for node in self.__map.itervalues():
- del node[:]
- root = self.__root
- root[:] = [root, root, None]
- self.__map.clear()
- except AttributeError:
- pass
- dict.clear(self)
-
- def popitem(self, last=True):
- '''od.popitem() -> (k, v), return and remove a (key, value) pair.
- Pairs are returned in LIFO order if last is true or FIFO order if false.
-
- '''
- if not self:
- raise KeyError('dictionary is empty')
- root = self.__root
- if last:
- link = root[0]
- link_prev = link[0]
- link_prev[1] = root
- root[0] = link_prev
- else:
- link = root[1]
- link_next = link[1]
- root[1] = link_next
- link_next[0] = root
- key = link[2]
- del self.__map[key]
- value = dict.pop(self, key)
- return key, value
-
- # -- the following methods do not depend on the internal structure --
-
- def keys(self):
- 'od.keys() -> list of keys in od'
- return list(self)
-
- def values(self):
- 'od.values() -> list of values in od'
- return [self[key] for key in self]
-
- def items(self):
- 'od.items() -> list of (key, value) pairs in od'
- return [(key, self[key]) for key in self]
-
- def iterkeys(self):
- 'od.iterkeys() -> an iterator over the keys in od'
- return iter(self)
-
- def itervalues(self):
- 'od.itervalues -> an iterator over the values in od'
- for k in self:
- yield self[k]
-
- def iteritems(self):
- 'od.iteritems -> an iterator over the (key, value) items in od'
- for k in self:
- yield (k, self[k])
-
- def update(*args, **kwds):
- '''od.update(E, **F) -> None. Update od from dict/iterable E and F.
-
- If E is a dict instance, does: for k in E: od[k] = E[k]
- If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
- Or if E is an iterable of items, does: for k, v in E: od[k] = v
- In either case, this is followed by: for k, v in F.items(): od[k] = v
-
- '''
- if len(args) > 2:
- raise TypeError('update() takes at most 2 positional '
- 'arguments (%d given)' % (len(args),))
- elif not args:
- raise TypeError('update() takes at least 1 argument (0 given)')
- self = args[0]
- # Make progressively weaker assumptions about "other"
- other = ()
- if len(args) == 2:
- other = args[1]
- if isinstance(other, dict):
- for key in other:
- self[key] = other[key]
- elif hasattr(other, 'keys'):
- for key in other.keys():
- self[key] = other[key]
- else:
- for key, value in other:
- self[key] = value
- for key, value in kwds.items():
- self[key] = value
-
- __update = update # let subclasses override update without breaking __init__
-
- __marker = object()
-
- def pop(self, key, default=__marker):
- '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
- If key is not found, d is returned if given, otherwise KeyError is raised.
-
- '''
- if key in self:
- result = self[key]
- del self[key]
- return result
- if default is self.__marker:
- raise KeyError(key)
- return default
-
- def setdefault(self, key, default=None):
- 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
- if key in self:
- return self[key]
- self[key] = default
- return default
-
- def __repr__(self, _repr_running={}):
- 'od.__repr__() <==> repr(od)'
- call_key = id(self), _get_ident()
- if call_key in _repr_running:
- return '...'
- _repr_running[call_key] = 1
- try:
- if not self:
- return '%s()' % (self.__class__.__name__,)
- return '%s(%r)' % (self.__class__.__name__, self.items())
- finally:
- del _repr_running[call_key]
-
- def __reduce__(self):
- 'Return state information for pickling'
- items = [[k, self[k]] for k in self]
- inst_dict = vars(self).copy()
- for k in vars(OrderedDict()):
- inst_dict.pop(k, None)
- if inst_dict:
- return (self.__class__, (items,), inst_dict)
- return self.__class__, (items,)
-
- def copy(self):
- 'od.copy() -> a shallow copy of od'
- return self.__class__(self)
-
- @classmethod
- def fromkeys(cls, iterable, value=None):
- '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
- and values equal to v (which defaults to None).
-
- '''
- d = cls()
- for key in iterable:
- d[key] = value
- return d
-
- def __eq__(self, other):
- '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
- while comparison to a regular mapping is order-insensitive.
-
- '''
- if isinstance(other, OrderedDict):
- return len(self)==len(other) and self.items() == other.items()
- return dict.__eq__(self, other)
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
- def __ne__(self, other):
- return not self == other
+"""This file dispatches to the correct implementation of OrderedDict."""
- # -- the following methods are only used in Python 2.7 --
+# TODO: this file, along with py26/ordereddict.py, can be removed when
+# TODO: support for python 2.6 will be dropped
- def viewkeys(self):
- "od.viewkeys() -> a set-like object providing a view on od's keys"
- return KeysView(self)
+# Removing this import will make python 2.6
+# fail on import of ordereddict
+from __future__ import absolute_import
- def viewvalues(self):
- "od.viewvalues() -> an object providing a view on od's values"
- return ValuesView(self)
+import sys
- def viewitems(self):
- "od.viewitems() -> a set-like object providing a view on od's items"
- return ItemsView(self)
+if sys.version_info[:2] == (2, 6):
+ import ordereddict
+ OrderedDict = ordereddict.OrderedDict
+else:
+ import collections
+ OrderedDict = collections.OrderedDict
diff --git a/lib/spack/external/py/AUTHORS b/lib/spack/external/py/AUTHORS
deleted file mode 100644
index 8c0cf9b71b..0000000000
--- a/lib/spack/external/py/AUTHORS
+++ /dev/null
@@ -1,24 +0,0 @@
-Holger Krekel, holger at merlinux eu
-Benjamin Peterson, benjamin at python org
-Ronny Pfannschmidt, Ronny.Pfannschmidt at gmx de
-Guido Wesdorp, johnny at johnnydebris net
-Samuele Pedroni, pedronis at openend se
-Carl Friedrich Bolz, cfbolz at gmx de
-Armin Rigo, arigo at tunes org
-Maciek Fijalkowski, fijal at genesilico pl
-Brian Dorsey, briandorsey at gmail com
-Floris Bruynooghe, flub at devork be
-merlinux GmbH, Germany, office at merlinux eu
-
-Contributors include::
-
-Ross Lawley
-Ralf Schmitt
-Chris Lamb
-Harald Armin Massa
-Martijn Faassen
-Ian Bicking
-Jan Balster
-Grig Gheorghiu
-Bob Ippolito
-Christian Tismer
diff --git a/lib/spack/external/py/LICENSE b/lib/spack/external/py/LICENSE
deleted file mode 100644
index 31ecdfb1db..0000000000
--- a/lib/spack/external/py/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-
- 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 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.
-
diff --git a/lib/spack/external/py/README.rst b/lib/spack/external/py/README.rst
deleted file mode 100644
index e836b7b50a..0000000000
--- a/lib/spack/external/py/README.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-.. image:: https://img.shields.io/pypi/pyversions/pytest.svg
- :target: https://pypi.org/project/py
-.. image:: https://img.shields.io/travis/pytest-dev/py.svg
- :target: https://travis-ci.org/pytest-dev/py
-
-The py lib is a Python development support library featuring
-the following tools and modules:
-
-* ``py.path``: uniform local and svn path objects
-* ``py.apipkg``: explicit API control and lazy-importing
-* ``py.iniconfig``: easy parsing of .ini files
-* ``py.code``: dynamic code generation and introspection
-
-NOTE: prior to the 1.4 release this distribution used to
-contain py.test which is now its own package, see http://pytest.org
-
-For questions and more information please visit http://pylib.readthedocs.org
-
-Bugs and issues: https://github.com/pytest-dev/py
-
-Authors: Holger Krekel and others, 2004-2016
diff --git a/lib/spack/external/py/__init__.py b/lib/spack/external/py/__init__.py
index c2273a2e64..85af650f5c 100644
--- a/lib/spack/external/py/__init__.py
+++ b/lib/spack/external/py/__init__.py
@@ -1,5 +1,5 @@
"""
-py.test and pylib: rapid testing and development utils
+pylib: rapid testing and development utils
this module uses apipkg.py for lazy-loading sub modules
and classes. The initpkg-dictionary below specifies
@@ -8,13 +8,15 @@ dictionary or an import path.
(c) Holger Krekel and others, 2004-2014
"""
-__version__ = '1.4.32'
+__version__ = '1.4.34'
from py import _apipkg
# so that py.error.* instances are picklable
import sys
sys.modules['py.error'] = _apipkg.AliasModule("py.error", "py._error", 'error')
+import py.error # "Dereference" it now just to be safe (issue110)
+
_apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs={
# access to all standard lib modules
diff --git a/lib/spack/external/py/_code/code.py b/lib/spack/external/py/_code/code.py
index f14c562a29..20fd965c97 100644
--- a/lib/spack/external/py/_code/code.py
+++ b/lib/spack/external/py/_code/code.py
@@ -419,7 +419,7 @@ class ExceptionInfo(object):
def __unicode__(self):
entry = self.traceback[-1]
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
- return unicode(loc)
+ return loc.__unicode__()
class FormattedExcinfo(object):
diff --git a/lib/spack/external/py/_path/common.py b/lib/spack/external/py/_path/common.py
index bf42ed5092..5512e51efe 100644
--- a/lib/spack/external/py/_path/common.py
+++ b/lib/spack/external/py/_path/common.py
@@ -1,6 +1,7 @@
"""
"""
import os, sys, posixpath
+import fnmatch
import py
# Moved from local.py.
@@ -169,11 +170,16 @@ class PathBase(object):
def readlines(self, cr=1):
""" read and return a list of lines from the path. if cr is False, the
newline will be removed from the end of each line. """
+ if sys.version_info < (3, ):
+ mode = 'rU'
+ else: # python 3 deprecates mode "U" in favor of "newline" option
+ mode = 'r'
+
if not cr:
- content = self.read('rU')
+ content = self.read(mode)
return content.split('\n')
else:
- f = self.open('rU')
+ f = self.open(mode)
try:
return f.readlines()
finally:
@@ -378,7 +384,7 @@ newline will be removed from the end of each line. """
return self.strpath == str(other)
def __fspath__(self):
- return str(self)
+ return self.strpath
class Visitor:
def __init__(self, fil, rec, ignore, bf, sort):
@@ -436,4 +442,4 @@ class FNMatcher:
name = str(path) # path.strpath # XXX svn?
if not os.path.isabs(pattern):
pattern = '*' + path.sep + pattern
- return py.std.fnmatch.fnmatch(name, pattern)
+ return fnmatch.fnmatch(name, pattern)
diff --git a/lib/spack/external/py/_path/local.py b/lib/spack/external/py/_path/local.py
index 0d4e4c93d1..2ffdaddf06 100644
--- a/lib/spack/external/py/_path/local.py
+++ b/lib/spack/external/py/_path/local.py
@@ -10,7 +10,7 @@ from py._path import common
from py._path.common import iswin32, fspath
from stat import S_ISLNK, S_ISDIR, S_ISREG
-from os.path import abspath, normpath, isabs, exists, isdir, isfile, islink, dirname
+from os.path import abspath, normcase, normpath, isabs, exists, isdir, isfile, islink, dirname
if sys.version_info > (3,0):
def map_as_list(func, iter):
@@ -205,14 +205,14 @@ class LocalPath(FSBase):
if rec:
# force remove of readonly files on windows
if iswin32:
- self.chmod(448, rec=1) # octcal 0700
+ self.chmod(0o700, rec=1)
py.error.checked_call(py.std.shutil.rmtree, self.strpath,
ignore_errors=ignore_errors)
else:
py.error.checked_call(os.rmdir, self.strpath)
else:
if iswin32:
- self.chmod(448) # octcal 0700
+ self.chmod(0o700)
py.error.checked_call(os.remove, self.strpath)
def computehash(self, hashtype="md5", chunksize=524288):
@@ -801,12 +801,13 @@ class LocalPath(FSBase):
if rootdir is None:
rootdir = cls.get_temproot()
+ nprefix = normcase(prefix)
def parse_num(path):
""" parse the number out of a path (if it matches the prefix) """
- bn = path.basename
- if bn.startswith(prefix):
+ nbasename = normcase(path.basename)
+ if nbasename.startswith(nprefix):
try:
- return int(bn[len(prefix):])
+ return int(nbasename[len(nprefix):])
except ValueError:
pass
@@ -898,6 +899,7 @@ class LocalPath(FSBase):
return udir
make_numbered_dir = classmethod(make_numbered_dir)
+
def copymode(src, dest):
""" copy permission from src to dst. """
py.std.shutil.copymode(src, dest)
diff --git a/lib/spack/external/py/_path/svnurl.py b/lib/spack/external/py/_path/svnurl.py
index 78d71317ac..6589a71d09 100644
--- a/lib/spack/external/py/_path/svnurl.py
+++ b/lib/spack/external/py/_path/svnurl.py
@@ -315,7 +315,7 @@ class InfoSvnCommand:
# locked, see 'svn help ls'
lspattern = re.compile(
r'^ *(?P<rev>\d+) +(?P<author>.+?) +(0? *(?P<size>\d+))? '
- '*(?P<date>\w+ +\d{2} +[\d:]+) +(?P<file>.*)$')
+ r'*(?P<date>\w+ +\d{2} +[\d:]+) +(?P<file>.*)$')
def __init__(self, line):
# this is a typical line from 'svn ls http://...'
#_ 1127 jum 0 Jul 13 15:28 branch/
diff --git a/lib/spack/external/py/_path/svnwc.py b/lib/spack/external/py/_path/svnwc.py
index 00d3b4bbaf..992223c04a 100644
--- a/lib/spack/external/py/_path/svnwc.py
+++ b/lib/spack/external/py/_path/svnwc.py
@@ -327,7 +327,7 @@ def fixlocale():
return ''
# some nasty chunk of code to solve path and url conversion and quoting issues
-ILLEGAL_CHARS = '* | \ / : < > ? \t \n \x0b \x0c \r'.split(' ')
+ILLEGAL_CHARS = '* | \\ / : < > ? \t \n \x0b \x0c \r'.split(' ')
if os.sep in ILLEGAL_CHARS:
ILLEGAL_CHARS.remove(os.sep)
ISWINDOWS = sys.platform == 'win32'
diff --git a/lib/spack/external/py26/ordereddict.py b/lib/spack/external/py26/ordereddict.py
new file mode 100644
index 0000000000..7242b5060d
--- /dev/null
+++ b/lib/spack/external/py26/ordereddict.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# 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 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.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+ def __init__(self, *args, **kwds):
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__end
+ except AttributeError:
+ self.clear()
+ self.update(*args, **kwds)
+
+ def clear(self):
+ self.__end = end = []
+ end += [None, end, end] # sentinel node for doubly linked list
+ self.__map = {} # key --> [key, prev, next]
+ dict.clear(self)
+
+ def __setitem__(self, key, value):
+ if key not in self:
+ end = self.__end
+ curr = end[1]
+ curr[2] = end[1] = self.__map[key] = [key, curr, end]
+ dict.__setitem__(self, key, value)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ key, prev, next = self.__map.pop(key)
+ prev[2] = next
+ next[1] = prev
+
+ def __iter__(self):
+ end = self.__end
+ curr = end[2]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[2]
+
+ def __reversed__(self):
+ end = self.__end
+ curr = end[1]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[1]
+
+ def popitem(self, last=True):
+ if not self:
+ raise KeyError('dictionary is empty')
+ if last:
+ key = reversed(self).next()
+ else:
+ key = iter(self).next()
+ value = self.pop(key)
+ return key, value
+
+ def __reduce__(self):
+ items = [[k, self[k]] for k in self]
+ tmp = self.__map, self.__end
+ del self.__map, self.__end
+ inst_dict = vars(self).copy()
+ self.__map, self.__end = tmp
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def keys(self):
+ return list(self)
+
+ setdefault = DictMixin.setdefault
+ update = DictMixin.update
+ pop = DictMixin.pop
+ values = DictMixin.values
+ items = DictMixin.items
+ iterkeys = DictMixin.iterkeys
+ itervalues = DictMixin.itervalues
+ iteritems = DictMixin.iteritems
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+
+ def copy(self):
+ return self.__class__(self)
+
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+
+ def __eq__(self, other):
+ if isinstance(other, OrderedDict):
+ if len(self) != len(other):
+ return False
+ for p, q in zip(self.items(), other.items()):
+ if p != q:
+ return False
+ return True
+ return dict.__eq__(self, other)
+
+ def __ne__(self, other):
+ return not self == other
diff --git a/lib/spack/external/pytest.py b/lib/spack/external/pytest.py
index e376e417e8..6e124db418 100644
--- a/lib/spack/external/pytest.py
+++ b/lib/spack/external/pytest.py
@@ -1,7 +1,55 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2004-2017 Holger Krekel and others
+#
+# 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 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.
+
# PYTHON_ARGCOMPLETE_OK
"""
pytest: unit and functional testing with Python.
"""
+
+
+# else we are imported
+
+from _pytest.config import (
+ main, UsageError, _preloadplugins, cmdline,
+ hookspec, hookimpl
+)
+from _pytest.fixtures import fixture, yield_fixture
+from _pytest.assertion import register_assert_rewrite
+from _pytest.freeze_support import freeze_includes
+from _pytest import __version__
+from _pytest.debugging import pytestPDB as __pytestPDB
+from _pytest.recwarn import warns, deprecated_call
+from _pytest.outcomes import fail, skip, importorskip, exit, xfail
+from _pytest.mark import MARK_GEN as mark, param
+from _pytest.main import Item, Collector, File, Session
+from _pytest.fixtures import fillfixtures as _fillfuncargs
+from _pytest.python import (
+ Module, Class, Instance, Function, Generator,
+)
+
+from _pytest.python_api import approx, raises
+
+set_trace = __pytestPDB.set_trace
+
__all__ = [
'main',
'UsageError',
@@ -9,20 +57,44 @@ __all__ = [
'hookspec',
'hookimpl',
'__version__',
+ 'register_assert_rewrite',
+ 'freeze_includes',
+ 'set_trace',
+ 'warns',
+ 'deprecated_call',
+ 'fixture',
+ 'yield_fixture',
+ 'fail',
+ 'skip',
+ 'xfail',
+ 'importorskip',
+ 'exit',
+ 'mark',
+ 'param',
+ 'approx',
+ '_fillfuncargs',
+
+ 'Item',
+ 'File',
+ 'Collector',
+ 'Session',
+ 'Module',
+ 'Class',
+ 'Instance',
+ 'Function',
+ 'Generator',
+ 'raises',
+
+
]
-if __name__ == '__main__': # if run as a script or by 'python -m pytest'
+if __name__ == '__main__':
+ # if run as a script or by 'python -m pytest'
# we trigger the below "else" condition by the following import
import pytest
raise SystemExit(pytest.main())
+else:
-# else we are imported
-
-from _pytest.config import (
- main, UsageError, _preloadplugins, cmdline,
- hookspec, hookimpl
-)
-from _pytest import __version__
-
-_preloadplugins() # to populate pytest.* namespace so help(pytest) works
-
+ from _pytest.compat import _setup_collect_fakemodule
+ _preloadplugins() # to populate pytest.* namespace so help(pytest) works
+ _setup_collect_fakemodule()
diff --git a/lib/spack/external/ruamel/__init__.py b/lib/spack/external/ruamel/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/spack/external/ruamel/__init__.py
diff --git a/lib/spack/external/ruamel/yaml/.ruamel/__init__.py b/lib/spack/external/ruamel/yaml/.ruamel/__init__.py
new file mode 100644
index 0000000000..ece379ce2f
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/.ruamel/__init__.py
@@ -0,0 +1,2 @@
+import pkg_resources
+pkg_resources.declare_namespace(__name__)
diff --git a/lib/spack/external/ruamel/yaml/LICENSE b/lib/spack/external/ruamel/yaml/LICENSE
new file mode 100644
index 0000000000..f6f753a366
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/LICENSE
@@ -0,0 +1,21 @@
+
+ The MIT License (MIT)
+
+ 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 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.
+
diff --git a/lib/spack/external/ruamel/yaml/README.rst b/lib/spack/external/ruamel/yaml/README.rst
new file mode 100644
index 0000000000..993cf35542
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/README.rst
@@ -0,0 +1,38 @@
+
+ruamel.yaml
+===========
+
+``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python.
+
+* `Overview <http://yaml.readthedocs.org/en/latest/overview.html>`_
+* `Installing <http://yaml.readthedocs.org/en/latest/install.html>`_
+* `Details <http://yaml.readthedocs.org/en/latest/detail.html>`_
+* `Examples <http://yaml.readthedocs.org/en/latest/example.html>`_
+* `Differences with PyYAML <http://yaml.readthedocs.org/en/latest/pyyaml.html>`_
+
+.. image:: https://readthedocs.org/projects/yaml/badge/?version=stable
+ :target: https://yaml.readthedocs.org/en/stable
+
+ChangeLog
+=========
+
+::
+
+ 0.11.15 (2016-XX-XX):
+ - Change to prevent FutureWarning in NumPy, as reported by tgehring
+ ("comparison to None will result in an elementwise object comparison in the future")
+
+ 0.11.14 (2016-07-06):
+ - fix preserve_quotes missing on original Loaders (as reported
+ by Leynos, bitbucket issue 38)
+
+ 0.11.13 (2016-07-06):
+ - documentation only, automated linux wheels
+
+ 0.11.12 (2016-07-06):
+ - added support for roundtrip of single/double quoted scalars using:
+ ruamel.yaml.round_trip_load(stream, preserve_quotes=True)
+
+ 0.11.0 (2016-02-18):
+ - RoundTripLoader loads 1.2 by default (no sexagesimals, 012 octals nor
+ yes/no/on/off booleans
diff --git a/lib/spack/external/ruamel/yaml/__init__.py b/lib/spack/external/ruamel/yaml/__init__.py
new file mode 100644
index 0000000000..b77032fc83
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/__init__.py
@@ -0,0 +1,85 @@
+# coding: utf-8
+
+from __future__ import print_function
+from __future__ import absolute_import
+
+# install_requires of ruamel.base is not really required but the old
+# ruamel.base installed __init__.py, and thus a new version should
+# be installed at some point
+
+_package_data = dict(
+ full_package_name="ruamel.yaml",
+ version_info=(0, 11, 15),
+ author="Anthon van der Neut",
+ author_email="a.van.der.neut@ruamel.eu",
+ description="ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order", # NOQA
+ entry_points=None,
+ install_requires=dict(
+ any=[],
+ py26=["ruamel.ordereddict"],
+ py27=["ruamel.ordereddict"]
+ ),
+ ext_modules=[dict(
+ name="_ruamel_yaml",
+ src=["ext/_ruamel_yaml.c", "ext/api.c", "ext/writer.c", "ext/dumper.c",
+ "ext/loader.c", "ext/reader.c", "ext/scanner.c", "ext/parser.c",
+ "ext/emitter.c"],
+ lib=[],
+ # test='#include "ext/yaml.h"\n\nint main(int argc, char* argv[])\n{\nyaml_parser_t parser;\nparser = parser; /* prevent warning */\nreturn 0;\n}\n' # NOQA
+ )
+ ],
+ classifiers=[
+ "Programming Language :: Python :: 2.6",
+ "Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3.3",
+ "Programming Language :: Python :: 3.4",
+ "Programming Language :: Python :: 3.5",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy",
+ "Programming Language :: Python :: Implementation :: Jython",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Topic :: Text Processing :: Markup"
+ ],
+ windows_wheels=True,
+ read_the_docs='yaml',
+ many_linux='libyaml-devel',
+)
+
+
+# < from ruamel.util.new import _convert_version
+def _convert_version(tup):
+ """create a PEP 386 pseudo-format conformant string from tuple tup"""
+ ret_val = str(tup[0]) # first is always digit
+ next_sep = "." # separator for next extension, can be "" or "."
+ for x in tup[1:]:
+ if isinstance(x, int):
+ ret_val += next_sep + str(x)
+ next_sep = '.'
+ continue
+ first_letter = x[0].lower()
+ next_sep = ''
+ if first_letter in 'abcr':
+ ret_val += 'rc' if first_letter == 'r' else first_letter
+ elif first_letter in 'pd':
+ ret_val += '.post' if first_letter == 'p' else '.dev'
+ return ret_val
+
+
+# <
+version_info = _package_data['version_info']
+__version__ = _convert_version(version_info)
+
+del _convert_version
+
+try:
+ from .cyaml import * # NOQA
+ __with_libyaml__ = True
+except (ImportError, ValueError): # for Jython
+ __with_libyaml__ = False
+
+
+# body extracted to main.py
+try:
+ from .main import * # NOQA
+except ImportError:
+ from ruamel.yaml.main import * # NOQA
diff --git a/lib/spack/external/ruamel/yaml/comments.py b/lib/spack/external/ruamel/yaml/comments.py
new file mode 100644
index 0000000000..b8a5010ad8
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/comments.py
@@ -0,0 +1,481 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+"""
+stuff to deal with comments and formatting on dict/list/ordereddict/set
+these are not really related, formatting could be factored out as
+a separate base
+"""
+
+from collections import MutableSet
+
+__all__ = ["CommentedSeq", "CommentedMap", "CommentedOrderedMap",
+ "CommentedSet", 'comment_attrib', 'merge_attrib']
+
+
+try:
+ from .compat import ordereddict
+except ImportError:
+ from ruamel.yaml.compat import ordereddict
+
+comment_attrib = '_yaml_comment'
+format_attrib = '_yaml_format'
+line_col_attrib = '_yaml_line_col'
+anchor_attrib = '_yaml_anchor'
+merge_attrib = '_yaml_merge'
+tag_attrib = '_yaml_tag'
+
+
+class Comment(object):
+ # sys.getsize tested the Comment objects, __slots__ make them bigger
+ # and adding self.end did not matter
+ attrib = comment_attrib
+
+ def __init__(self):
+ self.comment = None # [post, [pre]]
+ # map key (mapping/omap/dict) or index (sequence/list) to a list of
+ # dict: post_key, pre_key, post_value, pre_value
+ # list: pre item, post item
+ self._items = {}
+ # self._start = [] # should not put these on first item
+ self._end = [] # end of document comments
+
+ def __str__(self):
+ if self._end:
+ end = ',\n end=' + str(self._end)
+ else:
+ end = ''
+ return "Comment(comment={0},\n items={1}{2})".format(
+ self.comment, self._items, end)
+
+ @property
+ def items(self):
+ return self._items
+
+ @property
+ def end(self):
+ return self._end
+
+ @end.setter
+ def end(self, value):
+ self._end = value
+
+ @property
+ def start(self):
+ return self._start
+
+ @start.setter
+ def start(self, value):
+ self._start = value
+
+
+# to distinguish key from None
+def NoComment():
+ pass
+
+
+class Format(object):
+ attrib = format_attrib
+
+ def __init__(self):
+ self._flow_style = None
+
+ def set_flow_style(self):
+ self._flow_style = True
+
+ def set_block_style(self):
+ self._flow_style = False
+
+ def flow_style(self, default=None):
+ """if default (the flow_style) is None, the flow style tacked on to
+ the object explicitly will be taken. If that is None as well the
+ default flow style rules the format down the line, or the type
+ of the constituent values (simple -> flow, map/list -> block)"""
+ if self._flow_style is None:
+ return default
+ return self._flow_style
+
+
+class LineCol(object):
+ attrib = line_col_attrib
+
+ def __init__(self):
+ self.line = None
+ self.col = None
+ self.data = None
+
+ def add_kv_line_col(self, key, data):
+ if self.data is None:
+ self.data = {}
+ self.data[key] = data
+
+ def key(self, k):
+ return self._kv(k, 0, 1)
+
+ def value(self, k):
+ return self._kv(k, 2, 3)
+
+ def _kv(self, k, x0, x1):
+ if self.data is None:
+ return None
+ data = self.data[k]
+ return data[x0], data[x1]
+
+ def item(self, idx):
+ if self.data is None:
+ return None
+ return self.data[idx][0], self.data[idx][1]
+
+ def add_idx_line_col(self, key, data):
+ if self.data is None:
+ self.data = {}
+ self.data[key] = data
+
+
+class Anchor(object):
+ attrib = anchor_attrib
+
+ def __init__(self):
+ self.value = None
+ self.always_dump = False
+
+
+class Tag(object):
+ """store tag information for roundtripping"""
+ attrib = tag_attrib
+
+ def __init__(self):
+ self.value = None
+
+
+class CommentedBase(object):
+ @property
+ def ca(self):
+ if not hasattr(self, Comment.attrib):
+ setattr(self, Comment.attrib, Comment())
+ return getattr(self, Comment.attrib)
+
+ def yaml_end_comment_extend(self, comment, clear=False):
+ if clear:
+ self.ca.end = []
+ self.ca.end.extend(comment)
+
+ def yaml_key_comment_extend(self, key, comment, clear=False):
+ l = self.ca._items.setdefault(key, [None, None, None, None])
+ if clear or l[1] is None:
+ if comment[1] is not None:
+ assert isinstance(comment[1], list)
+ l[1] = comment[1]
+ else:
+ l[1].extend(comment[0])
+ l[0] = comment[0]
+
+ def yaml_value_comment_extend(self, key, comment, clear=False):
+ l = self.ca._items.setdefault(key, [None, None, None, None])
+ if clear or l[3] is None:
+ if comment[1] is not None:
+ assert isinstance(comment[1], list)
+ l[3] = comment[1]
+ else:
+ l[3].extend(comment[0])
+ l[2] = comment[0]
+
+ def yaml_set_start_comment(self, comment, indent=0):
+ """overwrites any preceding comment lines on an object
+ expects comment to be without `#` and possible have mutlple lines
+ """
+ from .error import Mark
+ from .tokens import CommentToken
+ pre_comments = self._yaml_get_pre_comment()
+ if comment[-1] == '\n':
+ comment = comment[:-1] # strip final newline if there
+ start_mark = Mark(None, None, None, indent, None, None)
+ for com in comment.split('\n'):
+ pre_comments.append(CommentToken('# ' + com + '\n', start_mark, None))
+
+ @property
+ def fa(self):
+ """format attribute
+
+ set_flow_style()/set_block_style()"""
+ if not hasattr(self, Format.attrib):
+ setattr(self, Format.attrib, Format())
+ return getattr(self, Format.attrib)
+
+ def yaml_add_eol_comment(self, comment, key=NoComment, column=None):
+ """
+ there is a problem as eol comments should start with ' #'
+ (but at the beginning of the line the space doesn't have to be before
+ the #. The column index is for the # mark
+ """
+ from .tokens import CommentToken
+ from .error import Mark
+ if column is None:
+ column = self._yaml_get_column(key)
+ if comment[0] != '#':
+ comment = '# ' + comment
+ if column is None:
+ if comment[0] == '#':
+ comment = ' ' + comment
+ column = 0
+ start_mark = Mark(None, None, None, column, None, None)
+ ct = [CommentToken(comment, start_mark, None), None]
+ self._yaml_add_eol_comment(ct, key=key)
+
+ @property
+ def lc(self):
+ if not hasattr(self, LineCol.attrib):
+ setattr(self, LineCol.attrib, LineCol())
+ return getattr(self, LineCol.attrib)
+
+ def _yaml_set_line_col(self, line, col):
+ self.lc.line = line
+ self.lc.col = col
+
+ def _yaml_set_kv_line_col(self, key, data):
+ self.lc.add_kv_line_col(key, data)
+
+ def _yaml_set_idx_line_col(self, key, data):
+ self.lc.add_idx_line_col(key, data)
+
+ @property
+ def anchor(self):
+ if not hasattr(self, Anchor.attrib):
+ setattr(self, Anchor.attrib, Anchor())
+ return getattr(self, Anchor.attrib)
+
+ def yaml_anchor(self):
+ if not hasattr(self, Anchor.attrib):
+ return None
+ return self.anchor
+
+ def yaml_set_anchor(self, value, always_dump=False):
+ self.anchor.value = value
+ self.anchor.always_dump = always_dump
+
+ @property
+ def tag(self):
+ if not hasattr(self, Tag.attrib):
+ setattr(self, Tag.attrib, Tag())
+ return getattr(self, Tag.attrib)
+
+ def yaml_set_tag(self, value):
+ self.tag.value = value
+
+
+class CommentedSeq(list, CommentedBase):
+ __slots__ = [Comment.attrib, ]
+
+ def _yaml_add_comment(self, comment, key=NoComment):
+ if key is not NoComment:
+ self.yaml_key_comment_extend(key, comment)
+ else:
+ self.ca.comment = comment
+
+ def _yaml_add_eol_comment(self, comment, key):
+ self._yaml_add_comment(comment, key=key)
+
+ def _yaml_get_columnX(self, key):
+ return self.ca.items[key][0].start_mark.column
+
+ def insert(self, idx, val):
+ """the comments after the insertion have to move forward"""
+ list.insert(self, idx, val)
+ for list_index in sorted(self.ca.items, reverse=True):
+ if list_index < idx:
+ break
+ self.ca.items[list_index+1] = self.ca.items.pop(list_index)
+
+ def pop(self, idx):
+ res = list.pop(self, idx)
+ self.ca.items.pop(idx, None) # might not be there -> default value
+ for list_index in sorted(self.ca.items):
+ if list_index < idx:
+ continue
+ self.ca.items[list_index-1] = self.ca.items.pop(list_index)
+ return res
+
+ def _yaml_get_column(self, key):
+ column = None
+ sel_idx = None
+ pre, post = key-1, key+1
+ if pre in self.ca.items:
+ sel_idx = pre
+ elif post in self.ca.items:
+ sel_idx = post
+ else:
+ # self.ca.items is not ordered
+ for row_idx, k1 in enumerate(self):
+ if row_idx >= key:
+ break
+ if row_idx not in self.ca.items:
+ continue
+ sel_idx = row_idx
+ if sel_idx is not None:
+ column = self._yaml_get_columnX(sel_idx)
+ return column
+
+ def _yaml_get_pre_comment(self):
+ if self.ca.comment is None:
+ pre_comments = []
+ self.ca.comment = [None, pre_comments]
+ else:
+ pre_comments = self.ca.comment[1] = []
+ return pre_comments
+
+
+class CommentedMap(ordereddict, CommentedBase):
+ __slots__ = [Comment.attrib, ]
+
+ def _yaml_add_comment(self, comment, key=NoComment, value=NoComment):
+ """values is set to key to indicate a value attachment of comment"""
+ if key is not NoComment:
+ self.yaml_key_comment_extend(key, comment)
+ return
+ if value is not NoComment:
+ self.yaml_value_comment_extend(value, comment)
+ else:
+ self.ca.comment = comment
+
+ def _yaml_add_eol_comment(self, comment, key):
+ """add on the value line, with value specified by the key"""
+ self._yaml_add_comment(comment, value=key)
+
+ def _yaml_get_columnX(self, key):
+ return self.ca.items[key][2].start_mark.column
+
+ def _yaml_get_column(self, key):
+ column = None
+ sel_idx = None
+ pre, post, last = None, None, None
+ for x in self:
+ if pre is not None and x != key:
+ post = x
+ break
+ if x == key:
+ pre = last
+ last = x
+ if pre in self.ca.items:
+ sel_idx = pre
+ elif post in self.ca.items:
+ sel_idx = post
+ else:
+ # self.ca.items is not ordered
+ for row_idx, k1 in enumerate(self):
+ if k1 >= key:
+ break
+ if k1 not in self.ca.items:
+ continue
+ sel_idx = k1
+ if sel_idx is not None:
+ column = self._yaml_get_columnX(sel_idx)
+ return column
+
+ def _yaml_get_pre_comment(self):
+ if self.ca.comment is None:
+ pre_comments = []
+ self.ca.comment = [None, pre_comments]
+ else:
+ pre_comments = self.ca.comment[1] = []
+ return pre_comments
+
+ def update(self, *vals, **kwds):
+ try:
+ ordereddict.update(self, *vals, **kwds)
+ except TypeError:
+ # probably a dict that is used
+ for x in vals:
+ self[x] = vals[x]
+
+ def insert(self, pos, key, value, comment=None):
+ """insert key value into given position
+ attach comment if provided
+ """
+ ordereddict.insert(self, pos, key, value)
+ if comment is not None:
+ self.yaml_add_eol_comment(comment, key=key)
+
+ def mlget(self, key, default=None, list_ok=False):
+ """multi-level get that expects dicts within dicts"""
+ if not isinstance(key, list):
+ return self.get(key, default)
+ # assume that the key is a list of recursively accessible dicts
+
+ def get_one_level(key_list, level, d):
+ if not list_ok:
+ assert isinstance(d, dict)
+ if level >= len(key_list):
+ if level > len(key_list):
+ raise IndexError
+ return d[key_list[level-1]]
+ return get_one_level(key_list, level+1, d[key_list[level-1]])
+
+ try:
+ return get_one_level(key, 1, self)
+ except KeyError:
+ return default
+ except (TypeError, IndexError):
+ if not list_ok:
+ raise
+ return default
+
+ def __getitem__(self, key):
+ try:
+ return ordereddict.__getitem__(self, key)
+ except KeyError:
+ for merged in getattr(self, merge_attrib, []):
+ if key in merged[1]:
+ return merged[1][key]
+ raise
+
+ def get(self, key, default=None):
+ try:
+ return self.__getitem__(key)
+ except:
+ return default
+
+ @property
+ def merge(self):
+ if not hasattr(self, merge_attrib):
+ setattr(self, merge_attrib, [])
+ return getattr(self, merge_attrib)
+
+ def add_yaml_merge(self, value):
+ self.merge.extend(value)
+
+
+class CommentedOrderedMap(CommentedMap):
+ __slots__ = [Comment.attrib, ]
+
+
+class CommentedSet(MutableSet, CommentedMap):
+ __slots__ = [Comment.attrib, 'odict']
+
+ def __init__(self, values=None):
+ self.odict = ordereddict()
+ MutableSet.__init__(self)
+ if values is not None:
+ self |= values
+
+ def add(self, value):
+ """Add an element."""
+ self.odict[value] = None
+
+ def discard(self, value):
+ """Remove an element. Do not raise an exception if absent."""
+ del self.odict[value]
+
+ def __contains__(self, x):
+ return x in self.odict
+
+ def __iter__(self):
+ for x in self.odict:
+ yield x
+
+ def __len__(self):
+ return len(self.odict)
+
+ def __repr__(self):
+ return 'set({0!r})'.format(self.odict.keys())
diff --git a/lib/spack/external/ruamel/yaml/compat.py b/lib/spack/external/ruamel/yaml/compat.py
new file mode 100644
index 0000000000..6eee151c51
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/compat.py
@@ -0,0 +1,120 @@
+# coding: utf-8
+
+from __future__ import print_function
+
+# partially from package six by Benjamin Peterson
+
+import sys
+import os
+import types
+
+try:
+ from ruamel.ordereddict import ordereddict
+except:
+ try:
+ from collections import OrderedDict # nopyqver
+ except ImportError:
+ from ordereddict import OrderedDict
+ # to get the right name import ... as ordereddict doesn't do that
+
+ class ordereddict(OrderedDict):
+ if not hasattr(OrderedDict, 'insert'):
+ def insert(self, pos, key, value):
+ if pos >= len(self):
+ self[key] = value
+ return
+ od = ordereddict()
+ od.update(self)
+ for k in od:
+ del self[k]
+ for index, old_key in enumerate(od):
+ if pos == index:
+ self[key] = value
+ self[old_key] = od[old_key]
+
+
+PY2 = sys.version_info[0] == 2
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+ def utf8(s):
+ return s
+
+ def to_str(s):
+ return s
+
+ def to_unicode(s):
+ return s
+
+else:
+ def utf8(s):
+ return s.encode('utf-8')
+
+ def to_str(s):
+ return str(s)
+
+ def to_unicode(s):
+ return unicode(s)
+
+if PY3:
+ string_types = str,
+ integer_types = int,
+ class_types = type,
+ text_type = str
+ binary_type = bytes
+
+ MAXSIZE = sys.maxsize
+ unichr = chr
+ import io
+ StringIO = io.StringIO
+ BytesIO = io.BytesIO
+
+else:
+ string_types = basestring,
+ integer_types = (int, long)
+ class_types = (type, types.ClassType)
+ text_type = unicode
+ binary_type = str
+
+ unichr = unichr # to allow importing
+ import StringIO
+ StringIO = StringIO.StringIO
+ import cStringIO
+ BytesIO = cStringIO.StringIO
+
+if PY3:
+ builtins_module = 'builtins'
+else:
+ builtins_module = '__builtin__'
+
+
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ return meta("NewBase", bases, {})
+
+DBG_TOKEN = 1
+DBG_EVENT = 2
+DBG_NODE = 4
+
+
+_debug = None
+
+
+# used from yaml util when testing
+def dbg(val=None):
+ global _debug
+ if _debug is None:
+ # set to true or false
+ _debug = os.environ.get('YAMLDEBUG')
+ if _debug is None:
+ _debug = 0
+ else:
+ _debug = int(_debug)
+ if val is None:
+ return _debug
+ return _debug & val
+
+
+def nprint(*args, **kw):
+ if dbg:
+ print(*args, **kw)
diff --git a/lib/spack/external/yaml/lib/yaml/composer.py b/lib/spack/external/ruamel/yaml/composer.py
index 06e5ac782f..fb0a55c759 100644
--- a/lib/spack/external/yaml/lib/yaml/composer.py
+++ b/lib/spack/external/ruamel/yaml/composer.py
@@ -1,15 +1,32 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+
+try:
+ from .error import MarkedYAMLError
+ from .compat import utf8
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import MarkedYAMLError
+ from ruamel.yaml.compat import utf8
+
+from ruamel.yaml.events import (
+ StreamStartEvent, StreamEndEvent, MappingStartEvent, MappingEndEvent,
+ SequenceStartEvent, SequenceEndEvent, AliasEvent, ScalarEvent,
+)
+from ruamel.yaml.nodes import (
+ MappingNode, ScalarNode, SequenceNode,
+)
__all__ = ['Composer', 'ComposerError']
-from error import MarkedYAMLError
-from events import *
-from nodes import *
class ComposerError(MarkedYAMLError):
pass
-class Composer(object):
+class Composer(object):
def __init__(self):
self.anchors = {}
@@ -38,9 +55,10 @@ class Composer(object):
# Ensure that the stream contains no more documents.
if not self.check_event(StreamEndEvent):
event = self.get_event()
- raise ComposerError("expected a single document in the stream",
- document.start_mark, "but found another document",
- event.start_mark)
+ raise ComposerError(
+ "expected a single document in the stream",
+ document.start_mark, "but found another document",
+ event.start_mark)
# Drop the STREAM-END event.
self.get_event()
@@ -63,18 +81,20 @@ class Composer(object):
def compose_node(self, parent, index):
if self.check_event(AliasEvent):
event = self.get_event()
- anchor = event.anchor
- if anchor not in self.anchors:
- raise ComposerError(None, None, "found undefined alias %r"
- % anchor.encode('utf-8'), event.start_mark)
- return self.anchors[anchor]
+ alias = event.anchor
+ if alias not in self.anchors:
+ raise ComposerError(
+ None, None, "found undefined alias %r"
+ % utf8(alias), event.start_mark)
+ return self.anchors[alias]
event = self.peek_event()
anchor = event.anchor
- if anchor is not None:
+ if anchor is not None: # have an anchor
if anchor in self.anchors:
- raise ComposerError("found duplicate anchor %r; first occurence"
- % anchor.encode('utf-8'), self.anchors[anchor].start_mark,
- "second occurence", event.start_mark)
+ raise ComposerError(
+ "found duplicate anchor %r; first occurence"
+ % utf8(anchor), self.anchors[anchor].start_mark,
+ "second occurence", event.start_mark)
self.descend_resolver(parent, index)
if self.check_event(ScalarEvent):
node = self.compose_scalar_node(anchor)
@@ -91,7 +111,8 @@ class Composer(object):
if tag is None or tag == u'!':
tag = self.resolve(ScalarNode, event.value, event.implicit)
node = ScalarNode(tag, event.value,
- event.start_mark, event.end_mark, style=event.style)
+ event.start_mark, event.end_mark, style=event.style,
+ comment=event.comment)
if anchor is not None:
self.anchors[anchor] = node
return node
@@ -102,8 +123,9 @@ class Composer(object):
if tag is None or tag == u'!':
tag = self.resolve(SequenceNode, None, start_event.implicit)
node = SequenceNode(tag, [],
- start_event.start_mark, None,
- flow_style=start_event.flow_style)
+ start_event.start_mark, None,
+ flow_style=start_event.flow_style,
+ comment=start_event.comment, anchor=anchor)
if anchor is not None:
self.anchors[anchor] = node
index = 0
@@ -111,7 +133,13 @@ class Composer(object):
node.value.append(self.compose_node(node, index))
index += 1
end_event = self.get_event()
+ if node.flow_style is True and end_event.comment is not None:
+ if node.comment is not None:
+ print('Warning: unexpected end_event commment in sequence '
+ 'node {0}'.format(node.flow_style))
+ node.comment = end_event.comment
node.end_mark = end_event.end_mark
+ self.check_end_doc_comment(end_event, node)
return node
def compose_mapping_node(self, anchor):
@@ -120,20 +148,35 @@ class Composer(object):
if tag is None or tag == u'!':
tag = self.resolve(MappingNode, None, start_event.implicit)
node = MappingNode(tag, [],
- start_event.start_mark, None,
- flow_style=start_event.flow_style)
+ start_event.start_mark, None,
+ flow_style=start_event.flow_style,
+ comment=start_event.comment, anchor=anchor)
if anchor is not None:
self.anchors[anchor] = node
while not self.check_event(MappingEndEvent):
- #key_event = self.peek_event()
+ # key_event = self.peek_event()
item_key = self.compose_node(node, None)
- #if item_key in node.value:
- # raise ComposerError("while composing a mapping", start_event.start_mark,
- # "found duplicate key", key_event.start_mark)
+ # if item_key in node.value:
+ # raise ComposerError("while composing a mapping",
+ # start_event.start_mark,
+ # "found duplicate key", key_event.start_mark)
item_value = self.compose_node(node, item_key)
- #node.value[item_key] = item_value
+ # node.value[item_key] = item_value
node.value.append((item_key, item_value))
end_event = self.get_event()
+ if node.flow_style is True and end_event.comment is not None:
+ node.comment = end_event.comment
node.end_mark = end_event.end_mark
+ self.check_end_doc_comment(end_event, node)
return node
+ def check_end_doc_comment(self, end_event, node):
+ if end_event.comment and end_event.comment[1]:
+ # pre comments on an end_event, no following to move to
+ if node.comment is None:
+ node.comment = [None, None]
+ assert not isinstance(node, ScalarEvent)
+ # this is a post comment on a mapping node, add as third element
+ # in the list
+ node.comment.append(end_event.comment[1])
+ end_event.comment[1] = None
diff --git a/lib/spack/external/ruamel/yaml/configobjwalker.py b/lib/spack/external/ruamel/yaml/configobjwalker.py
new file mode 100644
index 0000000000..bab910cb11
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/configobjwalker.py
@@ -0,0 +1,9 @@
+# coding: utf-8
+
+import warnings
+from ruamel.yaml.util import configobj_walker as new_configobj_walker
+
+
+def configobj_walker(cfg):
+ warnings.warn("configobj_walker has move to ruamel.yaml.util, please update your code")
+ return new_configobj_walker(cfg)
diff --git a/lib/spack/external/ruamel/yaml/constructor.py b/lib/spack/external/ruamel/yaml/constructor.py
new file mode 100644
index 0000000000..f809df4bf9
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/constructor.py
@@ -0,0 +1,1167 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import collections
+import datetime
+import base64
+import binascii
+import re
+import sys
+import types
+
+try:
+ from .error import * # NOQA
+ from .nodes import * # NOQA
+ from .compat import utf8, builtins_module, to_str, PY2, PY3, ordereddict, text_type
+ from .comments import * # NOQA
+ from .scalarstring import * # NOQA
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import * # NOQA
+ from ruamel.yaml.nodes import * # NOQA
+ from ruamel.yaml.compat import (utf8, builtins_module, to_str, PY2, PY3,
+ ordereddict, text_type)
+ from ruamel.yaml.comments import * # NOQA
+ from ruamel.yaml.scalarstring import * # NOQA
+
+
+__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
+ 'ConstructorError', 'RoundTripConstructor']
+
+
+class ConstructorError(MarkedYAMLError):
+ pass
+
+
+class BaseConstructor(object):
+
+ yaml_constructors = {}
+ yaml_multi_constructors = {}
+
+ def __init__(self, preserve_quotes=None):
+ self.constructed_objects = {}
+ self.recursive_objects = {}
+ self.state_generators = []
+ self.deep_construct = False
+ self._preserve_quotes = preserve_quotes
+
+ def check_data(self):
+ # If there are more documents available?
+ return self.check_node()
+
+ def get_data(self):
+ # Construct and return the next document.
+ if self.check_node():
+ return self.construct_document(self.get_node())
+
+ def get_single_data(self):
+ # Ensure that the stream contains a single document and construct it.
+ node = self.get_single_node()
+ if node is not None:
+ return self.construct_document(node)
+ return None
+
+ def construct_document(self, node):
+ data = self.construct_object(node)
+ while self.state_generators:
+ state_generators = self.state_generators
+ self.state_generators = []
+ for generator in state_generators:
+ for dummy in generator:
+ pass
+ self.constructed_objects = {}
+ self.recursive_objects = {}
+ self.deep_construct = False
+ return data
+
+ def construct_object(self, node, deep=False):
+ """deep is True when creating an object/mapping recursively,
+ in that case want the underlying elements available during construction
+ """
+ if node in self.constructed_objects:
+ return self.constructed_objects[node]
+ if deep:
+ old_deep = self.deep_construct
+ self.deep_construct = True
+ if node in self.recursive_objects:
+ raise ConstructorError(
+ None, None,
+ "found unconstructable recursive node", node.start_mark)
+ self.recursive_objects[node] = None
+ constructor = None
+ tag_suffix = None
+ if node.tag in self.yaml_constructors:
+ constructor = self.yaml_constructors[node.tag]
+ else:
+ for tag_prefix in self.yaml_multi_constructors:
+ if node.tag.startswith(tag_prefix):
+ tag_suffix = node.tag[len(tag_prefix):]
+ constructor = self.yaml_multi_constructors[tag_prefix]
+ break
+ else:
+ if None in self.yaml_multi_constructors:
+ tag_suffix = node.tag
+ constructor = self.yaml_multi_constructors[None]
+ elif None in self.yaml_constructors:
+ constructor = self.yaml_constructors[None]
+ elif isinstance(node, ScalarNode):
+ constructor = self.__class__.construct_scalar
+ elif isinstance(node, SequenceNode):
+ constructor = self.__class__.construct_sequence
+ elif isinstance(node, MappingNode):
+ constructor = self.__class__.construct_mapping
+ if tag_suffix is None:
+ data = constructor(self, node)
+ else:
+ data = constructor(self, tag_suffix, node)
+ if isinstance(data, types.GeneratorType):
+ generator = data
+ data = next(generator)
+ if self.deep_construct:
+ for dummy in generator:
+ pass
+ else:
+ self.state_generators.append(generator)
+ self.constructed_objects[node] = data
+ del self.recursive_objects[node]
+ if deep:
+ self.deep_construct = old_deep
+ return data
+
+ def construct_scalar(self, node):
+ if not isinstance(node, ScalarNode):
+ raise ConstructorError(
+ None, None,
+ "expected a scalar node, but found %s" % node.id,
+ node.start_mark)
+ return node.value
+
+ def construct_sequence(self, node, deep=False):
+ """deep is True when creating an object/mapping recursively,
+ in that case want the underlying elements available during construction
+ """
+ if not isinstance(node, SequenceNode):
+ raise ConstructorError(
+ None, None,
+ "expected a sequence node, but found %s" % node.id,
+ node.start_mark)
+ return [self.construct_object(child, deep=deep)
+ for child in node.value]
+
+ def construct_mapping(self, node, deep=False):
+ """deep is True when creating an object/mapping recursively,
+ in that case want the underlying elements available during construction
+ """
+ if not isinstance(node, MappingNode):
+ raise ConstructorError(
+ None, None,
+ "expected a mapping node, but found %s" % node.id,
+ node.start_mark)
+ mapping = {}
+ for key_node, value_node in node.value:
+ # keys can be list -> deep
+ key = self.construct_object(key_node, deep=True)
+ # lists are not hashable, but tuples are
+ if not isinstance(key, collections.Hashable):
+ if isinstance(key, list):
+ key = tuple(key)
+ if PY2:
+ try:
+ hash(key)
+ except TypeError as exc:
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "found unacceptable key (%s)" %
+ exc, key_node.start_mark)
+ else:
+ if not isinstance(key, collections.Hashable):
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "found unhashable key", key_node.start_mark)
+
+ value = self.construct_object(value_node, deep=deep)
+ mapping[key] = value
+ return mapping
+
+ def construct_pairs(self, node, deep=False):
+ if not isinstance(node, MappingNode):
+ raise ConstructorError(
+ None, None,
+ "expected a mapping node, but found %s" % node.id,
+ node.start_mark)
+ pairs = []
+ for key_node, value_node in node.value:
+ key = self.construct_object(key_node, deep=deep)
+ value = self.construct_object(value_node, deep=deep)
+ pairs.append((key, value))
+ return pairs
+
+ @classmethod
+ def add_constructor(cls, tag, constructor):
+ if 'yaml_constructors' not in cls.__dict__:
+ cls.yaml_constructors = cls.yaml_constructors.copy()
+ cls.yaml_constructors[tag] = constructor
+
+ @classmethod
+ def add_multi_constructor(cls, tag_prefix, multi_constructor):
+ if 'yaml_multi_constructors' not in cls.__dict__:
+ cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
+ cls.yaml_multi_constructors[tag_prefix] = multi_constructor
+
+
+class SafeConstructor(BaseConstructor):
+ def construct_scalar(self, node):
+ if isinstance(node, MappingNode):
+ for key_node, value_node in node.value:
+ if key_node.tag == u'tag:yaml.org,2002:value':
+ return self.construct_scalar(value_node)
+ return BaseConstructor.construct_scalar(self, node)
+
+ def flatten_mapping(self, node):
+ """
+ This implements the merge key feature http://yaml.org/type/merge.html
+ by inserting keys from the merge dict/list of dicts if not yet
+ available in this node
+ """
+ merge = []
+ index = 0
+ while index < len(node.value):
+ key_node, value_node = node.value[index]
+ if key_node.tag == u'tag:yaml.org,2002:merge':
+ del node.value[index]
+ if isinstance(value_node, MappingNode):
+ self.flatten_mapping(value_node)
+ merge.extend(value_node.value)
+ elif isinstance(value_node, SequenceNode):
+ submerge = []
+ for subnode in value_node.value:
+ if not isinstance(subnode, MappingNode):
+ raise ConstructorError(
+ "while constructing a mapping",
+ node.start_mark,
+ "expected a mapping for merging, but found %s"
+ % subnode.id, subnode.start_mark)
+ self.flatten_mapping(subnode)
+ submerge.append(subnode.value)
+ submerge.reverse()
+ for value in submerge:
+ merge.extend(value)
+ else:
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "expected a mapping or list of mappings for merging, "
+ "but found %s"
+ % value_node.id, value_node.start_mark)
+ elif key_node.tag == u'tag:yaml.org,2002:value':
+ key_node.tag = u'tag:yaml.org,2002:str'
+ index += 1
+ else:
+ index += 1
+ if merge:
+ node.value = merge + node.value
+
+ def construct_mapping(self, node, deep=False):
+ """deep is True when creating an object/mapping recursively,
+ in that case want the underlying elements available during construction
+ """
+ if isinstance(node, MappingNode):
+ self.flatten_mapping(node)
+ return BaseConstructor.construct_mapping(self, node, deep=deep)
+
+ def construct_yaml_null(self, node):
+ self.construct_scalar(node)
+ return None
+
+ # YAML 1.2 spec doesn't mention yes/no etc any more, 1.1 does
+ bool_values = {
+ u'yes': True,
+ u'no': False,
+ u'true': True,
+ u'false': False,
+ u'on': True,
+ u'off': False,
+ }
+
+ def construct_yaml_bool(self, node):
+ value = self.construct_scalar(node)
+ return self.bool_values[value.lower()]
+
+ def construct_yaml_int(self, node):
+ value = to_str(self.construct_scalar(node))
+ value = value.replace('_', '')
+ sign = +1
+ if value[0] == '-':
+ sign = -1
+ if value[0] in '+-':
+ value = value[1:]
+ if value == '0':
+ return 0
+ elif value.startswith('0b'):
+ return sign*int(value[2:], 2)
+ elif value.startswith('0x'):
+ return sign*int(value[2:], 16)
+ elif value.startswith('0o'):
+ return sign*int(value[2:], 8)
+ elif self.processing_version != (1, 2) and value[0] == '0':
+ return sign*int(value, 8)
+ elif self.processing_version != (1, 2) and ':' in value:
+ digits = [int(part) for part in value.split(':')]
+ digits.reverse()
+ base = 1
+ value = 0
+ for digit in digits:
+ value += digit*base
+ base *= 60
+ return sign*value
+ else:
+ return sign*int(value)
+
+ inf_value = 1e300
+ while inf_value != inf_value*inf_value:
+ inf_value *= inf_value
+ nan_value = -inf_value/inf_value # Trying to make a quiet NaN (like C99).
+
+ def construct_yaml_float(self, node):
+ value = to_str(self.construct_scalar(node))
+ value = value.replace('_', '').lower()
+ sign = +1
+ if value[0] == '-':
+ sign = -1
+ if value[0] in '+-':
+ value = value[1:]
+ if value == '.inf':
+ return sign*self.inf_value
+ elif value == '.nan':
+ return self.nan_value
+ elif ':' in value:
+ digits = [float(part) for part in value.split(':')]
+ digits.reverse()
+ base = 1
+ value = 0.0
+ for digit in digits:
+ value += digit*base
+ base *= 60
+ return sign*value
+ else:
+ return sign*float(value)
+
+ if PY3:
+ def construct_yaml_binary(self, node):
+ try:
+ value = self.construct_scalar(node).encode('ascii')
+ except UnicodeEncodeError as exc:
+ raise ConstructorError(
+ None, None,
+ "failed to convert base64 data into ascii: %s" % exc,
+ node.start_mark)
+ try:
+ if hasattr(base64, 'decodebytes'):
+ return base64.decodebytes(value)
+ else:
+ return base64.decodestring(value)
+ except binascii.Error as exc:
+ raise ConstructorError(
+ None, None,
+ "failed to decode base64 data: %s" % exc, node.start_mark)
+ else:
+ def construct_yaml_binary(self, node):
+ value = self.construct_scalar(node)
+ try:
+ return to_str(value).decode('base64')
+ except (binascii.Error, UnicodeEncodeError) as exc:
+ raise ConstructorError(
+ None, None,
+ "failed to decode base64 data: %s" % exc, node.start_mark)
+
+ timestamp_regexp = re.compile(
+ u'''^(?P<year>[0-9][0-9][0-9][0-9])
+ -(?P<month>[0-9][0-9]?)
+ -(?P<day>[0-9][0-9]?)
+ (?:(?:[Tt]|[ \\t]+)
+ (?P<hour>[0-9][0-9]?)
+ :(?P<minute>[0-9][0-9])
+ :(?P<second>[0-9][0-9])
+ (?:\\.(?P<fraction>[0-9]*))?
+ (?:[ \\t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
+ (?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
+
+ def construct_yaml_timestamp(self, node):
+ value = self.construct_scalar(node) # NOQA
+ match = self.timestamp_regexp.match(node.value)
+ values = match.groupdict()
+ year = int(values['year'])
+ month = int(values['month'])
+ day = int(values['day'])
+ if not values['hour']:
+ return datetime.date(year, month, day)
+ hour = int(values['hour'])
+ minute = int(values['minute'])
+ second = int(values['second'])
+ fraction = 0
+ if values['fraction']:
+ fraction = values['fraction'][:6]
+ while len(fraction) < 6:
+ fraction += '0'
+ fraction = int(fraction)
+ delta = None
+ if values['tz_sign']:
+ tz_hour = int(values['tz_hour'])
+ tz_minute = int(values['tz_minute'] or 0)
+ delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
+ if values['tz_sign'] == '-':
+ delta = -delta
+ data = datetime.datetime(year, month, day, hour, minute, second,
+ fraction)
+ if delta:
+ data -= delta
+ return data
+
+ def construct_yaml_omap(self, node):
+ # Note: we do now check for duplicate keys
+ omap = ordereddict()
+ yield omap
+ if not isinstance(node, SequenceNode):
+ raise ConstructorError(
+ "while constructing an ordered map", node.start_mark,
+ "expected a sequence, but found %s" % node.id, node.start_mark)
+ for subnode in node.value:
+ if not isinstance(subnode, MappingNode):
+ raise ConstructorError(
+ "while constructing an ordered map", node.start_mark,
+ "expected a mapping of length 1, but found %s" %
+ subnode.id,
+ subnode.start_mark)
+ if len(subnode.value) != 1:
+ raise ConstructorError(
+ "while constructing an ordered map", node.start_mark,
+ "expected a single mapping item, but found %d items" %
+ len(subnode.value),
+ subnode.start_mark)
+ key_node, value_node = subnode.value[0]
+ key = self.construct_object(key_node)
+ assert key not in omap
+ value = self.construct_object(value_node)
+ omap[key] = value
+
+ def construct_yaml_pairs(self, node):
+ # Note: the same code as `construct_yaml_omap`.
+ pairs = []
+ yield pairs
+ if not isinstance(node, SequenceNode):
+ raise ConstructorError(
+ "while constructing pairs", node.start_mark,
+ "expected a sequence, but found %s" % node.id, node.start_mark)
+ for subnode in node.value:
+ if not isinstance(subnode, MappingNode):
+ raise ConstructorError(
+ "while constructing pairs", node.start_mark,
+ "expected a mapping of length 1, but found %s" %
+ subnode.id,
+ subnode.start_mark)
+ if len(subnode.value) != 1:
+ raise ConstructorError(
+ "while constructing pairs", node.start_mark,
+ "expected a single mapping item, but found %d items" %
+ len(subnode.value),
+ subnode.start_mark)
+ key_node, value_node = subnode.value[0]
+ key = self.construct_object(key_node)
+ value = self.construct_object(value_node)
+ pairs.append((key, value))
+
+ def construct_yaml_set(self, node):
+ data = set()
+ yield data
+ value = self.construct_mapping(node)
+ data.update(value)
+
+ def construct_yaml_str(self, node):
+ value = self.construct_scalar(node)
+ if PY3:
+ return value
+ try:
+ return value.encode('ascii')
+ except UnicodeEncodeError:
+ return value
+
+ def construct_yaml_seq(self, node):
+ data = []
+ yield data
+ data.extend(self.construct_sequence(node))
+
+ def construct_yaml_map(self, node):
+ data = {}
+ yield data
+ value = self.construct_mapping(node)
+ data.update(value)
+
+ def construct_yaml_object(self, node, cls):
+ data = cls.__new__(cls)
+ yield data
+ if hasattr(data, '__setstate__'):
+ state = self.construct_mapping(node, deep=True)
+ data.__setstate__(state)
+ else:
+ state = self.construct_mapping(node)
+ data.__dict__.update(state)
+
+ def construct_undefined(self, node):
+ raise ConstructorError(
+ None, None,
+ "could not determine a constructor for the tag %r" %
+ utf8(node.tag),
+ node.start_mark)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:null',
+ SafeConstructor.construct_yaml_null)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:bool',
+ SafeConstructor.construct_yaml_bool)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:int',
+ SafeConstructor.construct_yaml_int)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:float',
+ SafeConstructor.construct_yaml_float)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:binary',
+ SafeConstructor.construct_yaml_binary)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:timestamp',
+ SafeConstructor.construct_yaml_timestamp)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:omap',
+ SafeConstructor.construct_yaml_omap)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:pairs',
+ SafeConstructor.construct_yaml_pairs)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:set',
+ SafeConstructor.construct_yaml_set)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:str',
+ SafeConstructor.construct_yaml_str)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:seq',
+ SafeConstructor.construct_yaml_seq)
+
+SafeConstructor.add_constructor(
+ u'tag:yaml.org,2002:map',
+ SafeConstructor.construct_yaml_map)
+
+SafeConstructor.add_constructor(
+ None, SafeConstructor.construct_undefined)
+
+
+class Constructor(SafeConstructor):
+
+ def construct_python_str(self, node):
+ return utf8(self.construct_scalar(node))
+
+ def construct_python_unicode(self, node):
+ return self.construct_scalar(node)
+
+ if PY3:
+ def construct_python_bytes(self, node):
+ try:
+ value = self.construct_scalar(node).encode('ascii')
+ except UnicodeEncodeError as exc:
+ raise ConstructorError(
+ None, None,
+ "failed to convert base64 data into ascii: %s" % exc,
+ node.start_mark)
+ try:
+ if hasattr(base64, 'decodebytes'):
+ return base64.decodebytes(value)
+ else:
+ return base64.decodestring(value)
+ except binascii.Error as exc:
+ raise ConstructorError(
+ None, None,
+ "failed to decode base64 data: %s" % exc, node.start_mark)
+
+ def construct_python_long(self, node):
+ val = self.construct_yaml_int(node)
+ if PY3:
+ return val
+ return int(val)
+
+ def construct_python_complex(self, node):
+ return complex(self.construct_scalar(node))
+
+ def construct_python_tuple(self, node):
+ return tuple(self.construct_sequence(node))
+
+ def find_python_module(self, name, mark):
+ if not name:
+ raise ConstructorError(
+ "while constructing a Python module", mark,
+ "expected non-empty name appended to the tag", mark)
+ try:
+ __import__(name)
+ except ImportError as exc:
+ raise ConstructorError(
+ "while constructing a Python module", mark,
+ "cannot find module %r (%s)" % (utf8(name), exc), mark)
+ return sys.modules[name]
+
+ def find_python_name(self, name, mark):
+ if not name:
+ raise ConstructorError(
+ "while constructing a Python object", mark,
+ "expected non-empty name appended to the tag", mark)
+ if u'.' in name:
+ module_name, object_name = name.rsplit('.', 1)
+ else:
+ module_name = builtins_module
+ object_name = name
+ try:
+ __import__(module_name)
+ except ImportError as exc:
+ raise ConstructorError(
+ "while constructing a Python object", mark,
+ "cannot find module %r (%s)" % (utf8(module_name), exc), mark)
+ module = sys.modules[module_name]
+ if not hasattr(module, object_name):
+ raise ConstructorError(
+ "while constructing a Python object", mark,
+ "cannot find %r in the module %r" % (utf8(object_name),
+ module.__name__), mark)
+ return getattr(module, object_name)
+
+ def construct_python_name(self, suffix, node):
+ value = self.construct_scalar(node)
+ if value:
+ raise ConstructorError(
+ "while constructing a Python name", node.start_mark,
+ "expected the empty value, but found %r" % utf8(value),
+ node.start_mark)
+ return self.find_python_name(suffix, node.start_mark)
+
+ def construct_python_module(self, suffix, node):
+ value = self.construct_scalar(node)
+ if value:
+ raise ConstructorError(
+ "while constructing a Python module", node.start_mark,
+ "expected the empty value, but found %r" % utf8(value),
+ node.start_mark)
+ return self.find_python_module(suffix, node.start_mark)
+
+ if PY2:
+ class classobj:
+ pass
+
+ def make_python_instance(self, suffix, node,
+ args=None, kwds=None, newobj=False):
+ if not args:
+ args = []
+ if not kwds:
+ kwds = {}
+ cls = self.find_python_name(suffix, node.start_mark)
+ if PY3:
+ if newobj and isinstance(cls, type):
+ return cls.__new__(cls, *args, **kwds)
+ else:
+ return cls(*args, **kwds)
+ else:
+ if newobj and isinstance(cls, type(self.classobj)) \
+ and not args and not kwds:
+ instance = self.classobj()
+ instance.__class__ = cls
+ return instance
+ elif newobj and isinstance(cls, type):
+ return cls.__new__(cls, *args, **kwds)
+ else:
+ return cls(*args, **kwds)
+
+ def set_python_instance_state(self, instance, state):
+ if hasattr(instance, '__setstate__'):
+ instance.__setstate__(state)
+ else:
+ slotstate = {}
+ if isinstance(state, tuple) and len(state) == 2:
+ state, slotstate = state
+ if hasattr(instance, '__dict__'):
+ instance.__dict__.update(state)
+ elif state:
+ slotstate.update(state)
+ for key, value in slotstate.items():
+ setattr(object, key, value)
+
+ def construct_python_object(self, suffix, node):
+ # Format:
+ # !!python/object:module.name { ... state ... }
+ instance = self.make_python_instance(suffix, node, newobj=True)
+ yield instance
+ deep = hasattr(instance, '__setstate__')
+ state = self.construct_mapping(node, deep=deep)
+ self.set_python_instance_state(instance, state)
+
+ def construct_python_object_apply(self, suffix, node, newobj=False):
+ # Format:
+ # !!python/object/apply # (or !!python/object/new)
+ # args: [ ... arguments ... ]
+ # kwds: { ... keywords ... }
+ # state: ... state ...
+ # listitems: [ ... listitems ... ]
+ # dictitems: { ... dictitems ... }
+ # or short format:
+ # !!python/object/apply [ ... arguments ... ]
+ # The difference between !!python/object/apply and !!python/object/new
+ # is how an object is created, check make_python_instance for details.
+ if isinstance(node, SequenceNode):
+ args = self.construct_sequence(node, deep=True)
+ kwds = {}
+ state = {}
+ listitems = []
+ dictitems = {}
+ else:
+ value = self.construct_mapping(node, deep=True)
+ args = value.get('args', [])
+ kwds = value.get('kwds', {})
+ state = value.get('state', {})
+ listitems = value.get('listitems', [])
+ dictitems = value.get('dictitems', {})
+ instance = self.make_python_instance(suffix, node, args, kwds, newobj)
+ if state:
+ self.set_python_instance_state(instance, state)
+ if listitems:
+ instance.extend(listitems)
+ if dictitems:
+ for key in dictitems:
+ instance[key] = dictitems[key]
+ return instance
+
+ def construct_python_object_new(self, suffix, node):
+ return self.construct_python_object_apply(suffix, node, newobj=True)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/none',
+ Constructor.construct_yaml_null)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/bool',
+ Constructor.construct_yaml_bool)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/str',
+ Constructor.construct_python_str)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/unicode',
+ Constructor.construct_python_unicode)
+
+if PY3:
+ Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/bytes',
+ Constructor.construct_python_bytes)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/int',
+ Constructor.construct_yaml_int)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/long',
+ Constructor.construct_python_long)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/float',
+ Constructor.construct_yaml_float)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/complex',
+ Constructor.construct_python_complex)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/list',
+ Constructor.construct_yaml_seq)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/tuple',
+ Constructor.construct_python_tuple)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:python/dict',
+ Constructor.construct_yaml_map)
+
+Constructor.add_multi_constructor(
+ u'tag:yaml.org,2002:python/name:',
+ Constructor.construct_python_name)
+
+Constructor.add_multi_constructor(
+ u'tag:yaml.org,2002:python/module:',
+ Constructor.construct_python_module)
+
+Constructor.add_multi_constructor(
+ u'tag:yaml.org,2002:python/object:',
+ Constructor.construct_python_object)
+
+Constructor.add_multi_constructor(
+ u'tag:yaml.org,2002:python/object/apply:',
+ Constructor.construct_python_object_apply)
+
+Constructor.add_multi_constructor(
+ u'tag:yaml.org,2002:python/object/new:',
+ Constructor.construct_python_object_new)
+
+
+class RoundTripConstructor(SafeConstructor):
+ """need to store the comments on the node itself,
+ as well as on the items
+ """
+
+ def construct_scalar(self, node):
+ if not isinstance(node, ScalarNode):
+ raise ConstructorError(
+ None, None,
+ "expected a scalar node, but found %s" % node.id,
+ node.start_mark)
+
+ if node.style == '|' and isinstance(node.value, text_type):
+ return PreservedScalarString(node.value)
+ elif self._preserve_quotes and isinstance(node.value, text_type):
+ if node.style == "'":
+ return SingleQuotedScalarString(node.value)
+ if node.style == '"':
+ return DoubleQuotedScalarString(node.value)
+ return node.value
+
+ def construct_yaml_str(self, node):
+ value = self.construct_scalar(node)
+ if isinstance(value, ScalarString):
+ return value
+ if PY3:
+ return value
+ try:
+ return value.encode('ascii')
+ except AttributeError:
+ # in case you replace the node dynamically e.g. with a dict
+ return value
+ except UnicodeEncodeError:
+ return value
+
+ def construct_sequence(self, node, seqtyp, deep=False):
+ if not isinstance(node, SequenceNode):
+ raise ConstructorError(
+ None, None,
+ "expected a sequence node, but found %s" % node.id,
+ node.start_mark)
+ ret_val = []
+ if node.comment:
+ seqtyp._yaml_add_comment(node.comment[:2])
+ if len(node.comment) > 2:
+ seqtyp.yaml_end_comment_extend(node.comment[2], clear=True)
+ if node.anchor:
+ from ruamel.yaml.serializer import templated_id
+ if not templated_id(node.anchor):
+ seqtyp.yaml_set_anchor(node.anchor)
+ for idx, child in enumerate(node.value):
+ ret_val.append(self.construct_object(child, deep=deep))
+ if child.comment:
+ seqtyp._yaml_add_comment(child.comment, key=idx)
+ seqtyp._yaml_set_idx_line_col(
+ idx, [child.start_mark.line, child.start_mark.column])
+ return ret_val
+
+ def flatten_mapping(self, node):
+ """
+ This implements the merge key feature http://yaml.org/type/merge.html
+ by inserting keys from the merge dict/list of dicts if not yet
+ available in this node
+ """
+
+ def constructed(value_node):
+ # If the contents of a merge are defined within the
+ # merge marker, then they won't have been constructed
+ # yet. But if they were already constructed, we need to use
+ # the existing object.
+ if value_node in self.constructed_objects:
+ value = self.constructed_objects[value_node]
+ else:
+ value = self.construct_object(value_node, deep=False)
+ return value
+
+ # merge = []
+ merge_map_list = []
+ index = 0
+ while index < len(node.value):
+ key_node, value_node = node.value[index]
+ if key_node.tag == u'tag:yaml.org,2002:merge':
+ del node.value[index]
+ if isinstance(value_node, MappingNode):
+ merge_map_list.append(
+ (index, constructed(value_node)))
+ # self.flatten_mapping(value_node)
+ # merge.extend(value_node.value)
+ elif isinstance(value_node, SequenceNode):
+ # submerge = []
+ for subnode in value_node.value:
+ if not isinstance(subnode, MappingNode):
+ raise ConstructorError(
+ "while constructing a mapping",
+ node.start_mark,
+ "expected a mapping for merging, but found %s"
+ % subnode.id, subnode.start_mark)
+ merge_map_list.append(
+ (index, constructed(subnode)))
+ # self.flatten_mapping(subnode)
+ # submerge.append(subnode.value)
+ # submerge.reverse()
+ # for value in submerge:
+ # merge.extend(value)
+ else:
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "expected a mapping or list of mappings for merging, "
+ "but found %s"
+ % value_node.id, value_node.start_mark)
+ elif key_node.tag == u'tag:yaml.org,2002:value':
+ key_node.tag = u'tag:yaml.org,2002:str'
+ index += 1
+ else:
+ index += 1
+ # print ('merge_map_list', merge_map_list)
+ return merge_map_list
+ # if merge:
+ # node.value = merge + node.value
+
+ def construct_mapping(self, node, maptyp, deep=False):
+ if not isinstance(node, MappingNode):
+ raise ConstructorError(
+ None, None,
+ "expected a mapping node, but found %s" % node.id,
+ node.start_mark)
+ merge_map = self.flatten_mapping(node)
+ if merge_map:
+ maptyp.add_yaml_merge(merge_map)
+ # mapping = {}
+ if node.comment:
+ maptyp._yaml_add_comment(node.comment[:2])
+ if len(node.comment) > 2:
+ maptyp.yaml_end_comment_extend(node.comment[2], clear=True)
+ if node.anchor:
+ from ruamel.yaml.serializer import templated_id
+ if not templated_id(node.anchor):
+ maptyp.yaml_set_anchor(node.anchor)
+ for key_node, value_node in node.value:
+ # keys can be list -> deep
+ key = self.construct_object(key_node, deep=True)
+ # lists are not hashable, but tuples are
+ if not isinstance(key, collections.Hashable):
+ if isinstance(key, list):
+ key = tuple(key)
+ if PY2:
+ try:
+ hash(key)
+ except TypeError as exc:
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "found unacceptable key (%s)" %
+ exc, key_node.start_mark)
+ else:
+ if not isinstance(key, collections.Hashable):
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "found unhashable key", key_node.start_mark)
+ value = self.construct_object(value_node, deep=deep)
+ if key_node.comment:
+ maptyp._yaml_add_comment(key_node.comment, key=key)
+ if value_node.comment:
+ maptyp._yaml_add_comment(value_node.comment, value=key)
+ maptyp._yaml_set_kv_line_col(
+ key, [key_node.start_mark.line, key_node.start_mark.column,
+ value_node.start_mark.line, value_node.start_mark.column])
+ maptyp[key] = value
+
+ def construct_setting(self, node, typ, deep=False):
+ if not isinstance(node, MappingNode):
+ raise ConstructorError(
+ None, None,
+ "expected a mapping node, but found %s" % node.id,
+ node.start_mark)
+ if node.comment:
+ typ._yaml_add_comment(node.comment[:2])
+ if len(node.comment) > 2:
+ typ.yaml_end_comment_extend(node.comment[2], clear=True)
+ if node.anchor:
+ from ruamel.yaml.serializer import templated_id
+ if not templated_id(node.anchor):
+ typ.yaml_set_anchor(node.anchor)
+ for key_node, value_node in node.value:
+ # keys can be list -> deep
+ key = self.construct_object(key_node, deep=True)
+ # lists are not hashable, but tuples are
+ if not isinstance(key, collections.Hashable):
+ if isinstance(key, list):
+ key = tuple(key)
+ if PY2:
+ try:
+ hash(key)
+ except TypeError as exc:
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "found unacceptable key (%s)" %
+ exc, key_node.start_mark)
+ else:
+ if not isinstance(key, collections.Hashable):
+ raise ConstructorError(
+ "while constructing a mapping", node.start_mark,
+ "found unhashable key", key_node.start_mark)
+ value = self.construct_object(value_node, deep=deep) # NOQA
+ if key_node.comment:
+ typ._yaml_add_comment(key_node.comment, key=key)
+ if value_node.comment:
+ typ._yaml_add_comment(value_node.comment, value=key)
+ typ.add(key)
+
+ def construct_yaml_seq(self, node):
+ data = CommentedSeq()
+ data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
+ if node.flow_style is True:
+ data.fa.set_flow_style()
+ elif node.flow_style is False:
+ data.fa.set_block_style()
+ if node.comment:
+ data._yaml_add_comment(node.comment)
+ yield data
+ data.extend(self.construct_sequence(node, data))
+
+ def construct_yaml_map(self, node):
+ data = CommentedMap()
+ data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
+ if node.flow_style is True:
+ data.fa.set_flow_style()
+ elif node.flow_style is False:
+ data.fa.set_block_style()
+ yield data
+ self.construct_mapping(node, data)
+
+ def construct_yaml_omap(self, node):
+ # Note: we do now check for duplicate keys
+ omap = CommentedOrderedMap()
+ omap._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
+ if node.flow_style is True:
+ omap.fa.set_flow_style()
+ elif node.flow_style is False:
+ omap.fa.set_block_style()
+ yield omap
+ if node.comment:
+ omap._yaml_add_comment(node.comment[:2])
+ if len(node.comment) > 2:
+ omap.yaml_end_comment_extend(node.comment[2], clear=True)
+ if not isinstance(node, SequenceNode):
+ raise ConstructorError(
+ "while constructing an ordered map", node.start_mark,
+ "expected a sequence, but found %s" % node.id, node.start_mark)
+ for subnode in node.value:
+ if not isinstance(subnode, MappingNode):
+ raise ConstructorError(
+ "while constructing an ordered map", node.start_mark,
+ "expected a mapping of length 1, but found %s" %
+ subnode.id,
+ subnode.start_mark)
+ if len(subnode.value) != 1:
+ raise ConstructorError(
+ "while constructing an ordered map", node.start_mark,
+ "expected a single mapping item, but found %d items" %
+ len(subnode.value),
+ subnode.start_mark)
+ key_node, value_node = subnode.value[0]
+ key = self.construct_object(key_node)
+ assert key not in omap
+ value = self.construct_object(value_node)
+ if key_node.comment:
+ omap._yaml_add_comment(key_node.comment, key=key)
+ if subnode.comment:
+ omap._yaml_add_comment(subnode.comment, key=key)
+ if value_node.comment:
+ omap._yaml_add_comment(value_node.comment, value=key)
+ omap[key] = value
+
+ def construct_yaml_set(self, node):
+ data = CommentedSet()
+ data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
+ yield data
+ self.construct_setting(node, data)
+
+ def construct_undefined(self, node):
+ try:
+ data = CommentedMap()
+ data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
+ if node.flow_style is True:
+ data.fa.set_flow_style()
+ elif node.flow_style is False:
+ data.fa.set_block_style()
+ data.yaml_set_tag(node.tag)
+ yield data
+ self.construct_mapping(node, data)
+ except:
+ raise ConstructorError(
+ None, None,
+ "could not determine a constructor for the tag %r" %
+ utf8(node.tag),
+ node.start_mark)
+
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:null',
+ RoundTripConstructor.construct_yaml_null)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:bool',
+ RoundTripConstructor.construct_yaml_bool)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:int',
+ RoundTripConstructor.construct_yaml_int)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:float',
+ RoundTripConstructor.construct_yaml_float)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:binary',
+ RoundTripConstructor.construct_yaml_binary)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:timestamp',
+ RoundTripConstructor.construct_yaml_timestamp)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:omap',
+ RoundTripConstructor.construct_yaml_omap)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:pairs',
+ RoundTripConstructor.construct_yaml_pairs)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:set',
+ RoundTripConstructor.construct_yaml_set)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:str',
+ RoundTripConstructor.construct_yaml_str)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:seq',
+ RoundTripConstructor.construct_yaml_seq)
+
+RoundTripConstructor.add_constructor(
+ u'tag:yaml.org,2002:map',
+ RoundTripConstructor.construct_yaml_map)
+
+RoundTripConstructor.add_constructor(
+ None, RoundTripConstructor.construct_undefined)
diff --git a/lib/spack/external/ruamel/yaml/dumper.py b/lib/spack/external/ruamel/yaml/dumper.py
new file mode 100644
index 0000000000..90e2ca9d1b
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/dumper.py
@@ -0,0 +1,102 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+
+__all__ = ['BaseDumper', 'SafeDumper', 'Dumper', 'RoundTripDumper']
+
+try:
+ from .emitter import * # NOQA
+ from .serializer import * # NOQA
+ from .representer import * # NOQA
+ from .resolver import * # NOQA
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.emitter import * # NOQA
+ from ruamel.yaml.serializer import * # NOQA
+ from ruamel.yaml.representer import * # NOQA
+ from ruamel.yaml.resolver import * # NOQA
+
+
+class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
+ def __init__(self, stream,
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=None, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
+ Emitter.__init__(self, stream, canonical=canonical,
+ indent=indent, width=width,
+ allow_unicode=allow_unicode, line_break=line_break,
+ block_seq_indent=block_seq_indent)
+ Serializer.__init__(self, encoding=encoding,
+ explicit_start=explicit_start,
+ explicit_end=explicit_end,
+ version=version, tags=tags)
+ Representer.__init__(self, default_style=default_style,
+ default_flow_style=default_flow_style)
+ Resolver.__init__(self)
+
+
+class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver):
+ def __init__(self, stream,
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=None, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
+ Emitter.__init__(self, stream, canonical=canonical,
+ indent=indent, width=width,
+ allow_unicode=allow_unicode, line_break=line_break,
+ block_seq_indent=block_seq_indent)
+ Serializer.__init__(self, encoding=encoding,
+ explicit_start=explicit_start,
+ explicit_end=explicit_end,
+ version=version, tags=tags)
+ SafeRepresenter.__init__(self, default_style=default_style,
+ default_flow_style=default_flow_style)
+ Resolver.__init__(self)
+
+
+class Dumper(Emitter, Serializer, Representer, Resolver):
+ def __init__(self, stream,
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=None, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
+ Emitter.__init__(self, stream, canonical=canonical,
+ indent=indent, width=width,
+ allow_unicode=allow_unicode, line_break=line_break,
+ block_seq_indent=block_seq_indent)
+ Serializer.__init__(self, encoding=encoding,
+ explicit_start=explicit_start,
+ explicit_end=explicit_end,
+ version=version, tags=tags)
+ Representer.__init__(self, default_style=default_style,
+ default_flow_style=default_flow_style)
+ Resolver.__init__(self)
+
+
+class RoundTripDumper(Emitter, Serializer, RoundTripRepresenter, VersionedResolver):
+ def __init__(self, stream,
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=None, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
+ Emitter.__init__(self, stream, canonical=canonical,
+ indent=indent, width=width,
+ allow_unicode=allow_unicode, line_break=line_break,
+ block_seq_indent=block_seq_indent,
+ top_level_colon_align=top_level_colon_align,
+ prefix_colon=prefix_colon)
+ Serializer.__init__(self, encoding=encoding,
+ explicit_start=explicit_start,
+ explicit_end=explicit_end,
+ version=version, tags=tags)
+ RoundTripRepresenter.__init__(self, default_style=default_style,
+ default_flow_style=default_flow_style)
+ VersionedResolver.__init__(self)
diff --git a/lib/spack/external/yaml/lib/yaml/emitter.py b/lib/spack/external/ruamel/yaml/emitter.py
index e5bcdcccbb..b754bc04e1 100644
--- a/lib/spack/external/yaml/lib/yaml/emitter.py
+++ b/lib/spack/external/ruamel/yaml/emitter.py
@@ -1,3 +1,7 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
# Emitter expects events obeying the following grammar:
# stream ::= STREAM-START document* STREAM-END
@@ -8,17 +12,25 @@
__all__ = ['Emitter', 'EmitterError']
-from error import YAMLError
-from events import *
+try:
+ from .error import YAMLError
+ from .events import * # NOQA
+ from .compat import utf8, text_type, PY2, nprint, dbg, DBG_EVENT
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import YAMLError
+ from ruamel.yaml.events import * # NOQA
+ from ruamel.yaml.compat import utf8, text_type, PY2, nprint, dbg, DBG_EVENT
+
class EmitterError(YAMLError):
pass
+
class ScalarAnalysis(object):
def __init__(self, scalar, empty, multiline,
- allow_flow_plain, allow_block_plain,
- allow_single_quoted, allow_double_quoted,
- allow_block):
+ allow_flow_plain, allow_block_plain,
+ allow_single_quoted, allow_double_quoted,
+ allow_block):
self.scalar = scalar
self.empty = empty
self.multiline = multiline
@@ -28,15 +40,18 @@ class ScalarAnalysis(object):
self.allow_double_quoted = allow_double_quoted
self.allow_block = allow_block
-class Emitter(object):
+class Emitter(object):
DEFAULT_TAG_PREFIXES = {
- u'!' : u'!',
- u'tag:yaml.org,2002:' : u'!!',
+ u'!': u'!',
+ u'tag:yaml.org,2002:': u'!!',
}
+ MAX_SIMPLE_KEY_LENGTH = 128
+
def __init__(self, stream, canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None):
+ allow_unicode=None, line_break=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
# The stream should have the methods `write` and possibly `flush`.
self.stream = stream
@@ -75,16 +90,25 @@ class Emitter(object):
self.column = 0
self.whitespace = True
self.indention = True
+ self.no_newline = None # set if directly after `- `
# Whether the document requires an explicit document indicator
self.open_ended = False
+ # colon handling
+ self.colon = u':'
+ self.prefixed_colon = self.colon if prefix_colon is None else prefix_colon + self.colon
+
# Formatting details.
self.canonical = canonical
self.allow_unicode = allow_unicode
+ self.block_seq_indent = block_seq_indent if block_seq_indent else 0
+ self.top_level_colon_align = top_level_colon_align
self.best_indent = 2
if indent and 1 < indent < 10:
self.best_indent = indent
+ # if self.best_indent < self.block_seq_indent + 1:
+ # self.best_indent = self.block_seq_indent + 1
self.best_width = 80
if width and width > self.best_indent*2:
self.best_width = width
@@ -109,6 +133,8 @@ class Emitter(object):
self.state = None
def emit(self, event):
+ if dbg(DBG_EVENT):
+ nprint(event)
self.events.append(event)
while not self.need_more_events():
self.event = self.events.pop(0)
@@ -143,7 +169,7 @@ class Emitter(object):
return False
return (len(self.events) < count+1)
- def increase_indent(self, flow=False, indentless=False):
+ def increase_indent(self, flow=False, sequence=None, indentless=False):
self.indents.append(self.indent)
if self.indent is None:
if flow:
@@ -152,6 +178,8 @@ class Emitter(object):
self.indent = 0
elif not indentless:
self.indent += self.best_indent
+ # if self.sequence_context and (self.block_seq_indent + 2) > self.best_indent:
+ # self.indent = self.block_seq_indent + 2
# States.
@@ -159,13 +187,19 @@ class Emitter(object):
def expect_stream_start(self):
if isinstance(self.event, StreamStartEvent):
- if self.event.encoding and not getattr(self.stream, 'encoding', None):
- self.encoding = self.event.encoding
+ if PY2:
+ if self.event.encoding \
+ and not getattr(self.stream, 'encoding', None):
+ self.encoding = self.event.encoding
+ else:
+ if self.event.encoding \
+ and not hasattr(self.stream, 'encoding'):
+ self.encoding = self.event.encoding
self.write_stream_start()
self.state = self.expect_first_document_start
else:
- raise EmitterError("expected StreamStartEvent, but got %s"
- % self.event)
+ raise EmitterError("expected StreamStartEvent, but got %s" %
+ self.event)
def expect_nothing(self):
raise EmitterError("expected nothing, but got %s" % self.event)
@@ -185,17 +219,19 @@ class Emitter(object):
self.write_version_directive(version_text)
self.tag_prefixes = self.DEFAULT_TAG_PREFIXES.copy()
if self.event.tags:
- handles = self.event.tags.keys()
- handles.sort()
+ handles = sorted(self.event.tags.keys())
for handle in handles:
prefix = self.event.tags[handle]
self.tag_prefixes[prefix] = handle
handle_text = self.prepare_tag_handle(handle)
prefix_text = self.prepare_tag_prefix(prefix)
self.write_tag_directive(handle_text, prefix_text)
- implicit = (first and not self.event.explicit and not self.canonical
- and not self.event.version and not self.event.tags
- and not self.check_empty_document())
+ implicit = (first and
+ not self.event.explicit and
+ not self.canonical and
+ not self.event.version and
+ not self.event.tags and
+ not self.check_empty_document())
if not implicit:
self.write_indent()
self.write_indicator(u'---', True)
@@ -209,8 +245,8 @@ class Emitter(object):
self.write_stream_end()
self.state = self.expect_nothing
else:
- raise EmitterError("expected DocumentStartEvent, but got %s"
- % self.event)
+ raise EmitterError("expected DocumentStartEvent, but got %s" %
+ self.event)
def expect_document_end(self):
if isinstance(self.event, DocumentEndEvent):
@@ -221,8 +257,8 @@ class Emitter(object):
self.flush_stream()
self.state = self.expect_document_start
else:
- raise EmitterError("expected DocumentEndEvent, but got %s"
- % self.event)
+ raise EmitterError("expected DocumentEndEvent, but got %s" %
+ self.event)
def expect_document_root(self):
self.states.append(self.expect_document_end)
@@ -231,9 +267,9 @@ class Emitter(object):
# Node handlers.
def expect_node(self, root=False, sequence=False, mapping=False,
- simple_key=False):
+ simple_key=False):
self.root_context = root
- self.sequence_context = sequence
+ self.sequence_context = sequence # not used in PyYAML
self.mapping_context = mapping
self.simple_key_context = simple_key
if isinstance(self.event, AliasEvent):
@@ -244,13 +280,22 @@ class Emitter(object):
if isinstance(self.event, ScalarEvent):
self.expect_scalar()
elif isinstance(self.event, SequenceStartEvent):
- if self.flow_level or self.canonical or self.event.flow_style \
- or self.check_empty_sequence():
+ if self.event.comment:
+ self.write_pre_comment(self.event)
+ if self.event.flow_style is False and self.event.comment:
+ self.write_post_comment(self.event)
+ # print('seq event', self.event)
+ if self.flow_level or self.canonical or self.event.flow_style or \
+ self.check_empty_sequence():
self.expect_flow_sequence()
else:
self.expect_block_sequence()
elif isinstance(self.event, MappingStartEvent):
- if self.flow_level or self.canonical or self.event.flow_style \
+ if self.event.flow_style is False and self.event.comment:
+ self.write_post_comment(self.event)
+ if self.event.comment and self.event.comment[1]:
+ self.write_pre_comment(self.event)
+ if self.flow_level or self.canonical or self.event.flow_style \
or self.check_empty_mapping():
self.expect_flow_mapping()
else:
@@ -275,7 +320,7 @@ class Emitter(object):
def expect_flow_sequence(self):
self.write_indicator(u'[', True, whitespace=True)
self.flow_level += 1
- self.increase_indent(flow=True)
+ self.increase_indent(flow=True, sequence=True)
self.state = self.expect_first_flow_sequence_item
def expect_first_flow_sequence_item(self):
@@ -298,6 +343,9 @@ class Emitter(object):
self.write_indicator(u',', False)
self.write_indent()
self.write_indicator(u']', False)
+ if self.event.comment and self.event.comment[0]:
+ # eol comment on flow sequence
+ self.write_post_comment(self.event)
self.state = self.states.pop()
else:
self.write_indicator(u',', False)
@@ -311,7 +359,7 @@ class Emitter(object):
def expect_flow_mapping(self):
self.write_indicator(u'{', True, whitespace=True)
self.flow_level += 1
- self.increase_indent(flow=True)
+ self.increase_indent(flow=True, sequence=False)
self.state = self.expect_first_flow_mapping_key
def expect_first_flow_mapping_key(self):
@@ -319,6 +367,9 @@ class Emitter(object):
self.indent = self.indents.pop()
self.flow_level -= 1
self.write_indicator(u'}', False)
+ # if self.event.comment and self.event.comment[0]:
+ # # eol comment on flow sequence
+ # self.write_post_comment(self.event)
self.state = self.states.pop()
else:
if self.canonical or self.column > self.best_width:
@@ -333,12 +384,17 @@ class Emitter(object):
def expect_flow_mapping_key(self):
if isinstance(self.event, MappingEndEvent):
+ # if self.event.comment and self.event.comment[1]:
+ # self.write_pre_comment(self.event)
self.indent = self.indents.pop()
self.flow_level -= 1
if self.canonical:
self.write_indicator(u',', False)
self.write_indent()
self.write_indicator(u'}', False)
+ if self.event.comment and self.event.comment[0]:
+ # eol comment on flow mapping
+ self.write_post_comment(self.event)
self.state = self.states.pop()
else:
self.write_indicator(u',', False)
@@ -353,14 +409,14 @@ class Emitter(object):
self.expect_node(mapping=True)
def expect_flow_mapping_simple_value(self):
- self.write_indicator(u':', False)
+ self.write_indicator(self.prefixed_colon, False)
self.states.append(self.expect_flow_mapping_key)
self.expect_node(mapping=True)
def expect_flow_mapping_value(self):
if self.canonical or self.column > self.best_width:
self.write_indent()
- self.write_indicator(u':', True)
+ self.write_indicator(self.prefixed_colon, True)
self.states.append(self.expect_flow_mapping_key)
self.expect_node(mapping=True)
@@ -368,7 +424,7 @@ class Emitter(object):
def expect_block_sequence(self):
indentless = (self.mapping_context and not self.indention)
- self.increase_indent(flow=False, indentless=indentless)
+ self.increase_indent(flow=False, sequence=True, indentless=indentless)
self.state = self.expect_first_block_sequence_item
def expect_first_block_sequence_item(self):
@@ -376,18 +432,26 @@ class Emitter(object):
def expect_block_sequence_item(self, first=False):
if not first and isinstance(self.event, SequenceEndEvent):
+ if self.event.comment and self.event.comment[1]:
+ # final comments from a doc
+ self.write_pre_comment(self.event)
self.indent = self.indents.pop()
self.state = self.states.pop()
else:
self.write_indent()
- self.write_indicator(u'-', True, indention=True)
+ if self.event.comment and self.event.comment[1]:
+ self.write_pre_comment(self.event)
+ self.write_indent()
+ self.write_indicator((u' ' * self.block_seq_indent) + u'-', True, indention=True)
+ if self.block_seq_indent + 2 > self.best_indent:
+ self.no_newline = True
self.states.append(self.expect_block_sequence_item)
self.expect_node(sequence=True)
# Block mapping handlers.
def expect_block_mapping(self):
- self.increase_indent(flow=False)
+ self.increase_indent(flow=False, sequence=False)
self.state = self.expect_first_block_mapping_key
def expect_first_block_mapping_key(self):
@@ -395,11 +459,19 @@ class Emitter(object):
def expect_block_mapping_key(self, first=False):
if not first and isinstance(self.event, MappingEndEvent):
+ if self.event.comment and self.event.comment[1]:
+ # final comments from a doc
+ self.write_pre_comment(self.event)
self.indent = self.indents.pop()
self.state = self.states.pop()
else:
+ if self.event.comment and self.event.comment[1]:
+ # final comments from a doc
+ self.write_pre_comment(self.event)
self.write_indent()
if self.check_simple_key():
+ if self.event.style == '?':
+ self.write_indicator(u'?', True, indention=True)
self.states.append(self.expect_block_mapping_simple_value)
self.expect_node(mapping=True, simple_key=True)
else:
@@ -408,32 +480,39 @@ class Emitter(object):
self.expect_node(mapping=True)
def expect_block_mapping_simple_value(self):
- self.write_indicator(u':', False)
+ if getattr(self.event, 'style', None) != '?':
+ # prefix = u''
+ if self.indent == 0 and self.top_level_colon_align is not None:
+ # write non-prefixed colon
+ c = u' ' * (self.top_level_colon_align - self.column) + self.colon
+ else:
+ c = self.prefixed_colon
+ self.write_indicator(c, False)
self.states.append(self.expect_block_mapping_key)
self.expect_node(mapping=True)
def expect_block_mapping_value(self):
self.write_indent()
- self.write_indicator(u':', True, indention=True)
+ self.write_indicator(self.prefixed_colon, True, indention=True)
self.states.append(self.expect_block_mapping_key)
self.expect_node(mapping=True)
# Checkers.
def check_empty_sequence(self):
- return (isinstance(self.event, SequenceStartEvent) and self.events
- and isinstance(self.events[0], SequenceEndEvent))
+ return (isinstance(self.event, SequenceStartEvent) and self.events and
+ isinstance(self.events[0], SequenceEndEvent))
def check_empty_mapping(self):
- return (isinstance(self.event, MappingStartEvent) and self.events
- and isinstance(self.events[0], MappingEndEvent))
+ return (isinstance(self.event, MappingStartEvent) and self.events and
+ isinstance(self.events[0], MappingEndEvent))
def check_empty_document(self):
if not isinstance(self.event, DocumentStartEvent) or not self.events:
return False
event = self.events[0]
- return (isinstance(event, ScalarEvent) and event.anchor is None
- and event.tag is None and event.implicit and event.value == u'')
+ return (isinstance(event, ScalarEvent) and event.anchor is None and
+ event.tag is None and event.implicit and event.value == u'')
def check_simple_key(self):
length = 0
@@ -450,10 +529,11 @@ class Emitter(object):
if self.analysis is None:
self.analysis = self.analyze_scalar(self.event.value)
length += len(self.analysis.scalar)
- return (length < 128 and (isinstance(self.event, AliasEvent)
- or (isinstance(self.event, ScalarEvent)
- and not self.analysis.empty and not self.analysis.multiline)
- or self.check_empty_sequence() or self.check_empty_mapping()))
+ return (length < self.MAX_SIMPLE_KEY_LENGTH and (
+ isinstance(self.event, AliasEvent) or
+ (isinstance(self.event, ScalarEvent) and
+ not self.analysis.empty and not self.analysis.multiline) or
+ self.check_empty_sequence() or self.check_empty_mapping()))
# Anchor, Tag, and Scalar processors.
@@ -473,8 +553,8 @@ class Emitter(object):
if self.style is None:
self.style = self.choose_scalar_style()
if ((not self.canonical or tag is None) and
- ((self.style == '' and self.event.implicit[0])
- or (self.style != '' and self.event.implicit[1]))):
+ ((self.style == '' and self.event.implicit[0]) or
+ (self.style != '' and self.event.implicit[1]))):
self.prepared_tag = None
return
if self.event.implicit[0] and tag is None:
@@ -497,15 +577,16 @@ class Emitter(object):
self.analysis = self.analyze_scalar(self.event.value)
if self.event.style == '"' or self.canonical:
return '"'
- if not self.event.style and self.event.implicit[0]:
+ if (not self.event.style or self.event.style == '?') and \
+ self.event.implicit[0]:
if (not (self.simple_key_context and
- (self.analysis.empty or self.analysis.multiline))
- and (self.flow_level and self.analysis.allow_flow_plain
- or (not self.flow_level and self.analysis.allow_block_plain))):
+ (self.analysis.empty or self.analysis.multiline)) and
+ (self.flow_level and self.analysis.allow_flow_plain or
+ (not self.flow_level and self.analysis.allow_block_plain))):
return ''
if self.event.style and self.event.style in '|>':
- if (not self.flow_level and not self.simple_key_context
- and self.analysis.allow_block):
+ if (not self.flow_level and not self.simple_key_context and
+ self.analysis.allow_block):
return self.event.style
if not self.event.style or self.event.style == '\'':
if (self.analysis.allow_single_quoted and
@@ -519,9 +600,11 @@ class Emitter(object):
if self.style is None:
self.style = self.choose_scalar_style()
split = (not self.simple_key_context)
- #if self.analysis.multiline and split \
- # and (not self.style or self.style in '\'\"'):
- # self.write_indent()
+ # if self.analysis.multiline and split \
+ # and (not self.style or self.style in '\'\"'):
+ # self.write_indent()
+ if self.sequence_context and not self.flow_level:
+ self.write_indent()
if self.style == '"':
self.write_double_quoted(self.analysis.scalar, split)
elif self.style == '\'':
@@ -534,13 +617,16 @@ class Emitter(object):
self.write_plain(self.analysis.scalar, split)
self.analysis = None
self.style = None
+ if self.event.comment:
+ self.write_post_comment(self.event)
# Analyzers.
def prepare_version(self, version):
major, minor = version
if major != 1:
- raise EmitterError("unsupported YAML version: %d.%d" % (major, minor))
+ raise EmitterError("unsupported YAML version: %d.%d" %
+ (major, minor))
return u'%d.%d' % (major, minor)
def prepare_tag_handle(self, handle):
@@ -548,12 +634,12 @@ class Emitter(object):
raise EmitterError("tag handle must not be empty")
if handle[0] != u'!' or handle[-1] != u'!':
raise EmitterError("tag handle must start and end with '!': %r"
- % (handle.encode('utf-8')))
+ % (utf8(handle)))
for ch in handle[1:-1]:
- if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
- or ch in u'-_'):
+ if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or
+ u'a' <= ch <= u'z' or ch in u'-_'):
raise EmitterError("invalid character %r in the tag handle: %r"
- % (ch.encode('utf-8'), handle.encode('utf-8')))
+ % (utf8(ch), utf8(handle)))
return handle
def prepare_tag_prefix(self, prefix):
@@ -572,7 +658,7 @@ class Emitter(object):
if start < end:
chunks.append(prefix[start:end])
start = end = end+1
- data = ch.encode('utf-8')
+ data = utf8(ch)
for ch in data:
chunks.append(u'%%%02X' % ord(ch))
if start < end:
@@ -586,8 +672,7 @@ class Emitter(object):
return tag
handle = None
suffix = tag
- prefixes = self.tag_prefixes.keys()
- prefixes.sort()
+ prefixes = sorted(self.tag_prefixes.keys())
for prefix in prefixes:
if tag.startswith(prefix) \
and (prefix == u'!' or len(prefix) < len(tag)):
@@ -605,7 +690,7 @@ class Emitter(object):
if start < end:
chunks.append(suffix[start:end])
start = end = end+1
- data = ch.encode('utf-8')
+ data = utf8(ch)
for ch in data:
chunks.append(u'%%%02X' % ord(ch))
if start < end:
@@ -620,20 +705,21 @@ class Emitter(object):
if not anchor:
raise EmitterError("anchor must not be empty")
for ch in anchor:
- if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
- or ch in u'-_'):
+ if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or
+ u'a' <= ch <= u'z' or ch in u'-_'):
raise EmitterError("invalid character %r in the anchor: %r"
- % (ch.encode('utf-8'), anchor.encode('utf-8')))
+ % (utf8(ch), utf8(anchor)))
return anchor
def analyze_scalar(self, scalar):
# Empty scalar is a special case.
if not scalar:
- return ScalarAnalysis(scalar=scalar, empty=True, multiline=False,
- allow_flow_plain=False, allow_block_plain=True,
- allow_single_quoted=True, allow_double_quoted=True,
- allow_block=False)
+ return ScalarAnalysis(
+ scalar=scalar, empty=True, multiline=False,
+ allow_flow_plain=False, allow_block_plain=True,
+ allow_single_quoted=True, allow_double_quoted=True,
+ allow_block=False)
# Indicators and special characters.
block_indicators = False
@@ -659,7 +745,7 @@ class Emitter(object):
# Last character or followed by a whitespace.
followed_by_whitespace = (len(scalar) == 1 or
- scalar[1] in u'\0 \t\r\n\x85\u2028\u2029')
+ scalar[1] in u'\0 \t\r\n\x85\u2028\u2029')
# The previous character is a space.
previous_space = False
@@ -674,7 +760,7 @@ class Emitter(object):
# Check for indicators.
if index == 0:
# Leading indicators are special characters.
- if ch in u'#,[]{}&*!|>\'\"%@`':
+ if ch in u'#,[]{}&*!|>\'\"%@`':
flow_indicators = True
block_indicators = True
if ch in u'?:':
@@ -700,9 +786,9 @@ class Emitter(object):
if ch in u'\n\x85\u2028\u2029':
line_breaks = True
if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'):
- if (ch == u'\x85' or u'\xA0' <= ch <= u'\uD7FF'
- or u'\uE000' <= ch <= u'\uFFFD') and ch != u'\uFEFF':
- unicode_characters = True
+ if (ch == u'\x85' or u'\xA0' <= ch <= u'\uD7FF' or
+ u'\uE000' <= ch <= u'\uFFFD') and ch != u'\uFEFF':
+ # unicode_characters = True
if not self.allow_unicode:
special_characters = True
else:
@@ -734,8 +820,9 @@ class Emitter(object):
# Prepare for the next character.
index += 1
preceeded_by_whitespace = (ch in u'\0 \t\r\n\x85\u2028\u2029')
- followed_by_whitespace = (index+1 >= len(scalar) or
- scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029')
+ followed_by_whitespace = (
+ index+1 >= len(scalar) or
+ scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029')
# Let's decide what styles are allowed.
allow_flow_plain = True
@@ -745,8 +832,7 @@ class Emitter(object):
allow_block = True
# Leading and trailing whitespaces are bad for plain scalars.
- if (leading_space or leading_break
- or trailing_space or trailing_break):
+ if (leading_space or leading_break or trailing_space or trailing_break):
allow_flow_plain = allow_block_plain = False
# We do not permit trailing spaces for block scalars.
@@ -761,8 +847,8 @@ class Emitter(object):
# Spaces followed by breaks, as well as special character are only
# allowed for double quoted scalars.
if space_break or special_characters:
- allow_flow_plain = allow_block_plain = \
- allow_single_quoted = allow_block = False
+ allow_flow_plain = allow_block_plain = \
+ allow_single_quoted = allow_block = False
# Although the plain scalar writer supports breaks, we never emit
# multiline plain scalars.
@@ -778,12 +864,12 @@ class Emitter(object):
allow_block_plain = False
return ScalarAnalysis(scalar=scalar,
- empty=False, multiline=line_breaks,
- allow_flow_plain=allow_flow_plain,
- allow_block_plain=allow_block_plain,
- allow_single_quoted=allow_single_quoted,
- allow_double_quoted=allow_double_quoted,
- allow_block=allow_block)
+ empty=False, multiline=line_breaks,
+ allow_flow_plain=allow_flow_plain,
+ allow_block_plain=allow_block_plain,
+ allow_single_quoted=allow_single_quoted,
+ allow_double_quoted=allow_double_quoted,
+ allow_block=allow_block)
# Writers.
@@ -800,7 +886,7 @@ class Emitter(object):
self.flush_stream()
def write_indicator(self, indicator, need_whitespace,
- whitespace=False, indention=False):
+ whitespace=False, indention=False):
if self.whitespace or not need_whitespace:
data = indicator
else:
@@ -817,7 +903,10 @@ class Emitter(object):
indent = self.indent or 0
if not self.indention or self.column > indent \
or (self.column == indent and not self.whitespace):
- self.write_line_break()
+ if self.no_newline:
+ self.no_newline = False
+ else:
+ self.write_line_break()
if self.column < indent:
self.whitespace = True
data = u' '*(indent-self.column)
@@ -933,10 +1022,9 @@ class Emitter(object):
if end < len(text):
ch = text[end]
if ch is None or ch in u'"\\\x85\u2028\u2029\uFEFF' \
- or not (u'\x20' <= ch <= u'\x7E'
- or (self.allow_unicode
- and (u'\xA0' <= ch <= u'\uD7FF'
- or u'\uE000' <= ch <= u'\uFFFD'))):
+ or not (u'\x20' <= ch <= u'\x7E' or
+ (self.allow_unicode and
+ (u'\xA0' <= ch <= u'\uD7FF' or u'\uE000' <= ch <= u'\uFFFD'))):
if start < end:
data = text[start:end]
self.column += len(data)
@@ -983,7 +1071,7 @@ class Emitter(object):
hints = u''
if text:
if text[0] in u' \n\x85\u2028\u2029':
- hints += unicode(self.best_indent)
+ hints += text_type(self.best_indent)
if text[-1] not in u'\n\x85\u2028\u2029':
hints += u'-'
elif len(text) == 1 or text[-2] in u'\n\x85\u2028\u2029':
@@ -1101,7 +1189,8 @@ class Emitter(object):
ch = text[end]
if spaces:
if ch != u' ':
- if start+1 == end and self.column > self.best_width and split:
+ if start+1 == end and self.column > self.best_width \
+ and split:
self.write_indent()
self.whitespace = False
self.indention = False
@@ -1138,3 +1227,56 @@ class Emitter(object):
breaks = (ch in u'\n\x85\u2028\u2029')
end += 1
+ def write_comment(self, comment):
+ value = comment.value
+ # print('{:02d} {:02d} {}'.format(self.column, comment.start_mark.column, value))
+ if value[-1] == '\n':
+ value = value[:-1]
+ try:
+ # get original column position
+ col = comment.start_mark.column
+ if col < self.column + 1:
+ ValueError
+ except ValueError:
+ col = self.column + 1
+ # print('post_comment', self.line, self.column, value)
+ try:
+ # at least one space if the current column >= the start column of the comment
+ # but not at the start of a line
+ nr_spaces = col - self.column
+ if self.column and value.strip() and nr_spaces < 1:
+ nr_spaces = 1
+ value = ' ' * nr_spaces + value
+ try:
+ if self.encoding:
+ value = value.encode(self.encoding)
+ except UnicodeDecodeError:
+ pass
+ self.stream.write(value)
+ except TypeError:
+ raise
+ self.write_line_break()
+
+ def write_pre_comment(self, event):
+ comments = event.comment[1]
+ if comments is None:
+ return
+ try:
+ for comment in comments:
+ if isinstance(event, MappingStartEvent) and \
+ getattr(comment, 'pre_done', None):
+ continue
+ if self.column != 0:
+ self.write_line_break()
+ self.write_comment(comment)
+ if isinstance(event, MappingStartEvent):
+ comment.pre_done = True
+ except TypeError:
+ print ('eventtt', type(event), event)
+ raise
+
+ def write_post_comment(self, event):
+ if self.event.comment[0] is None:
+ return
+ comment = event.comment[0]
+ self.write_comment(comment)
diff --git a/lib/spack/external/yaml/lib/yaml/error.py b/lib/spack/external/ruamel/yaml/error.py
index 577686db5f..1ec77e60ec 100644
--- a/lib/spack/external/yaml/lib/yaml/error.py
+++ b/lib/spack/external/ruamel/yaml/error.py
@@ -1,8 +1,16 @@
+# coding: utf-8
+
+from __future__ import absolute_import
__all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
-class Mark(object):
+try:
+ from .compat import utf8
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.compat import utf8
+
+class Mark(object):
def __init__(self, name, index, line, column, buffer, pointer):
self.name = name
self.index = index
@@ -16,7 +24,8 @@ class Mark(object):
return None
head = ''
start = self.pointer
- while start > 0 and self.buffer[start-1] not in u'\0\r\n\x85\u2028\u2029':
+ while (start > 0 and
+ self.buffer[start-1] not in u'\0\r\n\x85\u2028\u2029'):
start -= 1
if self.pointer-start > max_length/2-1:
head = ' ... '
@@ -24,15 +33,16 @@ class Mark(object):
break
tail = ''
end = self.pointer
- while end < len(self.buffer) and self.buffer[end] not in u'\0\r\n\x85\u2028\u2029':
+ while (end < len(self.buffer) and
+ self.buffer[end] not in u'\0\r\n\x85\u2028\u2029'):
end += 1
if end-self.pointer > max_length/2-1:
tail = ' ... '
end -= 5
break
- snippet = self.buffer[start:end].encode('utf-8')
- return ' '*indent + head + snippet + tail + '\n' \
- + ' '*(indent+self.pointer-start+len(head)) + '^'
+ snippet = utf8(self.buffer[start:end])
+ return ' '*indent + head + snippet + tail + '\n' \
+ + ' '*(indent+self.pointer-start+len(head)) + '^'
def __str__(self):
snippet = self.get_snippet()
@@ -42,13 +52,14 @@ class Mark(object):
where += ":\n"+snippet
return where
+
class YAMLError(Exception):
pass
-class MarkedYAMLError(YAMLError):
+class MarkedYAMLError(YAMLError):
def __init__(self, context=None, context_mark=None,
- problem=None, problem_mark=None, note=None):
+ problem=None, problem_mark=None, note=None):
self.context = context
self.context_mark = context_mark
self.problem = problem
@@ -60,10 +71,10 @@ class MarkedYAMLError(YAMLError):
if self.context is not None:
lines.append(self.context)
if self.context_mark is not None \
- and (self.problem is None or self.problem_mark is None
- or self.context_mark.name != self.problem_mark.name
- or self.context_mark.line != self.problem_mark.line
- or self.context_mark.column != self.problem_mark.column):
+ and (self.problem is None or self.problem_mark is None or
+ self.context_mark.name != self.problem_mark.name or
+ self.context_mark.line != self.problem_mark.line or
+ self.context_mark.column != self.problem_mark.column):
lines.append(str(self.context_mark))
if self.problem is not None:
lines.append(self.problem)
@@ -72,4 +83,3 @@ class MarkedYAMLError(YAMLError):
if self.note is not None:
lines.append(self.note)
return '\n'.join(lines)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/events.py b/lib/spack/external/ruamel/yaml/events.py
index f79ad389cb..7667c016be 100644
--- a/lib/spack/external/yaml/lib3/yaml/events.py
+++ b/lib/spack/external/ruamel/yaml/events.py
@@ -1,86 +1,106 @@
+# coding: utf-8
# Abstract classes.
+
+def CommentCheck():
+ pass
+
+
class Event(object):
- def __init__(self, start_mark=None, end_mark=None):
+ def __init__(self, start_mark=None, end_mark=None, comment=CommentCheck):
self.start_mark = start_mark
self.end_mark = end_mark
+ # assert comment is not CommentCheck
+ if comment is CommentCheck:
+ comment = None
+ self.comment = comment
+
def __repr__(self):
- attributes = [key for key in ['anchor', 'tag', 'implicit', 'value']
- if hasattr(self, key)]
+ attributes = [key for key in ['anchor', 'tag', 'implicit', 'value',
+ 'flow_style', 'style']
+ if hasattr(self, key)]
arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
- for key in attributes])
+ for key in attributes])
+ if self.comment not in [None, CommentCheck]:
+ arguments += ', comment={!r}'.format(self.comment)
return '%s(%s)' % (self.__class__.__name__, arguments)
+
class NodeEvent(Event):
- def __init__(self, anchor, start_mark=None, end_mark=None):
+ def __init__(self, anchor, start_mark=None, end_mark=None, comment=None):
+ Event.__init__(self, start_mark, end_mark, comment)
self.anchor = anchor
- self.start_mark = start_mark
- self.end_mark = end_mark
+
class CollectionStartEvent(NodeEvent):
def __init__(self, anchor, tag, implicit, start_mark=None, end_mark=None,
- flow_style=None):
+ flow_style=None, comment=None):
+ Event.__init__(self, start_mark, end_mark, comment)
self.anchor = anchor
self.tag = tag
self.implicit = implicit
- self.start_mark = start_mark
- self.end_mark = end_mark
self.flow_style = flow_style
+
class CollectionEndEvent(Event):
pass
# Implementations.
+
class StreamStartEvent(Event):
- def __init__(self, start_mark=None, end_mark=None, encoding=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
+ def __init__(self, start_mark=None, end_mark=None, encoding=None,
+ comment=None):
+ Event.__init__(self, start_mark, end_mark, comment)
self.encoding = encoding
+
class StreamEndEvent(Event):
pass
+
class DocumentStartEvent(Event):
def __init__(self, start_mark=None, end_mark=None,
- explicit=None, version=None, tags=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
+ explicit=None, version=None, tags=None, comment=None):
+ Event.__init__(self, start_mark, end_mark, comment)
self.explicit = explicit
self.version = version
self.tags = tags
+
class DocumentEndEvent(Event):
def __init__(self, start_mark=None, end_mark=None,
- explicit=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
+ explicit=None, comment=None):
+ Event.__init__(self, start_mark, end_mark, comment)
self.explicit = explicit
+
class AliasEvent(NodeEvent):
pass
+
class ScalarEvent(NodeEvent):
def __init__(self, anchor, tag, implicit, value,
- start_mark=None, end_mark=None, style=None):
- self.anchor = anchor
+ start_mark=None, end_mark=None, style=None, comment=None):
+ NodeEvent.__init__(self, anchor, start_mark, end_mark, comment)
self.tag = tag
self.implicit = implicit
self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
self.style = style
+
class SequenceStartEvent(CollectionStartEvent):
pass
+
class SequenceEndEvent(CollectionEndEvent):
pass
+
class MappingStartEvent(CollectionStartEvent):
pass
+
class MappingEndEvent(CollectionEndEvent):
pass
-
diff --git a/lib/spack/external/ruamel/yaml/loader.py b/lib/spack/external/ruamel/yaml/loader.py
new file mode 100644
index 0000000000..b5ba20a0a1
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/loader.py
@@ -0,0 +1,61 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+
+__all__ = ['BaseLoader', 'SafeLoader', 'Loader', 'RoundTripLoader']
+
+try:
+ from .reader import * # NOQA
+ from .scanner import * # NOQA
+ from .parser import * # NOQA
+ from .composer import * # NOQA
+ from .constructor import * # NOQA
+ from .resolver import * # NOQA
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.reader import * # NOQA
+ from ruamel.yaml.scanner import * # NOQA
+ from ruamel.yaml.parser import * # NOQA
+ from ruamel.yaml.composer import * # NOQA
+ from ruamel.yaml.constructor import * # NOQA
+ from ruamel.yaml.resolver import * # NOQA
+
+
+class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, BaseResolver):
+ def __init__(self, stream, version=None, preserve_quotes=None):
+ Reader.__init__(self, stream)
+ Scanner.__init__(self)
+ Parser.__init__(self)
+ Composer.__init__(self)
+ BaseConstructor.__init__(self)
+ BaseResolver.__init__(self)
+
+
+class SafeLoader(Reader, Scanner, Parser, Composer, SafeConstructor, Resolver):
+ def __init__(self, stream, version=None, preserve_quotes=None):
+ Reader.__init__(self, stream)
+ Scanner.__init__(self)
+ Parser.__init__(self)
+ Composer.__init__(self)
+ SafeConstructor.__init__(self)
+ Resolver.__init__(self)
+
+
+class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
+ def __init__(self, stream, version=None, preserve_quotes=None):
+ Reader.__init__(self, stream)
+ Scanner.__init__(self)
+ Parser.__init__(self)
+ Composer.__init__(self)
+ Constructor.__init__(self)
+ Resolver.__init__(self)
+
+
+class RoundTripLoader(Reader, RoundTripScanner, RoundTripParser, Composer,
+ RoundTripConstructor, VersionedResolver):
+ def __init__(self, stream, version=None, preserve_quotes=None):
+ Reader.__init__(self, stream)
+ RoundTripScanner.__init__(self)
+ RoundTripParser.__init__(self)
+ Composer.__init__(self)
+ RoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes)
+ VersionedResolver.__init__(self, version)
diff --git a/lib/spack/external/yaml/lib3/yaml/__init__.py b/lib/spack/external/ruamel/yaml/main.py
index d7d27fe63b..797bdcde65 100644
--- a/lib/spack/external/yaml/lib3/yaml/__init__.py
+++ b/lib/spack/external/ruamel/yaml/main.py
@@ -1,21 +1,20 @@
+# coding: utf-8
-from .error import *
+from __future__ import absolute_import
-from .tokens import *
-from .events import *
-from .nodes import *
-from .loader import *
-from .dumper import *
+from ruamel.yaml.error import * # NOQA
-__version__ = '3.12'
-try:
- from .cyaml import *
- __with_libyaml__ = True
-except ImportError:
- __with_libyaml__ = False
+from ruamel.yaml.tokens import * # NOQA
+from ruamel.yaml.events import * # NOQA
+from ruamel.yaml.nodes import * # NOQA
+
+from ruamel.yaml.loader import * # NOQA
+from ruamel.yaml.dumper import * # NOQA
+from ruamel.yaml.compat import StringIO, BytesIO, with_metaclass, PY3
+
+# import io
-import io
def scan(stream, Loader=Loader):
"""
@@ -28,6 +27,7 @@ def scan(stream, Loader=Loader):
finally:
loader.dispose()
+
def parse(stream, Loader=Loader):
"""
Parse a YAML stream and produce parsing events.
@@ -39,6 +39,7 @@ def parse(stream, Loader=Loader):
finally:
loader.dispose()
+
def compose(stream, Loader=Loader):
"""
Parse the first YAML document in a stream
@@ -50,6 +51,7 @@ def compose(stream, Loader=Loader):
finally:
loader.dispose()
+
def compose_all(stream, Loader=Loader):
"""
Parse all YAML documents in a stream
@@ -62,58 +64,81 @@ def compose_all(stream, Loader=Loader):
finally:
loader.dispose()
-def load(stream, Loader=Loader):
+
+def load(stream, Loader=Loader, version=None, preserve_quotes=None):
"""
Parse the first YAML document in a stream
and produce the corresponding Python object.
"""
- loader = Loader(stream)
+ loader = Loader(stream, version, preserve_quotes=preserve_quotes)
try:
return loader.get_single_data()
finally:
loader.dispose()
-def load_all(stream, Loader=Loader):
+
+def load_all(stream, Loader=Loader, version=None):
"""
Parse all YAML documents in a stream
and produce corresponding Python objects.
"""
- loader = Loader(stream)
+ loader = Loader(stream, version)
try:
while loader.check_data():
yield loader.get_data()
finally:
loader.dispose()
-def safe_load(stream):
+
+def safe_load(stream, version=None):
"""
Parse the first YAML document in a stream
and produce the corresponding Python object.
Resolve only basic YAML tags.
"""
- return load(stream, SafeLoader)
+ return load(stream, SafeLoader, version)
+
-def safe_load_all(stream):
+def safe_load_all(stream, version=None):
"""
Parse all YAML documents in a stream
and produce corresponding Python objects.
Resolve only basic YAML tags.
"""
- return load_all(stream, SafeLoader)
+ return load_all(stream, SafeLoader, version)
+
+
+def round_trip_load(stream, version=None, preserve_quotes=None):
+ """
+ Parse the first YAML document in a stream
+ and produce the corresponding Python object.
+ Resolve only basic YAML tags.
+ """
+ return load(stream, RoundTripLoader, version, preserve_quotes=preserve_quotes)
+
+
+def round_trip_load_all(stream, version=None, preserve_quotes=None):
+ """
+ Parse all YAML documents in a stream
+ and produce corresponding Python objects.
+ Resolve only basic YAML tags.
+ """
+ return load_all(stream, RoundTripLoader, version, preserve_quotes=preserve_quotes)
+
def emit(events, stream=None, Dumper=Dumper,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None):
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None):
"""
Emit YAML parsing events into a stream.
If stream is None, return the produced string instead.
"""
getvalue = None
if stream is None:
- stream = io.StringIO()
+ stream = StringIO()
getvalue = stream.getvalue
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
+ allow_unicode=allow_unicode, line_break=line_break)
try:
for event in events:
dumper.emit(event)
@@ -122,11 +147,14 @@ def emit(events, stream=None, Dumper=Dumper,
if getvalue:
return getvalue()
+enc = None if PY3 else 'utf-8'
+
+
def serialize_all(nodes, stream=None, Dumper=Dumper,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=enc, explicit_start=None, explicit_end=None,
+ version=None, tags=None):
"""
Serialize a sequence of representation trees into a YAML stream.
If stream is None, return the produced string instead.
@@ -134,14 +162,14 @@ def serialize_all(nodes, stream=None, Dumper=Dumper,
getvalue = None
if stream is None:
if encoding is None:
- stream = io.StringIO()
+ stream = StringIO()
else:
- stream = io.BytesIO()
+ stream = BytesIO()
getvalue = stream.getvalue
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break,
- encoding=encoding, version=version, tags=tags,
- explicit_start=explicit_start, explicit_end=explicit_end)
+ allow_unicode=allow_unicode, line_break=line_break,
+ encoding=encoding, version=version, tags=tags,
+ explicit_start=explicit_start, explicit_end=explicit_end)
try:
dumper.open()
for node in nodes:
@@ -152,6 +180,7 @@ def serialize_all(nodes, stream=None, Dumper=Dumper,
if getvalue:
return getvalue()
+
def serialize(node, stream=None, Dumper=Dumper, **kwds):
"""
Serialize a representation tree into a YAML stream.
@@ -159,29 +188,36 @@ def serialize(node, stream=None, Dumper=Dumper, **kwds):
"""
return serialize_all([node], stream, Dumper=Dumper, **kwds)
+
def dump_all(documents, stream=None, Dumper=Dumper,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=enc, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
"""
Serialize a sequence of Python objects into a YAML stream.
If stream is None, return the produced string instead.
"""
getvalue = None
+ if top_level_colon_align is True:
+ top_level_colon_align = max([len(str(x)) for x in documents[0]])
if stream is None:
if encoding is None:
- stream = io.StringIO()
+ stream = StringIO()
else:
- stream = io.BytesIO()
+ stream = BytesIO()
getvalue = stream.getvalue
dumper = Dumper(stream, default_style=default_style,
- default_flow_style=default_flow_style,
- canonical=canonical, indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break,
- encoding=encoding, version=version, tags=tags,
- explicit_start=explicit_start, explicit_end=explicit_end)
+ default_flow_style=default_flow_style,
+ canonical=canonical, indent=indent, width=width,
+ allow_unicode=allow_unicode, line_break=line_break,
+ encoding=encoding, explicit_start=explicit_start,
+ explicit_end=explicit_end, version=version,
+ tags=tags, block_seq_indent=block_seq_indent,
+ top_level_colon_align=top_level_colon_align, prefix_colon=prefix_colon,
+ )
try:
dumper.open()
for data in documents:
@@ -192,12 +228,31 @@ def dump_all(documents, stream=None, Dumper=Dumper,
if getvalue:
return getvalue()
-def dump(data, stream=None, Dumper=Dumper, **kwds):
+
+def dump(data, stream=None, Dumper=Dumper,
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=enc, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None):
"""
Serialize a Python object into a YAML stream.
If stream is None, return the produced string instead.
+
+ default_style ∈ None, '', '"', "'", '|', '>'
+
"""
- return dump_all([data], stream, Dumper=Dumper, **kwds)
+ return dump_all([data], stream, Dumper=Dumper,
+ default_style=default_style,
+ default_flow_style=default_flow_style,
+ canonical=canonical,
+ indent=indent, width=width,
+ allow_unicode=allow_unicode,
+ line_break=line_break,
+ encoding=encoding, explicit_start=explicit_start,
+ explicit_end=explicit_end,
+ version=version, tags=tags, block_seq_indent=block_seq_indent)
+
def safe_dump_all(documents, stream=None, **kwds):
"""
@@ -207,6 +262,7 @@ def safe_dump_all(documents, stream=None, **kwds):
"""
return dump_all(documents, stream, Dumper=SafeDumper, **kwds)
+
def safe_dump(data, stream=None, **kwds):
"""
Serialize a Python object into a YAML stream.
@@ -215,8 +271,30 @@ def safe_dump(data, stream=None, **kwds):
"""
return dump_all([data], stream, Dumper=SafeDumper, **kwds)
+
+def round_trip_dump(data, stream=None, Dumper=RoundTripDumper,
+ default_style=None, default_flow_style=None,
+ canonical=None, indent=None, width=None,
+ allow_unicode=None, line_break=None,
+ encoding=enc, explicit_start=None, explicit_end=None,
+ version=None, tags=None, block_seq_indent=None,
+ top_level_colon_align=None, prefix_colon=None):
+ allow_unicode = True if allow_unicode is None else allow_unicode
+ return dump_all([data], stream, Dumper=Dumper,
+ default_style=default_style,
+ default_flow_style=default_flow_style,
+ canonical=canonical,
+ indent=indent, width=width,
+ allow_unicode=allow_unicode,
+ line_break=line_break,
+ encoding=encoding, explicit_start=explicit_start,
+ explicit_end=explicit_end,
+ version=version, tags=tags, block_seq_indent=block_seq_indent,
+ top_level_colon_align=top_level_colon_align, prefix_colon=prefix_colon)
+
+
def add_implicit_resolver(tag, regexp, first=None,
- Loader=Loader, Dumper=Dumper):
+ Loader=Loader, Dumper=Dumper):
"""
Add an implicit scalar detector.
If an implicit scalar value matches the given regexp,
@@ -226,6 +304,7 @@ def add_implicit_resolver(tag, regexp, first=None,
Loader.add_implicit_resolver(tag, regexp, first)
Dumper.add_implicit_resolver(tag, regexp, first)
+
def add_path_resolver(tag, path, kind=None, Loader=Loader, Dumper=Dumper):
"""
Add a path based resolver for the given tag.
@@ -236,6 +315,7 @@ def add_path_resolver(tag, path, kind=None, Loader=Loader, Dumper=Dumper):
Loader.add_path_resolver(tag, path, kind)
Dumper.add_path_resolver(tag, path, kind)
+
def add_constructor(tag, constructor, Loader=Loader):
"""
Add a constructor for the given tag.
@@ -244,6 +324,7 @@ def add_constructor(tag, constructor, Loader=Loader):
"""
Loader.add_constructor(tag, constructor)
+
def add_multi_constructor(tag_prefix, multi_constructor, Loader=Loader):
"""
Add a multi-constructor for the given tag prefix.
@@ -253,6 +334,7 @@ def add_multi_constructor(tag_prefix, multi_constructor, Loader=Loader):
"""
Loader.add_multi_constructor(tag_prefix, multi_constructor)
+
def add_representer(data_type, representer, Dumper=Dumper):
"""
Add a representer for the given type.
@@ -262,6 +344,7 @@ def add_representer(data_type, representer, Dumper=Dumper):
"""
Dumper.add_representer(data_type, representer)
+
def add_multi_representer(data_type, multi_representer, Dumper=Dumper):
"""
Add a representer for the given type.
@@ -271,6 +354,7 @@ def add_multi_representer(data_type, multi_representer, Dumper=Dumper):
"""
Dumper.add_multi_representer(data_type, multi_representer)
+
class YAMLObjectMetaclass(type):
"""
The metaclass for YAMLObject.
@@ -281,12 +365,12 @@ class YAMLObjectMetaclass(type):
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
cls.yaml_dumper.add_representer(cls, cls.to_yaml)
-class YAMLObject(metaclass=YAMLObjectMetaclass):
+
+class YAMLObject(with_metaclass(YAMLObjectMetaclass)):
"""
An object that can dump itself to a YAML stream
and load itself from a YAML stream.
"""
-
__slots__ = () # no direct instantiation, so allow immutable subclasses
yaml_loader = Loader
@@ -308,5 +392,4 @@ class YAMLObject(metaclass=YAMLObjectMetaclass):
Convert a Python object to a representation node.
"""
return dumper.represent_yaml_object(cls.yaml_tag, data, cls,
- flow_style=cls.yaml_flow_style)
-
+ flow_style=cls.yaml_flow_style)
diff --git a/lib/spack/external/ruamel/yaml/nodes.py b/lib/spack/external/ruamel/yaml/nodes.py
new file mode 100644
index 0000000000..26c6d77ae6
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/nodes.py
@@ -0,0 +1,86 @@
+# coding: utf-8
+
+from __future__ import print_function
+
+
+class Node(object):
+ def __init__(self, tag, value, start_mark, end_mark, comment=None):
+ self.tag = tag
+ self.value = value
+ self.start_mark = start_mark
+ self.end_mark = end_mark
+ self.comment = comment
+ self.anchor = None
+
+ def __repr__(self):
+ value = self.value
+ # if isinstance(value, list):
+ # if len(value) == 0:
+ # value = '<empty>'
+ # elif len(value) == 1:
+ # value = '<1 item>'
+ # else:
+ # value = '<%d items>' % len(value)
+ # else:
+ # if len(value) > 75:
+ # value = repr(value[:70]+u' ... ')
+ # else:
+ # value = repr(value)
+ value = repr(value)
+ return '%s(tag=%r, value=%s)' % (self.__class__.__name__,
+ self.tag, value)
+
+ def dump(self, indent=0):
+ if isinstance(self.value, basestring):
+ print('{0}{1}(tag={!r}, value={!r})'.format(
+ ' ' * indent, self.__class__.__name__, self.tag, self.value))
+ if self.comment:
+ print(' {0}comment: {1})'.format(
+ ' ' * indent, self.comment))
+ return
+ print('{0}{1}(tag={!r})'.format(
+ ' ' * indent, self.__class__.__name__, self.tag))
+ if self.comment:
+ print(' {0}comment: {1})'.format(
+ ' ' * indent, self.comment))
+ for v in self.value:
+ if isinstance(v, tuple):
+ for v1 in v:
+ v1.dump(indent+1)
+ elif isinstance(v, Node):
+ v.dump(indent+1)
+ else:
+ print('Node value type?', type(v))
+
+
+class ScalarNode(Node):
+ """
+ styles:
+ ? -> set() ? key, no value
+ " -> double quoted
+ ' -> single quoted
+ | -> literal style
+ > ->
+ """
+ id = 'scalar'
+
+ def __init__(self, tag, value, start_mark=None, end_mark=None, style=None,
+ comment=None):
+ Node.__init__(self, tag, value, start_mark, end_mark, comment=comment)
+ self.style = style
+
+
+class CollectionNode(Node):
+ def __init__(self, tag, value, start_mark=None, end_mark=None,
+ flow_style=None, comment=None, anchor=None):
+ Node.__init__(self, tag, value, start_mark, end_mark, comment=comment)
+ self.flow_style = flow_style
+ self.anchor = anchor
+
+
+class SequenceNode(CollectionNode):
+ id = 'sequence'
+
+
+class MappingNode(CollectionNode):
+ id = 'mapping'
diff --git a/lib/spack/external/yaml/lib/yaml/parser.py b/lib/spack/external/ruamel/yaml/parser.py
index f9e3057f33..543cca9b43 100644
--- a/lib/spack/external/yaml/lib/yaml/parser.py
+++ b/lib/spack/external/ruamel/yaml/parser.py
@@ -1,13 +1,18 @@
+# coding: utf-8
+
+from __future__ import absolute_import
# The following YAML grammar is LL(1) and is parsed by a recursive descent
# parser.
#
-# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+# stream ::= STREAM-START implicit_document? explicit_document*
+# STREAM-END
# implicit_document ::= block_node DOCUMENT-END*
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
# block_node_or_indentless_sequence ::=
# ALIAS
-# | properties (block_content | indentless_block_sequence)?
+# | properties (block_content |
+# indentless_block_sequence)?
# | block_content
# | indentless_block_sequence
# block_node ::= ALIAS
@@ -21,7 +26,8 @@
# flow_content ::= flow_collection | SCALAR
# block_collection ::= block_sequence | block_mapping
# flow_collection ::= flow_sequence | flow_mapping
-# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
+# BLOCK-END
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
# block_mapping ::= BLOCK-MAPPING_START
# ((KEY block_node_or_indentless_sequence?)?
@@ -43,32 +49,44 @@
# stream: { STREAM-START }
# explicit_document: { DIRECTIVE DOCUMENT-START }
# implicit_document: FIRST(block_node)
-# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
+# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START
+# BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
-# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
+# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START
+# FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
# block_sequence: { BLOCK-SEQUENCE-START }
# block_mapping: { BLOCK-MAPPING-START }
-# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
+# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR
+# BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START
+# FLOW-MAPPING-START BLOCK-ENTRY }
# indentless_sequence: { ENTRY }
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
# flow_sequence: { FLOW-SEQUENCE-START }
# flow_mapping: { FLOW-MAPPING-START }
-# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
-# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
+# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START
+# FLOW-MAPPING-START KEY }
+# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START
+# FLOW-MAPPING-START KEY }
+
+__all__ = ['Parser', 'RoundTripParser', 'ParserError']
-__all__ = ['Parser', 'ParserError']
+# need to have full path, as pkg_resources tries to load parser.py in __init__.py
+# only to not do anything with the package afterwards
+# and for Jython too
+from ruamel.yaml.error import MarkedYAMLError # NOQA
+from ruamel.yaml.tokens import * # NOQA
+from ruamel.yaml.events import * # NOQA
+from ruamel.yaml.scanner import * # NOQA
+from ruamel.yaml.compat import utf8 # NOQA
-from error import MarkedYAMLError
-from tokens import *
-from events import *
-from scanner import *
class ParserError(MarkedYAMLError):
pass
+
class Parser(object):
# Since writing a recursive-descendant parser is a straightforward task, we
# do not give many comments here.
@@ -120,7 +138,8 @@ class Parser(object):
self.current_event = None
return value
- # stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+ # stream ::= STREAM-START implicit_document? explicit_document*
+ # STREAM-END
# implicit_document ::= block_node DOCUMENT-END*
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
@@ -128,8 +147,9 @@ class Parser(object):
# Parse the stream start.
token = self.get_token()
+ token.move_comment(self.peek_token())
event = StreamStartEvent(token.start_mark, token.end_mark,
- encoding=token.encoding)
+ encoding=token.encoding)
# Prepare the next state.
self.state = self.parse_implicit_document_start
@@ -140,12 +160,12 @@ class Parser(object):
# Parse an implicit document.
if not self.check_token(DirectiveToken, DocumentStartToken,
- StreamEndToken):
+ StreamEndToken):
self.tag_handles = self.DEFAULT_TAGS
token = self.peek_token()
start_mark = end_mark = token.start_mark
event = DocumentStartEvent(start_mark, end_mark,
- explicit=False)
+ explicit=False)
# Prepare the next state.
self.states.append(self.parse_document_end)
@@ -169,19 +189,21 @@ class Parser(object):
version, tags = self.process_directives()
if not self.check_token(DocumentStartToken):
raise ParserError(None, None,
- "expected '<document start>', but found %r"
- % self.peek_token().id,
- self.peek_token().start_mark)
+ "expected '<document start>', but found %r"
+ % self.peek_token().id,
+ self.peek_token().start_mark)
token = self.get_token()
end_mark = token.end_mark
- event = DocumentStartEvent(start_mark, end_mark,
- explicit=True, version=version, tags=tags)
+ event = DocumentStartEvent(
+ start_mark, end_mark,
+ explicit=True, version=version, tags=tags)
self.states.append(self.parse_document_end)
self.state = self.parse_document_content
else:
# Parse the end of the stream.
token = self.get_token()
- event = StreamEndEvent(token.start_mark, token.end_mark)
+ event = StreamEndEvent(token.start_mark, token.end_mark,
+ comment=token.comment)
assert not self.states
assert not self.marks
self.state = None
@@ -197,8 +219,7 @@ class Parser(object):
token = self.get_token()
end_mark = token.end_mark
explicit = True
- event = DocumentEndEvent(start_mark, end_mark,
- explicit=explicit)
+ event = DocumentEndEvent(start_mark, end_mark, explicit=explicit)
# Prepare the next state.
self.state = self.parse_document_start
@@ -206,8 +227,9 @@ class Parser(object):
return event
def parse_document_content(self):
- if self.check_token(DirectiveToken,
- DocumentStartToken, DocumentEndToken, StreamEndToken):
+ if self.check_token(
+ DirectiveToken,
+ DocumentStartToken, DocumentEndToken, StreamEndToken):
event = self.process_empty_scalar(self.peek_token().start_mark)
self.state = self.states.pop()
return event
@@ -221,20 +243,23 @@ class Parser(object):
token = self.get_token()
if token.name == u'YAML':
if self.yaml_version is not None:
- raise ParserError(None, None,
- "found duplicate YAML directive", token.start_mark)
+ raise ParserError(
+ None, None,
+ "found duplicate YAML directive", token.start_mark)
major, minor = token.value
if major != 1:
- raise ParserError(None, None,
- "found incompatible YAML document (version 1.* is required)",
- token.start_mark)
+ raise ParserError(
+ None, None,
+ "found incompatible YAML document (version 1.* is "
+ "required)",
+ token.start_mark)
self.yaml_version = token.value
elif token.name == u'TAG':
handle, prefix = token.value
if handle in self.tag_handles:
raise ParserError(None, None,
- "duplicate tag handle %r" % handle.encode('utf-8'),
- token.start_mark)
+ "duplicate tag handle %r" % utf8(handle),
+ token.start_mark)
self.tag_handles[handle] = prefix
if self.tag_handles:
value = self.yaml_version, self.tag_handles.copy()
@@ -270,6 +295,9 @@ class Parser(object):
def parse_block_node_or_indentless_sequence(self):
return self.parse_node(block=True, indentless_sequence=True)
+ def transform_tag(self, handle, suffix):
+ return self.tag_handles[handle] + suffix
+
def parse_node(self, block=False, indentless_sequence=False):
if self.check_token(AliasToken):
token = self.get_token()
@@ -302,16 +330,18 @@ class Parser(object):
handle, suffix = tag
if handle is not None:
if handle not in self.tag_handles:
- raise ParserError("while parsing a node", start_mark,
- "found undefined tag handle %r" % handle.encode('utf-8'),
- tag_mark)
- tag = self.tag_handles[handle]+suffix
+ raise ParserError(
+ "while parsing a node", start_mark,
+ "found undefined tag handle %r" % utf8(handle),
+ tag_mark)
+ tag = self.transform_tag(handle, suffix)
else:
tag = suffix
- #if tag == u'!':
- # raise ParserError("while parsing a node", start_mark,
- # "found non-specific tag '!'", tag_mark,
- # "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.")
+ # if tag == u'!':
+ # raise ParserError("while parsing a node", start_mark,
+ # "found non-specific tag '!'", tag_mark,
+ # "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag'
+ # and share your opinion.")
if start_mark is None:
start_mark = end_mark = self.peek_token().start_mark
event = None
@@ -319,7 +349,7 @@ class Parser(object):
if indentless_sequence and self.check_token(BlockEntryToken):
end_mark = self.peek_token().end_mark
event = SequenceStartEvent(anchor, tag, implicit,
- start_mark, end_mark)
+ start_mark, end_mark)
self.state = self.parse_indentless_sequence_entry
else:
if self.check_token(ScalarToken):
@@ -331,34 +361,52 @@ class Parser(object):
implicit = (False, True)
else:
implicit = (False, False)
- event = ScalarEvent(anchor, tag, implicit, token.value,
- start_mark, end_mark, style=token.style)
+ event = ScalarEvent(
+ anchor, tag, implicit, token.value,
+ start_mark, end_mark, style=token.style,
+ comment=token.comment
+ )
self.state = self.states.pop()
elif self.check_token(FlowSequenceStartToken):
end_mark = self.peek_token().end_mark
- event = SequenceStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=True)
+ event = SequenceStartEvent(
+ anchor, tag, implicit,
+ start_mark, end_mark, flow_style=True)
self.state = self.parse_flow_sequence_first_entry
elif self.check_token(FlowMappingStartToken):
end_mark = self.peek_token().end_mark
- event = MappingStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=True)
+ event = MappingStartEvent(
+ anchor, tag, implicit,
+ start_mark, end_mark, flow_style=True)
self.state = self.parse_flow_mapping_first_key
elif block and self.check_token(BlockSequenceStartToken):
end_mark = self.peek_token().start_mark
- event = SequenceStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=False)
+ # should inserting the comment be dependent on the
+ # indentation?
+ pt = self.peek_token()
+ comment = pt.comment
+ # print('pt0', type(pt))
+ if comment is None or comment[1] is None:
+ comment = pt.split_comment()
+ # print('pt1', comment)
+ event = SequenceStartEvent(
+ anchor, tag, implicit, start_mark, end_mark,
+ flow_style=False,
+ comment=comment,
+ )
self.state = self.parse_block_sequence_first_entry
elif block and self.check_token(BlockMappingStartToken):
end_mark = self.peek_token().start_mark
- event = MappingStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=False)
+ comment = self.peek_token().comment
+ event = MappingStartEvent(
+ anchor, tag, implicit, start_mark, end_mark,
+ flow_style=False, comment=comment)
self.state = self.parse_block_mapping_first_key
elif anchor is not None or tag is not None:
# Empty scalars are allowed even if a tag or an anchor is
# specified.
event = ScalarEvent(anchor, tag, (implicit, False), u'',
- start_mark, end_mark)
+ start_mark, end_mark)
self.state = self.states.pop()
else:
if block:
@@ -366,21 +414,26 @@ class Parser(object):
else:
node = 'flow'
token = self.peek_token()
- raise ParserError("while parsing a %s node" % node, start_mark,
- "expected the node content, but found %r" % token.id,
- token.start_mark)
+ raise ParserError(
+ "while parsing a %s node" % node, start_mark,
+ "expected the node content, but found %r" % token.id,
+ token.start_mark)
return event
- # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+ # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
+ # BLOCK-END
def parse_block_sequence_first_entry(self):
token = self.get_token()
+ # move any comment from start token
+ # token.move_comment(self.peek_token())
self.marks.append(token.start_mark)
return self.parse_block_sequence_entry()
def parse_block_sequence_entry(self):
if self.check_token(BlockEntryToken):
token = self.get_token()
+ token.move_comment(self.peek_token())
if not self.check_token(BlockEntryToken, BlockEndToken):
self.states.append(self.parse_block_sequence_entry)
return self.parse_block_node()
@@ -389,28 +442,38 @@ class Parser(object):
return self.process_empty_scalar(token.end_mark)
if not self.check_token(BlockEndToken):
token = self.peek_token()
- raise ParserError("while parsing a block collection", self.marks[-1],
- "expected <block end>, but found %r" % token.id, token.start_mark)
- token = self.get_token()
- event = SequenceEndEvent(token.start_mark, token.end_mark)
+ raise ParserError(
+ "while parsing a block collection", self.marks[-1],
+ "expected <block end>, but found %r" %
+ token.id, token.start_mark)
+ token = self.get_token() # BlockEndToken
+ event = SequenceEndEvent(token.start_mark, token.end_mark,
+ comment=token.comment)
self.state = self.states.pop()
self.marks.pop()
return event
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+ # indentless_sequence?
+ # sequence:
+ # - entry
+ # - nested
+
def parse_indentless_sequence_entry(self):
if self.check_token(BlockEntryToken):
token = self.get_token()
+ token.move_comment(self.peek_token())
if not self.check_token(BlockEntryToken,
- KeyToken, ValueToken, BlockEndToken):
+ KeyToken, ValueToken, BlockEndToken):
self.states.append(self.parse_indentless_sequence_entry)
return self.parse_block_node()
else:
self.state = self.parse_indentless_sequence_entry
return self.process_empty_scalar(token.end_mark)
token = self.peek_token()
- event = SequenceEndEvent(token.start_mark, token.start_mark)
+ event = SequenceEndEvent(token.start_mark, token.start_mark,
+ comment=token.comment)
self.state = self.states.pop()
return event
@@ -427,6 +490,7 @@ class Parser(object):
def parse_block_mapping_key(self):
if self.check_token(KeyToken):
token = self.get_token()
+ token.move_comment(self.peek_token())
if not self.check_token(KeyToken, ValueToken, BlockEndToken):
self.states.append(self.parse_block_mapping_value)
return self.parse_block_node_or_indentless_sequence()
@@ -435,10 +499,14 @@ class Parser(object):
return self.process_empty_scalar(token.end_mark)
if not self.check_token(BlockEndToken):
token = self.peek_token()
- raise ParserError("while parsing a block mapping", self.marks[-1],
- "expected <block end>, but found %r" % token.id, token.start_mark)
+ raise ParserError(
+ "while parsing a block mapping", self.marks[-1],
+ "expected <block end>, but found %r" % token.id,
+ token.start_mark)
token = self.get_token()
- event = MappingEndEvent(token.start_mark, token.end_mark)
+ token.move_comment(self.peek_token())
+ event = MappingEndEvent(token.start_mark, token.end_mark,
+ comment=token.comment)
self.state = self.states.pop()
self.marks.pop()
return event
@@ -446,6 +514,8 @@ class Parser(object):
def parse_block_mapping_value(self):
if self.check_token(ValueToken):
token = self.get_token()
+ # value token might have post comment move it to e.g. block
+ token.move_comment(self.peek_token())
if not self.check_token(KeyToken, ValueToken, BlockEndToken):
self.states.append(self.parse_block_mapping_key)
return self.parse_block_node_or_indentless_sequence()
@@ -480,21 +550,24 @@ class Parser(object):
self.get_token()
else:
token = self.peek_token()
- raise ParserError("while parsing a flow sequence", self.marks[-1],
- "expected ',' or ']', but got %r" % token.id, token.start_mark)
-
+ raise ParserError(
+ "while parsing a flow sequence", self.marks[-1],
+ "expected ',' or ']', but got %r" % token.id,
+ token.start_mark)
+
if self.check_token(KeyToken):
token = self.peek_token()
event = MappingStartEvent(None, None, True,
- token.start_mark, token.end_mark,
- flow_style=True)
+ token.start_mark, token.end_mark,
+ flow_style=True)
self.state = self.parse_flow_sequence_entry_mapping_key
return event
elif not self.check_token(FlowSequenceEndToken):
self.states.append(self.parse_flow_sequence_entry)
return self.parse_flow_node()
token = self.get_token()
- event = SequenceEndEvent(token.start_mark, token.end_mark)
+ event = SequenceEndEvent(token.start_mark, token.end_mark,
+ comment=token.comment)
self.state = self.states.pop()
self.marks.pop()
return event
@@ -502,7 +575,7 @@ class Parser(object):
def parse_flow_sequence_entry_mapping_key(self):
token = self.get_token()
if not self.check_token(ValueToken,
- FlowEntryToken, FlowSequenceEndToken):
+ FlowEntryToken, FlowSequenceEndToken):
self.states.append(self.parse_flow_sequence_entry_mapping_value)
return self.parse_flow_node()
else:
@@ -546,12 +619,14 @@ class Parser(object):
self.get_token()
else:
token = self.peek_token()
- raise ParserError("while parsing a flow mapping", self.marks[-1],
- "expected ',' or '}', but got %r" % token.id, token.start_mark)
+ raise ParserError(
+ "while parsing a flow mapping", self.marks[-1],
+ "expected ',' or '}', but got %r" % token.id,
+ token.start_mark)
if self.check_token(KeyToken):
token = self.get_token()
if not self.check_token(ValueToken,
- FlowEntryToken, FlowMappingEndToken):
+ FlowEntryToken, FlowMappingEndToken):
self.states.append(self.parse_flow_mapping_value)
return self.parse_flow_node()
else:
@@ -561,7 +636,8 @@ class Parser(object):
self.states.append(self.parse_flow_mapping_empty_value)
return self.parse_flow_node()
token = self.get_token()
- event = MappingEndEvent(token.start_mark, token.end_mark)
+ event = MappingEndEvent(token.start_mark, token.end_mark,
+ comment=token.comment)
self.state = self.states.pop()
self.marks.pop()
return event
@@ -587,3 +663,13 @@ class Parser(object):
def process_empty_scalar(self, mark):
return ScalarEvent(None, None, (True, False), u'', mark, mark)
+
+class RoundTripParser(Parser):
+ """roundtrip is a safe loader, that wants to see the unmangled tag"""
+ def transform_tag(self, handle, suffix):
+ # return self.tag_handles[handle]+suffix
+ if handle == '!!' and suffix in (u'null', u'bool', u'int', u'float', u'binary',
+ u'timestamp', u'omap', u'pairs', u'set', u'str',
+ u'seq', u'map'):
+ return Parser.transform_tag(self, handle, suffix)
+ return handle+suffix
diff --git a/lib/spack/external/yaml/lib3/yaml/reader.py b/lib/spack/external/ruamel/yaml/reader.py
index f70e920f44..376c6de8c6 100644
--- a/lib/spack/external/yaml/lib3/yaml/reader.py
+++ b/lib/spack/external/ruamel/yaml/reader.py
@@ -1,3 +1,6 @@
+# coding: utf-8
+
+from __future__ import absolute_import
# This module contains abstractions for the input stream. You don't have to
# looks further, there are no pretty code.
#
@@ -11,15 +14,24 @@
# Reader determines the encoding of `data` and converts it to unicode.
# Reader provides the following methods and attributes:
# reader.peek(length=1) - return the next `length` characters
-# reader.forward(length=1) - move the current position to `length` characters.
+# reader.forward(length=1) - move the current position to `length`
+# characters.
# reader.index - the number of the current character.
-# reader.line, stream.column - the line and the column of the current character.
+# reader.line, stream.column - the line and the column of the current
+# character.
-__all__ = ['Reader', 'ReaderError']
+import codecs
+import re
-from .error import YAMLError, Mark
+try:
+ from .error import YAMLError, Mark
+ from .compat import text_type, binary_type, PY3
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import YAMLError, Mark
+ from ruamel.yaml.compat import text_type, binary_type, PY3
+
+__all__ = ['Reader', 'ReaderError']
-import codecs, re
class ReaderError(YAMLError):
@@ -31,16 +43,17 @@ class ReaderError(YAMLError):
self.reason = reason
def __str__(self):
- if isinstance(self.character, bytes):
+ if isinstance(self.character, binary_type):
return "'%s' codec can't decode byte #x%02x: %s\n" \
- " in \"%s\", position %d" \
- % (self.encoding, ord(self.character), self.reason,
- self.name, self.position)
+ " in \"%s\", position %d" \
+ % (self.encoding, ord(self.character), self.reason,
+ self.name, self.position)
else:
return "unacceptable character #x%04x: %s\n" \
- " in \"%s\", position %d" \
- % (self.character, self.reason,
- self.name, self.position)
+ " in \"%s\", position %d" \
+ % (self.character, self.reason,
+ self.name, self.position)
+
class Reader(object):
# Reader:
@@ -49,8 +62,8 @@ class Reader(object):
# - adds '\0' to the end.
# Reader accepts
- # - a `bytes` object,
- # - a `str` object,
+ # - a `str` object (PY2) / a `bytes` object (PY3),
+ # - a `unicode` object (PY2) / a `str` object (PY3),
# - a file-like object with its `read` method returning `str`,
# - a file-like object with its `read` method returning `unicode`.
@@ -61,7 +74,7 @@ class Reader(object):
self.stream = None
self.stream_pointer = 0
self.eof = True
- self.buffer = ''
+ self.buffer = u''
self.pointer = 0
self.raw_buffer = None
self.raw_decode = None
@@ -69,11 +82,11 @@ class Reader(object):
self.index = 0
self.line = 0
self.column = 0
- if isinstance(stream, str):
+ if isinstance(stream, text_type):
self.name = "<unicode string>"
self.check_printable(stream)
- self.buffer = stream+'\0'
- elif isinstance(stream, bytes):
+ self.buffer = stream+u'\0'
+ elif isinstance(stream, binary_type):
self.name = "<byte string>"
self.raw_buffer = stream
self.determine_encoding()
@@ -103,26 +116,27 @@ class Reader(object):
ch = self.buffer[self.pointer]
self.pointer += 1
self.index += 1
- if ch in '\n\x85\u2028\u2029' \
- or (ch == '\r' and self.buffer[self.pointer] != '\n'):
+ if ch in u'\n\x85\u2028\u2029' \
+ or (ch == u'\r' and self.buffer[self.pointer] != u'\n'):
self.line += 1
self.column = 0
- elif ch != '\uFEFF':
+ elif ch != u'\uFEFF':
self.column += 1
length -= 1
def get_mark(self):
if self.stream is None:
return Mark(self.name, self.index, self.line, self.column,
- self.buffer, self.pointer)
+ self.buffer, self.pointer)
else:
return Mark(self.name, self.index, self.line, self.column,
- None, None)
+ None, None)
def determine_encoding(self):
- while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2):
+ while not self.eof and (self.raw_buffer is None or
+ len(self.raw_buffer) < 2):
self.update_raw()
- if isinstance(self.raw_buffer, bytes):
+ if isinstance(self.raw_buffer, binary_type):
if self.raw_buffer.startswith(codecs.BOM_UTF16_LE):
self.raw_decode = codecs.utf_16_le_decode
self.encoding = 'utf-16-le'
@@ -134,14 +148,16 @@ class Reader(object):
self.encoding = 'utf-8'
self.update(1)
- NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
+ NON_PRINTABLE = re.compile(
+ u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
+
def check_printable(self, data):
match = self.NON_PRINTABLE.search(data)
if match:
character = match.group()
position = self.index+(len(self.buffer)-self.pointer)+match.start()
raise ReaderError(self.name, position, ord(character),
- 'unicode', "special characters are not allowed")
+ 'unicode', "special characters are not allowed")
def update(self, length):
if self.raw_buffer is None:
@@ -154,15 +170,19 @@ class Reader(object):
if self.raw_decode is not None:
try:
data, converted = self.raw_decode(self.raw_buffer,
- 'strict', self.eof)
+ 'strict', self.eof)
except UnicodeDecodeError as exc:
- character = self.raw_buffer[exc.start]
+ if PY3:
+ character = self.raw_buffer[exc.start]
+ else:
+ character = exc.object[exc.start]
if self.stream is not None:
- position = self.stream_pointer-len(self.raw_buffer)+exc.start
+ position = self.stream_pointer - \
+ len(self.raw_buffer) + exc.start
else:
position = exc.start
raise ReaderError(self.name, position, character,
- exc.encoding, exc.reason)
+ exc.encoding, exc.reason)
else:
data = self.raw_buffer
converted = len(data)
@@ -170,11 +190,13 @@ class Reader(object):
self.buffer += data
self.raw_buffer = self.raw_buffer[converted:]
if self.eof:
- self.buffer += '\0'
+ self.buffer += u'\0'
self.raw_buffer = None
break
- def update_raw(self, size=4096):
+ def update_raw(self, size=None):
+ if size is None:
+ size = 4096 if PY3 else 1024
data = self.stream.read(size)
if self.raw_buffer is None:
self.raw_buffer = data
@@ -184,9 +206,8 @@ class Reader(object):
if not data:
self.eof = True
-#try:
-# import psyco
-# psyco.bind(Reader)
-#except ImportError:
-# pass
-
+# try:
+# import psyco
+# psyco.bind(Reader)
+# except ImportError:
+# pass
diff --git a/lib/spack/external/ruamel/yaml/representer.py b/lib/spack/external/ruamel/yaml/representer.py
new file mode 100644
index 0000000000..b4625bfae9
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/representer.py
@@ -0,0 +1,888 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+try:
+ from .error import * # NOQA
+ from .nodes import * # NOQA
+ from .compat import text_type, binary_type, to_unicode, PY2, PY3, ordereddict
+ from .scalarstring import * # NOQA
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import * # NOQA
+ from ruamel.yaml.nodes import * # NOQA
+ from ruamel.yaml.compat import text_type, binary_type, to_unicode, PY2, PY3, ordereddict
+ from ruamel.yaml.scalarstring import * # NOQA
+
+
+import datetime
+import sys
+import types
+if PY3:
+ import copyreg
+ import base64
+else:
+ import copy_reg as copyreg
+
+
+__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
+ 'RepresenterError', 'RoundTripRepresenter']
+
+
+class RepresenterError(YAMLError):
+ pass
+
+
+class BaseRepresenter(object):
+
+ yaml_representers = {}
+ yaml_multi_representers = {}
+
+ def __init__(self, default_style=None, default_flow_style=None):
+ self.default_style = default_style
+ self.default_flow_style = default_flow_style
+ self.represented_objects = {}
+ self.object_keeper = []
+ self.alias_key = None
+
+ def represent(self, data):
+ node = self.represent_data(data)
+ self.serialize(node)
+ self.represented_objects = {}
+ self.object_keeper = []
+ self.alias_key = None
+
+ if PY2:
+ def get_classobj_bases(self, cls):
+ bases = [cls]
+ for base in cls.__bases__:
+ bases.extend(self.get_classobj_bases(base))
+ return bases
+
+ def represent_data(self, data):
+ if self.ignore_aliases(data):
+ self.alias_key = None
+ else:
+ self.alias_key = id(data)
+ if self.alias_key is not None:
+ if self.alias_key in self.represented_objects:
+ node = self.represented_objects[self.alias_key]
+ # if node is None:
+ # raise RepresenterError(
+ # "recursive objects are not allowed: %r" % data)
+ return node
+ # self.represented_objects[alias_key] = None
+ self.object_keeper.append(data)
+ data_types = type(data).__mro__
+ if PY2:
+ # if type(data) is types.InstanceType:
+ if isinstance(data, types.InstanceType):
+ data_types = self.get_classobj_bases(data.__class__) + \
+ list(data_types)
+ if data_types[0] in self.yaml_representers:
+ node = self.yaml_representers[data_types[0]](self, data)
+ else:
+ for data_type in data_types:
+ if data_type in self.yaml_multi_representers:
+ node = self.yaml_multi_representers[data_type](self, data)
+ break
+ else:
+ if None in self.yaml_multi_representers:
+ node = self.yaml_multi_representers[None](self, data)
+ elif None in self.yaml_representers:
+ node = self.yaml_representers[None](self, data)
+ else:
+ node = ScalarNode(None, text_type(data))
+ # if alias_key is not None:
+ # self.represented_objects[alias_key] = node
+ return node
+
+ def represent_key(self, data):
+ """
+ David Fraser: Extract a method to represent keys in mappings, so that
+ a subclass can choose not to quote them (for example)
+ used in repesent_mapping
+ https://bitbucket.org/davidfraser/pyyaml/commits/d81df6eb95f20cac4a79eed95ae553b5c6f77b8c
+ """
+ return self.represent_data(data)
+
+ @classmethod
+ def add_representer(cls, data_type, representer):
+ if 'yaml_representers' not in cls.__dict__:
+ cls.yaml_representers = cls.yaml_representers.copy()
+ cls.yaml_representers[data_type] = representer
+
+ @classmethod
+ def add_multi_representer(cls, data_type, representer):
+ if 'yaml_multi_representers' not in cls.__dict__:
+ cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
+ cls.yaml_multi_representers[data_type] = representer
+
+ def represent_scalar(self, tag, value, style=None):
+ if style is None:
+ style = self.default_style
+ node = ScalarNode(tag, value, style=style)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ return node
+
+ def represent_sequence(self, tag, sequence, flow_style=None):
+ value = []
+ node = SequenceNode(tag, value, flow_style=flow_style)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ for item in sequence:
+ node_item = self.represent_data(item)
+ if not (isinstance(node_item, ScalarNode) and not node_item.style):
+ best_style = False
+ value.append(node_item)
+ if flow_style is None:
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style
+ return node
+
+ def represent_omap(self, tag, omap, flow_style=None):
+ value = []
+ node = SequenceNode(tag, value, flow_style=flow_style)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ for item_key in omap:
+ item_val = omap[item_key]
+ node_item = self.represent_data({item_key: item_val})
+ # if not (isinstance(node_item, ScalarNode) \
+ # and not node_item.style):
+ # best_style = False
+ value.append(node_item)
+ if flow_style is None:
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style
+ return node
+
+ def represent_mapping(self, tag, mapping, flow_style=None):
+ value = []
+ node = MappingNode(tag, value, flow_style=flow_style)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ if hasattr(mapping, 'items'):
+ mapping = list(mapping.items())
+ try:
+ mapping = sorted(mapping)
+ except TypeError:
+ pass
+ for item_key, item_value in mapping:
+ node_key = self.represent_key(item_key)
+ node_value = self.represent_data(item_value)
+ if not (isinstance(node_key, ScalarNode) and not node_key.style):
+ best_style = False
+ if not (isinstance(node_value, ScalarNode) and not
+ node_value.style):
+ best_style = False
+ value.append((node_key, node_value))
+ if flow_style is None:
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style
+ return node
+
+ def ignore_aliases(self, data):
+ return False
+
+
+class SafeRepresenter(BaseRepresenter):
+
+ def ignore_aliases(self, data):
+ # https://docs.python.org/3/reference/expressions.html#parenthesized-forms :
+ # "i.e. two occurrences of the empty tuple may or may not yield the same object"
+ # so "data is ()" should not be used
+ if data is None or data == ():
+ return True
+ if isinstance(data, (binary_type, text_type, bool, int, float)):
+ return True
+
+ def represent_none(self, data):
+ return self.represent_scalar(u'tag:yaml.org,2002:null',
+ u'null')
+
+ if PY3:
+ def represent_str(self, data):
+ return self.represent_scalar(u'tag:yaml.org,2002:str', data)
+
+ def represent_binary(self, data):
+ if hasattr(base64, 'encodebytes'):
+ data = base64.encodebytes(data).decode('ascii')
+ else:
+ data = base64.encodestring(data).decode('ascii')
+ return self.represent_scalar(u'tag:yaml.org,2002:binary', data,
+ style='|')
+ else:
+ def represent_str(self, data):
+ tag = None
+ style = None
+ try:
+ data = unicode(data, 'ascii')
+ tag = u'tag:yaml.org,2002:str'
+ except UnicodeDecodeError:
+ try:
+ data = unicode(data, 'utf-8')
+ tag = u'tag:yaml.org,2002:str'
+ except UnicodeDecodeError:
+ data = data.encode('base64')
+ tag = u'tag:yaml.org,2002:binary'
+ style = '|'
+ return self.represent_scalar(tag, data, style=style)
+
+ def represent_unicode(self, data):
+ return self.represent_scalar(u'tag:yaml.org,2002:str', data)
+
+ def represent_bool(self, data):
+ if data:
+ value = u'true'
+ else:
+ value = u'false'
+ return self.represent_scalar(u'tag:yaml.org,2002:bool', value)
+
+ def represent_int(self, data):
+ return self.represent_scalar(u'tag:yaml.org,2002:int', text_type(data))
+
+ if PY2:
+ def represent_long(self, data):
+ return self.represent_scalar(u'tag:yaml.org,2002:int',
+ text_type(data))
+
+ inf_value = 1e300
+ while repr(inf_value) != repr(inf_value*inf_value):
+ inf_value *= inf_value
+
+ def represent_float(self, data):
+ if data != data or (data == 0.0 and data == 1.0):
+ value = u'.nan'
+ elif data == self.inf_value:
+ value = u'.inf'
+ elif data == -self.inf_value:
+ value = u'-.inf'
+ else:
+ value = to_unicode(repr(data)).lower()
+ # Note that in some cases `repr(data)` represents a float number
+ # without the decimal parts. For instance:
+ # >>> repr(1e17)
+ # '1e17'
+ # Unfortunately, this is not a valid float representation according
+ # to the definition of the `!!float` tag. We fix this by adding
+ # '.0' before the 'e' symbol.
+ if u'.' not in value and u'e' in value:
+ value = value.replace(u'e', u'.0e', 1)
+ return self.represent_scalar(u'tag:yaml.org,2002:float', value)
+
+ def represent_list(self, data):
+ # pairs = (len(data) > 0 and isinstance(data, list))
+ # if pairs:
+ # for item in data:
+ # if not isinstance(item, tuple) or len(item) != 2:
+ # pairs = False
+ # break
+ # if not pairs:
+ return self.represent_sequence(u'tag:yaml.org,2002:seq', data)
+ # value = []
+ # for item_key, item_value in data:
+ # value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
+ # [(item_key, item_value)]))
+ # return SequenceNode(u'tag:yaml.org,2002:pairs', value)
+
+ def represent_dict(self, data):
+ return self.represent_mapping(u'tag:yaml.org,2002:map', data)
+
+ def represent_ordereddict(self, data):
+ return self.represent_omap(u'tag:yaml.org,2002:omap', data)
+
+ def represent_set(self, data):
+ value = {}
+ for key in data:
+ value[key] = None
+ return self.represent_mapping(u'tag:yaml.org,2002:set', value)
+
+ def represent_date(self, data):
+ value = to_unicode(data.isoformat())
+ return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
+
+ def represent_datetime(self, data):
+ value = to_unicode(data.isoformat(' '))
+ return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
+
+ def represent_yaml_object(self, tag, data, cls, flow_style=None):
+ if hasattr(data, '__getstate__'):
+ state = data.__getstate__()
+ else:
+ state = data.__dict__.copy()
+ return self.represent_mapping(tag, state, flow_style=flow_style)
+
+ def represent_undefined(self, data):
+ raise RepresenterError("cannot represent an object: %s" % data)
+
+SafeRepresenter.add_representer(type(None),
+ SafeRepresenter.represent_none)
+
+SafeRepresenter.add_representer(str,
+ SafeRepresenter.represent_str)
+
+if PY2:
+ SafeRepresenter.add_representer(unicode,
+ SafeRepresenter.represent_unicode)
+else:
+ SafeRepresenter.add_representer(bytes,
+ SafeRepresenter.represent_binary)
+
+SafeRepresenter.add_representer(bool,
+ SafeRepresenter.represent_bool)
+
+SafeRepresenter.add_representer(int,
+ SafeRepresenter.represent_int)
+
+if PY2:
+ SafeRepresenter.add_representer(long,
+ SafeRepresenter.represent_long)
+
+SafeRepresenter.add_representer(float,
+ SafeRepresenter.represent_float)
+
+SafeRepresenter.add_representer(list,
+ SafeRepresenter.represent_list)
+
+SafeRepresenter.add_representer(tuple,
+ SafeRepresenter.represent_list)
+
+SafeRepresenter.add_representer(dict,
+ SafeRepresenter.represent_dict)
+
+SafeRepresenter.add_representer(set,
+ SafeRepresenter.represent_set)
+
+SafeRepresenter.add_representer(ordereddict,
+ SafeRepresenter.represent_ordereddict)
+
+SafeRepresenter.add_representer(datetime.date,
+ SafeRepresenter.represent_date)
+
+SafeRepresenter.add_representer(datetime.datetime,
+ SafeRepresenter.represent_datetime)
+
+SafeRepresenter.add_representer(None,
+ SafeRepresenter.represent_undefined)
+
+
+class Representer(SafeRepresenter):
+ if PY2:
+ def represent_str(self, data):
+ tag = None
+ style = None
+ try:
+ data = unicode(data, 'ascii')
+ tag = u'tag:yaml.org,2002:str'
+ except UnicodeDecodeError:
+ try:
+ data = unicode(data, 'utf-8')
+ tag = u'tag:yaml.org,2002:python/str'
+ except UnicodeDecodeError:
+ data = data.encode('base64')
+ tag = u'tag:yaml.org,2002:binary'
+ style = '|'
+ return self.represent_scalar(tag, data, style=style)
+
+ def represent_unicode(self, data):
+ tag = None
+ try:
+ data.encode('ascii')
+ tag = u'tag:yaml.org,2002:python/unicode'
+ except UnicodeEncodeError:
+ tag = u'tag:yaml.org,2002:str'
+ return self.represent_scalar(tag, data)
+
+ def represent_long(self, data):
+ tag = u'tag:yaml.org,2002:int'
+ if int(data) is not data:
+ tag = u'tag:yaml.org,2002:python/long'
+ return self.represent_scalar(tag, to_unicode(data))
+
+ def represent_complex(self, data):
+ if data.imag == 0.0:
+ data = u'%r' % data.real
+ elif data.real == 0.0:
+ data = u'%rj' % data.imag
+ elif data.imag > 0:
+ data = u'%r+%rj' % (data.real, data.imag)
+ else:
+ data = u'%r%rj' % (data.real, data.imag)
+ return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
+
+ def represent_tuple(self, data):
+ return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
+
+ def represent_name(self, data):
+ name = u'%s.%s' % (data.__module__, data.__name__)
+ return self.represent_scalar(u'tag:yaml.org,2002:python/name:' +
+ name, u'')
+
+ def represent_module(self, data):
+ return self.represent_scalar(
+ u'tag:yaml.org,2002:python/module:'+data.__name__, u'')
+
+ if PY2:
+ def represent_instance(self, data):
+ # For instances of classic classes, we use __getinitargs__ and
+ # __getstate__ to serialize the data.
+
+ # If data.__getinitargs__ exists, the object must be reconstructed
+ # by calling cls(**args), where args is a tuple returned by
+ # __getinitargs__. Otherwise, the cls.__init__ method should never
+ # be called and the class instance is created by instantiating a
+ # trivial class and assigning to the instance's __class__ variable.
+
+ # If data.__getstate__ exists, it returns the state of the object.
+ # Otherwise, the state of the object is data.__dict__.
+
+ # We produce either a !!python/object or !!python/object/new node.
+ # If data.__getinitargs__ does not exist and state is a dictionary,
+ # we produce a !!python/object node . Otherwise we produce a
+ # !!python/object/new node.
+
+ cls = data.__class__
+ class_name = u'%s.%s' % (cls.__module__, cls.__name__)
+ args = None
+ state = None
+ if hasattr(data, '__getinitargs__'):
+ args = list(data.__getinitargs__())
+ if hasattr(data, '__getstate__'):
+ state = data.__getstate__()
+ else:
+ state = data.__dict__
+ if args is None and isinstance(state, dict):
+ return self.represent_mapping(
+ u'tag:yaml.org,2002:python/object:'+class_name, state)
+ if isinstance(state, dict) and not state:
+ return self.represent_sequence(
+ u'tag:yaml.org,2002:python/object/new:' +
+ class_name, args)
+ value = {}
+ if args:
+ value['args'] = args
+ value['state'] = state
+ return self.represent_mapping(
+ u'tag:yaml.org,2002:python/object/new:'+class_name, value)
+
+ def represent_object(self, data):
+ # We use __reduce__ API to save the data. data.__reduce__ returns
+ # a tuple of length 2-5:
+ # (function, args, state, listitems, dictitems)
+
+ # For reconstructing, we calls function(*args), then set its state,
+ # listitems, and dictitems if they are not None.
+
+ # A special case is when function.__name__ == '__newobj__'. In this
+ # case we create the object with args[0].__new__(*args).
+
+ # Another special case is when __reduce__ returns a string - we don't
+ # support it.
+
+ # We produce a !!python/object, !!python/object/new or
+ # !!python/object/apply node.
+
+ cls = type(data)
+ if cls in copyreg.dispatch_table:
+ reduce = copyreg.dispatch_table[cls](data)
+ elif hasattr(data, '__reduce_ex__'):
+ reduce = data.__reduce_ex__(2)
+ elif hasattr(data, '__reduce__'):
+ reduce = data.__reduce__()
+ else:
+ raise RepresenterError("cannot represent object: %r" % data)
+ reduce = (list(reduce)+[None]*5)[:5]
+ function, args, state, listitems, dictitems = reduce
+ args = list(args)
+ if state is None:
+ state = {}
+ if listitems is not None:
+ listitems = list(listitems)
+ if dictitems is not None:
+ dictitems = dict(dictitems)
+ if function.__name__ == '__newobj__':
+ function = args[0]
+ args = args[1:]
+ tag = u'tag:yaml.org,2002:python/object/new:'
+ newobj = True
+ else:
+ tag = u'tag:yaml.org,2002:python/object/apply:'
+ newobj = False
+ function_name = u'%s.%s' % (function.__module__, function.__name__)
+ if not args and not listitems and not dictitems \
+ and isinstance(state, dict) and newobj:
+ return self.represent_mapping(
+ u'tag:yaml.org,2002:python/object:'+function_name, state)
+ if not listitems and not dictitems \
+ and isinstance(state, dict) and not state:
+ return self.represent_sequence(tag+function_name, args)
+ value = {}
+ if args:
+ value['args'] = args
+ if state or not isinstance(state, dict):
+ value['state'] = state
+ if listitems:
+ value['listitems'] = listitems
+ if dictitems:
+ value['dictitems'] = dictitems
+ return self.represent_mapping(tag+function_name, value)
+
+if PY2:
+ Representer.add_representer(str,
+ Representer.represent_str)
+
+ Representer.add_representer(unicode,
+ Representer.represent_unicode)
+
+ Representer.add_representer(long,
+ Representer.represent_long)
+
+Representer.add_representer(complex,
+ Representer.represent_complex)
+
+Representer.add_representer(tuple,
+ Representer.represent_tuple)
+
+Representer.add_representer(type,
+ Representer.represent_name)
+
+if PY2:
+ Representer.add_representer(types.ClassType,
+ Representer.represent_name)
+
+Representer.add_representer(types.FunctionType,
+ Representer.represent_name)
+
+Representer.add_representer(types.BuiltinFunctionType,
+ Representer.represent_name)
+
+Representer.add_representer(types.ModuleType,
+ Representer.represent_module)
+
+if PY2:
+ Representer.add_multi_representer(types.InstanceType,
+ Representer.represent_instance)
+
+Representer.add_multi_representer(object,
+ Representer.represent_object)
+
+
+try:
+ from .comments import CommentedMap, CommentedOrderedMap, CommentedSeq, \
+ CommentedSet, comment_attrib, merge_attrib
+except ImportError: # for Jython
+ from ruamel.yaml.comments import CommentedMap, CommentedOrderedMap, \
+ CommentedSeq, CommentedSet, comment_attrib, merge_attrib
+
+
+class RoundTripRepresenter(SafeRepresenter):
+ # need to add type here and write out the .comment
+ # in serializer and emitter
+
+ def __init__(self, default_style=None, default_flow_style=None):
+ if default_flow_style is None:
+ default_flow_style = False
+ SafeRepresenter.__init__(self, default_style=default_style,
+ default_flow_style=default_flow_style)
+
+ def represent_none(self, data):
+ return self.represent_scalar(u'tag:yaml.org,2002:null',
+ u'')
+
+ def represent_preserved_scalarstring(self, data):
+ tag = None
+ style = '|'
+ if PY2 and not isinstance(data, unicode):
+ data = unicode(data, 'ascii')
+ tag = u'tag:yaml.org,2002:str'
+ return self.represent_scalar(tag, data, style=style)
+
+ def represent_single_quoted_scalarstring(self, data):
+ tag = None
+ style = "'"
+ if PY2 and not isinstance(data, unicode):
+ data = unicode(data, 'ascii')
+ tag = u'tag:yaml.org,2002:str'
+ return self.represent_scalar(tag, data, style=style)
+
+ def represent_double_quoted_scalarstring(self, data):
+ tag = None
+ style = '"'
+ if PY2 and not isinstance(data, unicode):
+ data = unicode(data, 'ascii')
+ tag = u'tag:yaml.org,2002:str'
+ return self.represent_scalar(tag, data, style=style)
+
+ def represent_sequence(self, tag, sequence, flow_style=None):
+ value = []
+ # if the flow_style is None, the flow style tacked on to the object
+ # explicitly will be taken. If that is None as well the default flow
+ # style rules
+ try:
+ flow_style = sequence.fa.flow_style(flow_style)
+ except AttributeError:
+ flow_style = flow_style
+ try:
+ anchor = sequence.yaml_anchor()
+ except AttributeError:
+ anchor = None
+ node = SequenceNode(tag, value, flow_style=flow_style, anchor=anchor)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ try:
+ comment = getattr(sequence, comment_attrib)
+ item_comments = comment.items
+ node.comment = comment.comment
+ try:
+ node.comment.append(comment.end)
+ except AttributeError:
+ pass
+ except AttributeError:
+ item_comments = {}
+ for idx, item in enumerate(sequence):
+ node_item = self.represent_data(item)
+ node_item.comment = item_comments.get(idx)
+ if not (isinstance(node_item, ScalarNode) and not node_item.style):
+ best_style = False
+ value.append(node_item)
+ if flow_style is None:
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style
+ return node
+
+ def represent_mapping(self, tag, mapping, flow_style=None):
+ value = []
+ try:
+ flow_style = mapping.fa.flow_style(flow_style)
+ except AttributeError:
+ flow_style = flow_style
+ try:
+ anchor = mapping.yaml_anchor()
+ except AttributeError:
+ anchor = None
+ node = MappingNode(tag, value, flow_style=flow_style, anchor=anchor)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ # no sorting! !!
+ try:
+ comment = getattr(mapping, comment_attrib)
+ node.comment = comment.comment
+ if node.comment and node.comment[1]:
+ for ct in node.comment[1]:
+ ct.reset()
+ item_comments = comment.items
+ for v in item_comments.values():
+ if v and v[1]:
+ for ct in v[1]:
+ ct.reset()
+ try:
+ node.comment.append(comment.end)
+ except AttributeError:
+ pass
+ except AttributeError:
+ item_comments = {}
+ for item_key, item_value in mapping.items():
+ node_key = self.represent_key(item_key)
+ node_value = self.represent_data(item_value)
+ item_comment = item_comments.get(item_key)
+ if item_comment:
+ assert getattr(node_key, 'comment', None) is None
+ node_key.comment = item_comment[:2]
+ nvc = getattr(node_value, 'comment', None)
+ if nvc is not None: # end comment already there
+ nvc[0] = item_comment[2]
+ nvc[1] = item_comment[3]
+ else:
+ node_value.comment = item_comment[2:]
+ if not (isinstance(node_key, ScalarNode) and not node_key.style):
+ best_style = False
+ if not (isinstance(node_value, ScalarNode) and not
+ node_value.style):
+ best_style = False
+ value.append((node_key, node_value))
+ if flow_style is None:
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style
+ merge_list = [m[1] for m in getattr(mapping, merge_attrib, [])]
+ if merge_list:
+ # because of the call to represent_data here, the anchors
+ # are marked as being used and thereby created
+ if len(merge_list) == 1:
+ arg = self.represent_data(merge_list[0])
+ else:
+ arg = self.represent_data(merge_list)
+ arg.flow_style = True
+ value.insert(0,
+ (ScalarNode(u'tag:yaml.org,2002:merge', '<<'), arg))
+ return node
+
+ def represent_omap(self, tag, omap, flow_style=None):
+ value = []
+ try:
+ flow_style = omap.fa.flow_style(flow_style)
+ except AttributeError:
+ flow_style = flow_style
+ try:
+ anchor = omap.yaml_anchor()
+ except AttributeError:
+ anchor = None
+ node = SequenceNode(tag, value, flow_style=flow_style, anchor=anchor)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ try:
+ comment = getattr(omap, comment_attrib)
+ node.comment = comment.comment
+ if node.comment and node.comment[1]:
+ for ct in node.comment[1]:
+ ct.reset()
+ item_comments = comment.items
+ for v in item_comments.values():
+ if v and v[1]:
+ for ct in v[1]:
+ ct.reset()
+ try:
+ node.comment.append(comment.end)
+ except AttributeError:
+ pass
+ except AttributeError:
+ item_comments = {}
+ for item_key in omap:
+ item_val = omap[item_key]
+ node_item = self.represent_data({item_key: item_val})
+ # node item has two scalars in value: node_key and node_value
+ item_comment = item_comments.get(item_key)
+ if item_comment:
+ if item_comment[1]:
+ node_item.comment = [None, item_comment[1]]
+ assert getattr(node_item.value[0][0], 'comment', None) is None
+ node_item.value[0][0].comment = [item_comment[0], None]
+ nvc = getattr(node_item.value[0][1], 'comment', None)
+ if nvc is not None: # end comment already there
+ nvc[0] = item_comment[2]
+ nvc[1] = item_comment[3]
+ else:
+ node_item.value[0][1].comment = item_comment[2:]
+ # if not (isinstance(node_item, ScalarNode) \
+ # and not node_item.style):
+ # best_style = False
+ value.append(node_item)
+ if flow_style is None:
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style
+ return node
+
+ def represent_set(self, setting):
+ flow_style = False
+ tag = u'tag:yaml.org,2002:set'
+ # return self.represent_mapping(tag, value)
+ value = []
+ flow_style = setting.fa.flow_style(flow_style)
+ try:
+ anchor = setting.yaml_anchor()
+ except AttributeError:
+ anchor = None
+ node = MappingNode(tag, value, flow_style=flow_style, anchor=anchor)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ # no sorting! !!
+ try:
+ comment = getattr(setting, comment_attrib)
+ node.comment = comment.comment
+ if node.comment and node.comment[1]:
+ for ct in node.comment[1]:
+ ct.reset()
+ item_comments = comment.items
+ for v in item_comments.values():
+ if v and v[1]:
+ for ct in v[1]:
+ ct.reset()
+ try:
+ node.comment.append(comment.end)
+ except AttributeError:
+ pass
+ except AttributeError:
+ item_comments = {}
+ for item_key in setting.odict:
+ node_key = self.represent_key(item_key)
+ node_value = self.represent_data(None)
+ item_comment = item_comments.get(item_key)
+ if item_comment:
+ assert getattr(node_key, 'comment', None) is None
+ node_key.comment = item_comment[:2]
+ node_key.style = node_value.style = "?"
+ if not (isinstance(node_key, ScalarNode) and not node_key.style):
+ best_style = False
+ if not (isinstance(node_value, ScalarNode) and not
+ node_value.style):
+ best_style = False
+ value.append((node_key, node_value))
+ best_style = best_style
+ return node
+
+ def represent_dict(self, data):
+ """write out tag if saved on loading"""
+ try:
+ t = data.tag.value
+ except AttributeError:
+ t = None
+ if t:
+ while t and t[0] == '!':
+ t = t[1:]
+ tag = 'tag:yaml.org,2002:' + t
+ else:
+ tag = u'tag:yaml.org,2002:map'
+ return self.represent_mapping(tag, data)
+
+
+RoundTripRepresenter.add_representer(type(None),
+ RoundTripRepresenter.represent_none)
+
+RoundTripRepresenter.add_representer(
+ PreservedScalarString,
+ RoundTripRepresenter.represent_preserved_scalarstring)
+
+RoundTripRepresenter.add_representer(
+ SingleQuotedScalarString,
+ RoundTripRepresenter.represent_single_quoted_scalarstring)
+
+RoundTripRepresenter.add_representer(
+ DoubleQuotedScalarString,
+ RoundTripRepresenter.represent_double_quoted_scalarstring)
+
+RoundTripRepresenter.add_representer(CommentedSeq,
+ RoundTripRepresenter.represent_list)
+
+RoundTripRepresenter.add_representer(CommentedMap,
+ RoundTripRepresenter.represent_dict)
+
+RoundTripRepresenter.add_representer(CommentedOrderedMap,
+ RoundTripRepresenter.represent_ordereddict)
+
+if sys.version_info >= (2, 7):
+ import collections
+ RoundTripRepresenter.add_representer(collections.OrderedDict,
+ RoundTripRepresenter.represent_ordereddict)
+
+RoundTripRepresenter.add_representer(CommentedSet,
+ RoundTripRepresenter.represent_set)
diff --git a/lib/spack/external/ruamel/yaml/resolver.py b/lib/spack/external/ruamel/yaml/resolver.py
new file mode 100644
index 0000000000..84227072e0
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/resolver.py
@@ -0,0 +1,397 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+
+import re
+
+try:
+ from .error import * # NOQA
+ from .nodes import * # NOQA
+ from .compat import string_types
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import * # NOQA
+ from ruamel.yaml.nodes import * # NOQA
+ from ruamel.yaml.compat import string_types
+
+__all__ = ['BaseResolver', 'Resolver', 'VersionedResolver']
+
+
+_DEFAULT_VERSION = (1, 2)
+
+
+class ResolverError(YAMLError):
+ pass
+
+
+class BaseResolver(object):
+
+ DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str'
+ DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq'
+ DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map'
+
+ yaml_implicit_resolvers = {}
+ yaml_path_resolvers = {}
+
+ def __init__(self):
+ self._loader_version = None
+ self.resolver_exact_paths = []
+ self.resolver_prefix_paths = []
+
+ @classmethod
+ def add_implicit_resolver(cls, tag, regexp, first):
+ if 'yaml_implicit_resolvers' not in cls.__dict__:
+ cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy()
+ if first is None:
+ first = [None]
+ for ch in first:
+ cls.yaml_implicit_resolvers.setdefault(ch, []).append(
+ (tag, regexp))
+
+ @classmethod
+ def add_path_resolver(cls, tag, path, kind=None):
+ # Note: `add_path_resolver` is experimental. The API could be changed.
+ # `new_path` is a pattern that is matched against the path from the
+ # root to the node that is being considered. `node_path` elements are
+ # tuples `(node_check, index_check)`. `node_check` is a node class:
+ # `ScalarNode`, `SequenceNode`, `MappingNode` or `None`. `None`
+ # matches any kind of a node. `index_check` could be `None`, a boolean
+ # value, a string value, or a number. `None` and `False` match against
+ # any _value_ of sequence and mapping nodes. `True` matches against
+ # any _key_ of a mapping node. A string `index_check` matches against
+ # a mapping value that corresponds to a scalar key which content is
+ # equal to the `index_check` value. An integer `index_check` matches
+ # against a sequence value with the index equal to `index_check`.
+ if 'yaml_path_resolvers' not in cls.__dict__:
+ cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()
+ new_path = []
+ for element in path:
+ if isinstance(element, (list, tuple)):
+ if len(element) == 2:
+ node_check, index_check = element
+ elif len(element) == 1:
+ node_check = element[0]
+ index_check = True
+ else:
+ raise ResolverError("Invalid path element: %s" % element)
+ else:
+ node_check = None
+ index_check = element
+ if node_check is str:
+ node_check = ScalarNode
+ elif node_check is list:
+ node_check = SequenceNode
+ elif node_check is dict:
+ node_check = MappingNode
+ elif node_check not in [ScalarNode, SequenceNode, MappingNode] \
+ and not isinstance(node_check, string_types) \
+ and node_check is not None:
+ raise ResolverError("Invalid node checker: %s" % node_check)
+ if not isinstance(index_check, (string_types, int)) \
+ and index_check is not None:
+ raise ResolverError("Invalid index checker: %s" % index_check)
+ new_path.append((node_check, index_check))
+ if kind is str:
+ kind = ScalarNode
+ elif kind is list:
+ kind = SequenceNode
+ elif kind is dict:
+ kind = MappingNode
+ elif kind not in [ScalarNode, SequenceNode, MappingNode] \
+ and kind is not None:
+ raise ResolverError("Invalid node kind: %s" % kind)
+ cls.yaml_path_resolvers[tuple(new_path), kind] = tag
+
+ def descend_resolver(self, current_node, current_index):
+ if not self.yaml_path_resolvers:
+ return
+ exact_paths = {}
+ prefix_paths = []
+ if current_node:
+ depth = len(self.resolver_prefix_paths)
+ for path, kind in self.resolver_prefix_paths[-1]:
+ if self.check_resolver_prefix(depth, path, kind,
+ current_node, current_index):
+ if len(path) > depth:
+ prefix_paths.append((path, kind))
+ else:
+ exact_paths[kind] = self.yaml_path_resolvers[path,
+ kind]
+ else:
+ for path, kind in self.yaml_path_resolvers:
+ if not path:
+ exact_paths[kind] = self.yaml_path_resolvers[path, kind]
+ else:
+ prefix_paths.append((path, kind))
+ self.resolver_exact_paths.append(exact_paths)
+ self.resolver_prefix_paths.append(prefix_paths)
+
+ def ascend_resolver(self):
+ if not self.yaml_path_resolvers:
+ return
+ self.resolver_exact_paths.pop()
+ self.resolver_prefix_paths.pop()
+
+ def check_resolver_prefix(self, depth, path, kind,
+ current_node, current_index):
+ node_check, index_check = path[depth-1]
+ if isinstance(node_check, string_types):
+ if current_node.tag != node_check:
+ return
+ elif node_check is not None:
+ if not isinstance(current_node, node_check):
+ return
+ if index_check is True and current_index is not None:
+ return
+ if (index_check is False or index_check is None) \
+ and current_index is None:
+ return
+ if isinstance(index_check, string_types):
+ if not (isinstance(current_index, ScalarNode) and
+ index_check == current_index.value):
+ return
+ elif isinstance(index_check, int) and not isinstance(index_check,
+ bool):
+ if index_check != current_index:
+ return
+ return True
+
+ def resolve(self, kind, value, implicit):
+ if kind is ScalarNode and implicit[0]:
+ if value == u'':
+ resolvers = self.yaml_implicit_resolvers.get(u'', [])
+ else:
+ resolvers = self.yaml_implicit_resolvers.get(value[0], [])
+ resolvers += self.yaml_implicit_resolvers.get(None, [])
+ for tag, regexp in resolvers:
+ if regexp.match(value):
+ return tag
+ implicit = implicit[1]
+ if self.yaml_path_resolvers:
+ exact_paths = self.resolver_exact_paths[-1]
+ if kind in exact_paths:
+ return exact_paths[kind]
+ if None in exact_paths:
+ return exact_paths[None]
+ if kind is ScalarNode:
+ return self.DEFAULT_SCALAR_TAG
+ elif kind is SequenceNode:
+ return self.DEFAULT_SEQUENCE_TAG
+ elif kind is MappingNode:
+ return self.DEFAULT_MAPPING_TAG
+
+ @property
+ def processing_version(self):
+ return None
+
+
+class Resolver(BaseResolver):
+ pass
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:bool',
+ re.compile(u'''^(?:yes|Yes|YES|no|No|NO
+ |true|True|TRUE|false|False|FALSE
+ |on|On|ON|off|Off|OFF)$''', re.X),
+ list(u'yYnNtTfFoO'))
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:float',
+ re.compile(u'''^(?:
+ [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
+ |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
+ |\\.[0-9_]+(?:[eE][-+][0-9]+)?
+ |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
+ |[-+]?\\.(?:inf|Inf|INF)
+ |\\.(?:nan|NaN|NAN))$''', re.X),
+ list(u'-+0123456789.'))
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:int',
+ re.compile(u'''^(?:[-+]?0b[0-1_]+
+ |[-+]?0o?[0-7_]+
+ |[-+]?(?:0|[1-9][0-9_]*)
+ |[-+]?0x[0-9a-fA-F_]+
+ |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
+ list(u'-+0123456789'))
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:merge',
+ re.compile(u'^(?:<<)$'),
+ [u'<'])
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:null',
+ re.compile(u'''^(?: ~
+ |null|Null|NULL
+ | )$''', re.X),
+ [u'~', u'n', u'N', u''])
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:timestamp',
+ re.compile(u'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
+ |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
+ (?:[Tt]|[ \\t]+)[0-9][0-9]?
+ :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?
+ (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
+ list(u'0123456789'))
+
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:value',
+ re.compile(u'^(?:=)$'),
+ [u'='])
+
+# The following resolver is only for documentation purposes. It cannot work
+# because plain scalars cannot start with '!', '&', or '*'.
+Resolver.add_implicit_resolver(
+ u'tag:yaml.org,2002:yaml',
+ re.compile(u'^(?:!|&|\\*)$'),
+ list(u'!&*'))
+
+# resolvers consist of
+# - a list of applicable version
+# - a tag
+# - a regexp
+# - a list of first characters to match
+implicit_resolvers = [
+ ([(1, 2)],
+ u'tag:yaml.org,2002:bool',
+ re.compile(u'''^(?:true|True|TRUE|false|False|FALSE)$''', re.X),
+ list(u'tTfF')),
+ ([(1, 1)],
+ u'tag:yaml.org,2002:bool',
+ re.compile(u'''^(?:yes|Yes|YES|no|No|NO
+ |true|True|TRUE|false|False|FALSE
+ |on|On|ON|off|Off|OFF)$''', re.X),
+ list(u'yYnNtTfFoO')),
+ ([(1, 2), (1, 1)],
+ u'tag:yaml.org,2002:float',
+ re.compile(u'''^(?:
+ [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
+ |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
+ |\\.[0-9_]+(?:[eE][-+][0-9]+)?
+ |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
+ |[-+]?\\.(?:inf|Inf|INF)
+ |\\.(?:nan|NaN|NAN))$''', re.X),
+ list(u'-+0123456789.')),
+ ([(1, 2)],
+ u'tag:yaml.org,2002:int',
+ re.compile(u'''^(?:[-+]?0b[0-1_]+
+ |[-+]?0o?[0-7_]+
+ |[-+]?(?:0|[1-9][0-9_]*)
+ |[-+]?0x[0-9a-fA-F_]+)$''', re.X),
+ list(u'-+0123456789')),
+ ([(1, 1)],
+ u'tag:yaml.org,2002:int',
+ re.compile(u'''^(?:[-+]?0b[0-1_]+
+ |[-+]?0o?[0-7_]+
+ |[-+]?(?:0|[1-9][0-9_]*)
+ |[-+]?0x[0-9a-fA-F_]+
+ |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
+ list(u'-+0123456789')),
+ ([(1, 2), (1, 1)],
+ u'tag:yaml.org,2002:merge',
+ re.compile(u'^(?:<<)$'),
+ [u'<']),
+ ([(1, 2), (1, 1)],
+ u'tag:yaml.org,2002:null',
+ re.compile(u'''^(?: ~
+ |null|Null|NULL
+ | )$''', re.X),
+ [u'~', u'n', u'N', u'']),
+ ([(1, 2), (1, 1)],
+ u'tag:yaml.org,2002:timestamp',
+ re.compile(u'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
+ |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
+ (?:[Tt]|[ \\t]+)[0-9][0-9]?
+ :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?
+ (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
+ list(u'0123456789')),
+ ([(1, 2), (1, 1)],
+ u'tag:yaml.org,2002:value',
+ re.compile(u'^(?:=)$'),
+ [u'=']),
+ # The following resolver is only for documentation purposes. It cannot work
+ # because plain scalars cannot start with '!', '&', or '*'.
+ ([(1, 2), (1, 1)],
+ u'tag:yaml.org,2002:yaml',
+ re.compile(u'^(?:!|&|\\*)$'),
+ list(u'!&*')),
+]
+
+
+class VersionedResolver(BaseResolver):
+ """
+ contrary to the "normal" resolver, the smart resolver delays loading
+ the pattern matching rules. That way it can decide to load 1.1 rules
+ or the (default) 1.2 that no longer support octal without 0o, sexagesimals
+ and Yes/No/On/Off booleans.
+ """
+
+ def __init__(self, version=None):
+ BaseResolver.__init__(self)
+ self._loader_version = self.get_loader_version(version)
+ self._version_implicit_resolver = {}
+
+ def add_version_implicit_resolver(self, version, tag, regexp, first):
+ if first is None:
+ first = [None]
+ impl_resolver = self._version_implicit_resolver.setdefault(version, {})
+ for ch in first:
+ impl_resolver.setdefault(ch, []).append((tag, regexp))
+
+ def get_loader_version(self, version):
+ if version is None or isinstance(version, tuple):
+ return version
+ if isinstance(version, list):
+ return tuple(version)
+ # assume string
+ return tuple(map(int, version.split(u'.')))
+
+ @property
+ def resolver(self):
+ """
+ select the resolver based on the version we are parsing
+ """
+ version = self.processing_version
+ if version not in self._version_implicit_resolver:
+ for x in implicit_resolvers:
+ if version in x[0]:
+ self.add_version_implicit_resolver(version, x[1], x[2], x[3])
+ return self._version_implicit_resolver[version]
+
+ def resolve(self, kind, value, implicit):
+ if kind is ScalarNode and implicit[0]:
+ if value == u'':
+ resolvers = self.resolver.get(u'', [])
+ else:
+ resolvers = self.resolver.get(value[0], [])
+ resolvers += self.resolver.get(None, [])
+ for tag, regexp in resolvers:
+ if regexp.match(value):
+ return tag
+ implicit = implicit[1]
+ if self.yaml_path_resolvers:
+ exact_paths = self.resolver_exact_paths[-1]
+ if kind in exact_paths:
+ return exact_paths[kind]
+ if None in exact_paths:
+ return exact_paths[None]
+ if kind is ScalarNode:
+ return self.DEFAULT_SCALAR_TAG
+ elif kind is SequenceNode:
+ return self.DEFAULT_SEQUENCE_TAG
+ elif kind is MappingNode:
+ return self.DEFAULT_MAPPING_TAG
+
+ @property
+ def processing_version(self):
+ try:
+ version = self.yaml_version
+ except AttributeError:
+ # dumping
+ version = self.use_version
+ if version is None:
+ version = self._loader_version
+ if version is None:
+ version = _DEFAULT_VERSION
+ return version
diff --git a/lib/spack/external/ruamel/yaml/scalarstring.py b/lib/spack/external/ruamel/yaml/scalarstring.py
new file mode 100644
index 0000000000..d3abaff4db
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/scalarstring.py
@@ -0,0 +1,60 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+__all__ = ["ScalarString", "PreservedScalarString", "SingleQuotedScalarString",
+ "DoubleQuotedScalarString"]
+
+try:
+ from .compat import text_type
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.compat import text_type
+
+
+class ScalarString(text_type):
+ def __new__(cls, *args, **kw):
+ return text_type.__new__(cls, *args, **kw)
+
+
+class PreservedScalarString(ScalarString):
+ def __new__(cls, value):
+ return ScalarString.__new__(cls, value)
+
+
+class SingleQuotedScalarString(ScalarString):
+ def __new__(cls, value):
+ return ScalarString.__new__(cls, value)
+
+
+class DoubleQuotedScalarString(ScalarString):
+ def __new__(cls, value):
+ return ScalarString.__new__(cls, value)
+
+
+def preserve_literal(s):
+ return PreservedScalarString(s.replace('\r\n', '\n').replace('\r', '\n'))
+
+
+def walk_tree(base):
+ """
+ the routine here walks over a simple yaml tree (recursing in
+ dict values and list items) and converts strings that
+ have multiple lines to literal scalars
+ """
+ from ruamel.yaml.compat import string_types
+
+ if isinstance(base, dict):
+ for k in base:
+ v = base[k]
+ if isinstance(v, string_types) and '\n' in v:
+ base[k] = preserve_literal(v)
+ else:
+ walk_tree(v)
+ elif isinstance(base, list):
+ for idx, elem in enumerate(base):
+ if isinstance(elem, string_types) and '\n' in elem:
+ print(elem)
+ base[idx] = preserve_literal(elem)
+ else:
+ walk_tree(elem)
diff --git a/lib/spack/external/yaml/lib/yaml/scanner.py b/lib/spack/external/ruamel/yaml/scanner.py
index 834f662a4c..61feb34043 100644
--- a/lib/spack/external/yaml/lib/yaml/scanner.py
+++ b/lib/spack/external/ruamel/yaml/scanner.py
@@ -1,3 +1,7 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from __future__ import print_function
# Scanner produces tokens of the following types:
# STREAM-START
@@ -21,17 +25,28 @@
# TAG(value)
# SCALAR(value, plain, style)
#
+# RoundTripScanner
+# COMMENT(value)
+#
# Read comments in the Scanner code for more details.
#
-__all__ = ['Scanner', 'ScannerError']
+__all__ = ['Scanner', 'RoundTripScanner', 'ScannerError']
+
+try:
+ from .error import MarkedYAMLError
+ from .tokens import * # NOQA
+ from .compat import utf8, unichr, PY3
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import MarkedYAMLError
+ from ruamel.yaml.tokens import * # NOQA
+ from ruamel.yaml.compat import utf8, unichr, PY3
-from error import MarkedYAMLError
-from tokens import *
class ScannerError(MarkedYAMLError):
pass
+
class SimpleKey(object):
# See below simple keys treatment.
@@ -43,6 +58,7 @@ class SimpleKey(object):
self.column = column
self.mark = mark
+
class Scanner(object):
def __init__(self):
@@ -52,9 +68,9 @@ class Scanner(object):
# input data to Unicode. It also adds NUL to the end.
#
# Reader supports the following methods
- # self.peek(i=0) # peek the next i-th character
- # self.prefix(l=1) # peek the next l characters
- # self.forward(l=1) # read the next l characters and move the pointer.
+ # self.peek(i=0) # peek the next i-th character
+ # self.prefix(l=1) # peek the next l characters
+ # self.forward(l=1) # read the next l characters and move the pointer
# Had we reached the end of the stream?
self.done = False
@@ -153,7 +169,10 @@ class Scanner(object):
def fetch_more_tokens(self):
# Eat whitespaces and comments until we reach the next token.
- self.scan_to_next_token()
+ comment = self.scan_to_next_token()
+
+ if comment is not None: # never happens for base scanner
+ return self.fetch_comment(comment)
# Remove obsolete possible simple keys.
self.stale_possible_simple_keys()
@@ -182,8 +201,8 @@ class Scanner(object):
return self.fetch_document_end()
# TODO: support for BOM within a stream.
- #if ch == u'\uFEFF':
- # return self.fetch_bom() <-- issue BOMToken
+ # if ch == u'\uFEFF':
+ # return self.fetch_bom() <-- issue BOMToken
# Note: the order of the following checks is NOT significant.
@@ -253,8 +272,8 @@ class Scanner(object):
# No? It's an error. Let's produce a nice error message.
raise ScannerError("while scanning for the next token", None,
- "found character %r that cannot start any token"
- % ch.encode('utf-8'), self.get_mark())
+ "found character %r that cannot start any token"
+ % utf8(ch), self.get_mark())
# Simple keys treatment.
@@ -280,13 +299,14 @@ class Scanner(object):
# - should be no longer than 1024 characters.
# Disabling this procedure will allow simple keys of any length and
# height (may cause problems if indentation is broken though).
- for level in self.possible_simple_keys.keys():
+ for level in list(self.possible_simple_keys):
key = self.possible_simple_keys[level]
if key.line != self.line \
or self.index-key.index > 1024:
if key.required:
- raise ScannerError("while scanning a simple key", key.mark,
- "could not find expected ':'", self.get_mark())
+ raise ScannerError(
+ "while scanning a simple key", key.mark,
+ "could not find expected ':'", self.get_mark())
del self.possible_simple_keys[level]
def save_possible_simple_key(self):
@@ -302,18 +322,20 @@ class Scanner(object):
if self.allow_simple_key:
self.remove_possible_simple_key()
token_number = self.tokens_taken+len(self.tokens)
- key = SimpleKey(token_number, required,
- self.index, self.line, self.column, self.get_mark())
+ key = SimpleKey(
+ token_number, required,
+ self.index, self.line, self.column, self.get_mark())
self.possible_simple_keys[self.flow_level] = key
def remove_possible_simple_key(self):
# Remove the saved possible key position at the current flow level.
if self.flow_level in self.possible_simple_keys:
key = self.possible_simple_keys[self.flow_level]
-
+
if key.required:
- raise ScannerError("while scanning a simple key", key.mark,
- "could not find expected ':'", self.get_mark())
+ raise ScannerError(
+ "while scanning a simple key", key.mark,
+ "could not find expected ':'", self.get_mark())
del self.possible_simple_keys[self.flow_level]
@@ -321,16 +343,17 @@ class Scanner(object):
def unwind_indent(self, column):
- ## In flow context, tokens should respect indentation.
- ## Actually the condition should be `self.indent >= column` according to
- ## the spec. But this condition will prohibit intuitively correct
- ## constructions such as
- ## key : {
- ## }
- #if self.flow_level and self.indent > column:
- # raise ScannerError(None, None,
- # "invalid intendation or unclosed '[' or '{'",
- # self.get_mark())
+ # In flow context, tokens should respect indentation.
+ # Actually the condition should be `self.indent >= column` according to
+ # the spec. But this condition will prohibit intuitively correct
+ # constructions such as
+ # key : {
+ # }
+ # ####
+ # if self.flow_level and self.indent > column:
+ # raise ScannerError(None, None,
+ # "invalid intendation or unclosed '[' or '{'",
+ # self.get_mark())
# In the flow context, indentation is ignored. We make the scanner less
# restrictive then specification requires.
@@ -359,11 +382,10 @@ class Scanner(object):
# Read the token.
mark = self.get_mark()
-
+
# Add STREAM-START.
self.tokens.append(StreamStartToken(mark, mark,
- encoding=self.encoding))
-
+ encoding=self.encoding))
def fetch_stream_end(self):
@@ -377,7 +399,7 @@ class Scanner(object):
# Read the token.
mark = self.get_mark()
-
+
# Add STREAM-END.
self.tokens.append(StreamEndToken(mark, mark))
@@ -385,7 +407,7 @@ class Scanner(object):
self.done = True
def fetch_directive(self):
-
+
# Set the current intendation to -1.
self.unwind_indent(-1)
@@ -486,8 +508,8 @@ class Scanner(object):
# Are we allowed to start a new entry?
if not self.allow_simple_key:
raise ScannerError(None, None,
- "sequence entries are not allowed here",
- self.get_mark())
+ "sequence entries are not allowed here",
+ self.get_mark())
# We may need to add BLOCK-SEQUENCE-START.
if self.add_indent(self.column):
@@ -512,15 +534,15 @@ class Scanner(object):
self.tokens.append(BlockEntryToken(start_mark, end_mark))
def fetch_key(self):
-
+
# Block context needs additional checks.
if not self.flow_level:
# Are we allowed to start a key (not nessesary a simple)?
if not self.allow_simple_key:
raise ScannerError(None, None,
- "mapping keys are not allowed here",
- self.get_mark())
+ "mapping keys are not allowed here",
+ self.get_mark())
# We may need to add BLOCK-MAPPING-START.
if self.add_indent(self.column):
@@ -543,26 +565,26 @@ class Scanner(object):
# Do we determine a simple key?
if self.flow_level in self.possible_simple_keys:
-
# Add KEY.
key = self.possible_simple_keys[self.flow_level]
del self.possible_simple_keys[self.flow_level]
self.tokens.insert(key.token_number-self.tokens_taken,
- KeyToken(key.mark, key.mark))
+ KeyToken(key.mark, key.mark))
# If this key starts a new block mapping, we need to add
# BLOCK-MAPPING-START.
if not self.flow_level:
if self.add_indent(key.column):
- self.tokens.insert(key.token_number-self.tokens_taken,
- BlockMappingStartToken(key.mark, key.mark))
+ self.tokens.insert(
+ key.token_number-self.tokens_taken,
+ BlockMappingStartToken(key.mark, key.mark))
# There cannot be two simple keys one after another.
self.allow_simple_key = False
# It must be a part of a complex key.
else:
-
+
# Block context needs additional checks.
# (Do we really need them? They will be catched by the parser
# anyway.)
@@ -572,8 +594,8 @@ class Scanner(object):
# we can start a simple key.
if not self.allow_simple_key:
raise ScannerError(None, None,
- "mapping values are not allowed here",
- self.get_mark())
+ "mapping values are not allowed here",
+ self.get_mark())
# If this value starts a new block mapping, we need to add
# BLOCK-MAPPING-START. It will be detected as an error later by
@@ -726,7 +748,6 @@ class Scanner(object):
return self.peek(1) in u'\0 \t\r\n\x85\u2028\u2029'
def check_plain(self):
-
# A plain scalar may start with any non-space character except:
# '-', '?', ':', ',', '[', ']', '{', '}',
# '#', '&', '*', '!', '|', '>', '\'', '\"',
@@ -740,9 +761,9 @@ class Scanner(object):
# '-' character) because we want the flow context to be space
# independent.
ch = self.peek()
- return ch not in u'\0 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'\"%@`' \
- or (self.peek(1) not in u'\0 \t\r\n\x85\u2028\u2029'
- and (ch == u'-' or (not self.flow_level and ch in u'?:')))
+ return ch not in u'\0 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'\"%@`' or \
+ (self.peek(1) not in u'\0 \t\r\n\x85\u2028\u2029' and
+ (ch == u'-' or (not self.flow_level and ch in u'?:')))
# Scanners.
@@ -804,21 +825,23 @@ class Scanner(object):
# See the specification for details.
length = 0
ch = self.peek(length)
- while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
- or ch in u'-_':
+ while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
+ or ch in u'-_:.':
length += 1
ch = self.peek(length)
if not length:
- raise ScannerError("while scanning a directive", start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning a directive", start_mark,
+ "expected alphabetic or numeric character, but found %r"
+ % utf8(ch), self.get_mark())
value = self.prefix(length)
self.forward(length)
ch = self.peek()
if ch not in u'\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning a directive", start_mark,
+ "expected alphabetic or numeric character, but found %r"
+ % utf8(ch), self.get_mark())
return value
def scan_yaml_directive_value(self, start_mark):
@@ -827,26 +850,29 @@ class Scanner(object):
self.forward()
major = self.scan_yaml_directive_number(start_mark)
if self.peek() != '.':
- raise ScannerError("while scanning a directive", start_mark,
- "expected a digit or '.', but found %r"
- % self.peek().encode('utf-8'),
- self.get_mark())
+ raise ScannerError(
+ "while scanning a directive", start_mark,
+ "expected a digit or '.', but found %r"
+ % utf8(self.peek()),
+ self.get_mark())
self.forward()
minor = self.scan_yaml_directive_number(start_mark)
if self.peek() not in u'\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected a digit or ' ', but found %r"
- % self.peek().encode('utf-8'),
- self.get_mark())
+ raise ScannerError(
+ "while scanning a directive", start_mark,
+ "expected a digit or ' ', but found %r"
+ % utf8(self.peek()),
+ self.get_mark())
return (major, minor)
def scan_yaml_directive_number(self, start_mark):
# See the specification for details.
ch = self.peek()
if not (u'0' <= ch <= u'9'):
- raise ScannerError("while scanning a directive", start_mark,
- "expected a digit, but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ raise ScannerError(
+ "while scanning a directive", start_mark,
+ "expected a digit, but found %r" % utf8(ch),
+ self.get_mark())
length = 0
while u'0' <= self.peek(length) <= u'9':
length += 1
@@ -870,8 +896,8 @@ class Scanner(object):
ch = self.peek()
if ch != u' ':
raise ScannerError("while scanning a directive", start_mark,
- "expected ' ', but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ "expected ' ', but found %r" % utf8(ch),
+ self.get_mark())
return value
def scan_tag_directive_prefix(self, start_mark):
@@ -880,8 +906,8 @@ class Scanner(object):
ch = self.peek()
if ch not in u'\0 \r\n\x85\u2028\u2029':
raise ScannerError("while scanning a directive", start_mark,
- "expected ' ', but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ "expected ' ', but found %r" % utf8(ch),
+ self.get_mark())
return value
def scan_directive_ignored_line(self, start_mark):
@@ -893,9 +919,10 @@ class Scanner(object):
self.forward()
ch = self.peek()
if ch not in u'\0\r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected a comment or a line break, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning a directive", start_mark,
+ "expected a comment or a line break, but found %r"
+ % utf8(ch), self.get_mark())
self.scan_line_break()
def scan_anchor(self, TokenClass):
@@ -916,21 +943,23 @@ class Scanner(object):
self.forward()
length = 0
ch = self.peek(length)
- while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
+ while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
or ch in u'-_':
length += 1
ch = self.peek(length)
if not length:
- raise ScannerError("while scanning an %s" % name, start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning an %s" % name, start_mark,
+ "expected alphabetic or numeric character, but found %r"
+ % utf8(ch), self.get_mark())
value = self.prefix(length)
self.forward(length)
ch = self.peek()
if ch not in u'\0 \t\r\n\x85\u2028\u2029?:,]}%@`':
- raise ScannerError("while scanning an %s" % name, start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning an %s" % name, start_mark,
+ "expected alphabetic or numeric character, but found %r"
+ % utf8(ch), self.get_mark())
end_mark = self.get_mark()
return TokenClass(value, start_mark, end_mark)
@@ -943,9 +972,10 @@ class Scanner(object):
self.forward(2)
suffix = self.scan_tag_uri('tag', start_mark)
if self.peek() != u'>':
- raise ScannerError("while parsing a tag", start_mark,
- "expected '>', but found %r" % self.peek().encode('utf-8'),
- self.get_mark())
+ raise ScannerError(
+ "while parsing a tag", start_mark,
+ "expected '>', but found %r" % utf8(self.peek()),
+ self.get_mark())
self.forward()
elif ch in u'\0 \t\r\n\x85\u2028\u2029':
handle = None
@@ -970,8 +1000,8 @@ class Scanner(object):
ch = self.peek()
if ch not in u'\0 \r\n\x85\u2028\u2029':
raise ScannerError("while scanning a tag", start_mark,
- "expected ' ', but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ "expected ' ', but found %r" % utf8(ch),
+ self.get_mark())
value = (handle, suffix)
end_mark = self.get_mark()
return TagToken(value, start_mark, end_mark)
@@ -1020,37 +1050,49 @@ class Scanner(object):
# Unfortunately, folding rules are ambiguous.
#
# This is the folding according to the specification:
-
+
if folded and line_break == u'\n' \
and leading_non_space and self.peek() not in u' \t':
if not breaks:
chunks.append(u' ')
else:
chunks.append(line_break)
-
+
# This is Clark Evans's interpretation (also in the spec
# examples):
#
- #if folded and line_break == u'\n':
- # if not breaks:
- # if self.peek() not in ' \t':
- # chunks.append(u' ')
- # else:
- # chunks.append(line_break)
- #else:
- # chunks.append(line_break)
+ # if folded and line_break == u'\n':
+ # if not breaks:
+ # if self.peek() not in ' \t':
+ # chunks.append(u' ')
+ # else:
+ # chunks.append(line_break)
+ # else:
+ # chunks.append(line_break)
else:
break
- # Chomp the tail.
- if chomping is not False:
+ # Process trailing line breaks. The 'chomping' setting determines
+ # whether they are included in the value.
+ comment = []
+ if chomping in [None, True]:
chunks.append(line_break)
if chomping is True:
chunks.extend(breaks)
+ elif chomping in [None, False]:
+ comment.extend(breaks)
# We are done.
- return ScalarToken(u''.join(chunks), False, start_mark, end_mark,
- style)
+ token = ScalarToken(u''.join(chunks), False, start_mark, end_mark,
+ style)
+ if len(comment) > 0:
+ # Keep track of the trailing whitespace as a comment token, if
+ # isn't all included in the actual value.
+ comment_end_mark = self.get_mark()
+ comment = CommentToken(''.join(comment), end_mark,
+ comment_end_mark)
+ token.add_post_comment(comment)
+ return token
def scan_block_scalar_indicators(self, start_mark):
# See the specification for details.
@@ -1067,16 +1109,19 @@ class Scanner(object):
if ch in u'0123456789':
increment = int(ch)
if increment == 0:
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected indentation indicator in the range 1-9, but found 0",
- self.get_mark())
+ raise ScannerError(
+ "while scanning a block scalar", start_mark,
+ "expected indentation indicator in the range 1-9, "
+ "but found 0", self.get_mark())
self.forward()
elif ch in u'0123456789':
increment = int(ch)
if increment == 0:
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected indentation indicator in the range 1-9, but found 0",
- self.get_mark())
+ raise ScannerError(
+ "while scanning a block scalar", start_mark,
+ "expected indentation indicator in the range 1-9, "
+ "but found 0",
+ self.get_mark())
self.forward()
ch = self.peek()
if ch in u'+-':
@@ -1087,9 +1132,10 @@ class Scanner(object):
self.forward()
ch = self.peek()
if ch not in u'\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected chomping or indentation indicators, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning a block scalar", start_mark,
+ "expected chomping or indentation indicators, but found %r"
+ % utf8(ch), self.get_mark())
return chomping, increment
def scan_block_scalar_ignored_line(self, start_mark):
@@ -1101,9 +1147,10 @@ class Scanner(object):
self.forward()
ch = self.peek()
if ch not in u'\0\r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected a comment or a line break, but found %r"
- % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning a block scalar", start_mark,
+ "expected a comment or a line break, but found %r"
+ % utf8(ch), self.get_mark())
self.scan_line_break()
def scan_block_scalar_indentation(self):
@@ -1156,7 +1203,7 @@ class Scanner(object):
self.forward()
end_mark = self.get_mark()
return ScalarToken(u''.join(chunks), False, start_mark, end_mark,
- style)
+ style)
ESCAPE_REPLACEMENTS = {
u'0': u'\0',
@@ -1171,6 +1218,7 @@ class Scanner(object):
u'e': u'\x1B',
u' ': u'\x20',
u'\"': u'\"',
+ u'/': u'/', # as per http://www.json.org/
u'\\': u'\\',
u'N': u'\x85',
u'_': u'\xA0',
@@ -1212,18 +1260,24 @@ class Scanner(object):
self.forward()
for k in range(length):
if self.peek(k) not in u'0123456789ABCDEFabcdef':
- raise ScannerError("while scanning a double-quoted scalar", start_mark,
- "expected escape sequence of %d hexdecimal numbers, but found %r" %
- (length, self.peek(k).encode('utf-8')), self.get_mark())
+ raise ScannerError(
+ "while scanning a double-quoted scalar",
+ start_mark,
+ "expected escape sequence of %d hexdecimal "
+ "numbers, but found %r" %
+ (length, utf8(self.peek(k))), self.get_mark())
code = int(self.prefix(length), 16)
chunks.append(unichr(code))
self.forward(length)
elif ch in u'\r\n\x85\u2028\u2029':
self.scan_line_break()
- chunks.extend(self.scan_flow_scalar_breaks(double, start_mark))
+ chunks.extend(self.scan_flow_scalar_breaks(
+ double, start_mark))
else:
- raise ScannerError("while scanning a double-quoted scalar", start_mark,
- "found unknown escape character %r" % ch.encode('utf-8'), self.get_mark())
+ raise ScannerError(
+ "while scanning a double-quoted scalar", start_mark,
+ "found unknown escape character %r" % utf8(ch),
+ self.get_mark())
else:
return chunks
@@ -1237,8 +1291,9 @@ class Scanner(object):
self.forward(length)
ch = self.peek()
if ch == u'\0':
- raise ScannerError("while scanning a quoted scalar", start_mark,
- "found unexpected end of stream", self.get_mark())
+ raise ScannerError(
+ "while scanning a quoted scalar", start_mark,
+ "found unexpected end of stream", self.get_mark())
elif ch in u'\r\n\x85\u2028\u2029':
line_break = self.scan_line_break()
breaks = self.scan_flow_scalar_breaks(double, start_mark)
@@ -1260,8 +1315,10 @@ class Scanner(object):
prefix = self.prefix(3)
if (prefix == u'---' or prefix == u'...') \
and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a quoted scalar", start_mark,
- "found unexpected document separator", self.get_mark())
+ raise ScannerError("while scanning a quoted scalar",
+ start_mark,
+ "found unexpected document separator",
+ self.get_mark())
while self.peek() in u' \t':
self.forward()
if self.peek() in u'\r\n\x85\u2028\u2029':
@@ -1281,8 +1338,8 @@ class Scanner(object):
indent = self.indent+1
# We allow zero indentation for scalars, but then we need to check for
# document separators at the beginning of the line.
- #if indent == 0:
- # indent = 1
+ # if indent == 0:
+ # indent = 1
spaces = []
while True:
length = 0
@@ -1290,19 +1347,22 @@ class Scanner(object):
break
while True:
ch = self.peek(length)
- if ch in u'\0 \t\r\n\x85\u2028\u2029' \
- or (not self.flow_level and ch == u':' and
- self.peek(length+1) in u'\0 \t\r\n\x85\u2028\u2029') \
- or (self.flow_level and ch in u',:?[]{}'):
+ if ch in u'\0 \t\r\n\x85\u2028\u2029' \
+ or (not self.flow_level and ch == u':' and
+ self.peek(length+1) in u'\0 \t\r\n\x85\u2028\u2029') \
+ or (self.flow_level and ch in u',:?[]{}'):
break
length += 1
# It's not clear what we should do with ':' in the flow context.
- if (self.flow_level and ch == u':'
- and self.peek(length+1) not in u'\0 \t\r\n\x85\u2028\u2029,[]{}'):
+ if (self.flow_level and ch == u':' and
+ self.peek(length+1) not in u'\0 \t\r\n\x85\u2028\u2029,[]{}'):
self.forward(length)
- raise ScannerError("while scanning a plain scalar", start_mark,
+ raise ScannerError(
+ "while scanning a plain scalar", start_mark,
"found unexpected ':'", self.get_mark(),
- "Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details.")
+ "Please check "
+ "http://pyyaml.org/wiki/YAMLColonInFlowContext "
+ "for details.")
if length == 0:
break
self.allow_simple_key = False
@@ -1314,7 +1374,13 @@ class Scanner(object):
if not spaces or self.peek() == u'#' \
or (not self.flow_level and self.column < indent):
break
- return ScalarToken(u''.join(chunks), True, start_mark, end_mark)
+
+ token = ScalarToken(u''.join(chunks), True, start_mark, end_mark)
+ if spaces and spaces[0] == '\n':
+ # Create a comment token to preserve the trailing line breaks.
+ comment = CommentToken(''.join(spaces) + '\n', start_mark, end_mark)
+ token.add_post_comment(comment)
+ return token
def scan_plain_spaces(self, indent, start_mark):
# See the specification for details.
@@ -1342,7 +1408,7 @@ class Scanner(object):
breaks.append(self.scan_line_break())
prefix = self.prefix(3)
if (prefix == u'---' or prefix == u'...') \
- and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
+ and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
return
if line_break != u'\n':
chunks.append(line_break)
@@ -1360,20 +1426,21 @@ class Scanner(object):
ch = self.peek()
if ch != u'!':
raise ScannerError("while scanning a %s" % name, start_mark,
- "expected '!', but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ "expected '!', but found %r" % utf8(ch),
+ self.get_mark())
length = 1
ch = self.peek(length)
if ch != u' ':
- while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
- or ch in u'-_':
+ while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' \
+ or u'a' <= ch <= u'z' \
+ or ch in u'-_':
length += 1
ch = self.peek(length)
if ch != u'!':
self.forward(length)
raise ScannerError("while scanning a %s" % name, start_mark,
- "expected '!', but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ "expected '!', but found %r" % utf8(ch),
+ self.get_mark())
length += 1
value = self.prefix(length)
self.forward(length)
@@ -1401,27 +1468,36 @@ class Scanner(object):
length = 0
if not chunks:
raise ScannerError("while parsing a %s" % name, start_mark,
- "expected URI, but found %r" % ch.encode('utf-8'),
- self.get_mark())
+ "expected URI, but found %r" % utf8(ch),
+ self.get_mark())
return u''.join(chunks)
def scan_uri_escapes(self, name, start_mark):
# See the specification for details.
- bytes = []
+ code_bytes = []
mark = self.get_mark()
while self.peek() == u'%':
self.forward()
for k in range(2):
if self.peek(k) not in u'0123456789ABCDEFabcdef':
- raise ScannerError("while scanning a %s" % name, start_mark,
- "expected URI escape sequence of 2 hexdecimal numbers, but found %r" %
- (self.peek(k).encode('utf-8')), self.get_mark())
- bytes.append(chr(int(self.prefix(2), 16)))
+ raise ScannerError(
+ "while scanning a %s" % name, start_mark,
+ "expected URI escape sequence of 2 hexdecimal numbers,"
+ " but found %r"
+ % utf8(self.peek(k)), self.get_mark())
+ if PY3:
+ code_bytes.append(int(self.prefix(2), 16))
+ else:
+ code_bytes.append(chr(int(self.prefix(2), 16)))
self.forward(2)
try:
- value = unicode(''.join(bytes), 'utf-8')
- except UnicodeDecodeError, exc:
- raise ScannerError("while scanning a %s" % name, start_mark, str(exc), mark)
+ if PY3:
+ value = bytes(code_bytes).decode('utf-8')
+ else:
+ value = unicode(''.join(code_bytes), 'utf-8')
+ except UnicodeDecodeError as exc:
+ raise ScannerError("while scanning a %s" % name, start_mark,
+ str(exc), mark)
return value
def scan_line_break(self):
@@ -1445,9 +1521,141 @@ class Scanner(object):
return ch
return u''
-#try:
-# import psyco
-# psyco.bind(Scanner)
-#except ImportError:
-# pass
+class RoundTripScanner(Scanner):
+ def check_token(self, *choices):
+ # Check if the next token is one of the given types.
+ while self.need_more_tokens():
+ self.fetch_more_tokens()
+ self._gather_comments()
+ if self.tokens:
+ if not choices:
+ return True
+ for choice in choices:
+ if isinstance(self.tokens[0], choice):
+ return True
+ return False
+
+ def peek_token(self):
+ # Return the next token, but do not delete if from the queue.
+ while self.need_more_tokens():
+ self.fetch_more_tokens()
+ self._gather_comments()
+ if self.tokens:
+ return self.tokens[0]
+
+ def _gather_comments(self):
+ """combine multiple comment lines"""
+ comments = []
+ if not self.tokens:
+ return comments
+ if isinstance(self.tokens[0], CommentToken):
+ comment = self.tokens.pop(0)
+ self.tokens_taken += 1
+ # print('################ dropping', comment)
+ comments.append(comment)
+ while self.need_more_tokens():
+ self.fetch_more_tokens()
+ if not self.tokens:
+ return comments
+ if isinstance(self.tokens[0], CommentToken):
+ self.tokens_taken += 1
+ comment = self.tokens.pop(0)
+ # print 'dropping2', comment
+ comments.append(comment)
+ if len(comments) >= 1:
+ # print(' len', len(comments), comments)
+ # print(' com', comments[0], comments[0].start_mark.line)
+ # print(' tok', self.tokens[0].end_mark.line)
+ self.tokens[0].add_pre_comments(comments)
+ # pull in post comment on e.g. ':'
+ if not self.done and len(self.tokens) < 2:
+ self.fetch_more_tokens()
+
+ def get_token(self):
+ # Return the next token.
+ while self.need_more_tokens():
+ self.fetch_more_tokens()
+ self._gather_comments()
+ if self.tokens:
+ # only add post comment to single line tokens:
+ # scalar, value token. FlowXEndToken, otherwise
+ # hidden streamtokens could get them (leave them and they will be
+ # pre comments for the next map/seq
+ if len(self.tokens) > 1 and \
+ isinstance(self.tokens[0], (
+ ScalarToken,
+ ValueToken,
+ FlowSequenceEndToken,
+ FlowMappingEndToken,
+ )) and \
+ isinstance(self.tokens[1], CommentToken) and \
+ self.tokens[0].end_mark.line == self.tokens[1].start_mark.line:
+ self.tokens_taken += 1
+ self.tokens[0].add_post_comment(self.tokens.pop(1))
+ self.tokens_taken += 1
+ return self.tokens.pop(0)
+
+ def fetch_comment(self, comment): # XXXX
+ value, start_mark, end_mark = comment
+ self.tokens.append(CommentToken(value, start_mark, end_mark))
+
+ # scanner
+
+ def scan_to_next_token(self):
+ # We ignore spaces, line breaks and comments.
+ # If we find a line break in the block context, we set the flag
+ # `allow_simple_key` on.
+ # The byte order mark is stripped if it's the first character in the
+ # stream. We do not yet support BOM inside the stream as the
+ # specification requires. Any such mark will be considered as a part
+ # of the document.
+ #
+ # TODO: We need to make tab handling rules more sane. A good rule is
+ # Tabs cannot precede tokens
+ # BLOCK-SEQUENCE-START, BLOCK-MAPPING-START, BLOCK-END,
+ # KEY(block), VALUE(block), BLOCK-ENTRY
+ # So the checking code is
+ # if <TAB>:
+ # self.allow_simple_keys = False
+ # We also need to add the check for `allow_simple_keys == True` to
+ # `unwind_indent` before issuing BLOCK-END.
+ # Scanners for block, flow, and plain scalars need to be modified.
+
+ if self.index == 0 and self.peek() == u'\uFEFF':
+ self.forward()
+ found = False
+ while not found:
+ while self.peek() == u' ':
+ self.forward()
+ ch = self.peek()
+ if ch == u'#':
+ start_mark = self.get_mark()
+ comment = ch
+ self.forward()
+ while ch not in u'\0\r\n\x85\u2028\u2029':
+ ch = self.peek()
+ if ch == u'\0': # don't gobble the end-of-stream character
+ break
+ comment += ch
+ self.forward()
+ # gather any blank lines following the comment too
+ ch = self.scan_line_break()
+ while len(ch) > 0:
+ comment += ch
+ ch = self.scan_line_break()
+ end_mark = self.get_mark()
+ if not self.flow_level:
+ self.allow_simple_key = True
+ return comment, start_mark, end_mark
+ if self.scan_line_break():
+ if not self.flow_level:
+ self.allow_simple_key = True
+ else:
+ found = True
+
+# try:
+# import psyco
+# psyco.bind(Scanner)
+# except ImportError:
+# pass
diff --git a/lib/spack/external/ruamel/yaml/serializer.py b/lib/spack/external/ruamel/yaml/serializer.py
new file mode 100644
index 0000000000..60dd5170ca
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/serializer.py
@@ -0,0 +1,178 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+
+import re
+
+try:
+ from .error import YAMLError
+ from .compat import nprint, DBG_NODE, dbg, string_types
+except (ImportError, ValueError): # for Jython
+ from ruamel.yaml.error import YAMLError
+ from ruamel.yaml.compat import nprint, DBG_NODE, dbg, string_types
+
+from ruamel.yaml.events import (
+ StreamStartEvent, StreamEndEvent, MappingStartEvent, MappingEndEvent,
+ SequenceStartEvent, SequenceEndEvent, AliasEvent, ScalarEvent,
+ DocumentStartEvent, DocumentEndEvent,
+)
+from ruamel.yaml.nodes import (
+ MappingNode, ScalarNode, SequenceNode,
+)
+
+__all__ = ['Serializer', 'SerializerError']
+
+
+class SerializerError(YAMLError):
+ pass
+
+
+class Serializer(object):
+
+ # 'id' and 3+ numbers, but not 000
+ ANCHOR_TEMPLATE = u'id%03d'
+ ANCHOR_RE = re.compile(u'id(?!000$)\\d{3,}')
+
+ def __init__(self, encoding=None, explicit_start=None, explicit_end=None,
+ version=None, tags=None):
+ self.use_encoding = encoding
+ self.use_explicit_start = explicit_start
+ self.use_explicit_end = explicit_end
+ if isinstance(version, string_types):
+ self.use_version = tuple(map(int, version.split('.')))
+ else:
+ self.use_version = version
+ self.use_tags = tags
+ self.serialized_nodes = {}
+ self.anchors = {}
+ self.last_anchor_id = 0
+ self.closed = None
+ self._templated_id = None
+
+ def open(self):
+ if self.closed is None:
+ self.emit(StreamStartEvent(encoding=self.use_encoding))
+ self.closed = False
+ elif self.closed:
+ raise SerializerError("serializer is closed")
+ else:
+ raise SerializerError("serializer is already opened")
+
+ def close(self):
+ if self.closed is None:
+ raise SerializerError("serializer is not opened")
+ elif not self.closed:
+ self.emit(StreamEndEvent())
+ self.closed = True
+
+ # def __del__(self):
+ # self.close()
+
+ def serialize(self, node):
+ if dbg(DBG_NODE):
+ nprint('Serializing nodes')
+ node.dump()
+ if self.closed is None:
+ raise SerializerError("serializer is not opened")
+ elif self.closed:
+ raise SerializerError("serializer is closed")
+ self.emit(DocumentStartEvent(explicit=self.use_explicit_start,
+ version=self.use_version,
+ tags=self.use_tags))
+ self.anchor_node(node)
+ self.serialize_node(node, None, None)
+ self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
+ self.serialized_nodes = {}
+ self.anchors = {}
+ self.last_anchor_id = 0
+
+ def anchor_node(self, node):
+ if node in self.anchors:
+ if self.anchors[node] is None:
+ self.anchors[node] = self.generate_anchor(node)
+ else:
+ anchor = None
+ try:
+ if node.anchor.always_dump:
+ anchor = node.anchor.value
+ except:
+ pass
+ self.anchors[node] = anchor
+ if isinstance(node, SequenceNode):
+ for item in node.value:
+ self.anchor_node(item)
+ elif isinstance(node, MappingNode):
+ for key, value in node.value:
+ self.anchor_node(key)
+ self.anchor_node(value)
+
+ def generate_anchor(self, node):
+ try:
+ anchor = node.anchor.value
+ except:
+ anchor = None
+ if anchor is None:
+ self.last_anchor_id += 1
+ return self.ANCHOR_TEMPLATE % self.last_anchor_id
+ return anchor
+
+ def serialize_node(self, node, parent, index):
+ alias = self.anchors[node]
+ if node in self.serialized_nodes:
+ self.emit(AliasEvent(alias))
+ else:
+ self.serialized_nodes[node] = True
+ self.descend_resolver(parent, index)
+ if isinstance(node, ScalarNode):
+ # here check if the node.tag equals the one that would result from parsing
+ # if not equal quoting is necessary for strings
+ detected_tag = self.resolve(ScalarNode, node.value, (True, False))
+ default_tag = self.resolve(ScalarNode, node.value, (False, True))
+ implicit = (node.tag == detected_tag), (node.tag == default_tag)
+ self.emit(ScalarEvent(alias, node.tag, implicit, node.value,
+ style=node.style, comment=node.comment))
+ elif isinstance(node, SequenceNode):
+ implicit = (node.tag == self.resolve(SequenceNode, node.value, True))
+ comment = node.comment
+ # print('comment >>>>>>>>>>>>>.', comment, node.flow_style)
+ end_comment = None
+ seq_comment = None
+ if node.flow_style is True:
+ if comment: # eol comment on flow style sequence
+ seq_comment = comment[0]
+ # comment[0] = None
+ if comment and len(comment) > 2:
+ end_comment = comment[2]
+ else:
+ end_comment = None
+ self.emit(SequenceStartEvent(alias, node.tag, implicit,
+ flow_style=node.flow_style,
+ comment=node.comment))
+ index = 0
+ for item in node.value:
+ self.serialize_node(item, node, index)
+ index += 1
+ self.emit(SequenceEndEvent(comment=[seq_comment, end_comment]))
+ elif isinstance(node, MappingNode):
+ implicit = (node.tag == self.resolve(MappingNode, node.value, True))
+ comment = node.comment
+ end_comment = None
+ map_comment = None
+ if node.flow_style is True:
+ if comment: # eol comment on flow style sequence
+ map_comment = comment[0]
+ # comment[0] = None
+ if comment and len(comment) > 2:
+ end_comment = comment[2]
+ self.emit(MappingStartEvent(alias, node.tag, implicit,
+ flow_style=node.flow_style,
+ comment=node.comment))
+ for key, value in node.value:
+ self.serialize_node(key, node, None)
+ self.serialize_node(value, node, key)
+ self.emit(MappingEndEvent(comment=[map_comment, end_comment]))
+ self.ascend_resolver()
+
+
+def templated_id(s):
+ return Serializer.ANCHOR_RE.match(s)
diff --git a/lib/spack/external/ruamel/yaml/setup.cfg b/lib/spack/external/ruamel/yaml/setup.cfg
new file mode 100644
index 0000000000..861a9f5542
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/lib/spack/external/ruamel/yaml/tokens.py b/lib/spack/external/ruamel/yaml/tokens.py
new file mode 100644
index 0000000000..bd97785b82
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/tokens.py
@@ -0,0 +1,195 @@
+# # header
+# coding: utf-8
+
+
+class Token(object):
+ def __init__(self, start_mark, end_mark):
+ self.start_mark = start_mark
+ self.end_mark = end_mark
+
+ def __repr__(self):
+ attributes = [key for key in self.__dict__
+ if not key.endswith('_mark')]
+ attributes.sort()
+ arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
+ for key in attributes])
+ return '%s(%s)' % (self.__class__.__name__, arguments)
+
+ def add_post_comment(self, comment):
+ if not hasattr(self, '_comment'):
+ self._comment = [None, None]
+ self._comment[0] = comment
+
+ def add_pre_comments(self, comments):
+ if not hasattr(self, '_comment'):
+ self._comment = [None, None]
+ assert self._comment[1] is None
+ self._comment[1] = comments
+
+ def get_comment(self):
+ return getattr(self, '_comment', None)
+
+ @property
+ def comment(self):
+ return getattr(self, '_comment', None)
+
+ def move_comment(self, target):
+ """move a comment from this token to target (normally next token)
+ used to combine e.g. comments before a BlockEntryToken to the
+ ScalarToken that follows it
+ """
+ c = self.comment
+ if c is None:
+ return
+ # don't push beyond last element
+ if isinstance(target, StreamEndToken):
+ return
+ delattr(self, '_comment')
+ tc = target.comment
+ if not tc: # target comment, just insert
+ target._comment = c
+ return self
+ if c[0] and tc[0] or c[1] and tc[1]:
+ raise NotImplementedError('overlap in comment %r %r' % c, tc)
+ if c[0]:
+ tc[0] = c[0]
+ if c[1]:
+ tc[1] = c[1]
+ return self
+
+ def split_comment(self):
+ """ split the post part of a comment, and return it
+ as comment to be added. Delete second part if [None, None]
+ abc: # this goes to sequence
+ # this goes to first element
+ - first element
+ """
+ comment = self.comment
+ if comment is None or comment[0] is None:
+ return None # nothing to do
+ ret_val = [comment[0], None]
+ if comment[1] is None:
+ delattr(self, '_comment')
+ return ret_val
+
+
+# class BOMToken(Token):
+# id = '<byte order mark>'
+
+class DirectiveToken(Token):
+ id = '<directive>'
+
+ def __init__(self, name, value, start_mark, end_mark):
+ Token.__init__(self, start_mark, end_mark)
+ self.name = name
+ self.value = value
+
+
+class DocumentStartToken(Token):
+ id = '<document start>'
+
+
+class DocumentEndToken(Token):
+ id = '<document end>'
+
+
+class StreamStartToken(Token):
+ id = '<stream start>'
+
+ def __init__(self, start_mark=None, end_mark=None, encoding=None):
+ Token.__init__(self, start_mark, end_mark)
+ self.encoding = encoding
+
+
+class StreamEndToken(Token):
+ id = '<stream end>'
+
+
+class BlockSequenceStartToken(Token):
+ id = '<block sequence start>'
+
+
+class BlockMappingStartToken(Token):
+ id = '<block mapping start>'
+
+
+class BlockEndToken(Token):
+ id = '<block end>'
+
+
+class FlowSequenceStartToken(Token):
+ id = '['
+
+
+class FlowMappingStartToken(Token):
+ id = '{'
+
+
+class FlowSequenceEndToken(Token):
+ id = ']'
+
+
+class FlowMappingEndToken(Token):
+ id = '}'
+
+
+class KeyToken(Token):
+ id = '?'
+
+
+class ValueToken(Token):
+ id = ':'
+
+
+class BlockEntryToken(Token):
+ id = '-'
+
+
+class FlowEntryToken(Token):
+ id = ','
+
+
+class AliasToken(Token):
+ id = '<alias>'
+
+ def __init__(self, value, start_mark, end_mark):
+ Token.__init__(self, start_mark, end_mark)
+ self.value = value
+
+
+class AnchorToken(Token):
+ id = '<anchor>'
+
+ def __init__(self, value, start_mark, end_mark):
+ Token.__init__(self, start_mark, end_mark)
+ self.value = value
+
+
+class TagToken(Token):
+ id = '<tag>'
+
+ def __init__(self, value, start_mark, end_mark):
+ Token.__init__(self, start_mark, end_mark)
+ self.value = value
+
+
+class ScalarToken(Token):
+ id = '<scalar>'
+
+ def __init__(self, value, plain, start_mark, end_mark, style=None):
+ Token.__init__(self, start_mark, end_mark)
+ self.value = value
+ self.plain = plain
+ self.style = style
+
+
+class CommentToken(Token):
+ id = '<comment>'
+
+ def __init__(self, value, start_mark, end_mark):
+ Token.__init__(self, start_mark, end_mark)
+ self.value = value
+
+ def reset(self):
+ if hasattr(self, 'pre_done'):
+ delattr(self, 'pre_done')
diff --git a/lib/spack/external/ruamel/yaml/util.py b/lib/spack/external/ruamel/yaml/util.py
new file mode 100644
index 0000000000..afc46fb12a
--- /dev/null
+++ b/lib/spack/external/ruamel/yaml/util.py
@@ -0,0 +1,139 @@
+# coding: utf-8
+
+"""
+some helper functions that might be generally useful
+"""
+
+from __future__ import print_function
+from __future__ import absolute_import
+
+from .compat import text_type, binary_type
+from .main import round_trip_load
+
+
+# originally as comment
+# https://github.com/pre-commit/pre-commit/pull/211#issuecomment-186466605
+# if you use this in your code, I suggest adding a test in your test suite
+# that check this routines output against a known piece of your YAML
+# before upgrades to this code break your round-tripped YAML
+def load_yaml_guess_indent(stream, **kw):
+ """guess the indent and block sequence indent of yaml stream/string
+
+ returns round_trip_loaded stream, indent level, block sequence indent
+ - block sequence indent is the number of spaces before a dash relative to previous indent
+ - if there are no block sequences, indent is taken from nested mappings, block sequence
+ indent is unset (None) in that case
+ """
+ # load a yaml file guess the indentation, if you use TABs ...
+ def leading_spaces(l):
+ idx = 0
+ while idx < len(l) and l[idx] == ' ':
+ idx += 1
+ return idx
+
+ if isinstance(stream, text_type):
+ yaml_str = stream
+ elif isinstance(stream, binary_type):
+ yaml_str = stream.decode('utf-8') # most likely, but the Reader checks BOM for this
+ else:
+ yaml_str = stream.read()
+ map_indent = None
+ indent = None # default if not found for some reason
+ block_seq_indent = None
+ prev_line_key_only = None
+ key_indent = 0
+ for line in yaml_str.splitlines():
+ rline = line.rstrip()
+ lline = rline.lstrip()
+ if lline.startswith('- '):
+ l_s = leading_spaces(line)
+ block_seq_indent = l_s - key_indent
+ idx = l_s + 1
+ while line[idx] == ' ': # this will end as we rstripped
+ idx += 1
+ if line[idx] == '#': # comment after -
+ continue
+ indent = idx - key_indent
+ break
+ if map_indent is None and prev_line_key_only is not None and rline:
+ idx = 0
+ while line[idx] in ' -':
+ idx += 1
+ if idx > prev_line_key_only:
+ map_indent = idx - prev_line_key_only
+ if rline.endswith(':'):
+ key_indent = leading_spaces(line)
+ idx = 0
+ while line[idx] == ' ': # this will end on ':'
+ idx += 1
+ prev_line_key_only = idx
+ continue
+ prev_line_key_only = None
+ if indent is None and map_indent is not None:
+ indent = map_indent
+ return round_trip_load(yaml_str, **kw), indent, block_seq_indent
+
+
+def configobj_walker(cfg):
+ """
+ walks over a ConfigObj (INI file with comments) generating
+ corresponding YAML output (including comments
+ """
+ from configobj import ConfigObj
+ assert isinstance(cfg, ConfigObj)
+ for c in cfg.initial_comment:
+ if c.strip():
+ yield c
+ for s in _walk_section(cfg):
+ if s.strip():
+ yield s
+ for c in cfg.final_comment:
+ if c.strip():
+ yield c
+
+
+def _walk_section(s, level=0):
+ from configobj import Section
+ assert isinstance(s, Section)
+ indent = u' ' * level
+ for name in s.scalars:
+ for c in s.comments[name]:
+ yield indent + c.strip()
+ x = s[name]
+ if u'\n' in x:
+ i = indent + u' '
+ x = u'|\n' + i + x.strip().replace(u'\n', u'\n' + i)
+ elif ':' in x:
+ x = u"'" + x.replace(u"'", u"''") + u"'"
+ line = u'{0}{1}: {2}'.format(indent, name, x)
+ c = s.inline_comments[name]
+ if c:
+ line += u' ' + c
+ yield line
+ for name in s.sections:
+ for c in s.comments[name]:
+ yield indent + c.strip()
+ line = u'{0}{1}:'.format(indent, name)
+ c = s.inline_comments[name]
+ if c:
+ line += u' ' + c
+ yield line
+ for val in _walk_section(s[name], level=level+1):
+ yield val
+
+# def config_obj_2_rt_yaml(cfg):
+# from .comments import CommentedMap, CommentedSeq
+# from configobj import ConfigObj
+# assert isinstance(cfg, ConfigObj)
+# #for c in cfg.initial_comment:
+# # if c.strip():
+# # pass
+# cm = CommentedMap()
+# for name in s.sections:
+# cm[name] = d = CommentedMap()
+#
+#
+# #for c in cfg.final_comment:
+# # if c.strip():
+# # yield c
+# return cm
diff --git a/lib/spack/external/six.py b/lib/spack/external/six.py
index 5293325821..6bf4fd3810 100644
--- a/lib/spack/external/six.py
+++ b/lib/spack/external/six.py
@@ -29,7 +29,7 @@ import sys
import types
__author__ = "Benjamin Peterson <benjamin@python.org>"
-__version__ = "1.10.0"
+__version__ = "1.11.0"
# Useful for very coarse version differentiation.
@@ -241,7 +241,6 @@ _moved_attributes = [
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
- MovedAttribute("getstatusoutput", "commands", "subprocess"),
MovedAttribute("getoutput", "commands", "subprocess"),
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
@@ -421,6 +420,8 @@ _urllib_request_moved_attributes = [
MovedAttribute("URLopener", "urllib", "urllib.request"),
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
+ MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
+ MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
]
for attr in _urllib_request_moved_attributes:
setattr(Module_six_moves_urllib_request, attr.name, attr)
@@ -820,10 +821,14 @@ def with_metaclass(meta, *bases):
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
- class metaclass(meta):
+ class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
+
+ @classmethod
+ def __prepare__(cls, name, this_bases):
+ return meta.__prepare__(name, bases)
return type.__new__(metaclass, 'temporary_class', (), {})
diff --git a/lib/spack/external/yaml/LICENSE b/lib/spack/external/yaml/LICENSE
deleted file mode 100644
index 050ced23f6..0000000000
--- a/lib/spack/external/yaml/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2006 Kirill Simonov
-
-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 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.
diff --git a/lib/spack/external/yaml/README b/lib/spack/external/yaml/README
deleted file mode 100644
index d186328eeb..0000000000
--- a/lib/spack/external/yaml/README
+++ /dev/null
@@ -1,35 +0,0 @@
-PyYAML - The next generation YAML parser and emitter for Python.
-
-To install, type 'python setup.py install'.
-
-By default, the setup.py script checks whether LibYAML is installed
-and if so, builds and installs LibYAML bindings. To skip the check
-and force installation of LibYAML bindings, use the option '--with-libyaml':
-'python setup.py --with-libyaml install'. To disable the check and
-skip building and installing LibYAML bindings, use '--without-libyaml':
-'python setup.py --without-libyaml install'.
-
-When LibYAML bindings are installed, you may use fast LibYAML-based
-parser and emitter as follows:
-
- >>> yaml.load(stream, Loader=yaml.CLoader)
- >>> yaml.dump(data, Dumper=yaml.CDumper)
-
-PyYAML includes a comprehensive test suite. To run the tests,
-type 'python setup.py test'.
-
-For more information, check the PyYAML homepage:
-'http://pyyaml.org/wiki/PyYAML'.
-
-For PyYAML tutorial and reference, see:
-'http://pyyaml.org/wiki/PyYAMLDocumentation'.
-
-Post your questions and opinions to the YAML-Core mailing list:
-'http://lists.sourceforge.net/lists/listinfo/yaml-core'.
-
-Submit bug reports and feature requests to the PyYAML bug tracker:
-'https://bitbucket.org/xi/pyyaml/issues/new'.
-
-PyYAML is written by Kirill Simonov <xi@resolvent.net>. It is released
-under the MIT license. See the file LICENSE for more details.
-
diff --git a/lib/spack/external/yaml/lib/yaml/__init__.py b/lib/spack/external/yaml/lib/yaml/__init__.py
deleted file mode 100644
index 87c15d38aa..0000000000
--- a/lib/spack/external/yaml/lib/yaml/__init__.py
+++ /dev/null
@@ -1,315 +0,0 @@
-
-from error import *
-
-from tokens import *
-from events import *
-from nodes import *
-
-from loader import *
-from dumper import *
-
-__version__ = '3.12'
-
-try:
- from cyaml import *
- __with_libyaml__ = True
-except ImportError:
- __with_libyaml__ = False
-
-def scan(stream, Loader=Loader):
- """
- Scan a YAML stream and produce scanning tokens.
- """
- loader = Loader(stream)
- try:
- while loader.check_token():
- yield loader.get_token()
- finally:
- loader.dispose()
-
-def parse(stream, Loader=Loader):
- """
- Parse a YAML stream and produce parsing events.
- """
- loader = Loader(stream)
- try:
- while loader.check_event():
- yield loader.get_event()
- finally:
- loader.dispose()
-
-def compose(stream, Loader=Loader):
- """
- Parse the first YAML document in a stream
- and produce the corresponding representation tree.
- """
- loader = Loader(stream)
- try:
- return loader.get_single_node()
- finally:
- loader.dispose()
-
-def compose_all(stream, Loader=Loader):
- """
- Parse all YAML documents in a stream
- and produce corresponding representation trees.
- """
- loader = Loader(stream)
- try:
- while loader.check_node():
- yield loader.get_node()
- finally:
- loader.dispose()
-
-def load(stream, Loader=Loader):
- """
- Parse the first YAML document in a stream
- and produce the corresponding Python object.
- """
- loader = Loader(stream)
- try:
- return loader.get_single_data()
- finally:
- loader.dispose()
-
-def load_all(stream, Loader=Loader):
- """
- Parse all YAML documents in a stream
- and produce corresponding Python objects.
- """
- loader = Loader(stream)
- try:
- while loader.check_data():
- yield loader.get_data()
- finally:
- loader.dispose()
-
-def safe_load(stream):
- """
- Parse the first YAML document in a stream
- and produce the corresponding Python object.
- Resolve only basic YAML tags.
- """
- return load(stream, SafeLoader)
-
-def safe_load_all(stream):
- """
- Parse all YAML documents in a stream
- and produce corresponding Python objects.
- Resolve only basic YAML tags.
- """
- return load_all(stream, SafeLoader)
-
-def emit(events, stream=None, Dumper=Dumper,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None):
- """
- Emit YAML parsing events into a stream.
- If stream is None, return the produced string instead.
- """
- getvalue = None
- if stream is None:
- from StringIO import StringIO
- stream = StringIO()
- getvalue = stream.getvalue
- dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- try:
- for event in events:
- dumper.emit(event)
- finally:
- dumper.dispose()
- if getvalue:
- return getvalue()
-
-def serialize_all(nodes, stream=None, Dumper=Dumper,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding='utf-8', explicit_start=None, explicit_end=None,
- version=None, tags=None):
- """
- Serialize a sequence of representation trees into a YAML stream.
- If stream is None, return the produced string instead.
- """
- getvalue = None
- if stream is None:
- if encoding is None:
- from StringIO import StringIO
- else:
- from cStringIO import StringIO
- stream = StringIO()
- getvalue = stream.getvalue
- dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break,
- encoding=encoding, version=version, tags=tags,
- explicit_start=explicit_start, explicit_end=explicit_end)
- try:
- dumper.open()
- for node in nodes:
- dumper.serialize(node)
- dumper.close()
- finally:
- dumper.dispose()
- if getvalue:
- return getvalue()
-
-def serialize(node, stream=None, Dumper=Dumper, **kwds):
- """
- Serialize a representation tree into a YAML stream.
- If stream is None, return the produced string instead.
- """
- return serialize_all([node], stream, Dumper=Dumper, **kwds)
-
-def dump_all(documents, stream=None, Dumper=Dumper,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding='utf-8', explicit_start=None, explicit_end=None,
- version=None, tags=None):
- """
- Serialize a sequence of Python objects into a YAML stream.
- If stream is None, return the produced string instead.
- """
- getvalue = None
- if stream is None:
- if encoding is None:
- from StringIO import StringIO
- else:
- from cStringIO import StringIO
- stream = StringIO()
- getvalue = stream.getvalue
- dumper = Dumper(stream, default_style=default_style,
- default_flow_style=default_flow_style,
- canonical=canonical, indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break,
- encoding=encoding, version=version, tags=tags,
- explicit_start=explicit_start, explicit_end=explicit_end)
- try:
- dumper.open()
- for data in documents:
- dumper.represent(data)
- dumper.close()
- finally:
- dumper.dispose()
- if getvalue:
- return getvalue()
-
-def dump(data, stream=None, Dumper=Dumper, **kwds):
- """
- Serialize a Python object into a YAML stream.
- If stream is None, return the produced string instead.
- """
- return dump_all([data], stream, Dumper=Dumper, **kwds)
-
-def safe_dump_all(documents, stream=None, **kwds):
- """
- Serialize a sequence of Python objects into a YAML stream.
- Produce only basic YAML tags.
- If stream is None, return the produced string instead.
- """
- return dump_all(documents, stream, Dumper=SafeDumper, **kwds)
-
-def safe_dump(data, stream=None, **kwds):
- """
- Serialize a Python object into a YAML stream.
- Produce only basic YAML tags.
- If stream is None, return the produced string instead.
- """
- return dump_all([data], stream, Dumper=SafeDumper, **kwds)
-
-def add_implicit_resolver(tag, regexp, first=None,
- Loader=Loader, Dumper=Dumper):
- """
- Add an implicit scalar detector.
- If an implicit scalar value matches the given regexp,
- the corresponding tag is assigned to the scalar.
- first is a sequence of possible initial characters or None.
- """
- Loader.add_implicit_resolver(tag, regexp, first)
- Dumper.add_implicit_resolver(tag, regexp, first)
-
-def add_path_resolver(tag, path, kind=None, Loader=Loader, Dumper=Dumper):
- """
- Add a path based resolver for the given tag.
- A path is a list of keys that forms a path
- to a node in the representation tree.
- Keys can be string values, integers, or None.
- """
- Loader.add_path_resolver(tag, path, kind)
- Dumper.add_path_resolver(tag, path, kind)
-
-def add_constructor(tag, constructor, Loader=Loader):
- """
- Add a constructor for the given tag.
- Constructor is a function that accepts a Loader instance
- and a node object and produces the corresponding Python object.
- """
- Loader.add_constructor(tag, constructor)
-
-def add_multi_constructor(tag_prefix, multi_constructor, Loader=Loader):
- """
- Add a multi-constructor for the given tag prefix.
- Multi-constructor is called for a node if its tag starts with tag_prefix.
- Multi-constructor accepts a Loader instance, a tag suffix,
- and a node object and produces the corresponding Python object.
- """
- Loader.add_multi_constructor(tag_prefix, multi_constructor)
-
-def add_representer(data_type, representer, Dumper=Dumper):
- """
- Add a representer for the given type.
- Representer is a function accepting a Dumper instance
- and an instance of the given data type
- and producing the corresponding representation node.
- """
- Dumper.add_representer(data_type, representer)
-
-def add_multi_representer(data_type, multi_representer, Dumper=Dumper):
- """
- Add a representer for the given type.
- Multi-representer is a function accepting a Dumper instance
- and an instance of the given data type or subtype
- and producing the corresponding representation node.
- """
- Dumper.add_multi_representer(data_type, multi_representer)
-
-class YAMLObjectMetaclass(type):
- """
- The metaclass for YAMLObject.
- """
- def __init__(cls, name, bases, kwds):
- super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
- if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
- cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
- cls.yaml_dumper.add_representer(cls, cls.to_yaml)
-
-class YAMLObject(object):
- """
- An object that can dump itself to a YAML stream
- and load itself from a YAML stream.
- """
-
- __metaclass__ = YAMLObjectMetaclass
- __slots__ = () # no direct instantiation, so allow immutable subclasses
-
- yaml_loader = Loader
- yaml_dumper = Dumper
-
- yaml_tag = None
- yaml_flow_style = None
-
- def from_yaml(cls, loader, node):
- """
- Convert a representation node to a Python object.
- """
- return loader.construct_yaml_object(node, cls)
- from_yaml = classmethod(from_yaml)
-
- def to_yaml(cls, dumper, data):
- """
- Convert a Python object to a representation node.
- """
- return dumper.represent_yaml_object(cls.yaml_tag, data, cls,
- flow_style=cls.yaml_flow_style)
- to_yaml = classmethod(to_yaml)
-
diff --git a/lib/spack/external/yaml/lib/yaml/constructor.py b/lib/spack/external/yaml/lib/yaml/constructor.py
deleted file mode 100644
index 635faac3e6..0000000000
--- a/lib/spack/external/yaml/lib/yaml/constructor.py
+++ /dev/null
@@ -1,675 +0,0 @@
-
-__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
- 'ConstructorError']
-
-from error import *
-from nodes import *
-
-import datetime
-
-import binascii, re, sys, types
-
-class ConstructorError(MarkedYAMLError):
- pass
-
-class BaseConstructor(object):
-
- yaml_constructors = {}
- yaml_multi_constructors = {}
-
- def __init__(self):
- self.constructed_objects = {}
- self.recursive_objects = {}
- self.state_generators = []
- self.deep_construct = False
-
- def check_data(self):
- # If there are more documents available?
- return self.check_node()
-
- def get_data(self):
- # Construct and return the next document.
- if self.check_node():
- return self.construct_document(self.get_node())
-
- def get_single_data(self):
- # Ensure that the stream contains a single document and construct it.
- node = self.get_single_node()
- if node is not None:
- return self.construct_document(node)
- return None
-
- def construct_document(self, node):
- data = self.construct_object(node)
- while self.state_generators:
- state_generators = self.state_generators
- self.state_generators = []
- for generator in state_generators:
- for dummy in generator:
- pass
- self.constructed_objects = {}
- self.recursive_objects = {}
- self.deep_construct = False
- return data
-
- def construct_object(self, node, deep=False):
- if node in self.constructed_objects:
- return self.constructed_objects[node]
- if deep:
- old_deep = self.deep_construct
- self.deep_construct = True
- if node in self.recursive_objects:
- raise ConstructorError(None, None,
- "found unconstructable recursive node", node.start_mark)
- self.recursive_objects[node] = None
- constructor = None
- tag_suffix = None
- if node.tag in self.yaml_constructors:
- constructor = self.yaml_constructors[node.tag]
- else:
- for tag_prefix in self.yaml_multi_constructors:
- if node.tag.startswith(tag_prefix):
- tag_suffix = node.tag[len(tag_prefix):]
- constructor = self.yaml_multi_constructors[tag_prefix]
- break
- else:
- if None in self.yaml_multi_constructors:
- tag_suffix = node.tag
- constructor = self.yaml_multi_constructors[None]
- elif None in self.yaml_constructors:
- constructor = self.yaml_constructors[None]
- elif isinstance(node, ScalarNode):
- constructor = self.__class__.construct_scalar
- elif isinstance(node, SequenceNode):
- constructor = self.__class__.construct_sequence
- elif isinstance(node, MappingNode):
- constructor = self.__class__.construct_mapping
- if tag_suffix is None:
- data = constructor(self, node)
- else:
- data = constructor(self, tag_suffix, node)
- if isinstance(data, types.GeneratorType):
- generator = data
- data = generator.next()
- if self.deep_construct:
- for dummy in generator:
- pass
- else:
- self.state_generators.append(generator)
- self.constructed_objects[node] = data
- del self.recursive_objects[node]
- if deep:
- self.deep_construct = old_deep
- return data
-
- def construct_scalar(self, node):
- if not isinstance(node, ScalarNode):
- raise ConstructorError(None, None,
- "expected a scalar node, but found %s" % node.id,
- node.start_mark)
- return node.value
-
- def construct_sequence(self, node, deep=False):
- if not isinstance(node, SequenceNode):
- raise ConstructorError(None, None,
- "expected a sequence node, but found %s" % node.id,
- node.start_mark)
- return [self.construct_object(child, deep=deep)
- for child in node.value]
-
- def construct_mapping(self, node, deep=False):
- if not isinstance(node, MappingNode):
- raise ConstructorError(None, None,
- "expected a mapping node, but found %s" % node.id,
- node.start_mark)
- mapping = {}
- for key_node, value_node in node.value:
- key = self.construct_object(key_node, deep=deep)
- try:
- hash(key)
- except TypeError, exc:
- raise ConstructorError("while constructing a mapping", node.start_mark,
- "found unacceptable key (%s)" % exc, key_node.start_mark)
- value = self.construct_object(value_node, deep=deep)
- mapping[key] = value
- return mapping
-
- def construct_pairs(self, node, deep=False):
- if not isinstance(node, MappingNode):
- raise ConstructorError(None, None,
- "expected a mapping node, but found %s" % node.id,
- node.start_mark)
- pairs = []
- for key_node, value_node in node.value:
- key = self.construct_object(key_node, deep=deep)
- value = self.construct_object(value_node, deep=deep)
- pairs.append((key, value))
- return pairs
-
- def add_constructor(cls, tag, constructor):
- if not 'yaml_constructors' in cls.__dict__:
- cls.yaml_constructors = cls.yaml_constructors.copy()
- cls.yaml_constructors[tag] = constructor
- add_constructor = classmethod(add_constructor)
-
- def add_multi_constructor(cls, tag_prefix, multi_constructor):
- if not 'yaml_multi_constructors' in cls.__dict__:
- cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
- cls.yaml_multi_constructors[tag_prefix] = multi_constructor
- add_multi_constructor = classmethod(add_multi_constructor)
-
-class SafeConstructor(BaseConstructor):
-
- def construct_scalar(self, node):
- if isinstance(node, MappingNode):
- for key_node, value_node in node.value:
- if key_node.tag == u'tag:yaml.org,2002:value':
- return self.construct_scalar(value_node)
- return BaseConstructor.construct_scalar(self, node)
-
- def flatten_mapping(self, node):
- merge = []
- index = 0
- while index < len(node.value):
- key_node, value_node = node.value[index]
- if key_node.tag == u'tag:yaml.org,2002:merge':
- del node.value[index]
- if isinstance(value_node, MappingNode):
- self.flatten_mapping(value_node)
- merge.extend(value_node.value)
- elif isinstance(value_node, SequenceNode):
- submerge = []
- for subnode in value_node.value:
- if not isinstance(subnode, MappingNode):
- raise ConstructorError("while constructing a mapping",
- node.start_mark,
- "expected a mapping for merging, but found %s"
- % subnode.id, subnode.start_mark)
- self.flatten_mapping(subnode)
- submerge.append(subnode.value)
- submerge.reverse()
- for value in submerge:
- merge.extend(value)
- else:
- raise ConstructorError("while constructing a mapping", node.start_mark,
- "expected a mapping or list of mappings for merging, but found %s"
- % value_node.id, value_node.start_mark)
- elif key_node.tag == u'tag:yaml.org,2002:value':
- key_node.tag = u'tag:yaml.org,2002:str'
- index += 1
- else:
- index += 1
- if merge:
- node.value = merge + node.value
-
- def construct_mapping(self, node, deep=False):
- if isinstance(node, MappingNode):
- self.flatten_mapping(node)
- return BaseConstructor.construct_mapping(self, node, deep=deep)
-
- def construct_yaml_null(self, node):
- self.construct_scalar(node)
- return None
-
- bool_values = {
- u'yes': True,
- u'no': False,
- u'true': True,
- u'false': False,
- u'on': True,
- u'off': False,
- }
-
- def construct_yaml_bool(self, node):
- value = self.construct_scalar(node)
- return self.bool_values[value.lower()]
-
- def construct_yaml_int(self, node):
- value = str(self.construct_scalar(node))
- value = value.replace('_', '')
- sign = +1
- if value[0] == '-':
- sign = -1
- if value[0] in '+-':
- value = value[1:]
- if value == '0':
- return 0
- elif value.startswith('0b'):
- return sign*int(value[2:], 2)
- elif value.startswith('0x'):
- return sign*int(value[2:], 16)
- elif value[0] == '0':
- return sign*int(value, 8)
- elif ':' in value:
- digits = [int(part) for part in value.split(':')]
- digits.reverse()
- base = 1
- value = 0
- for digit in digits:
- value += digit*base
- base *= 60
- return sign*value
- else:
- return sign*int(value)
-
- inf_value = 1e300
- while inf_value != inf_value*inf_value:
- inf_value *= inf_value
- nan_value = -inf_value/inf_value # Trying to make a quiet NaN (like C99).
-
- def construct_yaml_float(self, node):
- value = str(self.construct_scalar(node))
- value = value.replace('_', '').lower()
- sign = +1
- if value[0] == '-':
- sign = -1
- if value[0] in '+-':
- value = value[1:]
- if value == '.inf':
- return sign*self.inf_value
- elif value == '.nan':
- return self.nan_value
- elif ':' in value:
- digits = [float(part) for part in value.split(':')]
- digits.reverse()
- base = 1
- value = 0.0
- for digit in digits:
- value += digit*base
- base *= 60
- return sign*value
- else:
- return sign*float(value)
-
- def construct_yaml_binary(self, node):
- value = self.construct_scalar(node)
- try:
- return str(value).decode('base64')
- except (binascii.Error, UnicodeEncodeError), exc:
- raise ConstructorError(None, None,
- "failed to decode base64 data: %s" % exc, node.start_mark)
-
- timestamp_regexp = re.compile(
- ur'''^(?P<year>[0-9][0-9][0-9][0-9])
- -(?P<month>[0-9][0-9]?)
- -(?P<day>[0-9][0-9]?)
- (?:(?:[Tt]|[ \t]+)
- (?P<hour>[0-9][0-9]?)
- :(?P<minute>[0-9][0-9])
- :(?P<second>[0-9][0-9])
- (?:\.(?P<fraction>[0-9]*))?
- (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
- (?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
-
- def construct_yaml_timestamp(self, node):
- value = self.construct_scalar(node)
- match = self.timestamp_regexp.match(node.value)
- values = match.groupdict()
- year = int(values['year'])
- month = int(values['month'])
- day = int(values['day'])
- if not values['hour']:
- return datetime.date(year, month, day)
- hour = int(values['hour'])
- minute = int(values['minute'])
- second = int(values['second'])
- fraction = 0
- if values['fraction']:
- fraction = values['fraction'][:6]
- while len(fraction) < 6:
- fraction += '0'
- fraction = int(fraction)
- delta = None
- if values['tz_sign']:
- tz_hour = int(values['tz_hour'])
- tz_minute = int(values['tz_minute'] or 0)
- delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
- if values['tz_sign'] == '-':
- delta = -delta
- data = datetime.datetime(year, month, day, hour, minute, second, fraction)
- if delta:
- data -= delta
- return data
-
- def construct_yaml_omap(self, node):
- # Note: we do not check for duplicate keys, because it's too
- # CPU-expensive.
- omap = []
- yield omap
- if not isinstance(node, SequenceNode):
- raise ConstructorError("while constructing an ordered map", node.start_mark,
- "expected a sequence, but found %s" % node.id, node.start_mark)
- for subnode in node.value:
- if not isinstance(subnode, MappingNode):
- raise ConstructorError("while constructing an ordered map", node.start_mark,
- "expected a mapping of length 1, but found %s" % subnode.id,
- subnode.start_mark)
- if len(subnode.value) != 1:
- raise ConstructorError("while constructing an ordered map", node.start_mark,
- "expected a single mapping item, but found %d items" % len(subnode.value),
- subnode.start_mark)
- key_node, value_node = subnode.value[0]
- key = self.construct_object(key_node)
- value = self.construct_object(value_node)
- omap.append((key, value))
-
- def construct_yaml_pairs(self, node):
- # Note: the same code as `construct_yaml_omap`.
- pairs = []
- yield pairs
- if not isinstance(node, SequenceNode):
- raise ConstructorError("while constructing pairs", node.start_mark,
- "expected a sequence, but found %s" % node.id, node.start_mark)
- for subnode in node.value:
- if not isinstance(subnode, MappingNode):
- raise ConstructorError("while constructing pairs", node.start_mark,
- "expected a mapping of length 1, but found %s" % subnode.id,
- subnode.start_mark)
- if len(subnode.value) != 1:
- raise ConstructorError("while constructing pairs", node.start_mark,
- "expected a single mapping item, but found %d items" % len(subnode.value),
- subnode.start_mark)
- key_node, value_node = subnode.value[0]
- key = self.construct_object(key_node)
- value = self.construct_object(value_node)
- pairs.append((key, value))
-
- def construct_yaml_set(self, node):
- data = set()
- yield data
- value = self.construct_mapping(node)
- data.update(value)
-
- def construct_yaml_str(self, node):
- value = self.construct_scalar(node)
- try:
- return value.encode('ascii')
- except UnicodeEncodeError:
- return value
-
- def construct_yaml_seq(self, node):
- data = []
- yield data
- data.extend(self.construct_sequence(node))
-
- def construct_yaml_map(self, node):
- data = {}
- yield data
- value = self.construct_mapping(node)
- data.update(value)
-
- def construct_yaml_object(self, node, cls):
- data = cls.__new__(cls)
- yield data
- if hasattr(data, '__setstate__'):
- state = self.construct_mapping(node, deep=True)
- data.__setstate__(state)
- else:
- state = self.construct_mapping(node)
- data.__dict__.update(state)
-
- def construct_undefined(self, node):
- raise ConstructorError(None, None,
- "could not determine a constructor for the tag %r" % node.tag.encode('utf-8'),
- node.start_mark)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:null',
- SafeConstructor.construct_yaml_null)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:bool',
- SafeConstructor.construct_yaml_bool)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:int',
- SafeConstructor.construct_yaml_int)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:float',
- SafeConstructor.construct_yaml_float)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:binary',
- SafeConstructor.construct_yaml_binary)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:timestamp',
- SafeConstructor.construct_yaml_timestamp)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:omap',
- SafeConstructor.construct_yaml_omap)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:pairs',
- SafeConstructor.construct_yaml_pairs)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:set',
- SafeConstructor.construct_yaml_set)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:str',
- SafeConstructor.construct_yaml_str)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:seq',
- SafeConstructor.construct_yaml_seq)
-
-SafeConstructor.add_constructor(
- u'tag:yaml.org,2002:map',
- SafeConstructor.construct_yaml_map)
-
-SafeConstructor.add_constructor(None,
- SafeConstructor.construct_undefined)
-
-class Constructor(SafeConstructor):
-
- def construct_python_str(self, node):
- return self.construct_scalar(node).encode('utf-8')
-
- def construct_python_unicode(self, node):
- return self.construct_scalar(node)
-
- def construct_python_long(self, node):
- return long(self.construct_yaml_int(node))
-
- def construct_python_complex(self, node):
- return complex(self.construct_scalar(node))
-
- def construct_python_tuple(self, node):
- return tuple(self.construct_sequence(node))
-
- def find_python_module(self, name, mark):
- if not name:
- raise ConstructorError("while constructing a Python module", mark,
- "expected non-empty name appended to the tag", mark)
- try:
- __import__(name)
- except ImportError, exc:
- raise ConstructorError("while constructing a Python module", mark,
- "cannot find module %r (%s)" % (name.encode('utf-8'), exc), mark)
- return sys.modules[name]
-
- def find_python_name(self, name, mark):
- if not name:
- raise ConstructorError("while constructing a Python object", mark,
- "expected non-empty name appended to the tag", mark)
- if u'.' in name:
- module_name, object_name = name.rsplit('.', 1)
- else:
- module_name = '__builtin__'
- object_name = name
- try:
- __import__(module_name)
- except ImportError, exc:
- raise ConstructorError("while constructing a Python object", mark,
- "cannot find module %r (%s)" % (module_name.encode('utf-8'), exc), mark)
- module = sys.modules[module_name]
- if not hasattr(module, object_name):
- raise ConstructorError("while constructing a Python object", mark,
- "cannot find %r in the module %r" % (object_name.encode('utf-8'),
- module.__name__), mark)
- return getattr(module, object_name)
-
- def construct_python_name(self, suffix, node):
- value = self.construct_scalar(node)
- if value:
- raise ConstructorError("while constructing a Python name", node.start_mark,
- "expected the empty value, but found %r" % value.encode('utf-8'),
- node.start_mark)
- return self.find_python_name(suffix, node.start_mark)
-
- def construct_python_module(self, suffix, node):
- value = self.construct_scalar(node)
- if value:
- raise ConstructorError("while constructing a Python module", node.start_mark,
- "expected the empty value, but found %r" % value.encode('utf-8'),
- node.start_mark)
- return self.find_python_module(suffix, node.start_mark)
-
- class classobj: pass
-
- def make_python_instance(self, suffix, node,
- args=None, kwds=None, newobj=False):
- if not args:
- args = []
- if not kwds:
- kwds = {}
- cls = self.find_python_name(suffix, node.start_mark)
- if newobj and isinstance(cls, type(self.classobj)) \
- and not args and not kwds:
- instance = self.classobj()
- instance.__class__ = cls
- return instance
- elif newobj and isinstance(cls, type):
- return cls.__new__(cls, *args, **kwds)
- else:
- return cls(*args, **kwds)
-
- def set_python_instance_state(self, instance, state):
- if hasattr(instance, '__setstate__'):
- instance.__setstate__(state)
- else:
- slotstate = {}
- if isinstance(state, tuple) and len(state) == 2:
- state, slotstate = state
- if hasattr(instance, '__dict__'):
- instance.__dict__.update(state)
- elif state:
- slotstate.update(state)
- for key, value in slotstate.items():
- setattr(object, key, value)
-
- def construct_python_object(self, suffix, node):
- # Format:
- # !!python/object:module.name { ... state ... }
- instance = self.make_python_instance(suffix, node, newobj=True)
- yield instance
- deep = hasattr(instance, '__setstate__')
- state = self.construct_mapping(node, deep=deep)
- self.set_python_instance_state(instance, state)
-
- def construct_python_object_apply(self, suffix, node, newobj=False):
- # Format:
- # !!python/object/apply # (or !!python/object/new)
- # args: [ ... arguments ... ]
- # kwds: { ... keywords ... }
- # state: ... state ...
- # listitems: [ ... listitems ... ]
- # dictitems: { ... dictitems ... }
- # or short format:
- # !!python/object/apply [ ... arguments ... ]
- # The difference between !!python/object/apply and !!python/object/new
- # is how an object is created, check make_python_instance for details.
- if isinstance(node, SequenceNode):
- args = self.construct_sequence(node, deep=True)
- kwds = {}
- state = {}
- listitems = []
- dictitems = {}
- else:
- value = self.construct_mapping(node, deep=True)
- args = value.get('args', [])
- kwds = value.get('kwds', {})
- state = value.get('state', {})
- listitems = value.get('listitems', [])
- dictitems = value.get('dictitems', {})
- instance = self.make_python_instance(suffix, node, args, kwds, newobj)
- if state:
- self.set_python_instance_state(instance, state)
- if listitems:
- instance.extend(listitems)
- if dictitems:
- for key in dictitems:
- instance[key] = dictitems[key]
- return instance
-
- def construct_python_object_new(self, suffix, node):
- return self.construct_python_object_apply(suffix, node, newobj=True)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/none',
- Constructor.construct_yaml_null)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/bool',
- Constructor.construct_yaml_bool)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/str',
- Constructor.construct_python_str)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/unicode',
- Constructor.construct_python_unicode)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/int',
- Constructor.construct_yaml_int)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/long',
- Constructor.construct_python_long)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/float',
- Constructor.construct_yaml_float)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/complex',
- Constructor.construct_python_complex)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/list',
- Constructor.construct_yaml_seq)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/tuple',
- Constructor.construct_python_tuple)
-
-Constructor.add_constructor(
- u'tag:yaml.org,2002:python/dict',
- Constructor.construct_yaml_map)
-
-Constructor.add_multi_constructor(
- u'tag:yaml.org,2002:python/name:',
- Constructor.construct_python_name)
-
-Constructor.add_multi_constructor(
- u'tag:yaml.org,2002:python/module:',
- Constructor.construct_python_module)
-
-Constructor.add_multi_constructor(
- u'tag:yaml.org,2002:python/object:',
- Constructor.construct_python_object)
-
-Constructor.add_multi_constructor(
- u'tag:yaml.org,2002:python/object/apply:',
- Constructor.construct_python_object_apply)
-
-Constructor.add_multi_constructor(
- u'tag:yaml.org,2002:python/object/new:',
- Constructor.construct_python_object_new)
-
diff --git a/lib/spack/external/yaml/lib/yaml/cyaml.py b/lib/spack/external/yaml/lib/yaml/cyaml.py
deleted file mode 100644
index 68dcd75192..0000000000
--- a/lib/spack/external/yaml/lib/yaml/cyaml.py
+++ /dev/null
@@ -1,85 +0,0 @@
-
-__all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
- 'CBaseDumper', 'CSafeDumper', 'CDumper']
-
-from _yaml import CParser, CEmitter
-
-from constructor import *
-
-from serializer import *
-from representer import *
-
-from resolver import *
-
-class CBaseLoader(CParser, BaseConstructor, BaseResolver):
-
- def __init__(self, stream):
- CParser.__init__(self, stream)
- BaseConstructor.__init__(self)
- BaseResolver.__init__(self)
-
-class CSafeLoader(CParser, SafeConstructor, Resolver):
-
- def __init__(self, stream):
- CParser.__init__(self, stream)
- SafeConstructor.__init__(self)
- Resolver.__init__(self)
-
-class CLoader(CParser, Constructor, Resolver):
-
- def __init__(self, stream):
- CParser.__init__(self, stream)
- Constructor.__init__(self)
- Resolver.__init__(self)
-
-class CBaseDumper(CEmitter, BaseRepresenter, BaseResolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- CEmitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width, encoding=encoding,
- allow_unicode=allow_unicode, line_break=line_break,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class CSafeDumper(CEmitter, SafeRepresenter, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- CEmitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width, encoding=encoding,
- allow_unicode=allow_unicode, line_break=line_break,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- SafeRepresenter.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class CDumper(CEmitter, Serializer, Representer, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- CEmitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width, encoding=encoding,
- allow_unicode=allow_unicode, line_break=line_break,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
diff --git a/lib/spack/external/yaml/lib/yaml/dumper.py b/lib/spack/external/yaml/lib/yaml/dumper.py
deleted file mode 100644
index f811d2c919..0000000000
--- a/lib/spack/external/yaml/lib/yaml/dumper.py
+++ /dev/null
@@ -1,62 +0,0 @@
-
-__all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
-
-from emitter import *
-from serializer import *
-from representer import *
-from resolver import *
-
-class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- Emitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- Serializer.__init__(self, encoding=encoding,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- Emitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- Serializer.__init__(self, encoding=encoding,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- SafeRepresenter.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class Dumper(Emitter, Serializer, Representer, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- Emitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- Serializer.__init__(self, encoding=encoding,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
diff --git a/lib/spack/external/yaml/lib/yaml/events.py b/lib/spack/external/yaml/lib/yaml/events.py
deleted file mode 100644
index f79ad389cb..0000000000
--- a/lib/spack/external/yaml/lib/yaml/events.py
+++ /dev/null
@@ -1,86 +0,0 @@
-
-# Abstract classes.
-
-class Event(object):
- def __init__(self, start_mark=None, end_mark=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
- def __repr__(self):
- attributes = [key for key in ['anchor', 'tag', 'implicit', 'value']
- if hasattr(self, key)]
- arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
- for key in attributes])
- return '%s(%s)' % (self.__class__.__name__, arguments)
-
-class NodeEvent(Event):
- def __init__(self, anchor, start_mark=None, end_mark=None):
- self.anchor = anchor
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class CollectionStartEvent(NodeEvent):
- def __init__(self, anchor, tag, implicit, start_mark=None, end_mark=None,
- flow_style=None):
- self.anchor = anchor
- self.tag = tag
- self.implicit = implicit
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.flow_style = flow_style
-
-class CollectionEndEvent(Event):
- pass
-
-# Implementations.
-
-class StreamStartEvent(Event):
- def __init__(self, start_mark=None, end_mark=None, encoding=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.encoding = encoding
-
-class StreamEndEvent(Event):
- pass
-
-class DocumentStartEvent(Event):
- def __init__(self, start_mark=None, end_mark=None,
- explicit=None, version=None, tags=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.explicit = explicit
- self.version = version
- self.tags = tags
-
-class DocumentEndEvent(Event):
- def __init__(self, start_mark=None, end_mark=None,
- explicit=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.explicit = explicit
-
-class AliasEvent(NodeEvent):
- pass
-
-class ScalarEvent(NodeEvent):
- def __init__(self, anchor, tag, implicit, value,
- start_mark=None, end_mark=None, style=None):
- self.anchor = anchor
- self.tag = tag
- self.implicit = implicit
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.style = style
-
-class SequenceStartEvent(CollectionStartEvent):
- pass
-
-class SequenceEndEvent(CollectionEndEvent):
- pass
-
-class MappingStartEvent(CollectionStartEvent):
- pass
-
-class MappingEndEvent(CollectionEndEvent):
- pass
-
diff --git a/lib/spack/external/yaml/lib/yaml/loader.py b/lib/spack/external/yaml/lib/yaml/loader.py
deleted file mode 100644
index 293ff467b1..0000000000
--- a/lib/spack/external/yaml/lib/yaml/loader.py
+++ /dev/null
@@ -1,40 +0,0 @@
-
-__all__ = ['BaseLoader', 'SafeLoader', 'Loader']
-
-from reader import *
-from scanner import *
-from parser import *
-from composer import *
-from constructor import *
-from resolver import *
-
-class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, BaseResolver):
-
- def __init__(self, stream):
- Reader.__init__(self, stream)
- Scanner.__init__(self)
- Parser.__init__(self)
- Composer.__init__(self)
- BaseConstructor.__init__(self)
- BaseResolver.__init__(self)
-
-class SafeLoader(Reader, Scanner, Parser, Composer, SafeConstructor, Resolver):
-
- def __init__(self, stream):
- Reader.__init__(self, stream)
- Scanner.__init__(self)
- Parser.__init__(self)
- Composer.__init__(self)
- SafeConstructor.__init__(self)
- Resolver.__init__(self)
-
-class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
-
- def __init__(self, stream):
- Reader.__init__(self, stream)
- Scanner.__init__(self)
- Parser.__init__(self)
- Composer.__init__(self)
- Constructor.__init__(self)
- Resolver.__init__(self)
-
diff --git a/lib/spack/external/yaml/lib/yaml/nodes.py b/lib/spack/external/yaml/lib/yaml/nodes.py
deleted file mode 100644
index c4f070c41e..0000000000
--- a/lib/spack/external/yaml/lib/yaml/nodes.py
+++ /dev/null
@@ -1,49 +0,0 @@
-
-class Node(object):
- def __init__(self, tag, value, start_mark, end_mark):
- self.tag = tag
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- def __repr__(self):
- value = self.value
- #if isinstance(value, list):
- # if len(value) == 0:
- # value = '<empty>'
- # elif len(value) == 1:
- # value = '<1 item>'
- # else:
- # value = '<%d items>' % len(value)
- #else:
- # if len(value) > 75:
- # value = repr(value[:70]+u' ... ')
- # else:
- # value = repr(value)
- value = repr(value)
- return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
-
-class ScalarNode(Node):
- id = 'scalar'
- def __init__(self, tag, value,
- start_mark=None, end_mark=None, style=None):
- self.tag = tag
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.style = style
-
-class CollectionNode(Node):
- def __init__(self, tag, value,
- start_mark=None, end_mark=None, flow_style=None):
- self.tag = tag
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.flow_style = flow_style
-
-class SequenceNode(CollectionNode):
- id = 'sequence'
-
-class MappingNode(CollectionNode):
- id = 'mapping'
-
diff --git a/lib/spack/external/yaml/lib/yaml/reader.py b/lib/spack/external/yaml/lib/yaml/reader.py
deleted file mode 100644
index 3249e6b9f5..0000000000
--- a/lib/spack/external/yaml/lib/yaml/reader.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# This module contains abstractions for the input stream. You don't have to
-# looks further, there are no pretty code.
-#
-# We define two classes here.
-#
-# Mark(source, line, column)
-# It's just a record and its only use is producing nice error messages.
-# Parser does not use it for any other purposes.
-#
-# Reader(source, data)
-# Reader determines the encoding of `data` and converts it to unicode.
-# Reader provides the following methods and attributes:
-# reader.peek(length=1) - return the next `length` characters
-# reader.forward(length=1) - move the current position to `length` characters.
-# reader.index - the number of the current character.
-# reader.line, stream.column - the line and the column of the current character.
-
-__all__ = ['Reader', 'ReaderError']
-
-from error import YAMLError, Mark
-
-import codecs, re
-
-class ReaderError(YAMLError):
-
- def __init__(self, name, position, character, encoding, reason):
- self.name = name
- self.character = character
- self.position = position
- self.encoding = encoding
- self.reason = reason
-
- def __str__(self):
- if isinstance(self.character, str):
- return "'%s' codec can't decode byte #x%02x: %s\n" \
- " in \"%s\", position %d" \
- % (self.encoding, ord(self.character), self.reason,
- self.name, self.position)
- else:
- return "unacceptable character #x%04x: %s\n" \
- " in \"%s\", position %d" \
- % (self.character, self.reason,
- self.name, self.position)
-
-class Reader(object):
- # Reader:
- # - determines the data encoding and converts it to unicode,
- # - checks if characters are in allowed range,
- # - adds '\0' to the end.
-
- # Reader accepts
- # - a `str` object,
- # - a `unicode` object,
- # - a file-like object with its `read` method returning `str`,
- # - a file-like object with its `read` method returning `unicode`.
-
- # Yeah, it's ugly and slow.
-
- def __init__(self, stream):
- self.name = None
- self.stream = None
- self.stream_pointer = 0
- self.eof = True
- self.buffer = u''
- self.pointer = 0
- self.raw_buffer = None
- self.raw_decode = None
- self.encoding = None
- self.index = 0
- self.line = 0
- self.column = 0
- if isinstance(stream, unicode):
- self.name = "<unicode string>"
- self.check_printable(stream)
- self.buffer = stream+u'\0'
- elif isinstance(stream, str):
- self.name = "<string>"
- self.raw_buffer = stream
- self.determine_encoding()
- else:
- self.stream = stream
- self.name = getattr(stream, 'name', "<file>")
- self.eof = False
- self.raw_buffer = ''
- self.determine_encoding()
-
- def peek(self, index=0):
- try:
- return self.buffer[self.pointer+index]
- except IndexError:
- self.update(index+1)
- return self.buffer[self.pointer+index]
-
- def prefix(self, length=1):
- if self.pointer+length >= len(self.buffer):
- self.update(length)
- return self.buffer[self.pointer:self.pointer+length]
-
- def forward(self, length=1):
- if self.pointer+length+1 >= len(self.buffer):
- self.update(length+1)
- while length:
- ch = self.buffer[self.pointer]
- self.pointer += 1
- self.index += 1
- if ch in u'\n\x85\u2028\u2029' \
- or (ch == u'\r' and self.buffer[self.pointer] != u'\n'):
- self.line += 1
- self.column = 0
- elif ch != u'\uFEFF':
- self.column += 1
- length -= 1
-
- def get_mark(self):
- if self.stream is None:
- return Mark(self.name, self.index, self.line, self.column,
- self.buffer, self.pointer)
- else:
- return Mark(self.name, self.index, self.line, self.column,
- None, None)
-
- def determine_encoding(self):
- while not self.eof and len(self.raw_buffer) < 2:
- self.update_raw()
- if not isinstance(self.raw_buffer, unicode):
- if self.raw_buffer.startswith(codecs.BOM_UTF16_LE):
- self.raw_decode = codecs.utf_16_le_decode
- self.encoding = 'utf-16-le'
- elif self.raw_buffer.startswith(codecs.BOM_UTF16_BE):
- self.raw_decode = codecs.utf_16_be_decode
- self.encoding = 'utf-16-be'
- else:
- self.raw_decode = codecs.utf_8_decode
- self.encoding = 'utf-8'
- self.update(1)
-
- NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
- def check_printable(self, data):
- match = self.NON_PRINTABLE.search(data)
- if match:
- character = match.group()
- position = self.index+(len(self.buffer)-self.pointer)+match.start()
- raise ReaderError(self.name, position, ord(character),
- 'unicode', "special characters are not allowed")
-
- def update(self, length):
- if self.raw_buffer is None:
- return
- self.buffer = self.buffer[self.pointer:]
- self.pointer = 0
- while len(self.buffer) < length:
- if not self.eof:
- self.update_raw()
- if self.raw_decode is not None:
- try:
- data, converted = self.raw_decode(self.raw_buffer,
- 'strict', self.eof)
- except UnicodeDecodeError, exc:
- character = exc.object[exc.start]
- if self.stream is not None:
- position = self.stream_pointer-len(self.raw_buffer)+exc.start
- else:
- position = exc.start
- raise ReaderError(self.name, position, character,
- exc.encoding, exc.reason)
- else:
- data = self.raw_buffer
- converted = len(data)
- self.check_printable(data)
- self.buffer += data
- self.raw_buffer = self.raw_buffer[converted:]
- if self.eof:
- self.buffer += u'\0'
- self.raw_buffer = None
- break
-
- def update_raw(self, size=1024):
- data = self.stream.read(size)
- if data:
- self.raw_buffer += data
- self.stream_pointer += len(data)
- else:
- self.eof = True
-
-#try:
-# import psyco
-# psyco.bind(Reader)
-#except ImportError:
-# pass
-
diff --git a/lib/spack/external/yaml/lib/yaml/representer.py b/lib/spack/external/yaml/lib/yaml/representer.py
deleted file mode 100644
index 4ea8cb1fe1..0000000000
--- a/lib/spack/external/yaml/lib/yaml/representer.py
+++ /dev/null
@@ -1,486 +0,0 @@
-
-__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
- 'RepresenterError']
-
-from error import *
-from nodes import *
-
-import datetime
-
-import sys, copy_reg, types
-
-class RepresenterError(YAMLError):
- pass
-
-class BaseRepresenter(object):
-
- yaml_representers = {}
- yaml_multi_representers = {}
-
- def __init__(self, default_style=None, default_flow_style=None):
- self.default_style = default_style
- self.default_flow_style = default_flow_style
- self.represented_objects = {}
- self.object_keeper = []
- self.alias_key = None
-
- def represent(self, data):
- node = self.represent_data(data)
- self.serialize(node)
- self.represented_objects = {}
- self.object_keeper = []
- self.alias_key = None
-
- def get_classobj_bases(self, cls):
- bases = [cls]
- for base in cls.__bases__:
- bases.extend(self.get_classobj_bases(base))
- return bases
-
- def represent_data(self, data):
- if self.ignore_aliases(data):
- self.alias_key = None
- else:
- self.alias_key = id(data)
- if self.alias_key is not None:
- if self.alias_key in self.represented_objects:
- node = self.represented_objects[self.alias_key]
- #if node is None:
- # raise RepresenterError("recursive objects are not allowed: %r" % data)
- return node
- #self.represented_objects[alias_key] = None
- self.object_keeper.append(data)
- data_types = type(data).__mro__
- if type(data) is types.InstanceType:
- data_types = self.get_classobj_bases(data.__class__)+list(data_types)
- if data_types[0] in self.yaml_representers:
- node = self.yaml_representers[data_types[0]](self, data)
- else:
- for data_type in data_types:
- if data_type in self.yaml_multi_representers:
- node = self.yaml_multi_representers[data_type](self, data)
- break
- else:
- if None in self.yaml_multi_representers:
- node = self.yaml_multi_representers[None](self, data)
- elif None in self.yaml_representers:
- node = self.yaml_representers[None](self, data)
- else:
- node = ScalarNode(None, unicode(data))
- #if alias_key is not None:
- # self.represented_objects[alias_key] = node
- return node
-
- def add_representer(cls, data_type, representer):
- if not 'yaml_representers' in cls.__dict__:
- cls.yaml_representers = cls.yaml_representers.copy()
- cls.yaml_representers[data_type] = representer
- add_representer = classmethod(add_representer)
-
- def add_multi_representer(cls, data_type, representer):
- if not 'yaml_multi_representers' in cls.__dict__:
- cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
- cls.yaml_multi_representers[data_type] = representer
- add_multi_representer = classmethod(add_multi_representer)
-
- def represent_scalar(self, tag, value, style=None):
- if style is None:
- style = self.default_style
- node = ScalarNode(tag, value, style=style)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- return node
-
- def represent_sequence(self, tag, sequence, flow_style=None):
- value = []
- node = SequenceNode(tag, value, flow_style=flow_style)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- best_style = True
- for item in sequence:
- node_item = self.represent_data(item)
- if not (isinstance(node_item, ScalarNode) and not node_item.style):
- best_style = False
- value.append(node_item)
- if flow_style is None:
- if self.default_flow_style is not None:
- node.flow_style = self.default_flow_style
- else:
- node.flow_style = best_style
- return node
-
- def represent_mapping(self, tag, mapping, flow_style=None):
- value = []
- node = MappingNode(tag, value, flow_style=flow_style)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- best_style = True
- if hasattr(mapping, 'items'):
- mapping = mapping.items()
- mapping.sort()
- for item_key, item_value in mapping:
- node_key = self.represent_data(item_key)
- node_value = self.represent_data(item_value)
- if not (isinstance(node_key, ScalarNode) and not node_key.style):
- best_style = False
- if not (isinstance(node_value, ScalarNode) and not node_value.style):
- best_style = False
- value.append((node_key, node_value))
- if flow_style is None:
- if self.default_flow_style is not None:
- node.flow_style = self.default_flow_style
- else:
- node.flow_style = best_style
- return node
-
- def ignore_aliases(self, data):
- return False
-
-class SafeRepresenter(BaseRepresenter):
-
- def ignore_aliases(self, data):
- if data is None:
- return True
- if isinstance(data, tuple) and data == ():
- return True
- if isinstance(data, (str, unicode, bool, int, float)):
- return True
-
- def represent_none(self, data):
- return self.represent_scalar(u'tag:yaml.org,2002:null',
- u'null')
-
- def represent_str(self, data):
- tag = None
- style = None
- try:
- data = unicode(data, 'ascii')
- tag = u'tag:yaml.org,2002:str'
- except UnicodeDecodeError:
- try:
- data = unicode(data, 'utf-8')
- tag = u'tag:yaml.org,2002:str'
- except UnicodeDecodeError:
- data = data.encode('base64')
- tag = u'tag:yaml.org,2002:binary'
- style = '|'
- return self.represent_scalar(tag, data, style=style)
-
- def represent_unicode(self, data):
- return self.represent_scalar(u'tag:yaml.org,2002:str', data)
-
- def represent_bool(self, data):
- if data:
- value = u'true'
- else:
- value = u'false'
- return self.represent_scalar(u'tag:yaml.org,2002:bool', value)
-
- def represent_int(self, data):
- return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
-
- def represent_long(self, data):
- return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
-
- inf_value = 1e300
- while repr(inf_value) != repr(inf_value*inf_value):
- inf_value *= inf_value
-
- def represent_float(self, data):
- if data != data or (data == 0.0 and data == 1.0):
- value = u'.nan'
- elif data == self.inf_value:
- value = u'.inf'
- elif data == -self.inf_value:
- value = u'-.inf'
- else:
- value = unicode(repr(data)).lower()
- # Note that in some cases `repr(data)` represents a float number
- # without the decimal parts. For instance:
- # >>> repr(1e17)
- # '1e17'
- # Unfortunately, this is not a valid float representation according
- # to the definition of the `!!float` tag. We fix this by adding
- # '.0' before the 'e' symbol.
- if u'.' not in value and u'e' in value:
- value = value.replace(u'e', u'.0e', 1)
- return self.represent_scalar(u'tag:yaml.org,2002:float', value)
-
- def represent_list(self, data):
- #pairs = (len(data) > 0 and isinstance(data, list))
- #if pairs:
- # for item in data:
- # if not isinstance(item, tuple) or len(item) != 2:
- # pairs = False
- # break
- #if not pairs:
- return self.represent_sequence(u'tag:yaml.org,2002:seq', data)
- #value = []
- #for item_key, item_value in data:
- # value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
- # [(item_key, item_value)]))
- #return SequenceNode(u'tag:yaml.org,2002:pairs', value)
-
- def represent_dict(self, data):
- return self.represent_mapping(u'tag:yaml.org,2002:map', data)
-
- def represent_set(self, data):
- value = {}
- for key in data:
- value[key] = None
- return self.represent_mapping(u'tag:yaml.org,2002:set', value)
-
- def represent_date(self, data):
- value = unicode(data.isoformat())
- return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
-
- def represent_datetime(self, data):
- value = unicode(data.isoformat(' '))
- return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
-
- def represent_yaml_object(self, tag, data, cls, flow_style=None):
- if hasattr(data, '__getstate__'):
- state = data.__getstate__()
- else:
- state = data.__dict__.copy()
- return self.represent_mapping(tag, state, flow_style=flow_style)
-
- def represent_undefined(self, data):
- raise RepresenterError("cannot represent an object: %s" % data)
-
-SafeRepresenter.add_representer(type(None),
- SafeRepresenter.represent_none)
-
-SafeRepresenter.add_representer(str,
- SafeRepresenter.represent_str)
-
-SafeRepresenter.add_representer(unicode,
- SafeRepresenter.represent_unicode)
-
-SafeRepresenter.add_representer(bool,
- SafeRepresenter.represent_bool)
-
-SafeRepresenter.add_representer(int,
- SafeRepresenter.represent_int)
-
-SafeRepresenter.add_representer(long,
- SafeRepresenter.represent_long)
-
-SafeRepresenter.add_representer(float,
- SafeRepresenter.represent_float)
-
-SafeRepresenter.add_representer(list,
- SafeRepresenter.represent_list)
-
-SafeRepresenter.add_representer(tuple,
- SafeRepresenter.represent_list)
-
-SafeRepresenter.add_representer(dict,
- SafeRepresenter.represent_dict)
-
-SafeRepresenter.add_representer(set,
- SafeRepresenter.represent_set)
-
-SafeRepresenter.add_representer(datetime.date,
- SafeRepresenter.represent_date)
-
-SafeRepresenter.add_representer(datetime.datetime,
- SafeRepresenter.represent_datetime)
-
-SafeRepresenter.add_representer(None,
- SafeRepresenter.represent_undefined)
-
-class Representer(SafeRepresenter):
-
- def represent_str(self, data):
- tag = None
- style = None
- try:
- data = unicode(data, 'ascii')
- tag = u'tag:yaml.org,2002:str'
- except UnicodeDecodeError:
- try:
- data = unicode(data, 'utf-8')
- tag = u'tag:yaml.org,2002:python/str'
- except UnicodeDecodeError:
- data = data.encode('base64')
- tag = u'tag:yaml.org,2002:binary'
- style = '|'
- return self.represent_scalar(tag, data, style=style)
-
- def represent_unicode(self, data):
- tag = None
- try:
- data.encode('ascii')
- tag = u'tag:yaml.org,2002:python/unicode'
- except UnicodeEncodeError:
- tag = u'tag:yaml.org,2002:str'
- return self.represent_scalar(tag, data)
-
- def represent_long(self, data):
- tag = u'tag:yaml.org,2002:int'
- if int(data) is not data:
- tag = u'tag:yaml.org,2002:python/long'
- return self.represent_scalar(tag, unicode(data))
-
- def represent_complex(self, data):
- if data.imag == 0.0:
- data = u'%r' % data.real
- elif data.real == 0.0:
- data = u'%rj' % data.imag
- elif data.imag > 0:
- data = u'%r+%rj' % (data.real, data.imag)
- else:
- data = u'%r%rj' % (data.real, data.imag)
- return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
-
- def represent_tuple(self, data):
- return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
-
- def represent_name(self, data):
- name = u'%s.%s' % (data.__module__, data.__name__)
- return self.represent_scalar(u'tag:yaml.org,2002:python/name:'+name, u'')
-
- def represent_module(self, data):
- return self.represent_scalar(
- u'tag:yaml.org,2002:python/module:'+data.__name__, u'')
-
- def represent_instance(self, data):
- # For instances of classic classes, we use __getinitargs__ and
- # __getstate__ to serialize the data.
-
- # If data.__getinitargs__ exists, the object must be reconstructed by
- # calling cls(**args), where args is a tuple returned by
- # __getinitargs__. Otherwise, the cls.__init__ method should never be
- # called and the class instance is created by instantiating a trivial
- # class and assigning to the instance's __class__ variable.
-
- # If data.__getstate__ exists, it returns the state of the object.
- # Otherwise, the state of the object is data.__dict__.
-
- # We produce either a !!python/object or !!python/object/new node.
- # If data.__getinitargs__ does not exist and state is a dictionary, we
- # produce a !!python/object node . Otherwise we produce a
- # !!python/object/new node.
-
- cls = data.__class__
- class_name = u'%s.%s' % (cls.__module__, cls.__name__)
- args = None
- state = None
- if hasattr(data, '__getinitargs__'):
- args = list(data.__getinitargs__())
- if hasattr(data, '__getstate__'):
- state = data.__getstate__()
- else:
- state = data.__dict__
- if args is None and isinstance(state, dict):
- return self.represent_mapping(
- u'tag:yaml.org,2002:python/object:'+class_name, state)
- if isinstance(state, dict) and not state:
- return self.represent_sequence(
- u'tag:yaml.org,2002:python/object/new:'+class_name, args)
- value = {}
- if args:
- value['args'] = args
- value['state'] = state
- return self.represent_mapping(
- u'tag:yaml.org,2002:python/object/new:'+class_name, value)
-
- def represent_object(self, data):
- # We use __reduce__ API to save the data. data.__reduce__ returns
- # a tuple of length 2-5:
- # (function, args, state, listitems, dictitems)
-
- # For reconstructing, we calls function(*args), then set its state,
- # listitems, and dictitems if they are not None.
-
- # A special case is when function.__name__ == '__newobj__'. In this
- # case we create the object with args[0].__new__(*args).
-
- # Another special case is when __reduce__ returns a string - we don't
- # support it.
-
- # We produce a !!python/object, !!python/object/new or
- # !!python/object/apply node.
-
- cls = type(data)
- if cls in copy_reg.dispatch_table:
- reduce = copy_reg.dispatch_table[cls](data)
- elif hasattr(data, '__reduce_ex__'):
- reduce = data.__reduce_ex__(2)
- elif hasattr(data, '__reduce__'):
- reduce = data.__reduce__()
- else:
- raise RepresenterError("cannot represent object: %r" % data)
- reduce = (list(reduce)+[None]*5)[:5]
- function, args, state, listitems, dictitems = reduce
- args = list(args)
- if state is None:
- state = {}
- if listitems is not None:
- listitems = list(listitems)
- if dictitems is not None:
- dictitems = dict(dictitems)
- if function.__name__ == '__newobj__':
- function = args[0]
- args = args[1:]
- tag = u'tag:yaml.org,2002:python/object/new:'
- newobj = True
- else:
- tag = u'tag:yaml.org,2002:python/object/apply:'
- newobj = False
- function_name = u'%s.%s' % (function.__module__, function.__name__)
- if not args and not listitems and not dictitems \
- and isinstance(state, dict) and newobj:
- return self.represent_mapping(
- u'tag:yaml.org,2002:python/object:'+function_name, state)
- if not listitems and not dictitems \
- and isinstance(state, dict) and not state:
- return self.represent_sequence(tag+function_name, args)
- value = {}
- if args:
- value['args'] = args
- if state or not isinstance(state, dict):
- value['state'] = state
- if listitems:
- value['listitems'] = listitems
- if dictitems:
- value['dictitems'] = dictitems
- return self.represent_mapping(tag+function_name, value)
-
-Representer.add_representer(str,
- Representer.represent_str)
-
-Representer.add_representer(unicode,
- Representer.represent_unicode)
-
-Representer.add_representer(long,
- Representer.represent_long)
-
-Representer.add_representer(complex,
- Representer.represent_complex)
-
-Representer.add_representer(tuple,
- Representer.represent_tuple)
-
-Representer.add_representer(type,
- Representer.represent_name)
-
-Representer.add_representer(types.ClassType,
- Representer.represent_name)
-
-Representer.add_representer(types.FunctionType,
- Representer.represent_name)
-
-Representer.add_representer(types.BuiltinFunctionType,
- Representer.represent_name)
-
-Representer.add_representer(types.ModuleType,
- Representer.represent_module)
-
-Representer.add_multi_representer(types.InstanceType,
- Representer.represent_instance)
-
-Representer.add_multi_representer(object,
- Representer.represent_object)
-
diff --git a/lib/spack/external/yaml/lib/yaml/resolver.py b/lib/spack/external/yaml/lib/yaml/resolver.py
deleted file mode 100644
index 528fbc0ead..0000000000
--- a/lib/spack/external/yaml/lib/yaml/resolver.py
+++ /dev/null
@@ -1,227 +0,0 @@
-
-__all__ = ['BaseResolver', 'Resolver']
-
-from error import *
-from nodes import *
-
-import re
-
-class ResolverError(YAMLError):
- pass
-
-class BaseResolver(object):
-
- DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str'
- DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq'
- DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map'
-
- yaml_implicit_resolvers = {}
- yaml_path_resolvers = {}
-
- def __init__(self):
- self.resolver_exact_paths = []
- self.resolver_prefix_paths = []
-
- def add_implicit_resolver(cls, tag, regexp, first):
- if not 'yaml_implicit_resolvers' in cls.__dict__:
- implicit_resolvers = {}
- for key in cls.yaml_implicit_resolvers:
- implicit_resolvers[key] = cls.yaml_implicit_resolvers[key][:]
- cls.yaml_implicit_resolvers = implicit_resolvers
- if first is None:
- first = [None]
- for ch in first:
- cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
- add_implicit_resolver = classmethod(add_implicit_resolver)
-
- def add_path_resolver(cls, tag, path, kind=None):
- # Note: `add_path_resolver` is experimental. The API could be changed.
- # `new_path` is a pattern that is matched against the path from the
- # root to the node that is being considered. `node_path` elements are
- # tuples `(node_check, index_check)`. `node_check` is a node class:
- # `ScalarNode`, `SequenceNode`, `MappingNode` or `None`. `None`
- # matches any kind of a node. `index_check` could be `None`, a boolean
- # value, a string value, or a number. `None` and `False` match against
- # any _value_ of sequence and mapping nodes. `True` matches against
- # any _key_ of a mapping node. A string `index_check` matches against
- # a mapping value that corresponds to a scalar key which content is
- # equal to the `index_check` value. An integer `index_check` matches
- # against a sequence value with the index equal to `index_check`.
- if not 'yaml_path_resolvers' in cls.__dict__:
- cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()
- new_path = []
- for element in path:
- if isinstance(element, (list, tuple)):
- if len(element) == 2:
- node_check, index_check = element
- elif len(element) == 1:
- node_check = element[0]
- index_check = True
- else:
- raise ResolverError("Invalid path element: %s" % element)
- else:
- node_check = None
- index_check = element
- if node_check is str:
- node_check = ScalarNode
- elif node_check is list:
- node_check = SequenceNode
- elif node_check is dict:
- node_check = MappingNode
- elif node_check not in [ScalarNode, SequenceNode, MappingNode] \
- and not isinstance(node_check, basestring) \
- and node_check is not None:
- raise ResolverError("Invalid node checker: %s" % node_check)
- if not isinstance(index_check, (basestring, int)) \
- and index_check is not None:
- raise ResolverError("Invalid index checker: %s" % index_check)
- new_path.append((node_check, index_check))
- if kind is str:
- kind = ScalarNode
- elif kind is list:
- kind = SequenceNode
- elif kind is dict:
- kind = MappingNode
- elif kind not in [ScalarNode, SequenceNode, MappingNode] \
- and kind is not None:
- raise ResolverError("Invalid node kind: %s" % kind)
- cls.yaml_path_resolvers[tuple(new_path), kind] = tag
- add_path_resolver = classmethod(add_path_resolver)
-
- def descend_resolver(self, current_node, current_index):
- if not self.yaml_path_resolvers:
- return
- exact_paths = {}
- prefix_paths = []
- if current_node:
- depth = len(self.resolver_prefix_paths)
- for path, kind in self.resolver_prefix_paths[-1]:
- if self.check_resolver_prefix(depth, path, kind,
- current_node, current_index):
- if len(path) > depth:
- prefix_paths.append((path, kind))
- else:
- exact_paths[kind] = self.yaml_path_resolvers[path, kind]
- else:
- for path, kind in self.yaml_path_resolvers:
- if not path:
- exact_paths[kind] = self.yaml_path_resolvers[path, kind]
- else:
- prefix_paths.append((path, kind))
- self.resolver_exact_paths.append(exact_paths)
- self.resolver_prefix_paths.append(prefix_paths)
-
- def ascend_resolver(self):
- if not self.yaml_path_resolvers:
- return
- self.resolver_exact_paths.pop()
- self.resolver_prefix_paths.pop()
-
- def check_resolver_prefix(self, depth, path, kind,
- current_node, current_index):
- node_check, index_check = path[depth-1]
- if isinstance(node_check, basestring):
- if current_node.tag != node_check:
- return
- elif node_check is not None:
- if not isinstance(current_node, node_check):
- return
- if index_check is True and current_index is not None:
- return
- if (index_check is False or index_check is None) \
- and current_index is None:
- return
- if isinstance(index_check, basestring):
- if not (isinstance(current_index, ScalarNode)
- and index_check == current_index.value):
- return
- elif isinstance(index_check, int) and not isinstance(index_check, bool):
- if index_check != current_index:
- return
- return True
-
- def resolve(self, kind, value, implicit):
- if kind is ScalarNode and implicit[0]:
- if value == u'':
- resolvers = self.yaml_implicit_resolvers.get(u'', [])
- else:
- resolvers = self.yaml_implicit_resolvers.get(value[0], [])
- resolvers += self.yaml_implicit_resolvers.get(None, [])
- for tag, regexp in resolvers:
- if regexp.match(value):
- return tag
- implicit = implicit[1]
- if self.yaml_path_resolvers:
- exact_paths = self.resolver_exact_paths[-1]
- if kind in exact_paths:
- return exact_paths[kind]
- if None in exact_paths:
- return exact_paths[None]
- if kind is ScalarNode:
- return self.DEFAULT_SCALAR_TAG
- elif kind is SequenceNode:
- return self.DEFAULT_SEQUENCE_TAG
- elif kind is MappingNode:
- return self.DEFAULT_MAPPING_TAG
-
-class Resolver(BaseResolver):
- pass
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:bool',
- re.compile(ur'''^(?:yes|Yes|YES|no|No|NO
- |true|True|TRUE|false|False|FALSE
- |on|On|ON|off|Off|OFF)$''', re.X),
- list(u'yYnNtTfFoO'))
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:float',
- re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
- |\.[0-9_]+(?:[eE][-+][0-9]+)?
- |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
- |[-+]?\.(?:inf|Inf|INF)
- |\.(?:nan|NaN|NAN))$''', re.X),
- list(u'-+0123456789.'))
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:int',
- re.compile(ur'''^(?:[-+]?0b[0-1_]+
- |[-+]?0[0-7_]+
- |[-+]?(?:0|[1-9][0-9_]*)
- |[-+]?0x[0-9a-fA-F_]+
- |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
- list(u'-+0123456789'))
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:merge',
- re.compile(ur'^(?:<<)$'),
- [u'<'])
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:null',
- re.compile(ur'''^(?: ~
- |null|Null|NULL
- | )$''', re.X),
- [u'~', u'n', u'N', u''])
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:timestamp',
- re.compile(ur'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
- |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
- (?:[Tt]|[ \t]+)[0-9][0-9]?
- :[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)?
- (?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
- list(u'0123456789'))
-
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:value',
- re.compile(ur'^(?:=)$'),
- [u'='])
-
-# The following resolver is only for documentation purposes. It cannot work
-# because plain scalars cannot start with '!', '&', or '*'.
-Resolver.add_implicit_resolver(
- u'tag:yaml.org,2002:yaml',
- re.compile(ur'^(?:!|&|\*)$'),
- list(u'!&*'))
-
diff --git a/lib/spack/external/yaml/lib/yaml/serializer.py b/lib/spack/external/yaml/lib/yaml/serializer.py
deleted file mode 100644
index 0bf1e96dc1..0000000000
--- a/lib/spack/external/yaml/lib/yaml/serializer.py
+++ /dev/null
@@ -1,111 +0,0 @@
-
-__all__ = ['Serializer', 'SerializerError']
-
-from error import YAMLError
-from events import *
-from nodes import *
-
-class SerializerError(YAMLError):
- pass
-
-class Serializer(object):
-
- ANCHOR_TEMPLATE = u'id%03d'
-
- def __init__(self, encoding=None,
- explicit_start=None, explicit_end=None, version=None, tags=None):
- self.use_encoding = encoding
- self.use_explicit_start = explicit_start
- self.use_explicit_end = explicit_end
- self.use_version = version
- self.use_tags = tags
- self.serialized_nodes = {}
- self.anchors = {}
- self.last_anchor_id = 0
- self.closed = None
-
- def open(self):
- if self.closed is None:
- self.emit(StreamStartEvent(encoding=self.use_encoding))
- self.closed = False
- elif self.closed:
- raise SerializerError("serializer is closed")
- else:
- raise SerializerError("serializer is already opened")
-
- def close(self):
- if self.closed is None:
- raise SerializerError("serializer is not opened")
- elif not self.closed:
- self.emit(StreamEndEvent())
- self.closed = True
-
- #def __del__(self):
- # self.close()
-
- def serialize(self, node):
- if self.closed is None:
- raise SerializerError("serializer is not opened")
- elif self.closed:
- raise SerializerError("serializer is closed")
- self.emit(DocumentStartEvent(explicit=self.use_explicit_start,
- version=self.use_version, tags=self.use_tags))
- self.anchor_node(node)
- self.serialize_node(node, None, None)
- self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
- self.serialized_nodes = {}
- self.anchors = {}
- self.last_anchor_id = 0
-
- def anchor_node(self, node):
- if node in self.anchors:
- if self.anchors[node] is None:
- self.anchors[node] = self.generate_anchor(node)
- else:
- self.anchors[node] = None
- if isinstance(node, SequenceNode):
- for item in node.value:
- self.anchor_node(item)
- elif isinstance(node, MappingNode):
- for key, value in node.value:
- self.anchor_node(key)
- self.anchor_node(value)
-
- def generate_anchor(self, node):
- self.last_anchor_id += 1
- return self.ANCHOR_TEMPLATE % self.last_anchor_id
-
- def serialize_node(self, node, parent, index):
- alias = self.anchors[node]
- if node in self.serialized_nodes:
- self.emit(AliasEvent(alias))
- else:
- self.serialized_nodes[node] = True
- self.descend_resolver(parent, index)
- if isinstance(node, ScalarNode):
- detected_tag = self.resolve(ScalarNode, node.value, (True, False))
- default_tag = self.resolve(ScalarNode, node.value, (False, True))
- implicit = (node.tag == detected_tag), (node.tag == default_tag)
- self.emit(ScalarEvent(alias, node.tag, implicit, node.value,
- style=node.style))
- elif isinstance(node, SequenceNode):
- implicit = (node.tag
- == self.resolve(SequenceNode, node.value, True))
- self.emit(SequenceStartEvent(alias, node.tag, implicit,
- flow_style=node.flow_style))
- index = 0
- for item in node.value:
- self.serialize_node(item, node, index)
- index += 1
- self.emit(SequenceEndEvent())
- elif isinstance(node, MappingNode):
- implicit = (node.tag
- == self.resolve(MappingNode, node.value, True))
- self.emit(MappingStartEvent(alias, node.tag, implicit,
- flow_style=node.flow_style))
- for key, value in node.value:
- self.serialize_node(key, node, None)
- self.serialize_node(value, node, key)
- self.emit(MappingEndEvent())
- self.ascend_resolver()
-
diff --git a/lib/spack/external/yaml/lib/yaml/tokens.py b/lib/spack/external/yaml/lib/yaml/tokens.py
deleted file mode 100644
index 4d0b48a394..0000000000
--- a/lib/spack/external/yaml/lib/yaml/tokens.py
+++ /dev/null
@@ -1,104 +0,0 @@
-
-class Token(object):
- def __init__(self, start_mark, end_mark):
- self.start_mark = start_mark
- self.end_mark = end_mark
- def __repr__(self):
- attributes = [key for key in self.__dict__
- if not key.endswith('_mark')]
- attributes.sort()
- arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
- for key in attributes])
- return '%s(%s)' % (self.__class__.__name__, arguments)
-
-#class BOMToken(Token):
-# id = '<byte order mark>'
-
-class DirectiveToken(Token):
- id = '<directive>'
- def __init__(self, name, value, start_mark, end_mark):
- self.name = name
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class DocumentStartToken(Token):
- id = '<document start>'
-
-class DocumentEndToken(Token):
- id = '<document end>'
-
-class StreamStartToken(Token):
- id = '<stream start>'
- def __init__(self, start_mark=None, end_mark=None,
- encoding=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.encoding = encoding
-
-class StreamEndToken(Token):
- id = '<stream end>'
-
-class BlockSequenceStartToken(Token):
- id = '<block sequence start>'
-
-class BlockMappingStartToken(Token):
- id = '<block mapping start>'
-
-class BlockEndToken(Token):
- id = '<block end>'
-
-class FlowSequenceStartToken(Token):
- id = '['
-
-class FlowMappingStartToken(Token):
- id = '{'
-
-class FlowSequenceEndToken(Token):
- id = ']'
-
-class FlowMappingEndToken(Token):
- id = '}'
-
-class KeyToken(Token):
- id = '?'
-
-class ValueToken(Token):
- id = ':'
-
-class BlockEntryToken(Token):
- id = '-'
-
-class FlowEntryToken(Token):
- id = ','
-
-class AliasToken(Token):
- id = '<alias>'
- def __init__(self, value, start_mark, end_mark):
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class AnchorToken(Token):
- id = '<anchor>'
- def __init__(self, value, start_mark, end_mark):
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class TagToken(Token):
- id = '<tag>'
- def __init__(self, value, start_mark, end_mark):
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class ScalarToken(Token):
- id = '<scalar>'
- def __init__(self, value, plain, start_mark, end_mark, style=None):
- self.value = value
- self.plain = plain
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.style = style
-
diff --git a/lib/spack/external/yaml/lib3/yaml/composer.py b/lib/spack/external/yaml/lib3/yaml/composer.py
deleted file mode 100644
index d5c6a7acd9..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/composer.py
+++ /dev/null
@@ -1,139 +0,0 @@
-
-__all__ = ['Composer', 'ComposerError']
-
-from .error import MarkedYAMLError
-from .events import *
-from .nodes import *
-
-class ComposerError(MarkedYAMLError):
- pass
-
-class Composer:
-
- def __init__(self):
- self.anchors = {}
-
- def check_node(self):
- # Drop the STREAM-START event.
- if self.check_event(StreamStartEvent):
- self.get_event()
-
- # If there are more documents available?
- return not self.check_event(StreamEndEvent)
-
- def get_node(self):
- # Get the root node of the next document.
- if not self.check_event(StreamEndEvent):
- return self.compose_document()
-
- def get_single_node(self):
- # Drop the STREAM-START event.
- self.get_event()
-
- # Compose a document if the stream is not empty.
- document = None
- if not self.check_event(StreamEndEvent):
- document = self.compose_document()
-
- # Ensure that the stream contains no more documents.
- if not self.check_event(StreamEndEvent):
- event = self.get_event()
- raise ComposerError("expected a single document in the stream",
- document.start_mark, "but found another document",
- event.start_mark)
-
- # Drop the STREAM-END event.
- self.get_event()
-
- return document
-
- def compose_document(self):
- # Drop the DOCUMENT-START event.
- self.get_event()
-
- # Compose the root node.
- node = self.compose_node(None, None)
-
- # Drop the DOCUMENT-END event.
- self.get_event()
-
- self.anchors = {}
- return node
-
- def compose_node(self, parent, index):
- if self.check_event(AliasEvent):
- event = self.get_event()
- anchor = event.anchor
- if anchor not in self.anchors:
- raise ComposerError(None, None, "found undefined alias %r"
- % anchor, event.start_mark)
- return self.anchors[anchor]
- event = self.peek_event()
- anchor = event.anchor
- if anchor is not None:
- if anchor in self.anchors:
- raise ComposerError("found duplicate anchor %r; first occurence"
- % anchor, self.anchors[anchor].start_mark,
- "second occurence", event.start_mark)
- self.descend_resolver(parent, index)
- if self.check_event(ScalarEvent):
- node = self.compose_scalar_node(anchor)
- elif self.check_event(SequenceStartEvent):
- node = self.compose_sequence_node(anchor)
- elif self.check_event(MappingStartEvent):
- node = self.compose_mapping_node(anchor)
- self.ascend_resolver()
- return node
-
- def compose_scalar_node(self, anchor):
- event = self.get_event()
- tag = event.tag
- if tag is None or tag == '!':
- tag = self.resolve(ScalarNode, event.value, event.implicit)
- node = ScalarNode(tag, event.value,
- event.start_mark, event.end_mark, style=event.style)
- if anchor is not None:
- self.anchors[anchor] = node
- return node
-
- def compose_sequence_node(self, anchor):
- start_event = self.get_event()
- tag = start_event.tag
- if tag is None or tag == '!':
- tag = self.resolve(SequenceNode, None, start_event.implicit)
- node = SequenceNode(tag, [],
- start_event.start_mark, None,
- flow_style=start_event.flow_style)
- if anchor is not None:
- self.anchors[anchor] = node
- index = 0
- while not self.check_event(SequenceEndEvent):
- node.value.append(self.compose_node(node, index))
- index += 1
- end_event = self.get_event()
- node.end_mark = end_event.end_mark
- return node
-
- def compose_mapping_node(self, anchor):
- start_event = self.get_event()
- tag = start_event.tag
- if tag is None or tag == '!':
- tag = self.resolve(MappingNode, None, start_event.implicit)
- node = MappingNode(tag, [],
- start_event.start_mark, None,
- flow_style=start_event.flow_style)
- if anchor is not None:
- self.anchors[anchor] = node
- while not self.check_event(MappingEndEvent):
- #key_event = self.peek_event()
- item_key = self.compose_node(node, None)
- #if item_key in node.value:
- # raise ComposerError("while composing a mapping", start_event.start_mark,
- # "found duplicate key", key_event.start_mark)
- item_value = self.compose_node(node, item_key)
- #node.value[item_key] = item_value
- node.value.append((item_key, item_value))
- end_event = self.get_event()
- node.end_mark = end_event.end_mark
- return node
-
diff --git a/lib/spack/external/yaml/lib3/yaml/constructor.py b/lib/spack/external/yaml/lib3/yaml/constructor.py
deleted file mode 100644
index 981543aebb..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/constructor.py
+++ /dev/null
@@ -1,686 +0,0 @@
-
-__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
- 'ConstructorError']
-
-from .error import *
-from .nodes import *
-
-import collections, datetime, base64, binascii, re, sys, types
-
-class ConstructorError(MarkedYAMLError):
- pass
-
-class BaseConstructor:
-
- yaml_constructors = {}
- yaml_multi_constructors = {}
-
- def __init__(self):
- self.constructed_objects = {}
- self.recursive_objects = {}
- self.state_generators = []
- self.deep_construct = False
-
- def check_data(self):
- # If there are more documents available?
- return self.check_node()
-
- def get_data(self):
- # Construct and return the next document.
- if self.check_node():
- return self.construct_document(self.get_node())
-
- def get_single_data(self):
- # Ensure that the stream contains a single document and construct it.
- node = self.get_single_node()
- if node is not None:
- return self.construct_document(node)
- return None
-
- def construct_document(self, node):
- data = self.construct_object(node)
- while self.state_generators:
- state_generators = self.state_generators
- self.state_generators = []
- for generator in state_generators:
- for dummy in generator:
- pass
- self.constructed_objects = {}
- self.recursive_objects = {}
- self.deep_construct = False
- return data
-
- def construct_object(self, node, deep=False):
- if node in self.constructed_objects:
- return self.constructed_objects[node]
- if deep:
- old_deep = self.deep_construct
- self.deep_construct = True
- if node in self.recursive_objects:
- raise ConstructorError(None, None,
- "found unconstructable recursive node", node.start_mark)
- self.recursive_objects[node] = None
- constructor = None
- tag_suffix = None
- if node.tag in self.yaml_constructors:
- constructor = self.yaml_constructors[node.tag]
- else:
- for tag_prefix in self.yaml_multi_constructors:
- if node.tag.startswith(tag_prefix):
- tag_suffix = node.tag[len(tag_prefix):]
- constructor = self.yaml_multi_constructors[tag_prefix]
- break
- else:
- if None in self.yaml_multi_constructors:
- tag_suffix = node.tag
- constructor = self.yaml_multi_constructors[None]
- elif None in self.yaml_constructors:
- constructor = self.yaml_constructors[None]
- elif isinstance(node, ScalarNode):
- constructor = self.__class__.construct_scalar
- elif isinstance(node, SequenceNode):
- constructor = self.__class__.construct_sequence
- elif isinstance(node, MappingNode):
- constructor = self.__class__.construct_mapping
- if tag_suffix is None:
- data = constructor(self, node)
- else:
- data = constructor(self, tag_suffix, node)
- if isinstance(data, types.GeneratorType):
- generator = data
- data = next(generator)
- if self.deep_construct:
- for dummy in generator:
- pass
- else:
- self.state_generators.append(generator)
- self.constructed_objects[node] = data
- del self.recursive_objects[node]
- if deep:
- self.deep_construct = old_deep
- return data
-
- def construct_scalar(self, node):
- if not isinstance(node, ScalarNode):
- raise ConstructorError(None, None,
- "expected a scalar node, but found %s" % node.id,
- node.start_mark)
- return node.value
-
- def construct_sequence(self, node, deep=False):
- if not isinstance(node, SequenceNode):
- raise ConstructorError(None, None,
- "expected a sequence node, but found %s" % node.id,
- node.start_mark)
- return [self.construct_object(child, deep=deep)
- for child in node.value]
-
- def construct_mapping(self, node, deep=False):
- if not isinstance(node, MappingNode):
- raise ConstructorError(None, None,
- "expected a mapping node, but found %s" % node.id,
- node.start_mark)
- mapping = {}
- for key_node, value_node in node.value:
- key = self.construct_object(key_node, deep=deep)
- if not isinstance(key, collections.Hashable):
- raise ConstructorError("while constructing a mapping", node.start_mark,
- "found unhashable key", key_node.start_mark)
- value = self.construct_object(value_node, deep=deep)
- mapping[key] = value
- return mapping
-
- def construct_pairs(self, node, deep=False):
- if not isinstance(node, MappingNode):
- raise ConstructorError(None, None,
- "expected a mapping node, but found %s" % node.id,
- node.start_mark)
- pairs = []
- for key_node, value_node in node.value:
- key = self.construct_object(key_node, deep=deep)
- value = self.construct_object(value_node, deep=deep)
- pairs.append((key, value))
- return pairs
-
- @classmethod
- def add_constructor(cls, tag, constructor):
- if not 'yaml_constructors' in cls.__dict__:
- cls.yaml_constructors = cls.yaml_constructors.copy()
- cls.yaml_constructors[tag] = constructor
-
- @classmethod
- def add_multi_constructor(cls, tag_prefix, multi_constructor):
- if not 'yaml_multi_constructors' in cls.__dict__:
- cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
- cls.yaml_multi_constructors[tag_prefix] = multi_constructor
-
-class SafeConstructor(BaseConstructor):
-
- def construct_scalar(self, node):
- if isinstance(node, MappingNode):
- for key_node, value_node in node.value:
- if key_node.tag == 'tag:yaml.org,2002:value':
- return self.construct_scalar(value_node)
- return super().construct_scalar(node)
-
- def flatten_mapping(self, node):
- merge = []
- index = 0
- while index < len(node.value):
- key_node, value_node = node.value[index]
- if key_node.tag == 'tag:yaml.org,2002:merge':
- del node.value[index]
- if isinstance(value_node, MappingNode):
- self.flatten_mapping(value_node)
- merge.extend(value_node.value)
- elif isinstance(value_node, SequenceNode):
- submerge = []
- for subnode in value_node.value:
- if not isinstance(subnode, MappingNode):
- raise ConstructorError("while constructing a mapping",
- node.start_mark,
- "expected a mapping for merging, but found %s"
- % subnode.id, subnode.start_mark)
- self.flatten_mapping(subnode)
- submerge.append(subnode.value)
- submerge.reverse()
- for value in submerge:
- merge.extend(value)
- else:
- raise ConstructorError("while constructing a mapping", node.start_mark,
- "expected a mapping or list of mappings for merging, but found %s"
- % value_node.id, value_node.start_mark)
- elif key_node.tag == 'tag:yaml.org,2002:value':
- key_node.tag = 'tag:yaml.org,2002:str'
- index += 1
- else:
- index += 1
- if merge:
- node.value = merge + node.value
-
- def construct_mapping(self, node, deep=False):
- if isinstance(node, MappingNode):
- self.flatten_mapping(node)
- return super().construct_mapping(node, deep=deep)
-
- def construct_yaml_null(self, node):
- self.construct_scalar(node)
- return None
-
- bool_values = {
- 'yes': True,
- 'no': False,
- 'true': True,
- 'false': False,
- 'on': True,
- 'off': False,
- }
-
- def construct_yaml_bool(self, node):
- value = self.construct_scalar(node)
- return self.bool_values[value.lower()]
-
- def construct_yaml_int(self, node):
- value = self.construct_scalar(node)
- value = value.replace('_', '')
- sign = +1
- if value[0] == '-':
- sign = -1
- if value[0] in '+-':
- value = value[1:]
- if value == '0':
- return 0
- elif value.startswith('0b'):
- return sign*int(value[2:], 2)
- elif value.startswith('0x'):
- return sign*int(value[2:], 16)
- elif value[0] == '0':
- return sign*int(value, 8)
- elif ':' in value:
- digits = [int(part) for part in value.split(':')]
- digits.reverse()
- base = 1
- value = 0
- for digit in digits:
- value += digit*base
- base *= 60
- return sign*value
- else:
- return sign*int(value)
-
- inf_value = 1e300
- while inf_value != inf_value*inf_value:
- inf_value *= inf_value
- nan_value = -inf_value/inf_value # Trying to make a quiet NaN (like C99).
-
- def construct_yaml_float(self, node):
- value = self.construct_scalar(node)
- value = value.replace('_', '').lower()
- sign = +1
- if value[0] == '-':
- sign = -1
- if value[0] in '+-':
- value = value[1:]
- if value == '.inf':
- return sign*self.inf_value
- elif value == '.nan':
- return self.nan_value
- elif ':' in value:
- digits = [float(part) for part in value.split(':')]
- digits.reverse()
- base = 1
- value = 0.0
- for digit in digits:
- value += digit*base
- base *= 60
- return sign*value
- else:
- return sign*float(value)
-
- def construct_yaml_binary(self, node):
- try:
- value = self.construct_scalar(node).encode('ascii')
- except UnicodeEncodeError as exc:
- raise ConstructorError(None, None,
- "failed to convert base64 data into ascii: %s" % exc,
- node.start_mark)
- try:
- if hasattr(base64, 'decodebytes'):
- return base64.decodebytes(value)
- else:
- return base64.decodestring(value)
- except binascii.Error as exc:
- raise ConstructorError(None, None,
- "failed to decode base64 data: %s" % exc, node.start_mark)
-
- timestamp_regexp = re.compile(
- r'''^(?P<year>[0-9][0-9][0-9][0-9])
- -(?P<month>[0-9][0-9]?)
- -(?P<day>[0-9][0-9]?)
- (?:(?:[Tt]|[ \t]+)
- (?P<hour>[0-9][0-9]?)
- :(?P<minute>[0-9][0-9])
- :(?P<second>[0-9][0-9])
- (?:\.(?P<fraction>[0-9]*))?
- (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
- (?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
-
- def construct_yaml_timestamp(self, node):
- value = self.construct_scalar(node)
- match = self.timestamp_regexp.match(node.value)
- values = match.groupdict()
- year = int(values['year'])
- month = int(values['month'])
- day = int(values['day'])
- if not values['hour']:
- return datetime.date(year, month, day)
- hour = int(values['hour'])
- minute = int(values['minute'])
- second = int(values['second'])
- fraction = 0
- if values['fraction']:
- fraction = values['fraction'][:6]
- while len(fraction) < 6:
- fraction += '0'
- fraction = int(fraction)
- delta = None
- if values['tz_sign']:
- tz_hour = int(values['tz_hour'])
- tz_minute = int(values['tz_minute'] or 0)
- delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
- if values['tz_sign'] == '-':
- delta = -delta
- data = datetime.datetime(year, month, day, hour, minute, second, fraction)
- if delta:
- data -= delta
- return data
-
- def construct_yaml_omap(self, node):
- # Note: we do not check for duplicate keys, because it's too
- # CPU-expensive.
- omap = []
- yield omap
- if not isinstance(node, SequenceNode):
- raise ConstructorError("while constructing an ordered map", node.start_mark,
- "expected a sequence, but found %s" % node.id, node.start_mark)
- for subnode in node.value:
- if not isinstance(subnode, MappingNode):
- raise ConstructorError("while constructing an ordered map", node.start_mark,
- "expected a mapping of length 1, but found %s" % subnode.id,
- subnode.start_mark)
- if len(subnode.value) != 1:
- raise ConstructorError("while constructing an ordered map", node.start_mark,
- "expected a single mapping item, but found %d items" % len(subnode.value),
- subnode.start_mark)
- key_node, value_node = subnode.value[0]
- key = self.construct_object(key_node)
- value = self.construct_object(value_node)
- omap.append((key, value))
-
- def construct_yaml_pairs(self, node):
- # Note: the same code as `construct_yaml_omap`.
- pairs = []
- yield pairs
- if not isinstance(node, SequenceNode):
- raise ConstructorError("while constructing pairs", node.start_mark,
- "expected a sequence, but found %s" % node.id, node.start_mark)
- for subnode in node.value:
- if not isinstance(subnode, MappingNode):
- raise ConstructorError("while constructing pairs", node.start_mark,
- "expected a mapping of length 1, but found %s" % subnode.id,
- subnode.start_mark)
- if len(subnode.value) != 1:
- raise ConstructorError("while constructing pairs", node.start_mark,
- "expected a single mapping item, but found %d items" % len(subnode.value),
- subnode.start_mark)
- key_node, value_node = subnode.value[0]
- key = self.construct_object(key_node)
- value = self.construct_object(value_node)
- pairs.append((key, value))
-
- def construct_yaml_set(self, node):
- data = set()
- yield data
- value = self.construct_mapping(node)
- data.update(value)
-
- def construct_yaml_str(self, node):
- return self.construct_scalar(node)
-
- def construct_yaml_seq(self, node):
- data = []
- yield data
- data.extend(self.construct_sequence(node))
-
- def construct_yaml_map(self, node):
- data = {}
- yield data
- value = self.construct_mapping(node)
- data.update(value)
-
- def construct_yaml_object(self, node, cls):
- data = cls.__new__(cls)
- yield data
- if hasattr(data, '__setstate__'):
- state = self.construct_mapping(node, deep=True)
- data.__setstate__(state)
- else:
- state = self.construct_mapping(node)
- data.__dict__.update(state)
-
- def construct_undefined(self, node):
- raise ConstructorError(None, None,
- "could not determine a constructor for the tag %r" % node.tag,
- node.start_mark)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:null',
- SafeConstructor.construct_yaml_null)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:bool',
- SafeConstructor.construct_yaml_bool)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:int',
- SafeConstructor.construct_yaml_int)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:float',
- SafeConstructor.construct_yaml_float)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:binary',
- SafeConstructor.construct_yaml_binary)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:timestamp',
- SafeConstructor.construct_yaml_timestamp)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:omap',
- SafeConstructor.construct_yaml_omap)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:pairs',
- SafeConstructor.construct_yaml_pairs)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:set',
- SafeConstructor.construct_yaml_set)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:str',
- SafeConstructor.construct_yaml_str)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:seq',
- SafeConstructor.construct_yaml_seq)
-
-SafeConstructor.add_constructor(
- 'tag:yaml.org,2002:map',
- SafeConstructor.construct_yaml_map)
-
-SafeConstructor.add_constructor(None,
- SafeConstructor.construct_undefined)
-
-class Constructor(SafeConstructor):
-
- def construct_python_str(self, node):
- return self.construct_scalar(node)
-
- def construct_python_unicode(self, node):
- return self.construct_scalar(node)
-
- def construct_python_bytes(self, node):
- try:
- value = self.construct_scalar(node).encode('ascii')
- except UnicodeEncodeError as exc:
- raise ConstructorError(None, None,
- "failed to convert base64 data into ascii: %s" % exc,
- node.start_mark)
- try:
- if hasattr(base64, 'decodebytes'):
- return base64.decodebytes(value)
- else:
- return base64.decodestring(value)
- except binascii.Error as exc:
- raise ConstructorError(None, None,
- "failed to decode base64 data: %s" % exc, node.start_mark)
-
- def construct_python_long(self, node):
- return self.construct_yaml_int(node)
-
- def construct_python_complex(self, node):
- return complex(self.construct_scalar(node))
-
- def construct_python_tuple(self, node):
- return tuple(self.construct_sequence(node))
-
- def find_python_module(self, name, mark):
- if not name:
- raise ConstructorError("while constructing a Python module", mark,
- "expected non-empty name appended to the tag", mark)
- try:
- __import__(name)
- except ImportError as exc:
- raise ConstructorError("while constructing a Python module", mark,
- "cannot find module %r (%s)" % (name, exc), mark)
- return sys.modules[name]
-
- def find_python_name(self, name, mark):
- if not name:
- raise ConstructorError("while constructing a Python object", mark,
- "expected non-empty name appended to the tag", mark)
- if '.' in name:
- module_name, object_name = name.rsplit('.', 1)
- else:
- module_name = 'builtins'
- object_name = name
- try:
- __import__(module_name)
- except ImportError as exc:
- raise ConstructorError("while constructing a Python object", mark,
- "cannot find module %r (%s)" % (module_name, exc), mark)
- module = sys.modules[module_name]
- if not hasattr(module, object_name):
- raise ConstructorError("while constructing a Python object", mark,
- "cannot find %r in the module %r"
- % (object_name, module.__name__), mark)
- return getattr(module, object_name)
-
- def construct_python_name(self, suffix, node):
- value = self.construct_scalar(node)
- if value:
- raise ConstructorError("while constructing a Python name", node.start_mark,
- "expected the empty value, but found %r" % value, node.start_mark)
- return self.find_python_name(suffix, node.start_mark)
-
- def construct_python_module(self, suffix, node):
- value = self.construct_scalar(node)
- if value:
- raise ConstructorError("while constructing a Python module", node.start_mark,
- "expected the empty value, but found %r" % value, node.start_mark)
- return self.find_python_module(suffix, node.start_mark)
-
- def make_python_instance(self, suffix, node,
- args=None, kwds=None, newobj=False):
- if not args:
- args = []
- if not kwds:
- kwds = {}
- cls = self.find_python_name(suffix, node.start_mark)
- if newobj and isinstance(cls, type):
- return cls.__new__(cls, *args, **kwds)
- else:
- return cls(*args, **kwds)
-
- def set_python_instance_state(self, instance, state):
- if hasattr(instance, '__setstate__'):
- instance.__setstate__(state)
- else:
- slotstate = {}
- if isinstance(state, tuple) and len(state) == 2:
- state, slotstate = state
- if hasattr(instance, '__dict__'):
- instance.__dict__.update(state)
- elif state:
- slotstate.update(state)
- for key, value in slotstate.items():
- setattr(object, key, value)
-
- def construct_python_object(self, suffix, node):
- # Format:
- # !!python/object:module.name { ... state ... }
- instance = self.make_python_instance(suffix, node, newobj=True)
- yield instance
- deep = hasattr(instance, '__setstate__')
- state = self.construct_mapping(node, deep=deep)
- self.set_python_instance_state(instance, state)
-
- def construct_python_object_apply(self, suffix, node, newobj=False):
- # Format:
- # !!python/object/apply # (or !!python/object/new)
- # args: [ ... arguments ... ]
- # kwds: { ... keywords ... }
- # state: ... state ...
- # listitems: [ ... listitems ... ]
- # dictitems: { ... dictitems ... }
- # or short format:
- # !!python/object/apply [ ... arguments ... ]
- # The difference between !!python/object/apply and !!python/object/new
- # is how an object is created, check make_python_instance for details.
- if isinstance(node, SequenceNode):
- args = self.construct_sequence(node, deep=True)
- kwds = {}
- state = {}
- listitems = []
- dictitems = {}
- else:
- value = self.construct_mapping(node, deep=True)
- args = value.get('args', [])
- kwds = value.get('kwds', {})
- state = value.get('state', {})
- listitems = value.get('listitems', [])
- dictitems = value.get('dictitems', {})
- instance = self.make_python_instance(suffix, node, args, kwds, newobj)
- if state:
- self.set_python_instance_state(instance, state)
- if listitems:
- instance.extend(listitems)
- if dictitems:
- for key in dictitems:
- instance[key] = dictitems[key]
- return instance
-
- def construct_python_object_new(self, suffix, node):
- return self.construct_python_object_apply(suffix, node, newobj=True)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/none',
- Constructor.construct_yaml_null)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/bool',
- Constructor.construct_yaml_bool)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/str',
- Constructor.construct_python_str)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/unicode',
- Constructor.construct_python_unicode)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/bytes',
- Constructor.construct_python_bytes)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/int',
- Constructor.construct_yaml_int)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/long',
- Constructor.construct_python_long)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/float',
- Constructor.construct_yaml_float)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/complex',
- Constructor.construct_python_complex)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/list',
- Constructor.construct_yaml_seq)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/tuple',
- Constructor.construct_python_tuple)
-
-Constructor.add_constructor(
- 'tag:yaml.org,2002:python/dict',
- Constructor.construct_yaml_map)
-
-Constructor.add_multi_constructor(
- 'tag:yaml.org,2002:python/name:',
- Constructor.construct_python_name)
-
-Constructor.add_multi_constructor(
- 'tag:yaml.org,2002:python/module:',
- Constructor.construct_python_module)
-
-Constructor.add_multi_constructor(
- 'tag:yaml.org,2002:python/object:',
- Constructor.construct_python_object)
-
-Constructor.add_multi_constructor(
- 'tag:yaml.org,2002:python/object/apply:',
- Constructor.construct_python_object_apply)
-
-Constructor.add_multi_constructor(
- 'tag:yaml.org,2002:python/object/new:',
- Constructor.construct_python_object_new)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/cyaml.py b/lib/spack/external/yaml/lib3/yaml/cyaml.py
deleted file mode 100644
index d5cb87e994..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/cyaml.py
+++ /dev/null
@@ -1,85 +0,0 @@
-
-__all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
- 'CBaseDumper', 'CSafeDumper', 'CDumper']
-
-from _yaml import CParser, CEmitter
-
-from .constructor import *
-
-from .serializer import *
-from .representer import *
-
-from .resolver import *
-
-class CBaseLoader(CParser, BaseConstructor, BaseResolver):
-
- def __init__(self, stream):
- CParser.__init__(self, stream)
- BaseConstructor.__init__(self)
- BaseResolver.__init__(self)
-
-class CSafeLoader(CParser, SafeConstructor, Resolver):
-
- def __init__(self, stream):
- CParser.__init__(self, stream)
- SafeConstructor.__init__(self)
- Resolver.__init__(self)
-
-class CLoader(CParser, Constructor, Resolver):
-
- def __init__(self, stream):
- CParser.__init__(self, stream)
- Constructor.__init__(self)
- Resolver.__init__(self)
-
-class CBaseDumper(CEmitter, BaseRepresenter, BaseResolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- CEmitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width, encoding=encoding,
- allow_unicode=allow_unicode, line_break=line_break,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class CSafeDumper(CEmitter, SafeRepresenter, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- CEmitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width, encoding=encoding,
- allow_unicode=allow_unicode, line_break=line_break,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- SafeRepresenter.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class CDumper(CEmitter, Serializer, Representer, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- CEmitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width, encoding=encoding,
- allow_unicode=allow_unicode, line_break=line_break,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/dumper.py b/lib/spack/external/yaml/lib3/yaml/dumper.py
deleted file mode 100644
index 0b69128771..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/dumper.py
+++ /dev/null
@@ -1,62 +0,0 @@
-
-__all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
-
-from .emitter import *
-from .serializer import *
-from .representer import *
-from .resolver import *
-
-class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- Emitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- Serializer.__init__(self, encoding=encoding,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- Emitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- Serializer.__init__(self, encoding=encoding,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- SafeRepresenter.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
-class Dumper(Emitter, Serializer, Representer, Resolver):
-
- def __init__(self, stream,
- default_style=None, default_flow_style=None,
- canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None,
- encoding=None, explicit_start=None, explicit_end=None,
- version=None, tags=None):
- Emitter.__init__(self, stream, canonical=canonical,
- indent=indent, width=width,
- allow_unicode=allow_unicode, line_break=line_break)
- Serializer.__init__(self, encoding=encoding,
- explicit_start=explicit_start, explicit_end=explicit_end,
- version=version, tags=tags)
- Representer.__init__(self, default_style=default_style,
- default_flow_style=default_flow_style)
- Resolver.__init__(self)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/emitter.py b/lib/spack/external/yaml/lib3/yaml/emitter.py
deleted file mode 100644
index 34cb145a5f..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/emitter.py
+++ /dev/null
@@ -1,1137 +0,0 @@
-
-# Emitter expects events obeying the following grammar:
-# stream ::= STREAM-START document* STREAM-END
-# document ::= DOCUMENT-START node DOCUMENT-END
-# node ::= SCALAR | sequence | mapping
-# sequence ::= SEQUENCE-START node* SEQUENCE-END
-# mapping ::= MAPPING-START (node node)* MAPPING-END
-
-__all__ = ['Emitter', 'EmitterError']
-
-from .error import YAMLError
-from .events import *
-
-class EmitterError(YAMLError):
- pass
-
-class ScalarAnalysis:
- def __init__(self, scalar, empty, multiline,
- allow_flow_plain, allow_block_plain,
- allow_single_quoted, allow_double_quoted,
- allow_block):
- self.scalar = scalar
- self.empty = empty
- self.multiline = multiline
- self.allow_flow_plain = allow_flow_plain
- self.allow_block_plain = allow_block_plain
- self.allow_single_quoted = allow_single_quoted
- self.allow_double_quoted = allow_double_quoted
- self.allow_block = allow_block
-
-class Emitter:
-
- DEFAULT_TAG_PREFIXES = {
- '!' : '!',
- 'tag:yaml.org,2002:' : '!!',
- }
-
- def __init__(self, stream, canonical=None, indent=None, width=None,
- allow_unicode=None, line_break=None):
-
- # The stream should have the methods `write` and possibly `flush`.
- self.stream = stream
-
- # Encoding can be overriden by STREAM-START.
- self.encoding = None
-
- # Emitter is a state machine with a stack of states to handle nested
- # structures.
- self.states = []
- self.state = self.expect_stream_start
-
- # Current event and the event queue.
- self.events = []
- self.event = None
-
- # The current indentation level and the stack of previous indents.
- self.indents = []
- self.indent = None
-
- # Flow level.
- self.flow_level = 0
-
- # Contexts.
- self.root_context = False
- self.sequence_context = False
- self.mapping_context = False
- self.simple_key_context = False
-
- # Characteristics of the last emitted character:
- # - current position.
- # - is it a whitespace?
- # - is it an indention character
- # (indentation space, '-', '?', or ':')?
- self.line = 0
- self.column = 0
- self.whitespace = True
- self.indention = True
-
- # Whether the document requires an explicit document indicator
- self.open_ended = False
-
- # Formatting details.
- self.canonical = canonical
- self.allow_unicode = allow_unicode
- self.best_indent = 2
- if indent and 1 < indent < 10:
- self.best_indent = indent
- self.best_width = 80
- if width and width > self.best_indent*2:
- self.best_width = width
- self.best_line_break = '\n'
- if line_break in ['\r', '\n', '\r\n']:
- self.best_line_break = line_break
-
- # Tag prefixes.
- self.tag_prefixes = None
-
- # Prepared anchor and tag.
- self.prepared_anchor = None
- self.prepared_tag = None
-
- # Scalar analysis and style.
- self.analysis = None
- self.style = None
-
- def dispose(self):
- # Reset the state attributes (to clear self-references)
- self.states = []
- self.state = None
-
- def emit(self, event):
- self.events.append(event)
- while not self.need_more_events():
- self.event = self.events.pop(0)
- self.state()
- self.event = None
-
- # In some cases, we wait for a few next events before emitting.
-
- def need_more_events(self):
- if not self.events:
- return True
- event = self.events[0]
- if isinstance(event, DocumentStartEvent):
- return self.need_events(1)
- elif isinstance(event, SequenceStartEvent):
- return self.need_events(2)
- elif isinstance(event, MappingStartEvent):
- return self.need_events(3)
- else:
- return False
-
- def need_events(self, count):
- level = 0
- for event in self.events[1:]:
- if isinstance(event, (DocumentStartEvent, CollectionStartEvent)):
- level += 1
- elif isinstance(event, (DocumentEndEvent, CollectionEndEvent)):
- level -= 1
- elif isinstance(event, StreamEndEvent):
- level = -1
- if level < 0:
- return False
- return (len(self.events) < count+1)
-
- def increase_indent(self, flow=False, indentless=False):
- self.indents.append(self.indent)
- if self.indent is None:
- if flow:
- self.indent = self.best_indent
- else:
- self.indent = 0
- elif not indentless:
- self.indent += self.best_indent
-
- # States.
-
- # Stream handlers.
-
- def expect_stream_start(self):
- if isinstance(self.event, StreamStartEvent):
- if self.event.encoding and not hasattr(self.stream, 'encoding'):
- self.encoding = self.event.encoding
- self.write_stream_start()
- self.state = self.expect_first_document_start
- else:
- raise EmitterError("expected StreamStartEvent, but got %s"
- % self.event)
-
- def expect_nothing(self):
- raise EmitterError("expected nothing, but got %s" % self.event)
-
- # Document handlers.
-
- def expect_first_document_start(self):
- return self.expect_document_start(first=True)
-
- def expect_document_start(self, first=False):
- if isinstance(self.event, DocumentStartEvent):
- if (self.event.version or self.event.tags) and self.open_ended:
- self.write_indicator('...', True)
- self.write_indent()
- if self.event.version:
- version_text = self.prepare_version(self.event.version)
- self.write_version_directive(version_text)
- self.tag_prefixes = self.DEFAULT_TAG_PREFIXES.copy()
- if self.event.tags:
- handles = sorted(self.event.tags.keys())
- for handle in handles:
- prefix = self.event.tags[handle]
- self.tag_prefixes[prefix] = handle
- handle_text = self.prepare_tag_handle(handle)
- prefix_text = self.prepare_tag_prefix(prefix)
- self.write_tag_directive(handle_text, prefix_text)
- implicit = (first and not self.event.explicit and not self.canonical
- and not self.event.version and not self.event.tags
- and not self.check_empty_document())
- if not implicit:
- self.write_indent()
- self.write_indicator('---', True)
- if self.canonical:
- self.write_indent()
- self.state = self.expect_document_root
- elif isinstance(self.event, StreamEndEvent):
- if self.open_ended:
- self.write_indicator('...', True)
- self.write_indent()
- self.write_stream_end()
- self.state = self.expect_nothing
- else:
- raise EmitterError("expected DocumentStartEvent, but got %s"
- % self.event)
-
- def expect_document_end(self):
- if isinstance(self.event, DocumentEndEvent):
- self.write_indent()
- if self.event.explicit:
- self.write_indicator('...', True)
- self.write_indent()
- self.flush_stream()
- self.state = self.expect_document_start
- else:
- raise EmitterError("expected DocumentEndEvent, but got %s"
- % self.event)
-
- def expect_document_root(self):
- self.states.append(self.expect_document_end)
- self.expect_node(root=True)
-
- # Node handlers.
-
- def expect_node(self, root=False, sequence=False, mapping=False,
- simple_key=False):
- self.root_context = root
- self.sequence_context = sequence
- self.mapping_context = mapping
- self.simple_key_context = simple_key
- if isinstance(self.event, AliasEvent):
- self.expect_alias()
- elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)):
- self.process_anchor('&')
- self.process_tag()
- if isinstance(self.event, ScalarEvent):
- self.expect_scalar()
- elif isinstance(self.event, SequenceStartEvent):
- if self.flow_level or self.canonical or self.event.flow_style \
- or self.check_empty_sequence():
- self.expect_flow_sequence()
- else:
- self.expect_block_sequence()
- elif isinstance(self.event, MappingStartEvent):
- if self.flow_level or self.canonical or self.event.flow_style \
- or self.check_empty_mapping():
- self.expect_flow_mapping()
- else:
- self.expect_block_mapping()
- else:
- raise EmitterError("expected NodeEvent, but got %s" % self.event)
-
- def expect_alias(self):
- if self.event.anchor is None:
- raise EmitterError("anchor is not specified for alias")
- self.process_anchor('*')
- self.state = self.states.pop()
-
- def expect_scalar(self):
- self.increase_indent(flow=True)
- self.process_scalar()
- self.indent = self.indents.pop()
- self.state = self.states.pop()
-
- # Flow sequence handlers.
-
- def expect_flow_sequence(self):
- self.write_indicator('[', True, whitespace=True)
- self.flow_level += 1
- self.increase_indent(flow=True)
- self.state = self.expect_first_flow_sequence_item
-
- def expect_first_flow_sequence_item(self):
- if isinstance(self.event, SequenceEndEvent):
- self.indent = self.indents.pop()
- self.flow_level -= 1
- self.write_indicator(']', False)
- self.state = self.states.pop()
- else:
- if self.canonical or self.column > self.best_width:
- self.write_indent()
- self.states.append(self.expect_flow_sequence_item)
- self.expect_node(sequence=True)
-
- def expect_flow_sequence_item(self):
- if isinstance(self.event, SequenceEndEvent):
- self.indent = self.indents.pop()
- self.flow_level -= 1
- if self.canonical:
- self.write_indicator(',', False)
- self.write_indent()
- self.write_indicator(']', False)
- self.state = self.states.pop()
- else:
- self.write_indicator(',', False)
- if self.canonical or self.column > self.best_width:
- self.write_indent()
- self.states.append(self.expect_flow_sequence_item)
- self.expect_node(sequence=True)
-
- # Flow mapping handlers.
-
- def expect_flow_mapping(self):
- self.write_indicator('{', True, whitespace=True)
- self.flow_level += 1
- self.increase_indent(flow=True)
- self.state = self.expect_first_flow_mapping_key
-
- def expect_first_flow_mapping_key(self):
- if isinstance(self.event, MappingEndEvent):
- self.indent = self.indents.pop()
- self.flow_level -= 1
- self.write_indicator('}', False)
- self.state = self.states.pop()
- else:
- if self.canonical or self.column > self.best_width:
- self.write_indent()
- if not self.canonical and self.check_simple_key():
- self.states.append(self.expect_flow_mapping_simple_value)
- self.expect_node(mapping=True, simple_key=True)
- else:
- self.write_indicator('?', True)
- self.states.append(self.expect_flow_mapping_value)
- self.expect_node(mapping=True)
-
- def expect_flow_mapping_key(self):
- if isinstance(self.event, MappingEndEvent):
- self.indent = self.indents.pop()
- self.flow_level -= 1
- if self.canonical:
- self.write_indicator(',', False)
- self.write_indent()
- self.write_indicator('}', False)
- self.state = self.states.pop()
- else:
- self.write_indicator(',', False)
- if self.canonical or self.column > self.best_width:
- self.write_indent()
- if not self.canonical and self.check_simple_key():
- self.states.append(self.expect_flow_mapping_simple_value)
- self.expect_node(mapping=True, simple_key=True)
- else:
- self.write_indicator('?', True)
- self.states.append(self.expect_flow_mapping_value)
- self.expect_node(mapping=True)
-
- def expect_flow_mapping_simple_value(self):
- self.write_indicator(':', False)
- self.states.append(self.expect_flow_mapping_key)
- self.expect_node(mapping=True)
-
- def expect_flow_mapping_value(self):
- if self.canonical or self.column > self.best_width:
- self.write_indent()
- self.write_indicator(':', True)
- self.states.append(self.expect_flow_mapping_key)
- self.expect_node(mapping=True)
-
- # Block sequence handlers.
-
- def expect_block_sequence(self):
- indentless = (self.mapping_context and not self.indention)
- self.increase_indent(flow=False, indentless=indentless)
- self.state = self.expect_first_block_sequence_item
-
- def expect_first_block_sequence_item(self):
- return self.expect_block_sequence_item(first=True)
-
- def expect_block_sequence_item(self, first=False):
- if not first and isinstance(self.event, SequenceEndEvent):
- self.indent = self.indents.pop()
- self.state = self.states.pop()
- else:
- self.write_indent()
- self.write_indicator('-', True, indention=True)
- self.states.append(self.expect_block_sequence_item)
- self.expect_node(sequence=True)
-
- # Block mapping handlers.
-
- def expect_block_mapping(self):
- self.increase_indent(flow=False)
- self.state = self.expect_first_block_mapping_key
-
- def expect_first_block_mapping_key(self):
- return self.expect_block_mapping_key(first=True)
-
- def expect_block_mapping_key(self, first=False):
- if not first and isinstance(self.event, MappingEndEvent):
- self.indent = self.indents.pop()
- self.state = self.states.pop()
- else:
- self.write_indent()
- if self.check_simple_key():
- self.states.append(self.expect_block_mapping_simple_value)
- self.expect_node(mapping=True, simple_key=True)
- else:
- self.write_indicator('?', True, indention=True)
- self.states.append(self.expect_block_mapping_value)
- self.expect_node(mapping=True)
-
- def expect_block_mapping_simple_value(self):
- self.write_indicator(':', False)
- self.states.append(self.expect_block_mapping_key)
- self.expect_node(mapping=True)
-
- def expect_block_mapping_value(self):
- self.write_indent()
- self.write_indicator(':', True, indention=True)
- self.states.append(self.expect_block_mapping_key)
- self.expect_node(mapping=True)
-
- # Checkers.
-
- def check_empty_sequence(self):
- return (isinstance(self.event, SequenceStartEvent) and self.events
- and isinstance(self.events[0], SequenceEndEvent))
-
- def check_empty_mapping(self):
- return (isinstance(self.event, MappingStartEvent) and self.events
- and isinstance(self.events[0], MappingEndEvent))
-
- def check_empty_document(self):
- if not isinstance(self.event, DocumentStartEvent) or not self.events:
- return False
- event = self.events[0]
- return (isinstance(event, ScalarEvent) and event.anchor is None
- and event.tag is None and event.implicit and event.value == '')
-
- def check_simple_key(self):
- length = 0
- if isinstance(self.event, NodeEvent) and self.event.anchor is not None:
- if self.prepared_anchor is None:
- self.prepared_anchor = self.prepare_anchor(self.event.anchor)
- length += len(self.prepared_anchor)
- if isinstance(self.event, (ScalarEvent, CollectionStartEvent)) \
- and self.event.tag is not None:
- if self.prepared_tag is None:
- self.prepared_tag = self.prepare_tag(self.event.tag)
- length += len(self.prepared_tag)
- if isinstance(self.event, ScalarEvent):
- if self.analysis is None:
- self.analysis = self.analyze_scalar(self.event.value)
- length += len(self.analysis.scalar)
- return (length < 128 and (isinstance(self.event, AliasEvent)
- or (isinstance(self.event, ScalarEvent)
- and not self.analysis.empty and not self.analysis.multiline)
- or self.check_empty_sequence() or self.check_empty_mapping()))
-
- # Anchor, Tag, and Scalar processors.
-
- def process_anchor(self, indicator):
- if self.event.anchor is None:
- self.prepared_anchor = None
- return
- if self.prepared_anchor is None:
- self.prepared_anchor = self.prepare_anchor(self.event.anchor)
- if self.prepared_anchor:
- self.write_indicator(indicator+self.prepared_anchor, True)
- self.prepared_anchor = None
-
- def process_tag(self):
- tag = self.event.tag
- if isinstance(self.event, ScalarEvent):
- if self.style is None:
- self.style = self.choose_scalar_style()
- if ((not self.canonical or tag is None) and
- ((self.style == '' and self.event.implicit[0])
- or (self.style != '' and self.event.implicit[1]))):
- self.prepared_tag = None
- return
- if self.event.implicit[0] and tag is None:
- tag = '!'
- self.prepared_tag = None
- else:
- if (not self.canonical or tag is None) and self.event.implicit:
- self.prepared_tag = None
- return
- if tag is None:
- raise EmitterError("tag is not specified")
- if self.prepared_tag is None:
- self.prepared_tag = self.prepare_tag(tag)
- if self.prepared_tag:
- self.write_indicator(self.prepared_tag, True)
- self.prepared_tag = None
-
- def choose_scalar_style(self):
- if self.analysis is None:
- self.analysis = self.analyze_scalar(self.event.value)
- if self.event.style == '"' or self.canonical:
- return '"'
- if not self.event.style and self.event.implicit[0]:
- if (not (self.simple_key_context and
- (self.analysis.empty or self.analysis.multiline))
- and (self.flow_level and self.analysis.allow_flow_plain
- or (not self.flow_level and self.analysis.allow_block_plain))):
- return ''
- if self.event.style and self.event.style in '|>':
- if (not self.flow_level and not self.simple_key_context
- and self.analysis.allow_block):
- return self.event.style
- if not self.event.style or self.event.style == '\'':
- if (self.analysis.allow_single_quoted and
- not (self.simple_key_context and self.analysis.multiline)):
- return '\''
- return '"'
-
- def process_scalar(self):
- if self.analysis is None:
- self.analysis = self.analyze_scalar(self.event.value)
- if self.style is None:
- self.style = self.choose_scalar_style()
- split = (not self.simple_key_context)
- #if self.analysis.multiline and split \
- # and (not self.style or self.style in '\'\"'):
- # self.write_indent()
- if self.style == '"':
- self.write_double_quoted(self.analysis.scalar, split)
- elif self.style == '\'':
- self.write_single_quoted(self.analysis.scalar, split)
- elif self.style == '>':
- self.write_folded(self.analysis.scalar)
- elif self.style == '|':
- self.write_literal(self.analysis.scalar)
- else:
- self.write_plain(self.analysis.scalar, split)
- self.analysis = None
- self.style = None
-
- # Analyzers.
-
- def prepare_version(self, version):
- major, minor = version
- if major != 1:
- raise EmitterError("unsupported YAML version: %d.%d" % (major, minor))
- return '%d.%d' % (major, minor)
-
- def prepare_tag_handle(self, handle):
- if not handle:
- raise EmitterError("tag handle must not be empty")
- if handle[0] != '!' or handle[-1] != '!':
- raise EmitterError("tag handle must start and end with '!': %r" % handle)
- for ch in handle[1:-1]:
- if not ('0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-_'):
- raise EmitterError("invalid character %r in the tag handle: %r"
- % (ch, handle))
- return handle
-
- def prepare_tag_prefix(self, prefix):
- if not prefix:
- raise EmitterError("tag prefix must not be empty")
- chunks = []
- start = end = 0
- if prefix[0] == '!':
- end = 1
- while end < len(prefix):
- ch = prefix[end]
- if '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-;/?!:@&=+$,_.~*\'()[]':
- end += 1
- else:
- if start < end:
- chunks.append(prefix[start:end])
- start = end = end+1
- data = ch.encode('utf-8')
- for ch in data:
- chunks.append('%%%02X' % ord(ch))
- if start < end:
- chunks.append(prefix[start:end])
- return ''.join(chunks)
-
- def prepare_tag(self, tag):
- if not tag:
- raise EmitterError("tag must not be empty")
- if tag == '!':
- return tag
- handle = None
- suffix = tag
- prefixes = sorted(self.tag_prefixes.keys())
- for prefix in prefixes:
- if tag.startswith(prefix) \
- and (prefix == '!' or len(prefix) < len(tag)):
- handle = self.tag_prefixes[prefix]
- suffix = tag[len(prefix):]
- chunks = []
- start = end = 0
- while end < len(suffix):
- ch = suffix[end]
- if '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-;/?:@&=+$,_.~*\'()[]' \
- or (ch == '!' and handle != '!'):
- end += 1
- else:
- if start < end:
- chunks.append(suffix[start:end])
- start = end = end+1
- data = ch.encode('utf-8')
- for ch in data:
- chunks.append('%%%02X' % ord(ch))
- if start < end:
- chunks.append(suffix[start:end])
- suffix_text = ''.join(chunks)
- if handle:
- return '%s%s' % (handle, suffix_text)
- else:
- return '!<%s>' % suffix_text
-
- def prepare_anchor(self, anchor):
- if not anchor:
- raise EmitterError("anchor must not be empty")
- for ch in anchor:
- if not ('0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-_'):
- raise EmitterError("invalid character %r in the anchor: %r"
- % (ch, anchor))
- return anchor
-
- def analyze_scalar(self, scalar):
-
- # Empty scalar is a special case.
- if not scalar:
- return ScalarAnalysis(scalar=scalar, empty=True, multiline=False,
- allow_flow_plain=False, allow_block_plain=True,
- allow_single_quoted=True, allow_double_quoted=True,
- allow_block=False)
-
- # Indicators and special characters.
- block_indicators = False
- flow_indicators = False
- line_breaks = False
- special_characters = False
-
- # Important whitespace combinations.
- leading_space = False
- leading_break = False
- trailing_space = False
- trailing_break = False
- break_space = False
- space_break = False
-
- # Check document indicators.
- if scalar.startswith('---') or scalar.startswith('...'):
- block_indicators = True
- flow_indicators = True
-
- # First character or preceded by a whitespace.
- preceeded_by_whitespace = True
-
- # Last character or followed by a whitespace.
- followed_by_whitespace = (len(scalar) == 1 or
- scalar[1] in '\0 \t\r\n\x85\u2028\u2029')
-
- # The previous character is a space.
- previous_space = False
-
- # The previous character is a break.
- previous_break = False
-
- index = 0
- while index < len(scalar):
- ch = scalar[index]
-
- # Check for indicators.
- if index == 0:
- # Leading indicators are special characters.
- if ch in '#,[]{}&*!|>\'\"%@`':
- flow_indicators = True
- block_indicators = True
- if ch in '?:':
- flow_indicators = True
- if followed_by_whitespace:
- block_indicators = True
- if ch == '-' and followed_by_whitespace:
- flow_indicators = True
- block_indicators = True
- else:
- # Some indicators cannot appear within a scalar as well.
- if ch in ',?[]{}':
- flow_indicators = True
- if ch == ':':
- flow_indicators = True
- if followed_by_whitespace:
- block_indicators = True
- if ch == '#' and preceeded_by_whitespace:
- flow_indicators = True
- block_indicators = True
-
- # Check for line breaks, special, and unicode characters.
- if ch in '\n\x85\u2028\u2029':
- line_breaks = True
- if not (ch == '\n' or '\x20' <= ch <= '\x7E'):
- if (ch == '\x85' or '\xA0' <= ch <= '\uD7FF'
- or '\uE000' <= ch <= '\uFFFD') and ch != '\uFEFF':
- unicode_characters = True
- if not self.allow_unicode:
- special_characters = True
- else:
- special_characters = True
-
- # Detect important whitespace combinations.
- if ch == ' ':
- if index == 0:
- leading_space = True
- if index == len(scalar)-1:
- trailing_space = True
- if previous_break:
- break_space = True
- previous_space = True
- previous_break = False
- elif ch in '\n\x85\u2028\u2029':
- if index == 0:
- leading_break = True
- if index == len(scalar)-1:
- trailing_break = True
- if previous_space:
- space_break = True
- previous_space = False
- previous_break = True
- else:
- previous_space = False
- previous_break = False
-
- # Prepare for the next character.
- index += 1
- preceeded_by_whitespace = (ch in '\0 \t\r\n\x85\u2028\u2029')
- followed_by_whitespace = (index+1 >= len(scalar) or
- scalar[index+1] in '\0 \t\r\n\x85\u2028\u2029')
-
- # Let's decide what styles are allowed.
- allow_flow_plain = True
- allow_block_plain = True
- allow_single_quoted = True
- allow_double_quoted = True
- allow_block = True
-
- # Leading and trailing whitespaces are bad for plain scalars.
- if (leading_space or leading_break
- or trailing_space or trailing_break):
- allow_flow_plain = allow_block_plain = False
-
- # We do not permit trailing spaces for block scalars.
- if trailing_space:
- allow_block = False
-
- # Spaces at the beginning of a new line are only acceptable for block
- # scalars.
- if break_space:
- allow_flow_plain = allow_block_plain = allow_single_quoted = False
-
- # Spaces followed by breaks, as well as special character are only
- # allowed for double quoted scalars.
- if space_break or special_characters:
- allow_flow_plain = allow_block_plain = \
- allow_single_quoted = allow_block = False
-
- # Although the plain scalar writer supports breaks, we never emit
- # multiline plain scalars.
- if line_breaks:
- allow_flow_plain = allow_block_plain = False
-
- # Flow indicators are forbidden for flow plain scalars.
- if flow_indicators:
- allow_flow_plain = False
-
- # Block indicators are forbidden for block plain scalars.
- if block_indicators:
- allow_block_plain = False
-
- return ScalarAnalysis(scalar=scalar,
- empty=False, multiline=line_breaks,
- allow_flow_plain=allow_flow_plain,
- allow_block_plain=allow_block_plain,
- allow_single_quoted=allow_single_quoted,
- allow_double_quoted=allow_double_quoted,
- allow_block=allow_block)
-
- # Writers.
-
- def flush_stream(self):
- if hasattr(self.stream, 'flush'):
- self.stream.flush()
-
- def write_stream_start(self):
- # Write BOM if needed.
- if self.encoding and self.encoding.startswith('utf-16'):
- self.stream.write('\uFEFF'.encode(self.encoding))
-
- def write_stream_end(self):
- self.flush_stream()
-
- def write_indicator(self, indicator, need_whitespace,
- whitespace=False, indention=False):
- if self.whitespace or not need_whitespace:
- data = indicator
- else:
- data = ' '+indicator
- self.whitespace = whitespace
- self.indention = self.indention and indention
- self.column += len(data)
- self.open_ended = False
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
-
- def write_indent(self):
- indent = self.indent or 0
- if not self.indention or self.column > indent \
- or (self.column == indent and not self.whitespace):
- self.write_line_break()
- if self.column < indent:
- self.whitespace = True
- data = ' '*(indent-self.column)
- self.column = indent
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
-
- def write_line_break(self, data=None):
- if data is None:
- data = self.best_line_break
- self.whitespace = True
- self.indention = True
- self.line += 1
- self.column = 0
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
-
- def write_version_directive(self, version_text):
- data = '%%YAML %s' % version_text
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- self.write_line_break()
-
- def write_tag_directive(self, handle_text, prefix_text):
- data = '%%TAG %s %s' % (handle_text, prefix_text)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- self.write_line_break()
-
- # Scalar streams.
-
- def write_single_quoted(self, text, split=True):
- self.write_indicator('\'', True)
- spaces = False
- breaks = False
- start = end = 0
- while end <= len(text):
- ch = None
- if end < len(text):
- ch = text[end]
- if spaces:
- if ch is None or ch != ' ':
- if start+1 == end and self.column > self.best_width and split \
- and start != 0 and end != len(text):
- self.write_indent()
- else:
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end
- elif breaks:
- if ch is None or ch not in '\n\x85\u2028\u2029':
- if text[start] == '\n':
- self.write_line_break()
- for br in text[start:end]:
- if br == '\n':
- self.write_line_break()
- else:
- self.write_line_break(br)
- self.write_indent()
- start = end
- else:
- if ch is None or ch in ' \n\x85\u2028\u2029' or ch == '\'':
- if start < end:
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end
- if ch == '\'':
- data = '\'\''
- self.column += 2
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end + 1
- if ch is not None:
- spaces = (ch == ' ')
- breaks = (ch in '\n\x85\u2028\u2029')
- end += 1
- self.write_indicator('\'', False)
-
- ESCAPE_REPLACEMENTS = {
- '\0': '0',
- '\x07': 'a',
- '\x08': 'b',
- '\x09': 't',
- '\x0A': 'n',
- '\x0B': 'v',
- '\x0C': 'f',
- '\x0D': 'r',
- '\x1B': 'e',
- '\"': '\"',
- '\\': '\\',
- '\x85': 'N',
- '\xA0': '_',
- '\u2028': 'L',
- '\u2029': 'P',
- }
-
- def write_double_quoted(self, text, split=True):
- self.write_indicator('"', True)
- start = end = 0
- while end <= len(text):
- ch = None
- if end < len(text):
- ch = text[end]
- if ch is None or ch in '"\\\x85\u2028\u2029\uFEFF' \
- or not ('\x20' <= ch <= '\x7E'
- or (self.allow_unicode
- and ('\xA0' <= ch <= '\uD7FF'
- or '\uE000' <= ch <= '\uFFFD'))):
- if start < end:
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end
- if ch is not None:
- if ch in self.ESCAPE_REPLACEMENTS:
- data = '\\'+self.ESCAPE_REPLACEMENTS[ch]
- elif ch <= '\xFF':
- data = '\\x%02X' % ord(ch)
- elif ch <= '\uFFFF':
- data = '\\u%04X' % ord(ch)
- else:
- data = '\\U%08X' % ord(ch)
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end+1
- if 0 < end < len(text)-1 and (ch == ' ' or start >= end) \
- and self.column+(end-start) > self.best_width and split:
- data = text[start:end]+'\\'
- if start < end:
- start = end
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- self.write_indent()
- self.whitespace = False
- self.indention = False
- if text[start] == ' ':
- data = '\\'
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- end += 1
- self.write_indicator('"', False)
-
- def determine_block_hints(self, text):
- hints = ''
- if text:
- if text[0] in ' \n\x85\u2028\u2029':
- hints += str(self.best_indent)
- if text[-1] not in '\n\x85\u2028\u2029':
- hints += '-'
- elif len(text) == 1 or text[-2] in '\n\x85\u2028\u2029':
- hints += '+'
- return hints
-
- def write_folded(self, text):
- hints = self.determine_block_hints(text)
- self.write_indicator('>'+hints, True)
- if hints[-1:] == '+':
- self.open_ended = True
- self.write_line_break()
- leading_space = True
- spaces = False
- breaks = True
- start = end = 0
- while end <= len(text):
- ch = None
- if end < len(text):
- ch = text[end]
- if breaks:
- if ch is None or ch not in '\n\x85\u2028\u2029':
- if not leading_space and ch is not None and ch != ' ' \
- and text[start] == '\n':
- self.write_line_break()
- leading_space = (ch == ' ')
- for br in text[start:end]:
- if br == '\n':
- self.write_line_break()
- else:
- self.write_line_break(br)
- if ch is not None:
- self.write_indent()
- start = end
- elif spaces:
- if ch != ' ':
- if start+1 == end and self.column > self.best_width:
- self.write_indent()
- else:
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end
- else:
- if ch is None or ch in ' \n\x85\u2028\u2029':
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- if ch is None:
- self.write_line_break()
- start = end
- if ch is not None:
- breaks = (ch in '\n\x85\u2028\u2029')
- spaces = (ch == ' ')
- end += 1
-
- def write_literal(self, text):
- hints = self.determine_block_hints(text)
- self.write_indicator('|'+hints, True)
- if hints[-1:] == '+':
- self.open_ended = True
- self.write_line_break()
- breaks = True
- start = end = 0
- while end <= len(text):
- ch = None
- if end < len(text):
- ch = text[end]
- if breaks:
- if ch is None or ch not in '\n\x85\u2028\u2029':
- for br in text[start:end]:
- if br == '\n':
- self.write_line_break()
- else:
- self.write_line_break(br)
- if ch is not None:
- self.write_indent()
- start = end
- else:
- if ch is None or ch in '\n\x85\u2028\u2029':
- data = text[start:end]
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- if ch is None:
- self.write_line_break()
- start = end
- if ch is not None:
- breaks = (ch in '\n\x85\u2028\u2029')
- end += 1
-
- def write_plain(self, text, split=True):
- if self.root_context:
- self.open_ended = True
- if not text:
- return
- if not self.whitespace:
- data = ' '
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- self.whitespace = False
- self.indention = False
- spaces = False
- breaks = False
- start = end = 0
- while end <= len(text):
- ch = None
- if end < len(text):
- ch = text[end]
- if spaces:
- if ch != ' ':
- if start+1 == end and self.column > self.best_width and split:
- self.write_indent()
- self.whitespace = False
- self.indention = False
- else:
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end
- elif breaks:
- if ch not in '\n\x85\u2028\u2029':
- if text[start] == '\n':
- self.write_line_break()
- for br in text[start:end]:
- if br == '\n':
- self.write_line_break()
- else:
- self.write_line_break(br)
- self.write_indent()
- self.whitespace = False
- self.indention = False
- start = end
- else:
- if ch is None or ch in ' \n\x85\u2028\u2029':
- data = text[start:end]
- self.column += len(data)
- if self.encoding:
- data = data.encode(self.encoding)
- self.stream.write(data)
- start = end
- if ch is not None:
- spaces = (ch == ' ')
- breaks = (ch in '\n\x85\u2028\u2029')
- end += 1
-
diff --git a/lib/spack/external/yaml/lib3/yaml/error.py b/lib/spack/external/yaml/lib3/yaml/error.py
deleted file mode 100644
index b796b4dc51..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/error.py
+++ /dev/null
@@ -1,75 +0,0 @@
-
-__all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
-
-class Mark:
-
- def __init__(self, name, index, line, column, buffer, pointer):
- self.name = name
- self.index = index
- self.line = line
- self.column = column
- self.buffer = buffer
- self.pointer = pointer
-
- def get_snippet(self, indent=4, max_length=75):
- if self.buffer is None:
- return None
- head = ''
- start = self.pointer
- while start > 0 and self.buffer[start-1] not in '\0\r\n\x85\u2028\u2029':
- start -= 1
- if self.pointer-start > max_length/2-1:
- head = ' ... '
- start += 5
- break
- tail = ''
- end = self.pointer
- while end < len(self.buffer) and self.buffer[end] not in '\0\r\n\x85\u2028\u2029':
- end += 1
- if end-self.pointer > max_length/2-1:
- tail = ' ... '
- end -= 5
- break
- snippet = self.buffer[start:end]
- return ' '*indent + head + snippet + tail + '\n' \
- + ' '*(indent+self.pointer-start+len(head)) + '^'
-
- def __str__(self):
- snippet = self.get_snippet()
- where = " in \"%s\", line %d, column %d" \
- % (self.name, self.line+1, self.column+1)
- if snippet is not None:
- where += ":\n"+snippet
- return where
-
-class YAMLError(Exception):
- pass
-
-class MarkedYAMLError(YAMLError):
-
- def __init__(self, context=None, context_mark=None,
- problem=None, problem_mark=None, note=None):
- self.context = context
- self.context_mark = context_mark
- self.problem = problem
- self.problem_mark = problem_mark
- self.note = note
-
- def __str__(self):
- lines = []
- if self.context is not None:
- lines.append(self.context)
- if self.context_mark is not None \
- and (self.problem is None or self.problem_mark is None
- or self.context_mark.name != self.problem_mark.name
- or self.context_mark.line != self.problem_mark.line
- or self.context_mark.column != self.problem_mark.column):
- lines.append(str(self.context_mark))
- if self.problem is not None:
- lines.append(self.problem)
- if self.problem_mark is not None:
- lines.append(str(self.problem_mark))
- if self.note is not None:
- lines.append(self.note)
- return '\n'.join(lines)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/loader.py b/lib/spack/external/yaml/lib3/yaml/loader.py
deleted file mode 100644
index 08c8f01b34..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/loader.py
+++ /dev/null
@@ -1,40 +0,0 @@
-
-__all__ = ['BaseLoader', 'SafeLoader', 'Loader']
-
-from .reader import *
-from .scanner import *
-from .parser import *
-from .composer import *
-from .constructor import *
-from .resolver import *
-
-class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, BaseResolver):
-
- def __init__(self, stream):
- Reader.__init__(self, stream)
- Scanner.__init__(self)
- Parser.__init__(self)
- Composer.__init__(self)
- BaseConstructor.__init__(self)
- BaseResolver.__init__(self)
-
-class SafeLoader(Reader, Scanner, Parser, Composer, SafeConstructor, Resolver):
-
- def __init__(self, stream):
- Reader.__init__(self, stream)
- Scanner.__init__(self)
- Parser.__init__(self)
- Composer.__init__(self)
- SafeConstructor.__init__(self)
- Resolver.__init__(self)
-
-class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
-
- def __init__(self, stream):
- Reader.__init__(self, stream)
- Scanner.__init__(self)
- Parser.__init__(self)
- Composer.__init__(self)
- Constructor.__init__(self)
- Resolver.__init__(self)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/nodes.py b/lib/spack/external/yaml/lib3/yaml/nodes.py
deleted file mode 100644
index c4f070c41e..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/nodes.py
+++ /dev/null
@@ -1,49 +0,0 @@
-
-class Node(object):
- def __init__(self, tag, value, start_mark, end_mark):
- self.tag = tag
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- def __repr__(self):
- value = self.value
- #if isinstance(value, list):
- # if len(value) == 0:
- # value = '<empty>'
- # elif len(value) == 1:
- # value = '<1 item>'
- # else:
- # value = '<%d items>' % len(value)
- #else:
- # if len(value) > 75:
- # value = repr(value[:70]+u' ... ')
- # else:
- # value = repr(value)
- value = repr(value)
- return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
-
-class ScalarNode(Node):
- id = 'scalar'
- def __init__(self, tag, value,
- start_mark=None, end_mark=None, style=None):
- self.tag = tag
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.style = style
-
-class CollectionNode(Node):
- def __init__(self, tag, value,
- start_mark=None, end_mark=None, flow_style=None):
- self.tag = tag
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.flow_style = flow_style
-
-class SequenceNode(CollectionNode):
- id = 'sequence'
-
-class MappingNode(CollectionNode):
- id = 'mapping'
-
diff --git a/lib/spack/external/yaml/lib3/yaml/parser.py b/lib/spack/external/yaml/lib3/yaml/parser.py
deleted file mode 100644
index 13a5995d29..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/parser.py
+++ /dev/null
@@ -1,589 +0,0 @@
-
-# The following YAML grammar is LL(1) and is parsed by a recursive descent
-# parser.
-#
-# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
-# implicit_document ::= block_node DOCUMENT-END*
-# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-# block_node_or_indentless_sequence ::=
-# ALIAS
-# | properties (block_content | indentless_block_sequence)?
-# | block_content
-# | indentless_block_sequence
-# block_node ::= ALIAS
-# | properties block_content?
-# | block_content
-# flow_node ::= ALIAS
-# | properties flow_content?
-# | flow_content
-# properties ::= TAG ANCHOR? | ANCHOR TAG?
-# block_content ::= block_collection | flow_collection | SCALAR
-# flow_content ::= flow_collection | SCALAR
-# block_collection ::= block_sequence | block_mapping
-# flow_collection ::= flow_sequence | flow_mapping
-# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
-# block_mapping ::= BLOCK-MAPPING_START
-# ((KEY block_node_or_indentless_sequence?)?
-# (VALUE block_node_or_indentless_sequence?)?)*
-# BLOCK-END
-# flow_sequence ::= FLOW-SEQUENCE-START
-# (flow_sequence_entry FLOW-ENTRY)*
-# flow_sequence_entry?
-# FLOW-SEQUENCE-END
-# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-# flow_mapping ::= FLOW-MAPPING-START
-# (flow_mapping_entry FLOW-ENTRY)*
-# flow_mapping_entry?
-# FLOW-MAPPING-END
-# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-#
-# FIRST sets:
-#
-# stream: { STREAM-START }
-# explicit_document: { DIRECTIVE DOCUMENT-START }
-# implicit_document: FIRST(block_node)
-# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
-# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
-# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
-# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
-# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
-# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
-# block_sequence: { BLOCK-SEQUENCE-START }
-# block_mapping: { BLOCK-MAPPING-START }
-# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
-# indentless_sequence: { ENTRY }
-# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
-# flow_sequence: { FLOW-SEQUENCE-START }
-# flow_mapping: { FLOW-MAPPING-START }
-# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
-# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
-
-__all__ = ['Parser', 'ParserError']
-
-from .error import MarkedYAMLError
-from .tokens import *
-from .events import *
-from .scanner import *
-
-class ParserError(MarkedYAMLError):
- pass
-
-class Parser:
- # Since writing a recursive-descendant parser is a straightforward task, we
- # do not give many comments here.
-
- DEFAULT_TAGS = {
- '!': '!',
- '!!': 'tag:yaml.org,2002:',
- }
-
- def __init__(self):
- self.current_event = None
- self.yaml_version = None
- self.tag_handles = {}
- self.states = []
- self.marks = []
- self.state = self.parse_stream_start
-
- def dispose(self):
- # Reset the state attributes (to clear self-references)
- self.states = []
- self.state = None
-
- def check_event(self, *choices):
- # Check the type of the next event.
- if self.current_event is None:
- if self.state:
- self.current_event = self.state()
- if self.current_event is not None:
- if not choices:
- return True
- for choice in choices:
- if isinstance(self.current_event, choice):
- return True
- return False
-
- def peek_event(self):
- # Get the next event.
- if self.current_event is None:
- if self.state:
- self.current_event = self.state()
- return self.current_event
-
- def get_event(self):
- # Get the next event and proceed further.
- if self.current_event is None:
- if self.state:
- self.current_event = self.state()
- value = self.current_event
- self.current_event = None
- return value
-
- # stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
- # implicit_document ::= block_node DOCUMENT-END*
- # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-
- def parse_stream_start(self):
-
- # Parse the stream start.
- token = self.get_token()
- event = StreamStartEvent(token.start_mark, token.end_mark,
- encoding=token.encoding)
-
- # Prepare the next state.
- self.state = self.parse_implicit_document_start
-
- return event
-
- def parse_implicit_document_start(self):
-
- # Parse an implicit document.
- if not self.check_token(DirectiveToken, DocumentStartToken,
- StreamEndToken):
- self.tag_handles = self.DEFAULT_TAGS
- token = self.peek_token()
- start_mark = end_mark = token.start_mark
- event = DocumentStartEvent(start_mark, end_mark,
- explicit=False)
-
- # Prepare the next state.
- self.states.append(self.parse_document_end)
- self.state = self.parse_block_node
-
- return event
-
- else:
- return self.parse_document_start()
-
- def parse_document_start(self):
-
- # Parse any extra document end indicators.
- while self.check_token(DocumentEndToken):
- self.get_token()
-
- # Parse an explicit document.
- if not self.check_token(StreamEndToken):
- token = self.peek_token()
- start_mark = token.start_mark
- version, tags = self.process_directives()
- if not self.check_token(DocumentStartToken):
- raise ParserError(None, None,
- "expected '<document start>', but found %r"
- % self.peek_token().id,
- self.peek_token().start_mark)
- token = self.get_token()
- end_mark = token.end_mark
- event = DocumentStartEvent(start_mark, end_mark,
- explicit=True, version=version, tags=tags)
- self.states.append(self.parse_document_end)
- self.state = self.parse_document_content
- else:
- # Parse the end of the stream.
- token = self.get_token()
- event = StreamEndEvent(token.start_mark, token.end_mark)
- assert not self.states
- assert not self.marks
- self.state = None
- return event
-
- def parse_document_end(self):
-
- # Parse the document end.
- token = self.peek_token()
- start_mark = end_mark = token.start_mark
- explicit = False
- if self.check_token(DocumentEndToken):
- token = self.get_token()
- end_mark = token.end_mark
- explicit = True
- event = DocumentEndEvent(start_mark, end_mark,
- explicit=explicit)
-
- # Prepare the next state.
- self.state = self.parse_document_start
-
- return event
-
- def parse_document_content(self):
- if self.check_token(DirectiveToken,
- DocumentStartToken, DocumentEndToken, StreamEndToken):
- event = self.process_empty_scalar(self.peek_token().start_mark)
- self.state = self.states.pop()
- return event
- else:
- return self.parse_block_node()
-
- def process_directives(self):
- self.yaml_version = None
- self.tag_handles = {}
- while self.check_token(DirectiveToken):
- token = self.get_token()
- if token.name == 'YAML':
- if self.yaml_version is not None:
- raise ParserError(None, None,
- "found duplicate YAML directive", token.start_mark)
- major, minor = token.value
- if major != 1:
- raise ParserError(None, None,
- "found incompatible YAML document (version 1.* is required)",
- token.start_mark)
- self.yaml_version = token.value
- elif token.name == 'TAG':
- handle, prefix = token.value
- if handle in self.tag_handles:
- raise ParserError(None, None,
- "duplicate tag handle %r" % handle,
- token.start_mark)
- self.tag_handles[handle] = prefix
- if self.tag_handles:
- value = self.yaml_version, self.tag_handles.copy()
- else:
- value = self.yaml_version, None
- for key in self.DEFAULT_TAGS:
- if key not in self.tag_handles:
- self.tag_handles[key] = self.DEFAULT_TAGS[key]
- return value
-
- # block_node_or_indentless_sequence ::= ALIAS
- # | properties (block_content | indentless_block_sequence)?
- # | block_content
- # | indentless_block_sequence
- # block_node ::= ALIAS
- # | properties block_content?
- # | block_content
- # flow_node ::= ALIAS
- # | properties flow_content?
- # | flow_content
- # properties ::= TAG ANCHOR? | ANCHOR TAG?
- # block_content ::= block_collection | flow_collection | SCALAR
- # flow_content ::= flow_collection | SCALAR
- # block_collection ::= block_sequence | block_mapping
- # flow_collection ::= flow_sequence | flow_mapping
-
- def parse_block_node(self):
- return self.parse_node(block=True)
-
- def parse_flow_node(self):
- return self.parse_node()
-
- def parse_block_node_or_indentless_sequence(self):
- return self.parse_node(block=True, indentless_sequence=True)
-
- def parse_node(self, block=False, indentless_sequence=False):
- if self.check_token(AliasToken):
- token = self.get_token()
- event = AliasEvent(token.value, token.start_mark, token.end_mark)
- self.state = self.states.pop()
- else:
- anchor = None
- tag = None
- start_mark = end_mark = tag_mark = None
- if self.check_token(AnchorToken):
- token = self.get_token()
- start_mark = token.start_mark
- end_mark = token.end_mark
- anchor = token.value
- if self.check_token(TagToken):
- token = self.get_token()
- tag_mark = token.start_mark
- end_mark = token.end_mark
- tag = token.value
- elif self.check_token(TagToken):
- token = self.get_token()
- start_mark = tag_mark = token.start_mark
- end_mark = token.end_mark
- tag = token.value
- if self.check_token(AnchorToken):
- token = self.get_token()
- end_mark = token.end_mark
- anchor = token.value
- if tag is not None:
- handle, suffix = tag
- if handle is not None:
- if handle not in self.tag_handles:
- raise ParserError("while parsing a node", start_mark,
- "found undefined tag handle %r" % handle,
- tag_mark)
- tag = self.tag_handles[handle]+suffix
- else:
- tag = suffix
- #if tag == '!':
- # raise ParserError("while parsing a node", start_mark,
- # "found non-specific tag '!'", tag_mark,
- # "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.")
- if start_mark is None:
- start_mark = end_mark = self.peek_token().start_mark
- event = None
- implicit = (tag is None or tag == '!')
- if indentless_sequence and self.check_token(BlockEntryToken):
- end_mark = self.peek_token().end_mark
- event = SequenceStartEvent(anchor, tag, implicit,
- start_mark, end_mark)
- self.state = self.parse_indentless_sequence_entry
- else:
- if self.check_token(ScalarToken):
- token = self.get_token()
- end_mark = token.end_mark
- if (token.plain and tag is None) or tag == '!':
- implicit = (True, False)
- elif tag is None:
- implicit = (False, True)
- else:
- implicit = (False, False)
- event = ScalarEvent(anchor, tag, implicit, token.value,
- start_mark, end_mark, style=token.style)
- self.state = self.states.pop()
- elif self.check_token(FlowSequenceStartToken):
- end_mark = self.peek_token().end_mark
- event = SequenceStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=True)
- self.state = self.parse_flow_sequence_first_entry
- elif self.check_token(FlowMappingStartToken):
- end_mark = self.peek_token().end_mark
- event = MappingStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=True)
- self.state = self.parse_flow_mapping_first_key
- elif block and self.check_token(BlockSequenceStartToken):
- end_mark = self.peek_token().start_mark
- event = SequenceStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=False)
- self.state = self.parse_block_sequence_first_entry
- elif block and self.check_token(BlockMappingStartToken):
- end_mark = self.peek_token().start_mark
- event = MappingStartEvent(anchor, tag, implicit,
- start_mark, end_mark, flow_style=False)
- self.state = self.parse_block_mapping_first_key
- elif anchor is not None or tag is not None:
- # Empty scalars are allowed even if a tag or an anchor is
- # specified.
- event = ScalarEvent(anchor, tag, (implicit, False), '',
- start_mark, end_mark)
- self.state = self.states.pop()
- else:
- if block:
- node = 'block'
- else:
- node = 'flow'
- token = self.peek_token()
- raise ParserError("while parsing a %s node" % node, start_mark,
- "expected the node content, but found %r" % token.id,
- token.start_mark)
- return event
-
- # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-
- def parse_block_sequence_first_entry(self):
- token = self.get_token()
- self.marks.append(token.start_mark)
- return self.parse_block_sequence_entry()
-
- def parse_block_sequence_entry(self):
- if self.check_token(BlockEntryToken):
- token = self.get_token()
- if not self.check_token(BlockEntryToken, BlockEndToken):
- self.states.append(self.parse_block_sequence_entry)
- return self.parse_block_node()
- else:
- self.state = self.parse_block_sequence_entry
- return self.process_empty_scalar(token.end_mark)
- if not self.check_token(BlockEndToken):
- token = self.peek_token()
- raise ParserError("while parsing a block collection", self.marks[-1],
- "expected <block end>, but found %r" % token.id, token.start_mark)
- token = self.get_token()
- event = SequenceEndEvent(token.start_mark, token.end_mark)
- self.state = self.states.pop()
- self.marks.pop()
- return event
-
- # indentless_sequence ::= (BLOCK-ENTRY block_node?)+
-
- def parse_indentless_sequence_entry(self):
- if self.check_token(BlockEntryToken):
- token = self.get_token()
- if not self.check_token(BlockEntryToken,
- KeyToken, ValueToken, BlockEndToken):
- self.states.append(self.parse_indentless_sequence_entry)
- return self.parse_block_node()
- else:
- self.state = self.parse_indentless_sequence_entry
- return self.process_empty_scalar(token.end_mark)
- token = self.peek_token()
- event = SequenceEndEvent(token.start_mark, token.start_mark)
- self.state = self.states.pop()
- return event
-
- # block_mapping ::= BLOCK-MAPPING_START
- # ((KEY block_node_or_indentless_sequence?)?
- # (VALUE block_node_or_indentless_sequence?)?)*
- # BLOCK-END
-
- def parse_block_mapping_first_key(self):
- token = self.get_token()
- self.marks.append(token.start_mark)
- return self.parse_block_mapping_key()
-
- def parse_block_mapping_key(self):
- if self.check_token(KeyToken):
- token = self.get_token()
- if not self.check_token(KeyToken, ValueToken, BlockEndToken):
- self.states.append(self.parse_block_mapping_value)
- return self.parse_block_node_or_indentless_sequence()
- else:
- self.state = self.parse_block_mapping_value
- return self.process_empty_scalar(token.end_mark)
- if not self.check_token(BlockEndToken):
- token = self.peek_token()
- raise ParserError("while parsing a block mapping", self.marks[-1],
- "expected <block end>, but found %r" % token.id, token.start_mark)
- token = self.get_token()
- event = MappingEndEvent(token.start_mark, token.end_mark)
- self.state = self.states.pop()
- self.marks.pop()
- return event
-
- def parse_block_mapping_value(self):
- if self.check_token(ValueToken):
- token = self.get_token()
- if not self.check_token(KeyToken, ValueToken, BlockEndToken):
- self.states.append(self.parse_block_mapping_key)
- return self.parse_block_node_or_indentless_sequence()
- else:
- self.state = self.parse_block_mapping_key
- return self.process_empty_scalar(token.end_mark)
- else:
- self.state = self.parse_block_mapping_key
- token = self.peek_token()
- return self.process_empty_scalar(token.start_mark)
-
- # flow_sequence ::= FLOW-SEQUENCE-START
- # (flow_sequence_entry FLOW-ENTRY)*
- # flow_sequence_entry?
- # FLOW-SEQUENCE-END
- # flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
- #
- # Note that while production rules for both flow_sequence_entry and
- # flow_mapping_entry are equal, their interpretations are different.
- # For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
- # generate an inline mapping (set syntax).
-
- def parse_flow_sequence_first_entry(self):
- token = self.get_token()
- self.marks.append(token.start_mark)
- return self.parse_flow_sequence_entry(first=True)
-
- def parse_flow_sequence_entry(self, first=False):
- if not self.check_token(FlowSequenceEndToken):
- if not first:
- if self.check_token(FlowEntryToken):
- self.get_token()
- else:
- token = self.peek_token()
- raise ParserError("while parsing a flow sequence", self.marks[-1],
- "expected ',' or ']', but got %r" % token.id, token.start_mark)
-
- if self.check_token(KeyToken):
- token = self.peek_token()
- event = MappingStartEvent(None, None, True,
- token.start_mark, token.end_mark,
- flow_style=True)
- self.state = self.parse_flow_sequence_entry_mapping_key
- return event
- elif not self.check_token(FlowSequenceEndToken):
- self.states.append(self.parse_flow_sequence_entry)
- return self.parse_flow_node()
- token = self.get_token()
- event = SequenceEndEvent(token.start_mark, token.end_mark)
- self.state = self.states.pop()
- self.marks.pop()
- return event
-
- def parse_flow_sequence_entry_mapping_key(self):
- token = self.get_token()
- if not self.check_token(ValueToken,
- FlowEntryToken, FlowSequenceEndToken):
- self.states.append(self.parse_flow_sequence_entry_mapping_value)
- return self.parse_flow_node()
- else:
- self.state = self.parse_flow_sequence_entry_mapping_value
- return self.process_empty_scalar(token.end_mark)
-
- def parse_flow_sequence_entry_mapping_value(self):
- if self.check_token(ValueToken):
- token = self.get_token()
- if not self.check_token(FlowEntryToken, FlowSequenceEndToken):
- self.states.append(self.parse_flow_sequence_entry_mapping_end)
- return self.parse_flow_node()
- else:
- self.state = self.parse_flow_sequence_entry_mapping_end
- return self.process_empty_scalar(token.end_mark)
- else:
- self.state = self.parse_flow_sequence_entry_mapping_end
- token = self.peek_token()
- return self.process_empty_scalar(token.start_mark)
-
- def parse_flow_sequence_entry_mapping_end(self):
- self.state = self.parse_flow_sequence_entry
- token = self.peek_token()
- return MappingEndEvent(token.start_mark, token.start_mark)
-
- # flow_mapping ::= FLOW-MAPPING-START
- # (flow_mapping_entry FLOW-ENTRY)*
- # flow_mapping_entry?
- # FLOW-MAPPING-END
- # flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-
- def parse_flow_mapping_first_key(self):
- token = self.get_token()
- self.marks.append(token.start_mark)
- return self.parse_flow_mapping_key(first=True)
-
- def parse_flow_mapping_key(self, first=False):
- if not self.check_token(FlowMappingEndToken):
- if not first:
- if self.check_token(FlowEntryToken):
- self.get_token()
- else:
- token = self.peek_token()
- raise ParserError("while parsing a flow mapping", self.marks[-1],
- "expected ',' or '}', but got %r" % token.id, token.start_mark)
- if self.check_token(KeyToken):
- token = self.get_token()
- if not self.check_token(ValueToken,
- FlowEntryToken, FlowMappingEndToken):
- self.states.append(self.parse_flow_mapping_value)
- return self.parse_flow_node()
- else:
- self.state = self.parse_flow_mapping_value
- return self.process_empty_scalar(token.end_mark)
- elif not self.check_token(FlowMappingEndToken):
- self.states.append(self.parse_flow_mapping_empty_value)
- return self.parse_flow_node()
- token = self.get_token()
- event = MappingEndEvent(token.start_mark, token.end_mark)
- self.state = self.states.pop()
- self.marks.pop()
- return event
-
- def parse_flow_mapping_value(self):
- if self.check_token(ValueToken):
- token = self.get_token()
- if not self.check_token(FlowEntryToken, FlowMappingEndToken):
- self.states.append(self.parse_flow_mapping_key)
- return self.parse_flow_node()
- else:
- self.state = self.parse_flow_mapping_key
- return self.process_empty_scalar(token.end_mark)
- else:
- self.state = self.parse_flow_mapping_key
- token = self.peek_token()
- return self.process_empty_scalar(token.start_mark)
-
- def parse_flow_mapping_empty_value(self):
- self.state = self.parse_flow_mapping_key
- return self.process_empty_scalar(self.peek_token().start_mark)
-
- def process_empty_scalar(self, mark):
- return ScalarEvent(None, None, (True, False), '', mark, mark)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/representer.py b/lib/spack/external/yaml/lib3/yaml/representer.py
deleted file mode 100644
index b9e65c5109..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/representer.py
+++ /dev/null
@@ -1,387 +0,0 @@
-
-__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
- 'RepresenterError']
-
-from .error import *
-from .nodes import *
-
-import datetime, sys, copyreg, types, base64, collections
-
-class RepresenterError(YAMLError):
- pass
-
-class BaseRepresenter:
-
- yaml_representers = {}
- yaml_multi_representers = {}
-
- def __init__(self, default_style=None, default_flow_style=None):
- self.default_style = default_style
- self.default_flow_style = default_flow_style
- self.represented_objects = {}
- self.object_keeper = []
- self.alias_key = None
-
- def represent(self, data):
- node = self.represent_data(data)
- self.serialize(node)
- self.represented_objects = {}
- self.object_keeper = []
- self.alias_key = None
-
- def represent_data(self, data):
- if self.ignore_aliases(data):
- self.alias_key = None
- else:
- self.alias_key = id(data)
- if self.alias_key is not None:
- if self.alias_key in self.represented_objects:
- node = self.represented_objects[self.alias_key]
- #if node is None:
- # raise RepresenterError("recursive objects are not allowed: %r" % data)
- return node
- #self.represented_objects[alias_key] = None
- self.object_keeper.append(data)
- data_types = type(data).__mro__
- if data_types[0] in self.yaml_representers:
- node = self.yaml_representers[data_types[0]](self, data)
- else:
- for data_type in data_types:
- if data_type in self.yaml_multi_representers:
- node = self.yaml_multi_representers[data_type](self, data)
- break
- else:
- if None in self.yaml_multi_representers:
- node = self.yaml_multi_representers[None](self, data)
- elif None in self.yaml_representers:
- node = self.yaml_representers[None](self, data)
- else:
- node = ScalarNode(None, str(data))
- #if alias_key is not None:
- # self.represented_objects[alias_key] = node
- return node
-
- @classmethod
- def add_representer(cls, data_type, representer):
- if not 'yaml_representers' in cls.__dict__:
- cls.yaml_representers = cls.yaml_representers.copy()
- cls.yaml_representers[data_type] = representer
-
- @classmethod
- def add_multi_representer(cls, data_type, representer):
- if not 'yaml_multi_representers' in cls.__dict__:
- cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
- cls.yaml_multi_representers[data_type] = representer
-
- def represent_scalar(self, tag, value, style=None):
- if style is None:
- style = self.default_style
- node = ScalarNode(tag, value, style=style)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- return node
-
- def represent_sequence(self, tag, sequence, flow_style=None):
- value = []
- node = SequenceNode(tag, value, flow_style=flow_style)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- best_style = True
- for item in sequence:
- node_item = self.represent_data(item)
- if not (isinstance(node_item, ScalarNode) and not node_item.style):
- best_style = False
- value.append(node_item)
- if flow_style is None:
- if self.default_flow_style is not None:
- node.flow_style = self.default_flow_style
- else:
- node.flow_style = best_style
- return node
-
- def represent_mapping(self, tag, mapping, flow_style=None):
- value = []
- node = MappingNode(tag, value, flow_style=flow_style)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- best_style = True
- if hasattr(mapping, 'items'):
- mapping = list(mapping.items())
- try:
- mapping = sorted(mapping)
- except TypeError:
- pass
- for item_key, item_value in mapping:
- node_key = self.represent_data(item_key)
- node_value = self.represent_data(item_value)
- if not (isinstance(node_key, ScalarNode) and not node_key.style):
- best_style = False
- if not (isinstance(node_value, ScalarNode) and not node_value.style):
- best_style = False
- value.append((node_key, node_value))
- if flow_style is None:
- if self.default_flow_style is not None:
- node.flow_style = self.default_flow_style
- else:
- node.flow_style = best_style
- return node
-
- def ignore_aliases(self, data):
- return False
-
-class SafeRepresenter(BaseRepresenter):
-
- def ignore_aliases(self, data):
- if data is None:
- return True
- if isinstance(data, tuple) and data == ():
- return True
- if isinstance(data, (str, bytes, bool, int, float)):
- return True
-
- def represent_none(self, data):
- return self.represent_scalar('tag:yaml.org,2002:null', 'null')
-
- def represent_str(self, data):
- return self.represent_scalar('tag:yaml.org,2002:str', data)
-
- def represent_binary(self, data):
- if hasattr(base64, 'encodebytes'):
- data = base64.encodebytes(data).decode('ascii')
- else:
- data = base64.encodestring(data).decode('ascii')
- return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|')
-
- def represent_bool(self, data):
- if data:
- value = 'true'
- else:
- value = 'false'
- return self.represent_scalar('tag:yaml.org,2002:bool', value)
-
- def represent_int(self, data):
- return self.represent_scalar('tag:yaml.org,2002:int', str(data))
-
- inf_value = 1e300
- while repr(inf_value) != repr(inf_value*inf_value):
- inf_value *= inf_value
-
- def represent_float(self, data):
- if data != data or (data == 0.0 and data == 1.0):
- value = '.nan'
- elif data == self.inf_value:
- value = '.inf'
- elif data == -self.inf_value:
- value = '-.inf'
- else:
- value = repr(data).lower()
- # Note that in some cases `repr(data)` represents a float number
- # without the decimal parts. For instance:
- # >>> repr(1e17)
- # '1e17'
- # Unfortunately, this is not a valid float representation according
- # to the definition of the `!!float` tag. We fix this by adding
- # '.0' before the 'e' symbol.
- if '.' not in value and 'e' in value:
- value = value.replace('e', '.0e', 1)
- return self.represent_scalar('tag:yaml.org,2002:float', value)
-
- def represent_list(self, data):
- #pairs = (len(data) > 0 and isinstance(data, list))
- #if pairs:
- # for item in data:
- # if not isinstance(item, tuple) or len(item) != 2:
- # pairs = False
- # break
- #if not pairs:
- return self.represent_sequence('tag:yaml.org,2002:seq', data)
- #value = []
- #for item_key, item_value in data:
- # value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
- # [(item_key, item_value)]))
- #return SequenceNode(u'tag:yaml.org,2002:pairs', value)
-
- def represent_dict(self, data):
- return self.represent_mapping('tag:yaml.org,2002:map', data)
-
- def represent_set(self, data):
- value = {}
- for key in data:
- value[key] = None
- return self.represent_mapping('tag:yaml.org,2002:set', value)
-
- def represent_date(self, data):
- value = data.isoformat()
- return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
-
- def represent_datetime(self, data):
- value = data.isoformat(' ')
- return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
-
- def represent_yaml_object(self, tag, data, cls, flow_style=None):
- if hasattr(data, '__getstate__'):
- state = data.__getstate__()
- else:
- state = data.__dict__.copy()
- return self.represent_mapping(tag, state, flow_style=flow_style)
-
- def represent_undefined(self, data):
- raise RepresenterError("cannot represent an object: %s" % data)
-
-SafeRepresenter.add_representer(type(None),
- SafeRepresenter.represent_none)
-
-SafeRepresenter.add_representer(str,
- SafeRepresenter.represent_str)
-
-SafeRepresenter.add_representer(bytes,
- SafeRepresenter.represent_binary)
-
-SafeRepresenter.add_representer(bool,
- SafeRepresenter.represent_bool)
-
-SafeRepresenter.add_representer(int,
- SafeRepresenter.represent_int)
-
-SafeRepresenter.add_representer(float,
- SafeRepresenter.represent_float)
-
-SafeRepresenter.add_representer(list,
- SafeRepresenter.represent_list)
-
-SafeRepresenter.add_representer(tuple,
- SafeRepresenter.represent_list)
-
-SafeRepresenter.add_representer(dict,
- SafeRepresenter.represent_dict)
-
-SafeRepresenter.add_representer(set,
- SafeRepresenter.represent_set)
-
-SafeRepresenter.add_representer(datetime.date,
- SafeRepresenter.represent_date)
-
-SafeRepresenter.add_representer(datetime.datetime,
- SafeRepresenter.represent_datetime)
-
-SafeRepresenter.add_representer(None,
- SafeRepresenter.represent_undefined)
-
-class Representer(SafeRepresenter):
-
- def represent_complex(self, data):
- if data.imag == 0.0:
- data = '%r' % data.real
- elif data.real == 0.0:
- data = '%rj' % data.imag
- elif data.imag > 0:
- data = '%r+%rj' % (data.real, data.imag)
- else:
- data = '%r%rj' % (data.real, data.imag)
- return self.represent_scalar('tag:yaml.org,2002:python/complex', data)
-
- def represent_tuple(self, data):
- return self.represent_sequence('tag:yaml.org,2002:python/tuple', data)
-
- def represent_name(self, data):
- name = '%s.%s' % (data.__module__, data.__name__)
- return self.represent_scalar('tag:yaml.org,2002:python/name:'+name, '')
-
- def represent_module(self, data):
- return self.represent_scalar(
- 'tag:yaml.org,2002:python/module:'+data.__name__, '')
-
- def represent_object(self, data):
- # We use __reduce__ API to save the data. data.__reduce__ returns
- # a tuple of length 2-5:
- # (function, args, state, listitems, dictitems)
-
- # For reconstructing, we calls function(*args), then set its state,
- # listitems, and dictitems if they are not None.
-
- # A special case is when function.__name__ == '__newobj__'. In this
- # case we create the object with args[0].__new__(*args).
-
- # Another special case is when __reduce__ returns a string - we don't
- # support it.
-
- # We produce a !!python/object, !!python/object/new or
- # !!python/object/apply node.
-
- cls = type(data)
- if cls in copyreg.dispatch_table:
- reduce = copyreg.dispatch_table[cls](data)
- elif hasattr(data, '__reduce_ex__'):
- reduce = data.__reduce_ex__(2)
- elif hasattr(data, '__reduce__'):
- reduce = data.__reduce__()
- else:
- raise RepresenterError("cannot represent object: %r" % data)
- reduce = (list(reduce)+[None]*5)[:5]
- function, args, state, listitems, dictitems = reduce
- args = list(args)
- if state is None:
- state = {}
- if listitems is not None:
- listitems = list(listitems)
- if dictitems is not None:
- dictitems = dict(dictitems)
- if function.__name__ == '__newobj__':
- function = args[0]
- args = args[1:]
- tag = 'tag:yaml.org,2002:python/object/new:'
- newobj = True
- else:
- tag = 'tag:yaml.org,2002:python/object/apply:'
- newobj = False
- function_name = '%s.%s' % (function.__module__, function.__name__)
- if not args and not listitems and not dictitems \
- and isinstance(state, dict) and newobj:
- return self.represent_mapping(
- 'tag:yaml.org,2002:python/object:'+function_name, state)
- if not listitems and not dictitems \
- and isinstance(state, dict) and not state:
- return self.represent_sequence(tag+function_name, args)
- value = {}
- if args:
- value['args'] = args
- if state or not isinstance(state, dict):
- value['state'] = state
- if listitems:
- value['listitems'] = listitems
- if dictitems:
- value['dictitems'] = dictitems
- return self.represent_mapping(tag+function_name, value)
-
- def represent_ordered_dict(self, data):
- # Provide uniform representation across different Python versions.
- data_type = type(data)
- tag = 'tag:yaml.org,2002:python/object/apply:%s.%s' \
- % (data_type.__module__, data_type.__name__)
- items = [[key, value] for key, value in data.items()]
- return self.represent_sequence(tag, [items])
-
-Representer.add_representer(complex,
- Representer.represent_complex)
-
-Representer.add_representer(tuple,
- Representer.represent_tuple)
-
-Representer.add_representer(type,
- Representer.represent_name)
-
-Representer.add_representer(collections.OrderedDict,
- Representer.represent_ordered_dict)
-
-Representer.add_representer(types.FunctionType,
- Representer.represent_name)
-
-Representer.add_representer(types.BuiltinFunctionType,
- Representer.represent_name)
-
-Representer.add_representer(types.ModuleType,
- Representer.represent_module)
-
-Representer.add_multi_representer(object,
- Representer.represent_object)
-
diff --git a/lib/spack/external/yaml/lib3/yaml/resolver.py b/lib/spack/external/yaml/lib3/yaml/resolver.py
deleted file mode 100644
index 02b82e73ee..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/resolver.py
+++ /dev/null
@@ -1,227 +0,0 @@
-
-__all__ = ['BaseResolver', 'Resolver']
-
-from .error import *
-from .nodes import *
-
-import re
-
-class ResolverError(YAMLError):
- pass
-
-class BaseResolver:
-
- DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str'
- DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq'
- DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map'
-
- yaml_implicit_resolvers = {}
- yaml_path_resolvers = {}
-
- def __init__(self):
- self.resolver_exact_paths = []
- self.resolver_prefix_paths = []
-
- @classmethod
- def add_implicit_resolver(cls, tag, regexp, first):
- if not 'yaml_implicit_resolvers' in cls.__dict__:
- implicit_resolvers = {}
- for key in cls.yaml_implicit_resolvers:
- implicit_resolvers[key] = cls.yaml_implicit_resolvers[key][:]
- cls.yaml_implicit_resolvers = implicit_resolvers
- if first is None:
- first = [None]
- for ch in first:
- cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
-
- @classmethod
- def add_path_resolver(cls, tag, path, kind=None):
- # Note: `add_path_resolver` is experimental. The API could be changed.
- # `new_path` is a pattern that is matched against the path from the
- # root to the node that is being considered. `node_path` elements are
- # tuples `(node_check, index_check)`. `node_check` is a node class:
- # `ScalarNode`, `SequenceNode`, `MappingNode` or `None`. `None`
- # matches any kind of a node. `index_check` could be `None`, a boolean
- # value, a string value, or a number. `None` and `False` match against
- # any _value_ of sequence and mapping nodes. `True` matches against
- # any _key_ of a mapping node. A string `index_check` matches against
- # a mapping value that corresponds to a scalar key which content is
- # equal to the `index_check` value. An integer `index_check` matches
- # against a sequence value with the index equal to `index_check`.
- if not 'yaml_path_resolvers' in cls.__dict__:
- cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()
- new_path = []
- for element in path:
- if isinstance(element, (list, tuple)):
- if len(element) == 2:
- node_check, index_check = element
- elif len(element) == 1:
- node_check = element[0]
- index_check = True
- else:
- raise ResolverError("Invalid path element: %s" % element)
- else:
- node_check = None
- index_check = element
- if node_check is str:
- node_check = ScalarNode
- elif node_check is list:
- node_check = SequenceNode
- elif node_check is dict:
- node_check = MappingNode
- elif node_check not in [ScalarNode, SequenceNode, MappingNode] \
- and not isinstance(node_check, str) \
- and node_check is not None:
- raise ResolverError("Invalid node checker: %s" % node_check)
- if not isinstance(index_check, (str, int)) \
- and index_check is not None:
- raise ResolverError("Invalid index checker: %s" % index_check)
- new_path.append((node_check, index_check))
- if kind is str:
- kind = ScalarNode
- elif kind is list:
- kind = SequenceNode
- elif kind is dict:
- kind = MappingNode
- elif kind not in [ScalarNode, SequenceNode, MappingNode] \
- and kind is not None:
- raise ResolverError("Invalid node kind: %s" % kind)
- cls.yaml_path_resolvers[tuple(new_path), kind] = tag
-
- def descend_resolver(self, current_node, current_index):
- if not self.yaml_path_resolvers:
- return
- exact_paths = {}
- prefix_paths = []
- if current_node:
- depth = len(self.resolver_prefix_paths)
- for path, kind in self.resolver_prefix_paths[-1]:
- if self.check_resolver_prefix(depth, path, kind,
- current_node, current_index):
- if len(path) > depth:
- prefix_paths.append((path, kind))
- else:
- exact_paths[kind] = self.yaml_path_resolvers[path, kind]
- else:
- for path, kind in self.yaml_path_resolvers:
- if not path:
- exact_paths[kind] = self.yaml_path_resolvers[path, kind]
- else:
- prefix_paths.append((path, kind))
- self.resolver_exact_paths.append(exact_paths)
- self.resolver_prefix_paths.append(prefix_paths)
-
- def ascend_resolver(self):
- if not self.yaml_path_resolvers:
- return
- self.resolver_exact_paths.pop()
- self.resolver_prefix_paths.pop()
-
- def check_resolver_prefix(self, depth, path, kind,
- current_node, current_index):
- node_check, index_check = path[depth-1]
- if isinstance(node_check, str):
- if current_node.tag != node_check:
- return
- elif node_check is not None:
- if not isinstance(current_node, node_check):
- return
- if index_check is True and current_index is not None:
- return
- if (index_check is False or index_check is None) \
- and current_index is None:
- return
- if isinstance(index_check, str):
- if not (isinstance(current_index, ScalarNode)
- and index_check == current_index.value):
- return
- elif isinstance(index_check, int) and not isinstance(index_check, bool):
- if index_check != current_index:
- return
- return True
-
- def resolve(self, kind, value, implicit):
- if kind is ScalarNode and implicit[0]:
- if value == '':
- resolvers = self.yaml_implicit_resolvers.get('', [])
- else:
- resolvers = self.yaml_implicit_resolvers.get(value[0], [])
- resolvers += self.yaml_implicit_resolvers.get(None, [])
- for tag, regexp in resolvers:
- if regexp.match(value):
- return tag
- implicit = implicit[1]
- if self.yaml_path_resolvers:
- exact_paths = self.resolver_exact_paths[-1]
- if kind in exact_paths:
- return exact_paths[kind]
- if None in exact_paths:
- return exact_paths[None]
- if kind is ScalarNode:
- return self.DEFAULT_SCALAR_TAG
- elif kind is SequenceNode:
- return self.DEFAULT_SEQUENCE_TAG
- elif kind is MappingNode:
- return self.DEFAULT_MAPPING_TAG
-
-class Resolver(BaseResolver):
- pass
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:bool',
- re.compile(r'''^(?:yes|Yes|YES|no|No|NO
- |true|True|TRUE|false|False|FALSE
- |on|On|ON|off|Off|OFF)$''', re.X),
- list('yYnNtTfFoO'))
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:float',
- re.compile(r'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
- |\.[0-9_]+(?:[eE][-+][0-9]+)?
- |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
- |[-+]?\.(?:inf|Inf|INF)
- |\.(?:nan|NaN|NAN))$''', re.X),
- list('-+0123456789.'))
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:int',
- re.compile(r'''^(?:[-+]?0b[0-1_]+
- |[-+]?0[0-7_]+
- |[-+]?(?:0|[1-9][0-9_]*)
- |[-+]?0x[0-9a-fA-F_]+
- |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
- list('-+0123456789'))
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:merge',
- re.compile(r'^(?:<<)$'),
- ['<'])
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:null',
- re.compile(r'''^(?: ~
- |null|Null|NULL
- | )$''', re.X),
- ['~', 'n', 'N', ''])
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:timestamp',
- re.compile(r'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
- |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
- (?:[Tt]|[ \t]+)[0-9][0-9]?
- :[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)?
- (?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
- list('0123456789'))
-
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:value',
- re.compile(r'^(?:=)$'),
- ['='])
-
-# The following resolver is only for documentation purposes. It cannot work
-# because plain scalars cannot start with '!', '&', or '*'.
-Resolver.add_implicit_resolver(
- 'tag:yaml.org,2002:yaml',
- re.compile(r'^(?:!|&|\*)$'),
- list('!&*'))
-
diff --git a/lib/spack/external/yaml/lib3/yaml/scanner.py b/lib/spack/external/yaml/lib3/yaml/scanner.py
deleted file mode 100644
index c8d127b8ec..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/scanner.py
+++ /dev/null
@@ -1,1444 +0,0 @@
-
-# Scanner produces tokens of the following types:
-# STREAM-START
-# STREAM-END
-# DIRECTIVE(name, value)
-# DOCUMENT-START
-# DOCUMENT-END
-# BLOCK-SEQUENCE-START
-# BLOCK-MAPPING-START
-# BLOCK-END
-# FLOW-SEQUENCE-START
-# FLOW-MAPPING-START
-# FLOW-SEQUENCE-END
-# FLOW-MAPPING-END
-# BLOCK-ENTRY
-# FLOW-ENTRY
-# KEY
-# VALUE
-# ALIAS(value)
-# ANCHOR(value)
-# TAG(value)
-# SCALAR(value, plain, style)
-#
-# Read comments in the Scanner code for more details.
-#
-
-__all__ = ['Scanner', 'ScannerError']
-
-from .error import MarkedYAMLError
-from .tokens import *
-
-class ScannerError(MarkedYAMLError):
- pass
-
-class SimpleKey:
- # See below simple keys treatment.
-
- def __init__(self, token_number, required, index, line, column, mark):
- self.token_number = token_number
- self.required = required
- self.index = index
- self.line = line
- self.column = column
- self.mark = mark
-
-class Scanner:
-
- def __init__(self):
- """Initialize the scanner."""
- # It is assumed that Scanner and Reader will have a common descendant.
- # Reader do the dirty work of checking for BOM and converting the
- # input data to Unicode. It also adds NUL to the end.
- #
- # Reader supports the following methods
- # self.peek(i=0) # peek the next i-th character
- # self.prefix(l=1) # peek the next l characters
- # self.forward(l=1) # read the next l characters and move the pointer.
-
- # Had we reached the end of the stream?
- self.done = False
-
- # The number of unclosed '{' and '['. `flow_level == 0` means block
- # context.
- self.flow_level = 0
-
- # List of processed tokens that are not yet emitted.
- self.tokens = []
-
- # Add the STREAM-START token.
- self.fetch_stream_start()
-
- # Number of tokens that were emitted through the `get_token` method.
- self.tokens_taken = 0
-
- # The current indentation level.
- self.indent = -1
-
- # Past indentation levels.
- self.indents = []
-
- # Variables related to simple keys treatment.
-
- # A simple key is a key that is not denoted by the '?' indicator.
- # Example of simple keys:
- # ---
- # block simple key: value
- # ? not a simple key:
- # : { flow simple key: value }
- # We emit the KEY token before all keys, so when we find a potential
- # simple key, we try to locate the corresponding ':' indicator.
- # Simple keys should be limited to a single line and 1024 characters.
-
- # Can a simple key start at the current position? A simple key may
- # start:
- # - at the beginning of the line, not counting indentation spaces
- # (in block context),
- # - after '{', '[', ',' (in the flow context),
- # - after '?', ':', '-' (in the block context).
- # In the block context, this flag also signifies if a block collection
- # may start at the current position.
- self.allow_simple_key = True
-
- # Keep track of possible simple keys. This is a dictionary. The key
- # is `flow_level`; there can be no more that one possible simple key
- # for each level. The value is a SimpleKey record:
- # (token_number, required, index, line, column, mark)
- # A simple key may start with ALIAS, ANCHOR, TAG, SCALAR(flow),
- # '[', or '{' tokens.
- self.possible_simple_keys = {}
-
- # Public methods.
-
- def check_token(self, *choices):
- # Check if the next token is one of the given types.
- while self.need_more_tokens():
- self.fetch_more_tokens()
- if self.tokens:
- if not choices:
- return True
- for choice in choices:
- if isinstance(self.tokens[0], choice):
- return True
- return False
-
- def peek_token(self):
- # Return the next token, but do not delete if from the queue.
- while self.need_more_tokens():
- self.fetch_more_tokens()
- if self.tokens:
- return self.tokens[0]
-
- def get_token(self):
- # Return the next token.
- while self.need_more_tokens():
- self.fetch_more_tokens()
- if self.tokens:
- self.tokens_taken += 1
- return self.tokens.pop(0)
-
- # Private methods.
-
- def need_more_tokens(self):
- if self.done:
- return False
- if not self.tokens:
- return True
- # The current token may be a potential simple key, so we
- # need to look further.
- self.stale_possible_simple_keys()
- if self.next_possible_simple_key() == self.tokens_taken:
- return True
-
- def fetch_more_tokens(self):
-
- # Eat whitespaces and comments until we reach the next token.
- self.scan_to_next_token()
-
- # Remove obsolete possible simple keys.
- self.stale_possible_simple_keys()
-
- # Compare the current indentation and column. It may add some tokens
- # and decrease the current indentation level.
- self.unwind_indent(self.column)
-
- # Peek the next character.
- ch = self.peek()
-
- # Is it the end of stream?
- if ch == '\0':
- return self.fetch_stream_end()
-
- # Is it a directive?
- if ch == '%' and self.check_directive():
- return self.fetch_directive()
-
- # Is it the document start?
- if ch == '-' and self.check_document_start():
- return self.fetch_document_start()
-
- # Is it the document end?
- if ch == '.' and self.check_document_end():
- return self.fetch_document_end()
-
- # TODO: support for BOM within a stream.
- #if ch == '\uFEFF':
- # return self.fetch_bom() <-- issue BOMToken
-
- # Note: the order of the following checks is NOT significant.
-
- # Is it the flow sequence start indicator?
- if ch == '[':
- return self.fetch_flow_sequence_start()
-
- # Is it the flow mapping start indicator?
- if ch == '{':
- return self.fetch_flow_mapping_start()
-
- # Is it the flow sequence end indicator?
- if ch == ']':
- return self.fetch_flow_sequence_end()
-
- # Is it the flow mapping end indicator?
- if ch == '}':
- return self.fetch_flow_mapping_end()
-
- # Is it the flow entry indicator?
- if ch == ',':
- return self.fetch_flow_entry()
-
- # Is it the block entry indicator?
- if ch == '-' and self.check_block_entry():
- return self.fetch_block_entry()
-
- # Is it the key indicator?
- if ch == '?' and self.check_key():
- return self.fetch_key()
-
- # Is it the value indicator?
- if ch == ':' and self.check_value():
- return self.fetch_value()
-
- # Is it an alias?
- if ch == '*':
- return self.fetch_alias()
-
- # Is it an anchor?
- if ch == '&':
- return self.fetch_anchor()
-
- # Is it a tag?
- if ch == '!':
- return self.fetch_tag()
-
- # Is it a literal scalar?
- if ch == '|' and not self.flow_level:
- return self.fetch_literal()
-
- # Is it a folded scalar?
- if ch == '>' and not self.flow_level:
- return self.fetch_folded()
-
- # Is it a single quoted scalar?
- if ch == '\'':
- return self.fetch_single()
-
- # Is it a double quoted scalar?
- if ch == '\"':
- return self.fetch_double()
-
- # It must be a plain scalar then.
- if self.check_plain():
- return self.fetch_plain()
-
- # No? It's an error. Let's produce a nice error message.
- raise ScannerError("while scanning for the next token", None,
- "found character %r that cannot start any token" % ch,
- self.get_mark())
-
- # Simple keys treatment.
-
- def next_possible_simple_key(self):
- # Return the number of the nearest possible simple key. Actually we
- # don't need to loop through the whole dictionary. We may replace it
- # with the following code:
- # if not self.possible_simple_keys:
- # return None
- # return self.possible_simple_keys[
- # min(self.possible_simple_keys.keys())].token_number
- min_token_number = None
- for level in self.possible_simple_keys:
- key = self.possible_simple_keys[level]
- if min_token_number is None or key.token_number < min_token_number:
- min_token_number = key.token_number
- return min_token_number
-
- def stale_possible_simple_keys(self):
- # Remove entries that are no longer possible simple keys. According to
- # the YAML specification, simple keys
- # - should be limited to a single line,
- # - should be no longer than 1024 characters.
- # Disabling this procedure will allow simple keys of any length and
- # height (may cause problems if indentation is broken though).
- for level in list(self.possible_simple_keys):
- key = self.possible_simple_keys[level]
- if key.line != self.line \
- or self.index-key.index > 1024:
- if key.required:
- raise ScannerError("while scanning a simple key", key.mark,
- "could not find expected ':'", self.get_mark())
- del self.possible_simple_keys[level]
-
- def save_possible_simple_key(self):
- # The next token may start a simple key. We check if it's possible
- # and save its position. This function is called for
- # ALIAS, ANCHOR, TAG, SCALAR(flow), '[', and '{'.
-
- # Check if a simple key is required at the current position.
- required = not self.flow_level and self.indent == self.column
-
- # The next token might be a simple key. Let's save it's number and
- # position.
- if self.allow_simple_key:
- self.remove_possible_simple_key()
- token_number = self.tokens_taken+len(self.tokens)
- key = SimpleKey(token_number, required,
- self.index, self.line, self.column, self.get_mark())
- self.possible_simple_keys[self.flow_level] = key
-
- def remove_possible_simple_key(self):
- # Remove the saved possible key position at the current flow level.
- if self.flow_level in self.possible_simple_keys:
- key = self.possible_simple_keys[self.flow_level]
-
- if key.required:
- raise ScannerError("while scanning a simple key", key.mark,
- "could not find expected ':'", self.get_mark())
-
- del self.possible_simple_keys[self.flow_level]
-
- # Indentation functions.
-
- def unwind_indent(self, column):
-
- ## In flow context, tokens should respect indentation.
- ## Actually the condition should be `self.indent >= column` according to
- ## the spec. But this condition will prohibit intuitively correct
- ## constructions such as
- ## key : {
- ## }
- #if self.flow_level and self.indent > column:
- # raise ScannerError(None, None,
- # "invalid intendation or unclosed '[' or '{'",
- # self.get_mark())
-
- # In the flow context, indentation is ignored. We make the scanner less
- # restrictive then specification requires.
- if self.flow_level:
- return
-
- # In block context, we may need to issue the BLOCK-END tokens.
- while self.indent > column:
- mark = self.get_mark()
- self.indent = self.indents.pop()
- self.tokens.append(BlockEndToken(mark, mark))
-
- def add_indent(self, column):
- # Check if we need to increase indentation.
- if self.indent < column:
- self.indents.append(self.indent)
- self.indent = column
- return True
- return False
-
- # Fetchers.
-
- def fetch_stream_start(self):
- # We always add STREAM-START as the first token and STREAM-END as the
- # last token.
-
- # Read the token.
- mark = self.get_mark()
-
- # Add STREAM-START.
- self.tokens.append(StreamStartToken(mark, mark,
- encoding=self.encoding))
-
-
- def fetch_stream_end(self):
-
- # Set the current intendation to -1.
- self.unwind_indent(-1)
-
- # Reset simple keys.
- self.remove_possible_simple_key()
- self.allow_simple_key = False
- self.possible_simple_keys = {}
-
- # Read the token.
- mark = self.get_mark()
-
- # Add STREAM-END.
- self.tokens.append(StreamEndToken(mark, mark))
-
- # The steam is finished.
- self.done = True
-
- def fetch_directive(self):
-
- # Set the current intendation to -1.
- self.unwind_indent(-1)
-
- # Reset simple keys.
- self.remove_possible_simple_key()
- self.allow_simple_key = False
-
- # Scan and add DIRECTIVE.
- self.tokens.append(self.scan_directive())
-
- def fetch_document_start(self):
- self.fetch_document_indicator(DocumentStartToken)
-
- def fetch_document_end(self):
- self.fetch_document_indicator(DocumentEndToken)
-
- def fetch_document_indicator(self, TokenClass):
-
- # Set the current intendation to -1.
- self.unwind_indent(-1)
-
- # Reset simple keys. Note that there could not be a block collection
- # after '---'.
- self.remove_possible_simple_key()
- self.allow_simple_key = False
-
- # Add DOCUMENT-START or DOCUMENT-END.
- start_mark = self.get_mark()
- self.forward(3)
- end_mark = self.get_mark()
- self.tokens.append(TokenClass(start_mark, end_mark))
-
- def fetch_flow_sequence_start(self):
- self.fetch_flow_collection_start(FlowSequenceStartToken)
-
- def fetch_flow_mapping_start(self):
- self.fetch_flow_collection_start(FlowMappingStartToken)
-
- def fetch_flow_collection_start(self, TokenClass):
-
- # '[' and '{' may start a simple key.
- self.save_possible_simple_key()
-
- # Increase the flow level.
- self.flow_level += 1
-
- # Simple keys are allowed after '[' and '{'.
- self.allow_simple_key = True
-
- # Add FLOW-SEQUENCE-START or FLOW-MAPPING-START.
- start_mark = self.get_mark()
- self.forward()
- end_mark = self.get_mark()
- self.tokens.append(TokenClass(start_mark, end_mark))
-
- def fetch_flow_sequence_end(self):
- self.fetch_flow_collection_end(FlowSequenceEndToken)
-
- def fetch_flow_mapping_end(self):
- self.fetch_flow_collection_end(FlowMappingEndToken)
-
- def fetch_flow_collection_end(self, TokenClass):
-
- # Reset possible simple key on the current level.
- self.remove_possible_simple_key()
-
- # Decrease the flow level.
- self.flow_level -= 1
-
- # No simple keys after ']' or '}'.
- self.allow_simple_key = False
-
- # Add FLOW-SEQUENCE-END or FLOW-MAPPING-END.
- start_mark = self.get_mark()
- self.forward()
- end_mark = self.get_mark()
- self.tokens.append(TokenClass(start_mark, end_mark))
-
- def fetch_flow_entry(self):
-
- # Simple keys are allowed after ','.
- self.allow_simple_key = True
-
- # Reset possible simple key on the current level.
- self.remove_possible_simple_key()
-
- # Add FLOW-ENTRY.
- start_mark = self.get_mark()
- self.forward()
- end_mark = self.get_mark()
- self.tokens.append(FlowEntryToken(start_mark, end_mark))
-
- def fetch_block_entry(self):
-
- # Block context needs additional checks.
- if not self.flow_level:
-
- # Are we allowed to start a new entry?
- if not self.allow_simple_key:
- raise ScannerError(None, None,
- "sequence entries are not allowed here",
- self.get_mark())
-
- # We may need to add BLOCK-SEQUENCE-START.
- if self.add_indent(self.column):
- mark = self.get_mark()
- self.tokens.append(BlockSequenceStartToken(mark, mark))
-
- # It's an error for the block entry to occur in the flow context,
- # but we let the parser detect this.
- else:
- pass
-
- # Simple keys are allowed after '-'.
- self.allow_simple_key = True
-
- # Reset possible simple key on the current level.
- self.remove_possible_simple_key()
-
- # Add BLOCK-ENTRY.
- start_mark = self.get_mark()
- self.forward()
- end_mark = self.get_mark()
- self.tokens.append(BlockEntryToken(start_mark, end_mark))
-
- def fetch_key(self):
-
- # Block context needs additional checks.
- if not self.flow_level:
-
- # Are we allowed to start a key (not nessesary a simple)?
- if not self.allow_simple_key:
- raise ScannerError(None, None,
- "mapping keys are not allowed here",
- self.get_mark())
-
- # We may need to add BLOCK-MAPPING-START.
- if self.add_indent(self.column):
- mark = self.get_mark()
- self.tokens.append(BlockMappingStartToken(mark, mark))
-
- # Simple keys are allowed after '?' in the block context.
- self.allow_simple_key = not self.flow_level
-
- # Reset possible simple key on the current level.
- self.remove_possible_simple_key()
-
- # Add KEY.
- start_mark = self.get_mark()
- self.forward()
- end_mark = self.get_mark()
- self.tokens.append(KeyToken(start_mark, end_mark))
-
- def fetch_value(self):
-
- # Do we determine a simple key?
- if self.flow_level in self.possible_simple_keys:
-
- # Add KEY.
- key = self.possible_simple_keys[self.flow_level]
- del self.possible_simple_keys[self.flow_level]
- self.tokens.insert(key.token_number-self.tokens_taken,
- KeyToken(key.mark, key.mark))
-
- # If this key starts a new block mapping, we need to add
- # BLOCK-MAPPING-START.
- if not self.flow_level:
- if self.add_indent(key.column):
- self.tokens.insert(key.token_number-self.tokens_taken,
- BlockMappingStartToken(key.mark, key.mark))
-
- # There cannot be two simple keys one after another.
- self.allow_simple_key = False
-
- # It must be a part of a complex key.
- else:
-
- # Block context needs additional checks.
- # (Do we really need them? They will be catched by the parser
- # anyway.)
- if not self.flow_level:
-
- # We are allowed to start a complex value if and only if
- # we can start a simple key.
- if not self.allow_simple_key:
- raise ScannerError(None, None,
- "mapping values are not allowed here",
- self.get_mark())
-
- # If this value starts a new block mapping, we need to add
- # BLOCK-MAPPING-START. It will be detected as an error later by
- # the parser.
- if not self.flow_level:
- if self.add_indent(self.column):
- mark = self.get_mark()
- self.tokens.append(BlockMappingStartToken(mark, mark))
-
- # Simple keys are allowed after ':' in the block context.
- self.allow_simple_key = not self.flow_level
-
- # Reset possible simple key on the current level.
- self.remove_possible_simple_key()
-
- # Add VALUE.
- start_mark = self.get_mark()
- self.forward()
- end_mark = self.get_mark()
- self.tokens.append(ValueToken(start_mark, end_mark))
-
- def fetch_alias(self):
-
- # ALIAS could be a simple key.
- self.save_possible_simple_key()
-
- # No simple keys after ALIAS.
- self.allow_simple_key = False
-
- # Scan and add ALIAS.
- self.tokens.append(self.scan_anchor(AliasToken))
-
- def fetch_anchor(self):
-
- # ANCHOR could start a simple key.
- self.save_possible_simple_key()
-
- # No simple keys after ANCHOR.
- self.allow_simple_key = False
-
- # Scan and add ANCHOR.
- self.tokens.append(self.scan_anchor(AnchorToken))
-
- def fetch_tag(self):
-
- # TAG could start a simple key.
- self.save_possible_simple_key()
-
- # No simple keys after TAG.
- self.allow_simple_key = False
-
- # Scan and add TAG.
- self.tokens.append(self.scan_tag())
-
- def fetch_literal(self):
- self.fetch_block_scalar(style='|')
-
- def fetch_folded(self):
- self.fetch_block_scalar(style='>')
-
- def fetch_block_scalar(self, style):
-
- # A simple key may follow a block scalar.
- self.allow_simple_key = True
-
- # Reset possible simple key on the current level.
- self.remove_possible_simple_key()
-
- # Scan and add SCALAR.
- self.tokens.append(self.scan_block_scalar(style))
-
- def fetch_single(self):
- self.fetch_flow_scalar(style='\'')
-
- def fetch_double(self):
- self.fetch_flow_scalar(style='"')
-
- def fetch_flow_scalar(self, style):
-
- # A flow scalar could be a simple key.
- self.save_possible_simple_key()
-
- # No simple keys after flow scalars.
- self.allow_simple_key = False
-
- # Scan and add SCALAR.
- self.tokens.append(self.scan_flow_scalar(style))
-
- def fetch_plain(self):
-
- # A plain scalar could be a simple key.
- self.save_possible_simple_key()
-
- # No simple keys after plain scalars. But note that `scan_plain` will
- # change this flag if the scan is finished at the beginning of the
- # line.
- self.allow_simple_key = False
-
- # Scan and add SCALAR. May change `allow_simple_key`.
- self.tokens.append(self.scan_plain())
-
- # Checkers.
-
- def check_directive(self):
-
- # DIRECTIVE: ^ '%' ...
- # The '%' indicator is already checked.
- if self.column == 0:
- return True
-
- def check_document_start(self):
-
- # DOCUMENT-START: ^ '---' (' '|'\n')
- if self.column == 0:
- if self.prefix(3) == '---' \
- and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
- return True
-
- def check_document_end(self):
-
- # DOCUMENT-END: ^ '...' (' '|'\n')
- if self.column == 0:
- if self.prefix(3) == '...' \
- and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
- return True
-
- def check_block_entry(self):
-
- # BLOCK-ENTRY: '-' (' '|'\n')
- return self.peek(1) in '\0 \t\r\n\x85\u2028\u2029'
-
- def check_key(self):
-
- # KEY(flow context): '?'
- if self.flow_level:
- return True
-
- # KEY(block context): '?' (' '|'\n')
- else:
- return self.peek(1) in '\0 \t\r\n\x85\u2028\u2029'
-
- def check_value(self):
-
- # VALUE(flow context): ':'
- if self.flow_level:
- return True
-
- # VALUE(block context): ':' (' '|'\n')
- else:
- return self.peek(1) in '\0 \t\r\n\x85\u2028\u2029'
-
- def check_plain(self):
-
- # A plain scalar may start with any non-space character except:
- # '-', '?', ':', ',', '[', ']', '{', '}',
- # '#', '&', '*', '!', '|', '>', '\'', '\"',
- # '%', '@', '`'.
- #
- # It may also start with
- # '-', '?', ':'
- # if it is followed by a non-space character.
- #
- # Note that we limit the last rule to the block context (except the
- # '-' character) because we want the flow context to be space
- # independent.
- ch = self.peek()
- return ch not in '\0 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'\"%@`' \
- or (self.peek(1) not in '\0 \t\r\n\x85\u2028\u2029'
- and (ch == '-' or (not self.flow_level and ch in '?:')))
-
- # Scanners.
-
- def scan_to_next_token(self):
- # We ignore spaces, line breaks and comments.
- # If we find a line break in the block context, we set the flag
- # `allow_simple_key` on.
- # The byte order mark is stripped if it's the first character in the
- # stream. We do not yet support BOM inside the stream as the
- # specification requires. Any such mark will be considered as a part
- # of the document.
- #
- # TODO: We need to make tab handling rules more sane. A good rule is
- # Tabs cannot precede tokens
- # BLOCK-SEQUENCE-START, BLOCK-MAPPING-START, BLOCK-END,
- # KEY(block), VALUE(block), BLOCK-ENTRY
- # So the checking code is
- # if <TAB>:
- # self.allow_simple_keys = False
- # We also need to add the check for `allow_simple_keys == True` to
- # `unwind_indent` before issuing BLOCK-END.
- # Scanners for block, flow, and plain scalars need to be modified.
-
- if self.index == 0 and self.peek() == '\uFEFF':
- self.forward()
- found = False
- while not found:
- while self.peek() == ' ':
- self.forward()
- if self.peek() == '#':
- while self.peek() not in '\0\r\n\x85\u2028\u2029':
- self.forward()
- if self.scan_line_break():
- if not self.flow_level:
- self.allow_simple_key = True
- else:
- found = True
-
- def scan_directive(self):
- # See the specification for details.
- start_mark = self.get_mark()
- self.forward()
- name = self.scan_directive_name(start_mark)
- value = None
- if name == 'YAML':
- value = self.scan_yaml_directive_value(start_mark)
- end_mark = self.get_mark()
- elif name == 'TAG':
- value = self.scan_tag_directive_value(start_mark)
- end_mark = self.get_mark()
- else:
- end_mark = self.get_mark()
- while self.peek() not in '\0\r\n\x85\u2028\u2029':
- self.forward()
- self.scan_directive_ignored_line(start_mark)
- return DirectiveToken(name, value, start_mark, end_mark)
-
- def scan_directive_name(self, start_mark):
- # See the specification for details.
- length = 0
- ch = self.peek(length)
- while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-_':
- length += 1
- ch = self.peek(length)
- if not length:
- raise ScannerError("while scanning a directive", start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch, self.get_mark())
- value = self.prefix(length)
- self.forward(length)
- ch = self.peek()
- if ch not in '\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch, self.get_mark())
- return value
-
- def scan_yaml_directive_value(self, start_mark):
- # See the specification for details.
- while self.peek() == ' ':
- self.forward()
- major = self.scan_yaml_directive_number(start_mark)
- if self.peek() != '.':
- raise ScannerError("while scanning a directive", start_mark,
- "expected a digit or '.', but found %r" % self.peek(),
- self.get_mark())
- self.forward()
- minor = self.scan_yaml_directive_number(start_mark)
- if self.peek() not in '\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected a digit or ' ', but found %r" % self.peek(),
- self.get_mark())
- return (major, minor)
-
- def scan_yaml_directive_number(self, start_mark):
- # See the specification for details.
- ch = self.peek()
- if not ('0' <= ch <= '9'):
- raise ScannerError("while scanning a directive", start_mark,
- "expected a digit, but found %r" % ch, self.get_mark())
- length = 0
- while '0' <= self.peek(length) <= '9':
- length += 1
- value = int(self.prefix(length))
- self.forward(length)
- return value
-
- def scan_tag_directive_value(self, start_mark):
- # See the specification for details.
- while self.peek() == ' ':
- self.forward()
- handle = self.scan_tag_directive_handle(start_mark)
- while self.peek() == ' ':
- self.forward()
- prefix = self.scan_tag_directive_prefix(start_mark)
- return (handle, prefix)
-
- def scan_tag_directive_handle(self, start_mark):
- # See the specification for details.
- value = self.scan_tag_handle('directive', start_mark)
- ch = self.peek()
- if ch != ' ':
- raise ScannerError("while scanning a directive", start_mark,
- "expected ' ', but found %r" % ch, self.get_mark())
- return value
-
- def scan_tag_directive_prefix(self, start_mark):
- # See the specification for details.
- value = self.scan_tag_uri('directive', start_mark)
- ch = self.peek()
- if ch not in '\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected ' ', but found %r" % ch, self.get_mark())
- return value
-
- def scan_directive_ignored_line(self, start_mark):
- # See the specification for details.
- while self.peek() == ' ':
- self.forward()
- if self.peek() == '#':
- while self.peek() not in '\0\r\n\x85\u2028\u2029':
- self.forward()
- ch = self.peek()
- if ch not in '\0\r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a directive", start_mark,
- "expected a comment or a line break, but found %r"
- % ch, self.get_mark())
- self.scan_line_break()
-
- def scan_anchor(self, TokenClass):
- # The specification does not restrict characters for anchors and
- # aliases. This may lead to problems, for instance, the document:
- # [ *alias, value ]
- # can be interpteted in two ways, as
- # [ "value" ]
- # and
- # [ *alias , "value" ]
- # Therefore we restrict aliases to numbers and ASCII letters.
- start_mark = self.get_mark()
- indicator = self.peek()
- if indicator == '*':
- name = 'alias'
- else:
- name = 'anchor'
- self.forward()
- length = 0
- ch = self.peek(length)
- while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-_':
- length += 1
- ch = self.peek(length)
- if not length:
- raise ScannerError("while scanning an %s" % name, start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch, self.get_mark())
- value = self.prefix(length)
- self.forward(length)
- ch = self.peek()
- if ch not in '\0 \t\r\n\x85\u2028\u2029?:,]}%@`':
- raise ScannerError("while scanning an %s" % name, start_mark,
- "expected alphabetic or numeric character, but found %r"
- % ch, self.get_mark())
- end_mark = self.get_mark()
- return TokenClass(value, start_mark, end_mark)
-
- def scan_tag(self):
- # See the specification for details.
- start_mark = self.get_mark()
- ch = self.peek(1)
- if ch == '<':
- handle = None
- self.forward(2)
- suffix = self.scan_tag_uri('tag', start_mark)
- if self.peek() != '>':
- raise ScannerError("while parsing a tag", start_mark,
- "expected '>', but found %r" % self.peek(),
- self.get_mark())
- self.forward()
- elif ch in '\0 \t\r\n\x85\u2028\u2029':
- handle = None
- suffix = '!'
- self.forward()
- else:
- length = 1
- use_handle = False
- while ch not in '\0 \r\n\x85\u2028\u2029':
- if ch == '!':
- use_handle = True
- break
- length += 1
- ch = self.peek(length)
- handle = '!'
- if use_handle:
- handle = self.scan_tag_handle('tag', start_mark)
- else:
- handle = '!'
- self.forward()
- suffix = self.scan_tag_uri('tag', start_mark)
- ch = self.peek()
- if ch not in '\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a tag", start_mark,
- "expected ' ', but found %r" % ch, self.get_mark())
- value = (handle, suffix)
- end_mark = self.get_mark()
- return TagToken(value, start_mark, end_mark)
-
- def scan_block_scalar(self, style):
- # See the specification for details.
-
- if style == '>':
- folded = True
- else:
- folded = False
-
- chunks = []
- start_mark = self.get_mark()
-
- # Scan the header.
- self.forward()
- chomping, increment = self.scan_block_scalar_indicators(start_mark)
- self.scan_block_scalar_ignored_line(start_mark)
-
- # Determine the indentation level and go to the first non-empty line.
- min_indent = self.indent+1
- if min_indent < 1:
- min_indent = 1
- if increment is None:
- breaks, max_indent, end_mark = self.scan_block_scalar_indentation()
- indent = max(min_indent, max_indent)
- else:
- indent = min_indent+increment-1
- breaks, end_mark = self.scan_block_scalar_breaks(indent)
- line_break = ''
-
- # Scan the inner part of the block scalar.
- while self.column == indent and self.peek() != '\0':
- chunks.extend(breaks)
- leading_non_space = self.peek() not in ' \t'
- length = 0
- while self.peek(length) not in '\0\r\n\x85\u2028\u2029':
- length += 1
- chunks.append(self.prefix(length))
- self.forward(length)
- line_break = self.scan_line_break()
- breaks, end_mark = self.scan_block_scalar_breaks(indent)
- if self.column == indent and self.peek() != '\0':
-
- # Unfortunately, folding rules are ambiguous.
- #
- # This is the folding according to the specification:
-
- if folded and line_break == '\n' \
- and leading_non_space and self.peek() not in ' \t':
- if not breaks:
- chunks.append(' ')
- else:
- chunks.append(line_break)
-
- # This is Clark Evans's interpretation (also in the spec
- # examples):
- #
- #if folded and line_break == '\n':
- # if not breaks:
- # if self.peek() not in ' \t':
- # chunks.append(' ')
- # else:
- # chunks.append(line_break)
- #else:
- # chunks.append(line_break)
- else:
- break
-
- # Chomp the tail.
- if chomping is not False:
- chunks.append(line_break)
- if chomping is True:
- chunks.extend(breaks)
-
- # We are done.
- return ScalarToken(''.join(chunks), False, start_mark, end_mark,
- style)
-
- def scan_block_scalar_indicators(self, start_mark):
- # See the specification for details.
- chomping = None
- increment = None
- ch = self.peek()
- if ch in '+-':
- if ch == '+':
- chomping = True
- else:
- chomping = False
- self.forward()
- ch = self.peek()
- if ch in '0123456789':
- increment = int(ch)
- if increment == 0:
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected indentation indicator in the range 1-9, but found 0",
- self.get_mark())
- self.forward()
- elif ch in '0123456789':
- increment = int(ch)
- if increment == 0:
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected indentation indicator in the range 1-9, but found 0",
- self.get_mark())
- self.forward()
- ch = self.peek()
- if ch in '+-':
- if ch == '+':
- chomping = True
- else:
- chomping = False
- self.forward()
- ch = self.peek()
- if ch not in '\0 \r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected chomping or indentation indicators, but found %r"
- % ch, self.get_mark())
- return chomping, increment
-
- def scan_block_scalar_ignored_line(self, start_mark):
- # See the specification for details.
- while self.peek() == ' ':
- self.forward()
- if self.peek() == '#':
- while self.peek() not in '\0\r\n\x85\u2028\u2029':
- self.forward()
- ch = self.peek()
- if ch not in '\0\r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a block scalar", start_mark,
- "expected a comment or a line break, but found %r" % ch,
- self.get_mark())
- self.scan_line_break()
-
- def scan_block_scalar_indentation(self):
- # See the specification for details.
- chunks = []
- max_indent = 0
- end_mark = self.get_mark()
- while self.peek() in ' \r\n\x85\u2028\u2029':
- if self.peek() != ' ':
- chunks.append(self.scan_line_break())
- end_mark = self.get_mark()
- else:
- self.forward()
- if self.column > max_indent:
- max_indent = self.column
- return chunks, max_indent, end_mark
-
- def scan_block_scalar_breaks(self, indent):
- # See the specification for details.
- chunks = []
- end_mark = self.get_mark()
- while self.column < indent and self.peek() == ' ':
- self.forward()
- while self.peek() in '\r\n\x85\u2028\u2029':
- chunks.append(self.scan_line_break())
- end_mark = self.get_mark()
- while self.column < indent and self.peek() == ' ':
- self.forward()
- return chunks, end_mark
-
- def scan_flow_scalar(self, style):
- # See the specification for details.
- # Note that we loose indentation rules for quoted scalars. Quoted
- # scalars don't need to adhere indentation because " and ' clearly
- # mark the beginning and the end of them. Therefore we are less
- # restrictive then the specification requires. We only need to check
- # that document separators are not included in scalars.
- if style == '"':
- double = True
- else:
- double = False
- chunks = []
- start_mark = self.get_mark()
- quote = self.peek()
- self.forward()
- chunks.extend(self.scan_flow_scalar_non_spaces(double, start_mark))
- while self.peek() != quote:
- chunks.extend(self.scan_flow_scalar_spaces(double, start_mark))
- chunks.extend(self.scan_flow_scalar_non_spaces(double, start_mark))
- self.forward()
- end_mark = self.get_mark()
- return ScalarToken(''.join(chunks), False, start_mark, end_mark,
- style)
-
- ESCAPE_REPLACEMENTS = {
- '0': '\0',
- 'a': '\x07',
- 'b': '\x08',
- 't': '\x09',
- '\t': '\x09',
- 'n': '\x0A',
- 'v': '\x0B',
- 'f': '\x0C',
- 'r': '\x0D',
- 'e': '\x1B',
- ' ': '\x20',
- '\"': '\"',
- '\\': '\\',
- 'N': '\x85',
- '_': '\xA0',
- 'L': '\u2028',
- 'P': '\u2029',
- }
-
- ESCAPE_CODES = {
- 'x': 2,
- 'u': 4,
- 'U': 8,
- }
-
- def scan_flow_scalar_non_spaces(self, double, start_mark):
- # See the specification for details.
- chunks = []
- while True:
- length = 0
- while self.peek(length) not in '\'\"\\\0 \t\r\n\x85\u2028\u2029':
- length += 1
- if length:
- chunks.append(self.prefix(length))
- self.forward(length)
- ch = self.peek()
- if not double and ch == '\'' and self.peek(1) == '\'':
- chunks.append('\'')
- self.forward(2)
- elif (double and ch == '\'') or (not double and ch in '\"\\'):
- chunks.append(ch)
- self.forward()
- elif double and ch == '\\':
- self.forward()
- ch = self.peek()
- if ch in self.ESCAPE_REPLACEMENTS:
- chunks.append(self.ESCAPE_REPLACEMENTS[ch])
- self.forward()
- elif ch in self.ESCAPE_CODES:
- length = self.ESCAPE_CODES[ch]
- self.forward()
- for k in range(length):
- if self.peek(k) not in '0123456789ABCDEFabcdef':
- raise ScannerError("while scanning a double-quoted scalar", start_mark,
- "expected escape sequence of %d hexdecimal numbers, but found %r" %
- (length, self.peek(k)), self.get_mark())
- code = int(self.prefix(length), 16)
- chunks.append(chr(code))
- self.forward(length)
- elif ch in '\r\n\x85\u2028\u2029':
- self.scan_line_break()
- chunks.extend(self.scan_flow_scalar_breaks(double, start_mark))
- else:
- raise ScannerError("while scanning a double-quoted scalar", start_mark,
- "found unknown escape character %r" % ch, self.get_mark())
- else:
- return chunks
-
- def scan_flow_scalar_spaces(self, double, start_mark):
- # See the specification for details.
- chunks = []
- length = 0
- while self.peek(length) in ' \t':
- length += 1
- whitespaces = self.prefix(length)
- self.forward(length)
- ch = self.peek()
- if ch == '\0':
- raise ScannerError("while scanning a quoted scalar", start_mark,
- "found unexpected end of stream", self.get_mark())
- elif ch in '\r\n\x85\u2028\u2029':
- line_break = self.scan_line_break()
- breaks = self.scan_flow_scalar_breaks(double, start_mark)
- if line_break != '\n':
- chunks.append(line_break)
- elif not breaks:
- chunks.append(' ')
- chunks.extend(breaks)
- else:
- chunks.append(whitespaces)
- return chunks
-
- def scan_flow_scalar_breaks(self, double, start_mark):
- # See the specification for details.
- chunks = []
- while True:
- # Instead of checking indentation, we check for document
- # separators.
- prefix = self.prefix(3)
- if (prefix == '---' or prefix == '...') \
- and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
- raise ScannerError("while scanning a quoted scalar", start_mark,
- "found unexpected document separator", self.get_mark())
- while self.peek() in ' \t':
- self.forward()
- if self.peek() in '\r\n\x85\u2028\u2029':
- chunks.append(self.scan_line_break())
- else:
- return chunks
-
- def scan_plain(self):
- # See the specification for details.
- # We add an additional restriction for the flow context:
- # plain scalars in the flow context cannot contain ',', ':' and '?'.
- # We also keep track of the `allow_simple_key` flag here.
- # Indentation rules are loosed for the flow context.
- chunks = []
- start_mark = self.get_mark()
- end_mark = start_mark
- indent = self.indent+1
- # We allow zero indentation for scalars, but then we need to check for
- # document separators at the beginning of the line.
- #if indent == 0:
- # indent = 1
- spaces = []
- while True:
- length = 0
- if self.peek() == '#':
- break
- while True:
- ch = self.peek(length)
- if ch in '\0 \t\r\n\x85\u2028\u2029' \
- or (not self.flow_level and ch == ':' and
- self.peek(length+1) in '\0 \t\r\n\x85\u2028\u2029') \
- or (self.flow_level and ch in ',:?[]{}'):
- break
- length += 1
- # It's not clear what we should do with ':' in the flow context.
- if (self.flow_level and ch == ':'
- and self.peek(length+1) not in '\0 \t\r\n\x85\u2028\u2029,[]{}'):
- self.forward(length)
- raise ScannerError("while scanning a plain scalar", start_mark,
- "found unexpected ':'", self.get_mark(),
- "Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details.")
- if length == 0:
- break
- self.allow_simple_key = False
- chunks.extend(spaces)
- chunks.append(self.prefix(length))
- self.forward(length)
- end_mark = self.get_mark()
- spaces = self.scan_plain_spaces(indent, start_mark)
- if not spaces or self.peek() == '#' \
- or (not self.flow_level and self.column < indent):
- break
- return ScalarToken(''.join(chunks), True, start_mark, end_mark)
-
- def scan_plain_spaces(self, indent, start_mark):
- # See the specification for details.
- # The specification is really confusing about tabs in plain scalars.
- # We just forbid them completely. Do not use tabs in YAML!
- chunks = []
- length = 0
- while self.peek(length) in ' ':
- length += 1
- whitespaces = self.prefix(length)
- self.forward(length)
- ch = self.peek()
- if ch in '\r\n\x85\u2028\u2029':
- line_break = self.scan_line_break()
- self.allow_simple_key = True
- prefix = self.prefix(3)
- if (prefix == '---' or prefix == '...') \
- and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
- return
- breaks = []
- while self.peek() in ' \r\n\x85\u2028\u2029':
- if self.peek() == ' ':
- self.forward()
- else:
- breaks.append(self.scan_line_break())
- prefix = self.prefix(3)
- if (prefix == '---' or prefix == '...') \
- and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
- return
- if line_break != '\n':
- chunks.append(line_break)
- elif not breaks:
- chunks.append(' ')
- chunks.extend(breaks)
- elif whitespaces:
- chunks.append(whitespaces)
- return chunks
-
- def scan_tag_handle(self, name, start_mark):
- # See the specification for details.
- # For some strange reasons, the specification does not allow '_' in
- # tag handles. I have allowed it anyway.
- ch = self.peek()
- if ch != '!':
- raise ScannerError("while scanning a %s" % name, start_mark,
- "expected '!', but found %r" % ch, self.get_mark())
- length = 1
- ch = self.peek(length)
- if ch != ' ':
- while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-_':
- length += 1
- ch = self.peek(length)
- if ch != '!':
- self.forward(length)
- raise ScannerError("while scanning a %s" % name, start_mark,
- "expected '!', but found %r" % ch, self.get_mark())
- length += 1
- value = self.prefix(length)
- self.forward(length)
- return value
-
- def scan_tag_uri(self, name, start_mark):
- # See the specification for details.
- # Note: we do not check if URI is well-formed.
- chunks = []
- length = 0
- ch = self.peek(length)
- while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \
- or ch in '-;/?:@&=+$,_.!~*\'()[]%':
- if ch == '%':
- chunks.append(self.prefix(length))
- self.forward(length)
- length = 0
- chunks.append(self.scan_uri_escapes(name, start_mark))
- else:
- length += 1
- ch = self.peek(length)
- if length:
- chunks.append(self.prefix(length))
- self.forward(length)
- length = 0
- if not chunks:
- raise ScannerError("while parsing a %s" % name, start_mark,
- "expected URI, but found %r" % ch, self.get_mark())
- return ''.join(chunks)
-
- def scan_uri_escapes(self, name, start_mark):
- # See the specification for details.
- codes = []
- mark = self.get_mark()
- while self.peek() == '%':
- self.forward()
- for k in range(2):
- if self.peek(k) not in '0123456789ABCDEFabcdef':
- raise ScannerError("while scanning a %s" % name, start_mark,
- "expected URI escape sequence of 2 hexdecimal numbers, but found %r"
- % self.peek(k), self.get_mark())
- codes.append(int(self.prefix(2), 16))
- self.forward(2)
- try:
- value = bytes(codes).decode('utf-8')
- except UnicodeDecodeError as exc:
- raise ScannerError("while scanning a %s" % name, start_mark, str(exc), mark)
- return value
-
- def scan_line_break(self):
- # Transforms:
- # '\r\n' : '\n'
- # '\r' : '\n'
- # '\n' : '\n'
- # '\x85' : '\n'
- # '\u2028' : '\u2028'
- # '\u2029 : '\u2029'
- # default : ''
- ch = self.peek()
- if ch in '\r\n\x85':
- if self.prefix(2) == '\r\n':
- self.forward(2)
- else:
- self.forward()
- return '\n'
- elif ch in '\u2028\u2029':
- self.forward()
- return ch
- return ''
-
-#try:
-# import psyco
-# psyco.bind(Scanner)
-#except ImportError:
-# pass
-
diff --git a/lib/spack/external/yaml/lib3/yaml/serializer.py b/lib/spack/external/yaml/lib3/yaml/serializer.py
deleted file mode 100644
index fe911e67ae..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/serializer.py
+++ /dev/null
@@ -1,111 +0,0 @@
-
-__all__ = ['Serializer', 'SerializerError']
-
-from .error import YAMLError
-from .events import *
-from .nodes import *
-
-class SerializerError(YAMLError):
- pass
-
-class Serializer:
-
- ANCHOR_TEMPLATE = 'id%03d'
-
- def __init__(self, encoding=None,
- explicit_start=None, explicit_end=None, version=None, tags=None):
- self.use_encoding = encoding
- self.use_explicit_start = explicit_start
- self.use_explicit_end = explicit_end
- self.use_version = version
- self.use_tags = tags
- self.serialized_nodes = {}
- self.anchors = {}
- self.last_anchor_id = 0
- self.closed = None
-
- def open(self):
- if self.closed is None:
- self.emit(StreamStartEvent(encoding=self.use_encoding))
- self.closed = False
- elif self.closed:
- raise SerializerError("serializer is closed")
- else:
- raise SerializerError("serializer is already opened")
-
- def close(self):
- if self.closed is None:
- raise SerializerError("serializer is not opened")
- elif not self.closed:
- self.emit(StreamEndEvent())
- self.closed = True
-
- #def __del__(self):
- # self.close()
-
- def serialize(self, node):
- if self.closed is None:
- raise SerializerError("serializer is not opened")
- elif self.closed:
- raise SerializerError("serializer is closed")
- self.emit(DocumentStartEvent(explicit=self.use_explicit_start,
- version=self.use_version, tags=self.use_tags))
- self.anchor_node(node)
- self.serialize_node(node, None, None)
- self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
- self.serialized_nodes = {}
- self.anchors = {}
- self.last_anchor_id = 0
-
- def anchor_node(self, node):
- if node in self.anchors:
- if self.anchors[node] is None:
- self.anchors[node] = self.generate_anchor(node)
- else:
- self.anchors[node] = None
- if isinstance(node, SequenceNode):
- for item in node.value:
- self.anchor_node(item)
- elif isinstance(node, MappingNode):
- for key, value in node.value:
- self.anchor_node(key)
- self.anchor_node(value)
-
- def generate_anchor(self, node):
- self.last_anchor_id += 1
- return self.ANCHOR_TEMPLATE % self.last_anchor_id
-
- def serialize_node(self, node, parent, index):
- alias = self.anchors[node]
- if node in self.serialized_nodes:
- self.emit(AliasEvent(alias))
- else:
- self.serialized_nodes[node] = True
- self.descend_resolver(parent, index)
- if isinstance(node, ScalarNode):
- detected_tag = self.resolve(ScalarNode, node.value, (True, False))
- default_tag = self.resolve(ScalarNode, node.value, (False, True))
- implicit = (node.tag == detected_tag), (node.tag == default_tag)
- self.emit(ScalarEvent(alias, node.tag, implicit, node.value,
- style=node.style))
- elif isinstance(node, SequenceNode):
- implicit = (node.tag
- == self.resolve(SequenceNode, node.value, True))
- self.emit(SequenceStartEvent(alias, node.tag, implicit,
- flow_style=node.flow_style))
- index = 0
- for item in node.value:
- self.serialize_node(item, node, index)
- index += 1
- self.emit(SequenceEndEvent())
- elif isinstance(node, MappingNode):
- implicit = (node.tag
- == self.resolve(MappingNode, node.value, True))
- self.emit(MappingStartEvent(alias, node.tag, implicit,
- flow_style=node.flow_style))
- for key, value in node.value:
- self.serialize_node(key, node, None)
- self.serialize_node(value, node, key)
- self.emit(MappingEndEvent())
- self.ascend_resolver()
-
diff --git a/lib/spack/external/yaml/lib3/yaml/tokens.py b/lib/spack/external/yaml/lib3/yaml/tokens.py
deleted file mode 100644
index 4d0b48a394..0000000000
--- a/lib/spack/external/yaml/lib3/yaml/tokens.py
+++ /dev/null
@@ -1,104 +0,0 @@
-
-class Token(object):
- def __init__(self, start_mark, end_mark):
- self.start_mark = start_mark
- self.end_mark = end_mark
- def __repr__(self):
- attributes = [key for key in self.__dict__
- if not key.endswith('_mark')]
- attributes.sort()
- arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
- for key in attributes])
- return '%s(%s)' % (self.__class__.__name__, arguments)
-
-#class BOMToken(Token):
-# id = '<byte order mark>'
-
-class DirectiveToken(Token):
- id = '<directive>'
- def __init__(self, name, value, start_mark, end_mark):
- self.name = name
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class DocumentStartToken(Token):
- id = '<document start>'
-
-class DocumentEndToken(Token):
- id = '<document end>'
-
-class StreamStartToken(Token):
- id = '<stream start>'
- def __init__(self, start_mark=None, end_mark=None,
- encoding=None):
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.encoding = encoding
-
-class StreamEndToken(Token):
- id = '<stream end>'
-
-class BlockSequenceStartToken(Token):
- id = '<block sequence start>'
-
-class BlockMappingStartToken(Token):
- id = '<block mapping start>'
-
-class BlockEndToken(Token):
- id = '<block end>'
-
-class FlowSequenceStartToken(Token):
- id = '['
-
-class FlowMappingStartToken(Token):
- id = '{'
-
-class FlowSequenceEndToken(Token):
- id = ']'
-
-class FlowMappingEndToken(Token):
- id = '}'
-
-class KeyToken(Token):
- id = '?'
-
-class ValueToken(Token):
- id = ':'
-
-class BlockEntryToken(Token):
- id = '-'
-
-class FlowEntryToken(Token):
- id = ','
-
-class AliasToken(Token):
- id = '<alias>'
- def __init__(self, value, start_mark, end_mark):
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class AnchorToken(Token):
- id = '<anchor>'
- def __init__(self, value, start_mark, end_mark):
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class TagToken(Token):
- id = '<tag>'
- def __init__(self, value, start_mark, end_mark):
- self.value = value
- self.start_mark = start_mark
- self.end_mark = end_mark
-
-class ScalarToken(Token):
- id = '<scalar>'
- def __init__(self, value, plain, start_mark, end_mark, style=None):
- self.value = value
- self.plain = plain
- self.start_mark = start_mark
- self.end_mark = end_mark
- self.style = style
-
diff --git a/lib/spack/llnl/__init__.py b/lib/spack/llnl/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/llnl/__init__.py
+++ b/lib/spack/llnl/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/llnl/util/__init__.py b/lib/spack/llnl/util/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/llnl/util/__init__.py
+++ b/lib/spack/llnl/util/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/llnl/util/argparsewriter.py b/lib/spack/llnl/util/argparsewriter.py
new file mode 100644
index 0000000000..7ae89b81a8
--- /dev/null
+++ b/lib/spack/llnl/util/argparsewriter.py
@@ -0,0 +1,203 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from __future__ import print_function
+import re
+import argparse
+import errno
+import sys
+
+
+class ArgparseWriter(object):
+ """Analyzes an argparse ArgumentParser for easy generation of help."""
+ def __init__(self):
+ self.level = 0
+
+ def _write(self, parser, root=True, level=0):
+ self.parser = parser
+ self.level = level
+ actions = parser._actions
+
+ # allow root level to be flattened with rest of commands
+ if type(root) == int:
+ self.level = root
+ root = True
+
+ # go through actions and split them into optionals, positionals,
+ # and subcommands
+ optionals = []
+ positionals = []
+ subcommands = []
+ for action in actions:
+ if action.option_strings:
+ optionals.append(action)
+ elif isinstance(action, argparse._SubParsersAction):
+ for subaction in action._choices_actions:
+ subparser = action._name_parser_map[subaction.dest]
+ subcommands.append(subparser)
+ else:
+ positionals.append(action)
+
+ groups = parser._mutually_exclusive_groups
+ fmt = parser._get_formatter()
+ description = parser.description
+
+ def action_group(function, actions):
+ for action in actions:
+ arg = fmt._format_action_invocation(action)
+ help = action.help if action.help else ''
+ function(arg, re.sub('\n', ' ', help))
+
+ if root:
+ self.begin_command(parser.prog)
+
+ if description:
+ self.description(parser.description)
+
+ usage = fmt._format_usage(None, actions, groups, '').strip()
+ self.usage(usage)
+
+ if positionals:
+ self.begin_positionals()
+ action_group(self.positional, positionals)
+ self.end_positionals()
+
+ if optionals:
+ self.begin_optionals()
+ action_group(self.optional, optionals)
+ self.end_optionals()
+
+ if subcommands:
+ self.begin_subcommands(subcommands)
+ for subparser in subcommands:
+ self._write(subparser, root=True, level=level + 1)
+ self.end_subcommands(subcommands)
+
+ if root:
+ self.end_command(parser.prog)
+
+ def write(self, parser, root=True):
+ """Write out details about an ArgumentParser.
+
+ Args:
+ parser (ArgumentParser): an ``argparse`` parser
+ root (bool or int): if bool, whether to include the root parser;
+ or ``1`` to flatten the root parser with first-level
+ subcommands
+ """
+ try:
+ self._write(parser, root, level=0)
+ except IOError as e:
+ # swallow pipe errors
+ if e.errno != errno.EPIPE:
+ raise
+
+ def begin_command(self, prog):
+ pass
+
+ def end_command(self, prog):
+ pass
+
+ def description(self, description):
+ pass
+
+ def usage(self, usage):
+ pass
+
+ def begin_positionals(self):
+ pass
+
+ def positional(self, name, help):
+ pass
+
+ def end_positionals(self):
+ pass
+
+ def begin_optionals(self):
+ pass
+
+ def optional(self, option, help):
+ pass
+
+ def end_optionals(self):
+ pass
+
+ def begin_subcommands(self, subcommands):
+ pass
+
+ def end_subcommands(self, subcommands):
+ pass
+
+
+_rst_levels = ['=', '-', '^', '~', ':', '`']
+
+
+class ArgparseRstWriter(ArgparseWriter):
+ """Write argparse output as rst sections."""
+
+ def __init__(self, out=sys.stdout, rst_levels=_rst_levels,
+ strip_root_prog=True):
+ """Create a new ArgparseRstWriter.
+
+ Args:
+ out (file object): file to write to
+ rst_levels (list of str): list of characters
+ for rst section headings
+ strip_root_prog (bool): if ``True``, strip the base command name
+ from subcommands in output
+ """
+ super(ArgparseWriter, self).__init__()
+ self.out = out
+ self.rst_levels = rst_levels
+ self.strip_root_prog = strip_root_prog
+
+ def line(self, string=''):
+ self.out.write('%s\n' % string)
+
+ def begin_command(self, prog):
+ self.line()
+ self.line('----')
+ self.line()
+ self.line('.. _%s:\n' % prog.replace(' ', '-'))
+ self.line('%s' % prog)
+ self.line(self.rst_levels[self.level] * len(prog) + '\n')
+
+ def description(self, description):
+ self.line('%s\n' % description)
+
+ def usage(self, usage):
+ self.line('.. code-block:: console\n')
+ self.line(' %s\n' % usage)
+
+ def begin_positionals(self):
+ self.line()
+ self.line('**Positional arguments**\n')
+
+ def positional(self, name, help):
+ self.line(name)
+ self.line(' %s\n' % help)
+
+ def begin_optionals(self):
+ self.line()
+ self.line('**Optional arguments**\n')
+
+ def optional(self, opts, help):
+ self.line('``%s``' % opts)
+ self.line(' %s\n' % help)
+
+ def begin_subcommands(self, subcommands):
+ self.line()
+ self.line('**Subcommands**\n')
+ self.line('.. hlist::')
+ self.line(' :columns: 4\n')
+
+ for cmd in subcommands:
+ prog = cmd.prog
+ if self.strip_root_prog:
+ prog = re.sub(r'^[^ ]* ', '', prog)
+
+ self.line(' * :ref:`%s <%s>`'
+ % (prog, cmd.prog.replace(' ', '-')))
+ self.line()
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index 36be87580c..bb74eea9e7 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -1,39 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import collections
import errno
import hashlib
import fileinput
-import fnmatch
import glob
+import grp
import numbers
import os
+import pwd
import re
import shutil
import stat
-import subprocess
import sys
import tempfile
from contextlib import contextmanager
@@ -41,6 +22,7 @@ from contextlib import contextmanager
import six
from llnl.util import tty
from llnl.util.lang import dedupe
+from spack.util.executable import Executable
__all__ = [
'FileFilter',
@@ -59,8 +41,9 @@ __all__ = [
'fix_darwin_install_name',
'force_remove',
'force_symlink',
- 'hide_files',
+ 'copy',
'install',
+ 'copy_tree',
'install_tree',
'is_exe',
'join_path',
@@ -78,6 +61,18 @@ __all__ = [
]
+def path_contains_subdirectory(path, root):
+ norm_root = os.path.abspath(root).rstrip(os.path.sep) + os.path.sep
+ norm_path = os.path.abspath(path).rstrip(os.path.sep) + os.path.sep
+ return norm_path.startswith(norm_root)
+
+
+def same_path(path1, path2):
+ norm1 = os.path.abspath(path1).rstrip(os.path.sep)
+ norm2 = os.path.abspath(path2).rstrip(os.path.sep)
+ return norm1 == norm2
+
+
def filter_file(regex, repl, *filenames, **kwargs):
r"""Like sed, but uses python regular expressions.
@@ -119,9 +114,15 @@ def filter_file(regex, repl, *filenames, **kwargs):
regex = re.escape(regex)
for filename in filenames:
+
+ msg = 'FILTER FILE: {0} [replacing "{1}"]'
+ tty.debug(msg.format(filename, regex))
+
backup_filename = filename + "~"
if ignore_absent and not os.path.exists(filename):
+ msg = 'FILTER FILE: file "{0}" not found. Skipping to next file.'
+ tty.debug(msg.format(filename))
continue
# Create backup file. Don't overwrite an existing backup
@@ -196,9 +197,9 @@ def change_sed_delimiter(old_delim, new_delim, *filenames):
def set_install_permissions(path):
"""Set appropriate permissions on the installed file."""
-# If this points to a file maintained in a Spack prefix, it is assumed that
-# this function will be invoked on the target. If the file is outside a
-# Spack-maintained prefix, the permissions should not be modified.
+ # If this points to a file maintained in a Spack prefix, it is assumed that
+ # this function will be invoked on the target. If the file is outside a
+ # Spack-maintained prefix, the permissions should not be modified.
if os.path.islink(path):
return
if os.path.isdir(path):
@@ -207,6 +208,40 @@ def set_install_permissions(path):
os.chmod(path, 0o644)
+def group_ids(uid=None):
+ """Get group ids that a uid is a member of.
+
+ Arguments:
+ uid (int): id of user, or None for current user
+
+ Returns:
+ (list of int): gids of groups the user is a member of
+ """
+ if uid is None:
+ uid = os.getuid()
+ user = pwd.getpwuid(uid).pw_name
+ return [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
+
+
+def chgrp(path, group):
+ """Implement the bash chgrp function on a single path"""
+ gid = grp.getgrnam(group).gr_gid
+ os.chown(path, -1, gid)
+
+
+def chmod_x(entry, perms):
+ """Implements chmod, treating all executable bits as set using the chmod
+ utility's `+X` option.
+ """
+ mode = os.stat(entry).st_mode
+ if os.path.isfile(entry):
+ if not mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
+ perms &= ~stat.S_IXUSR
+ perms &= ~stat.S_IXGRP
+ perms &= ~stat.S_IXOTH
+ os.chmod(entry, perms)
+
+
def copy_mode(src, dest):
"""Set the mode of dest to that of src unless it is a link.
"""
@@ -231,27 +266,135 @@ def unset_executable_mode(path):
os.chmod(path, mode)
-def install(src, dest):
- """Manually install a file to a particular location."""
- tty.debug("Installing %s to %s" % (src, dest))
+def copy(src, dest, _permissions=False):
+ """Copies the file *src* to the file or directory *dest*.
+
+ If *dest* specifies a directory, the file will be copied into *dest*
+ using the base filename from *src*.
+
+ Parameters:
+ src (str): the file to copy
+ dest (str): the destination file or directory
+ _permissions (bool): for internal use only
+ """
+ if _permissions:
+ tty.debug('Installing {0} to {1}'.format(src, dest))
+ else:
+ tty.debug('Copying {0} to {1}'.format(src, dest))
# Expand dest to its eventual full path if it is a directory.
if os.path.isdir(dest):
dest = join_path(dest, os.path.basename(src))
shutil.copy(src, dest)
- set_install_permissions(dest)
- copy_mode(src, dest)
+ if _permissions:
+ set_install_permissions(dest)
+ copy_mode(src, dest)
+
+
+def install(src, dest):
+ """Installs the file *src* to the file or directory *dest*.
+
+ Same as :py:func:`copy` with the addition of setting proper
+ permissions on the installed file.
+
+ Parameters:
+ src (str): the file to install
+ dest (str): the destination file or directory
+ """
+ copy(src, dest, _permissions=True)
+
+
+def resolve_link_target_relative_to_the_link(l):
+ """
+ os.path.isdir uses os.path.exists, which for links will check
+ the existence of the link target. If the link target is relative to
+ the link, we need to construct a pathname that is valid from
+ our cwd (which may not be the same as the link's directory)
+ """
+ target = os.readlink(l)
+ if os.path.isabs(target):
+ return target
+ link_dir = os.path.dirname(os.path.abspath(l))
+ return os.path.join(link_dir, target)
+
+
+def copy_tree(src, dest, symlinks=True, ignore=None, _permissions=False):
+ """Recursively copy an entire directory tree rooted at *src*.
-def install_tree(src, dest, **kwargs):
- """Manually install a directory tree to a particular location."""
- tty.debug("Installing %s to %s" % (src, dest))
- shutil.copytree(src, dest, **kwargs)
+ If the destination directory *dest* does not already exist, it will
+ be created as well as missing parent directories.
- for s, d in traverse_tree(src, dest, follow_nonexisting=False):
- set_install_permissions(d)
- copy_mode(s, d)
+ If *symlinks* is true, symbolic links in the source tree are represented
+ as symbolic links in the new tree and the metadata of the original links
+ will be copied as far as the platform allows; if false, the contents and
+ metadata of the linked files are copied to the new tree.
+
+ If *ignore* is set, then each path relative to *src* will be passed to
+ this function; the function returns whether that path should be skipped.
+
+ Parameters:
+ src (str): the directory to copy
+ dest (str): the destination directory
+ symlinks (bool): whether or not to preserve symlinks
+ ignore (function): function indicating which files to ignore
+ _permissions (bool): for internal use only
+ """
+ if _permissions:
+ tty.debug('Installing {0} to {1}'.format(src, dest))
+ else:
+ tty.debug('Copying {0} to {1}'.format(src, dest))
+
+ mkdirp(dest)
+
+ src = os.path.abspath(src)
+ dest = os.path.abspath(dest)
+
+ for s, d in traverse_tree(src, dest, order='pre',
+ follow_symlinks=not symlinks,
+ ignore=ignore,
+ follow_nonexisting=True):
+ if os.path.islink(s):
+ link_target = resolve_link_target_relative_to_the_link(s)
+ if symlinks:
+ target = os.readlink(s)
+ if os.path.isabs(target):
+ new_target = re.sub(src, dest, target)
+ if new_target != target:
+ tty.debug("Redirecting link {0} to {1}"
+ .format(target, new_target))
+ target = new_target
+
+ os.symlink(target, d)
+ elif os.path.isdir(link_target):
+ mkdirp(d)
+ else:
+ shutil.copyfile(s, d)
+ else:
+ if os.path.isdir(s):
+ mkdirp(d)
+ else:
+ shutil.copyfile(s, d)
+
+ if _permissions:
+ set_install_permissions(d)
+ copy_mode(s, d)
+
+
+def install_tree(src, dest, symlinks=True, ignore=None):
+ """Recursively install an entire directory tree rooted at *src*.
+
+ Same as :py:func:`copy_tree` with the addition of setting proper
+ permissions on the installed files and directories.
+
+ Parameters:
+ src (str): the directory to install
+ dest (str): the destination directory
+ symlinks (bool): whether or not to preserve symlinks
+ ignore (function): function indicating which files to ignore
+ """
+ copy_tree(src, dest, symlinks=symlinks, ignore=ignore, _permissions=True)
def is_exe(path):
@@ -259,12 +402,34 @@ def is_exe(path):
return os.path.isfile(path) and os.access(path, os.X_OK)
-def mkdirp(*paths):
- """Creates a directory, as well as parent directories if needed."""
+def get_filetype(path_name):
+ """
+ Return the output of file path_name as a string to identify file type.
+ """
+ file = Executable('file')
+ file.add_default_env('LC_ALL', 'C')
+ output = file('-b', '-h', '%s' % path_name,
+ output=str, error=str)
+ return output.strip()
+
+
+def mkdirp(*paths, **kwargs):
+ """Creates a directory, as well as parent directories if needed.
+
+ Arguments:
+ paths (str): paths to create with mkdirp
+
+ Keyword Aguments:
+ mode (permission bits or None, optional): optional permissions to
+ set on the created directory -- use OS default if not provided
+ """
+ mode = kwargs.get('mode', None)
for path in paths:
if not os.path.exists(path):
try:
os.makedirs(path)
+ if mode is not None:
+ os.chmod(path, mode)
except OSError as e:
if e.errno != errno.EEXIST or not os.path.isdir(path):
raise e
@@ -347,18 +512,6 @@ def replace_directory_transaction(directory_name, tmp_root=None):
tty.debug('TEMPORARY DIRECTORY DELETED [{0}]'.format(tmp_dir))
-@contextmanager
-def hide_files(*file_list):
- try:
- baks = ['%s.bak' % f for f in file_list]
- for f, bak in zip(file_list, baks):
- shutil.move(f, bak)
- yield
- finally:
- for f, bak in zip(file_list, baks):
- shutil.move(bak, f)
-
-
def hash_directory(directory):
"""Hashes recursively the content of a directory.
@@ -385,6 +538,30 @@ def hash_directory(directory):
return md5_hash.hexdigest()
+@contextmanager
+def write_tmp_and_move(filename):
+ """Write to a temporary file, then move into place."""
+ dirname = os.path.dirname(filename)
+ basename = os.path.basename(filename)
+ tmp = os.path.join(dirname, '.%s.tmp' % basename)
+ with open(tmp, 'w') as f:
+ yield f
+ shutil.move(tmp, filename)
+
+
+@contextmanager
+def open_if_filename(str_or_file, mode='r'):
+ """Takes either a path or a file object, and opens it if it is a path.
+
+ If it's a file object, just yields the file object.
+ """
+ if isinstance(str_or_file, six.string_types):
+ with open(str_or_file, mode) as f:
+ yield f
+ else:
+ yield str_or_file
+
+
def touch(path):
"""Creates an empty file at the specified path."""
perms = (os.O_WRONLY | os.O_CREAT | os.O_NONBLOCK | os.O_NOCTTY)
@@ -459,7 +636,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
Keyword Arguments:
order (str): Whether to do pre- or post-order traversal. Accepted
values are 'pre' and 'post'
- ignore (str): Predicate indicating which files to ignore
+ ignore (function): function indicating which files to ignore
follow_nonexisting (bool): Whether to descend into directories in
``src`` that do not exit in ``dest``. Default is True
follow_links (bool): Whether to descend into symlinks in ``src``
@@ -473,7 +650,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
raise ValueError("Order must be 'pre' or 'post'.")
# List of relative paths to ignore under the src root.
- ignore = kwargs.get('ignore', lambda filename: False)
+ ignore = kwargs.get('ignore', None) or (lambda filename: False)
# Don't descend into ignored directories
if ignore(rel_path):
@@ -492,6 +669,9 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
rel_child = os.path.join(rel_path, f)
# Treat as a directory
+ # TODO: for symlinks, os.path.isdir looks for the link target. If the
+ # target is relative to the link, then that may not resolve properly
+ # relative to our cwd - see resolve_link_target_relative_to_the_link
if os.path.isdir(source_child) and (
follow_links or not os.path.islink(source_child)):
@@ -578,12 +758,10 @@ def fix_darwin_install_name(path):
libs = glob.glob(join_path(path, "*.dylib"))
for lib in libs:
# fix install name first:
- subprocess.Popen(
- ["install_name_tool", "-id", lib, lib],
- stdout=subprocess.PIPE).communicate()[0]
- long_deps = subprocess.Popen(
- ["otool", "-L", lib],
- stdout=subprocess.PIPE).communicate()[0].split('\n')
+ install_name_tool = Executable('install_name_tool')
+ install_name_tool('-id', lib, lib)
+ otool = Executable('otool')
+ long_deps = otool('-L', lib, output=str).split('\n')
deps = [dep.partition(' ')[0][1::] for dep in long_deps[2:-1]]
# fix all dependencies:
for dep in deps:
@@ -594,13 +772,11 @@ def fix_darwin_install_name(path):
# but we don't know builddir (nor how symbolic links look
# in builddir). We thus only compare the basenames.
if os.path.basename(dep) == os.path.basename(loc):
- subprocess.Popen(
- ["install_name_tool", "-change", dep, loc, lib],
- stdout=subprocess.PIPE).communicate()[0]
+ install_name_tool('-change', dep, loc, lib)
break
-def find(root, files, recurse=True):
+def find(root, files, recursive=True):
"""Search for ``files`` starting from the ``root`` directory.
Like GNU/BSD find but written entirely in Python.
@@ -621,7 +797,7 @@ def find(root, files, recurse=True):
is equivalent to:
- >>> find('/usr/local/bin', 'python', recurse=False)
+ >>> find('/usr/local/bin', 'python', recursive=False)
Accepts any glob characters accepted by fnmatch:
@@ -646,7 +822,7 @@ def find(root, files, recurse=True):
if isinstance(files, six.string_types):
files = [files]
- if recurse:
+ if recursive:
return _find_recursive(root, files)
else:
return _find_non_recursive(root, files)
@@ -660,11 +836,14 @@ def _find_recursive(root, search_files):
# found in a key, and reconstructing the stable order later.
found_files = collections.defaultdict(list)
+ # Make the path absolute to have os.walk also return an absolute path
+ root = os.path.abspath(root)
+
for path, _, list_files in os.walk(root):
for search_file in search_files:
- for list_file in list_files:
- if fnmatch.fnmatch(list_file, search_file):
- found_files[search_file].append(join_path(path, list_file))
+ matches = glob.glob(os.path.join(path, search_file))
+ matches = [os.path.join(path, x) for x in matches]
+ found_files[search_file].extend(matches)
answer = []
for search_file in search_files:
@@ -678,10 +857,13 @@ def _find_non_recursive(root, search_files):
# can return files in any order (does not preserve stability)
found_files = collections.defaultdict(list)
- for list_file in os.listdir(root):
- for search_file in search_files:
- if fnmatch.fnmatch(list_file, search_file):
- found_files[search_file].append(join_path(root, list_file))
+ # Make the path absolute to have absolute path returned
+ root = os.path.abspath(root)
+
+ for search_file in search_files:
+ matches = glob.glob(os.path.join(root, search_file))
+ matches = [os.path.join(root, x) for x in matches]
+ found_files[search_file].extend(matches)
answer = []
for search_file in search_files:
@@ -872,7 +1054,7 @@ class HeaderList(FileList):
self._macro_definitions.append(macro)
-def find_headers(headers, root, recurse=False):
+def find_headers(headers, root, recursive=False):
"""Returns an iterable object containing a list of full paths to
headers if found.
@@ -890,7 +1072,7 @@ def find_headers(headers, root, recurse=False):
Parameters:
headers (str or list of str): Header name(s) to search for
root (str): The root directory to start searching from
- recurses (bool, optional): if False search only root folder,
+ recursive (bool, optional): if False search only root folder,
if True descends top-down from the root. Defaults to False.
Returns:
@@ -910,7 +1092,7 @@ def find_headers(headers, root, recurse=False):
# List of headers we are searching with suffixes
headers = ['{0}.{1}'.format(header, suffix) for header in headers]
- return HeaderList(find(root, headers, recurse))
+ return HeaderList(find(root, headers, recursive))
class LibraryList(FileList):
@@ -1051,7 +1233,7 @@ def find_system_libraries(libraries, shared=True):
for library in libraries:
for root in search_locations:
- result = find_libraries(library, root, shared, recurse=True)
+ result = find_libraries(library, root, shared, recursive=True)
if result:
libraries_found += result
break
@@ -1059,7 +1241,7 @@ def find_system_libraries(libraries, shared=True):
return libraries_found
-def find_libraries(libraries, root, shared=True, recurse=False):
+def find_libraries(libraries, root, shared=True, recursive=False):
"""Returns an iterable of full paths to libraries found in a root dir.
Accepts any glob characters accepted by fnmatch:
@@ -1078,7 +1260,7 @@ def find_libraries(libraries, root, shared=True, recurse=False):
root (str): The root directory to start searching from
shared (bool, optional): if True searches for shared libraries,
otherwise for static. Defaults to True.
- recurse (bool, optional): if False search only root folder,
+ recursive (bool, optional): if False search only root folder,
if True descends top-down from the root. Defaults to False.
Returns:
@@ -1100,4 +1282,4 @@ def find_libraries(libraries, root, shared=True, recurse=False):
# List of libraries we are searching with suffixes
libraries = ['{0}.{1}'.format(lib, suffix) for lib in libraries]
- return LibraryList(find(root, libraries, recurse))
+ return LibraryList(find(root, libraries, recursive))
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 7189b6c0f3..0a86896f5b 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import division
import os
@@ -29,7 +10,7 @@ import re
import functools
import collections
import inspect
-from datetime import datetime
+from datetime import datetime, timedelta
from six import string_types
# Ignore emacs backups when listing modules
@@ -165,6 +146,26 @@ def has_method(cls, name):
return False
+def union_dicts(*dicts):
+ """Use update() to combine all dicts into one.
+
+ This builds a new dictionary, into which we ``update()`` each element
+ of ``dicts`` in order. Items from later dictionaries will override
+ items from earlier dictionaries.
+
+ Args:
+ dicts (list): list of dictionaries
+
+ Return: (dict): a merged dictionary containing combined keys and
+ values from ``dicts``.
+
+ """
+ result = {}
+ for d in dicts:
+ result.update(d)
+ return result
+
+
class memoized(object):
"""Decorator that caches the results of a function, storing them
in an attribute of that function."""
@@ -282,8 +283,8 @@ class HashableMap(collections.MutableMapping):
def copy(self):
"""Type-agnostic clone method. Preserves subclass type."""
# Construct a new dict of my type
- T = type(self)
- clone = T()
+ self_type = type(self)
+ clone = self_type()
# Copy everything from this dict into it.
for key in self:
@@ -442,6 +443,65 @@ def pretty_date(time, now=None):
return str(diff) + " years ago"
+def pretty_string_to_date(date_str, now=None):
+ """Parses a string representing a date and returns a datetime object.
+
+ Args:
+ date_str (str): string representing a date. This string might be
+ in different format (like ``YYYY``, ``YYYY-MM``, ``YYYY-MM-DD``)
+ or be a *pretty date* (like ``yesterday`` or ``two months ago``)
+
+ Returns:
+ (datetime): datetime object corresponding to ``date_str``
+ """
+
+ pattern = {}
+
+ now = now or datetime.now()
+
+ # datetime formats
+ pattern[re.compile(r'^\d{4}$')] = lambda x: datetime.strptime(x, '%Y')
+ pattern[re.compile(r'^\d{4}-\d{2}$')] = lambda x: datetime.strptime(
+ x, '%Y-%m'
+ )
+ pattern[re.compile(r'^\d{4}-\d{2}-\d{2}$')] = lambda x: datetime.strptime(
+ x, '%Y-%m-%d'
+ )
+
+ pretty_regex = re.compile(
+ r'(a|\d+)\s*(year|month|week|day|hour|minute|second)s?\s*ago')
+
+ def _n_xxx_ago(x):
+ how_many, time_period = pretty_regex.search(x).groups()
+
+ how_many = 1 if how_many == 'a' else int(how_many)
+
+ # timedelta natively supports time periods up to 'weeks'.
+ # To apply month or year we convert to 30 and 365 days
+ if time_period == 'month':
+ how_many *= 30
+ time_period = 'day'
+ elif time_period == 'year':
+ how_many *= 365
+ time_period = 'day'
+
+ kwargs = {(time_period + 's'): how_many}
+ return now - timedelta(**kwargs)
+
+ pattern[pretty_regex] = _n_xxx_ago
+
+ # yesterday
+ callback = lambda x: now - timedelta(days=1)
+ pattern[re.compile('^yesterday$')] = callback
+
+ for regexp, parser in pattern.items():
+ if bool(regexp.match(date_str)):
+ return parser(date_str)
+
+ msg = 'date "{0}" does not match any valid format'.format(date_str)
+ raise ValueError(msg)
+
+
class RequiredAttributeError(ValueError):
def __init__(self, message):
@@ -458,5 +518,74 @@ class ObjectWrapper(object):
def __init__(self, wrapped_object):
wrapped_cls = type(wrapped_object)
wrapped_name = wrapped_cls.__name__
- self.__class__ = type(wrapped_name, (type(self), wrapped_cls), {})
+
+ # If the wrapped object is already an ObjectWrapper, or a derived class
+ # of it, adding type(self) in front of type(wrapped_object)
+ # results in an inconsistent MRO.
+ #
+ # TODO: the implementation below doesn't account for the case where we
+ # TODO: have different base classes of ObjectWrapper, say A and B, and
+ # TODO: we want to wrap an instance of A with B.
+ if type(self) not in wrapped_cls.__mro__:
+ self.__class__ = type(wrapped_name, (type(self), wrapped_cls), {})
+ else:
+ self.__class__ = type(wrapped_name, (wrapped_cls,), {})
+
self.__dict__ = wrapped_object.__dict__
+
+
+class Singleton(object):
+ """Simple wrapper for lazily initialized singleton objects."""
+
+ def __init__(self, factory):
+ """Create a new singleton to be inited with the factory function.
+
+ Args:
+ factory (function): function taking no arguments that
+ creates the singleton instance.
+ """
+ self.factory = factory
+ self._instance = None
+
+ @property
+ def instance(self):
+ if self._instance is None:
+ self._instance = self.factory()
+ return self._instance
+
+ def __getattr__(self, name):
+ return getattr(self.instance, name)
+
+ def __getitem__(self, name):
+ return self.instance[name]
+
+ def __contains__(self, element):
+ return element in self.instance
+
+ def __iter__(self):
+ return iter(self.instance)
+
+ def __str__(self):
+ return str(self.instance)
+
+ def __repr__(self):
+ return repr(self.instance)
+
+
+class LazyReference(object):
+ """Lazily evaluated reference to part of a singleton."""
+
+ def __init__(self, ref_function):
+ self.ref_function = ref_function
+
+ def __getattr__(self, name):
+ return getattr(self.ref_function(), name)
+
+ def __getitem__(self, name):
+ return self.ref_function()[name]
+
+ def __str__(self):
+ return str(self.ref_function())
+
+ def __repr__(self):
+ return repr(self.ref_function())
diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py
index 60ab5cb2b0..e675523015 100644
--- a/lib/spack/llnl/util/link_tree.py
+++ b/lib/spack/llnl/util/link_tree.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""LinkTree class for setting up trees of symbolic links."""
import os
@@ -29,6 +10,7 @@ import shutil
import filecmp
from llnl.util.filesystem import traverse_tree, mkdirp, touch
+import llnl.util.tty as tty
__all__ = ['LinkTree']
@@ -44,37 +26,49 @@ class LinkTree(object):
Trees comprise symlinks only to files; directries are never
symlinked to, to prevent the source directory from ever being
modified.
-
"""
-
def __init__(self, source_root):
if not os.path.exists(source_root):
raise IOError("No such file or directory: '%s'", source_root)
self._root = source_root
- def find_conflict(self, dest_root, **kwargs):
+ def find_conflict(self, dest_root, ignore=None,
+ ignore_file_conflicts=False):
"""Returns the first file in dest that conflicts with src"""
- kwargs['follow_nonexisting'] = False
+ ignore = ignore or (lambda x: False)
+ conflicts = self.find_dir_conflicts(dest_root, ignore)
+
+ if not ignore_file_conflicts:
+ conflicts.extend(
+ dst for src, dst
+ in self.get_file_map(dest_root, ignore).items()
+ if os.path.exists(dst))
+
+ if conflicts:
+ return conflicts[0]
+
+ def find_dir_conflicts(self, dest_root, ignore):
+ conflicts = []
+ kwargs = {'follow_nonexisting': False, 'ignore': ignore}
for src, dest in traverse_tree(self._root, dest_root, **kwargs):
if os.path.isdir(src):
if os.path.exists(dest) and not os.path.isdir(dest):
- return dest
- elif os.path.exists(dest):
- return dest
- return None
-
- def merge(self, dest_root, link=os.symlink, **kwargs):
- """Link all files in src into dest, creating directories
- if necessary.
- If ignore_conflicts is True, do not break when the target exists but
- rather return a list of files that could not be linked.
- Note that files blocking directories will still cause an error.
- """
- kwargs['order'] = 'pre'
- ignore_conflicts = kwargs.get("ignore_conflicts", False)
- existing = []
+ conflicts.append("File blocks directory: %s" % dest)
+ elif os.path.exists(dest) and os.path.isdir(dest):
+ conflicts.append("Directory blocks directory: %s" % dest)
+ return conflicts
+
+ def get_file_map(self, dest_root, ignore):
+ merge_map = {}
+ kwargs = {'follow_nonexisting': True, 'ignore': ignore}
for src, dest in traverse_tree(self._root, dest_root, **kwargs):
+ if not os.path.isdir(src):
+ merge_map[src] = dest
+ return merge_map
+
+ def merge_directories(self, dest_root, ignore):
+ for src, dest in traverse_tree(self._root, dest_root, ignore=ignore):
if os.path.isdir(src):
if not os.path.exists(dest):
mkdirp(dest)
@@ -88,31 +82,13 @@ class LinkTree(object):
marker = os.path.join(dest, empty_file_name)
touch(marker)
- else:
- if os.path.exists(dest):
- if ignore_conflicts:
- existing.append(src)
- else:
- raise AssertionError("File already exists: %s" % dest)
- else:
- link(src, dest)
- if ignore_conflicts:
- return existing
-
- def unmerge(self, dest_root, **kwargs):
- """Unlink all files in dest that exist in src.
-
- Unlinks directories in dest if they are empty.
-
- """
- kwargs['order'] = 'post'
- for src, dest in traverse_tree(self._root, dest_root, **kwargs):
+ def unmerge_directories(self, dest_root, ignore):
+ for src, dest in traverse_tree(
+ self._root, dest_root, ignore=ignore, order='post'):
if os.path.isdir(src):
- # Skip non-existing links.
if not os.path.exists(dest):
continue
-
- if not os.path.isdir(dest):
+ elif not os.path.isdir(dest):
raise ValueError("File blocks directory: %s" % dest)
# remove directory if it is empty.
@@ -124,11 +100,61 @@ class LinkTree(object):
if os.path.exists(marker):
os.remove(marker)
- elif os.path.exists(dest):
- if not os.path.islink(dest):
- raise ValueError("%s is not a link tree!" % dest)
- # remove if dest is a hardlink/symlink to src; this will only
- # be false if two packages are merged into a prefix and have a
- # conflicting file
- if filecmp.cmp(src, dest, shallow=True):
- os.remove(dest)
+ def merge(self, dest_root, **kwargs):
+ """Link all files in src into dest, creating directories
+ if necessary.
+ If ignore_conflicts is True, do not break when the target exists but
+ rather return a list of files that could not be linked.
+ Note that files blocking directories will still cause an error.
+ """
+ ignore_conflicts = kwargs.get("ignore_conflicts", False)
+
+ ignore = kwargs.get('ignore', lambda x: False)
+ conflict = self.find_conflict(
+ dest_root, ignore=ignore, ignore_file_conflicts=ignore_conflicts)
+ if conflict:
+ raise MergeConflictError(conflict)
+
+ self.merge_directories(dest_root, ignore)
+ existing = []
+ merge_file = kwargs.get('merge_file', merge_link)
+ for src, dst in self.get_file_map(dest_root, ignore).items():
+ if os.path.exists(dst):
+ existing.append(dst)
+ else:
+ merge_file(src, dst)
+
+ for c in existing:
+ tty.warn("Could not merge: %s" % c)
+
+ def unmerge(self, dest_root, **kwargs):
+ """Unlink all files in dest that exist in src.
+
+ Unlinks directories in dest if they are empty.
+ """
+ remove_file = kwargs.get('remove_file', remove_link)
+ ignore = kwargs.get('ignore', lambda x: False)
+ for src, dst in self.get_file_map(dest_root, ignore).items():
+ remove_file(src, dst)
+ self.unmerge_directories(dest_root, ignore)
+
+
+def merge_link(src, dest):
+ os.symlink(src, dest)
+
+
+def remove_link(src, dest):
+ if not os.path.islink(dest):
+ raise ValueError("%s is not a link tree!" % dest)
+ # remove if dest is a hardlink/symlink to src; this will only
+ # be false if two packages are merged into a prefix and have a
+ # conflicting file
+ if filecmp.cmp(src, dest, shallow=True):
+ os.remove(dest)
+
+
+class MergeConflictError(Exception):
+
+ def __init__(self, path):
+ super(MergeConflictError, self).__init__(
+ "Package merge blocked by file: %s" % path)
diff --git a/lib/spack/llnl/util/lock.py b/lib/spack/llnl/util/lock.py
index 5467838744..3beb219bd9 100644
--- a/lib/spack/llnl/util/lock.py
+++ b/lib/spack/llnl/util/lock.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import fcntl
import errno
@@ -32,14 +13,8 @@ import llnl.util.tty as tty
__all__ = ['Lock', 'LockTransaction', 'WriteTransaction', 'ReadTransaction',
- 'LockError']
-
-
-# Default timeout in seconds, after which locks will raise exceptions.
-_default_timeout = 60
-
-# Sleep time per iteration in spin loop (in seconds)
-_sleep_time = 1e-5
+ 'LockError', 'LockTimeoutError',
+ 'LockPermissionError', 'LockROFileError', 'CantCreateLockError']
class Lock(object):
@@ -49,9 +24,15 @@ class Lock(object):
any filesystem implementation that supports locking through the fcntl
calls. This includes distributed filesystems like Lustre (when flock
is enabled) and recent NFS versions.
+
+ Note that this is for managing contention over resources *between*
+ processes and not for managing contention between threads in a process: the
+ functions of this object are not thread-safe. A process also must not
+ maintain multiple locks on the same file.
"""
- def __init__(self, path, start=0, length=0):
+ def __init__(self, path, start=0, length=0, debug=False,
+ default_timeout=None):
"""Construct a new lock on the file at ``path``.
By default, the lock applies to the whole file. Optionally,
@@ -72,12 +53,44 @@ class Lock(object):
self._start = start
self._length = length
- # PID and host of lock holder
+ # enable debug mode
+ self.debug = debug
+
+ # If the user doesn't set a default timeout, or if they choose
+ # None, 0, etc. then lock attempts will not time out (unless the
+ # user sets a timeout for each attempt)
+ self.default_timeout = default_timeout or None
+
+ # PID and host of lock holder (only used in debug mode)
self.pid = self.old_pid = None
self.host = self.old_host = None
- def _lock(self, op, timeout=_default_timeout):
- """This takes a lock using POSIX locks (``fnctl.lockf``).
+ @staticmethod
+ def _poll_interval_generator(_wait_times=None):
+ """This implements a backoff scheme for polling a contended resource
+ by suggesting a succession of wait times between polls.
+
+ It suggests a poll interval of .1s until 2 seconds have passed,
+ then a poll interval of .2s until 10 seconds have passed, and finally
+ (for all requests after 10s) suggests a poll interval of .5s.
+
+ This doesn't actually track elapsed time, it estimates the waiting
+ time as though the caller always waits for the full length of time
+ suggested by this function.
+ """
+ num_requests = 0
+ stage1, stage2, stage3 = _wait_times or (1e-1, 2e-1, 5e-1)
+ wait_time = stage1
+ while True:
+ if num_requests >= 60: # 40 * .2 = 8
+ wait_time = stage3
+ elif num_requests >= 20: # 20 * .1 = 2
+ wait_time = stage2
+ num_requests += 1
+ yield wait_time
+
+ def _lock(self, op, timeout=None):
+ """This takes a lock using POSIX locks (``fcntl.lockf``).
The lock is implemented as a spin lock using a nonblocking call
to ``lockf()``.
@@ -86,77 +99,113 @@ class Lock(object):
pid and host to the lock file, in case the holding process needs
to be killed later.
- If the lock times out, it raises a ``LockError``.
+ If the lock times out, it raises a ``LockError``. If the lock is
+ successfully acquired, the total wait time and the number of attempts
+ is returned.
"""
- start_time = time.time()
- while (time.time() - start_time) < timeout:
- try:
- # If we could write the file, we'd have opened it 'r+'.
- # Raise an error when we attempt to upgrade to a write lock.
- if op == fcntl.LOCK_EX:
- if self._file and self._file.mode == 'r':
- raise LockError(
- "Can't take exclusive lock on read-only file: %s"
- % self.path)
-
- # Create file and parent directories if they don't exist.
- if self._file is None:
- self._ensure_parent_directory()
-
- # Prefer to open 'r+' to allow upgrading to write
- # lock later if possible. Open read-only if we can't
- # write the lock file at all.
- os_mode, fd_mode = (os.O_RDWR | os.O_CREAT), 'r+'
- if os.path.exists(self.path) and not os.access(
- self.path, os.W_OK):
+ assert op in (fcntl.LOCK_SH, fcntl.LOCK_EX)
+
+ timeout = timeout or self.default_timeout
+
+ # Create file and parent directories if they don't exist.
+ if self._file is None:
+ parent = self._ensure_parent_directory()
+
+ # Open writable files as 'r+' so we can upgrade to write later
+ os_mode, fd_mode = (os.O_RDWR | os.O_CREAT), 'r+'
+ if os.path.exists(self.path):
+ if not os.access(self.path, os.W_OK):
+ if op == fcntl.LOCK_SH:
+ # can still lock read-only files if we open 'r'
os_mode, fd_mode = os.O_RDONLY, 'r'
+ else:
+ raise LockROFileError(self.path)
+
+ elif not os.access(parent, os.W_OK):
+ raise CantCreateLockError(self.path)
+
+ fd = os.open(self.path, os_mode)
+ self._file = os.fdopen(fd, fd_mode)
- fd = os.open(self.path, os_mode)
- self._file = os.fdopen(fd, fd_mode)
+ elif op == fcntl.LOCK_EX and self._file.mode == 'r':
+ # Attempt to upgrade to write lock w/a read-only file.
+ # If the file were writable, we'd have opened it 'r+'
+ raise LockROFileError(self.path)
- # Try to get the lock (will raise if not available.)
- fcntl.lockf(self._file, op | fcntl.LOCK_NB,
- self._length, self._start, os.SEEK_SET)
+ poll_intervals = iter(Lock._poll_interval_generator())
+ start_time = time.time()
+ num_attempts = 0
+ while (not timeout) or (time.time() - start_time) < timeout:
+ num_attempts += 1
+ if self._poll_lock(op):
+ total_wait_time = time.time() - start_time
+ return total_wait_time, num_attempts
+
+ time.sleep(next(poll_intervals))
+
+ num_attempts += 1
+ if self._poll_lock(op):
+ total_wait_time = time.time() - start_time
+ return total_wait_time, num_attempts
+
+ raise LockTimeoutError("Timed out waiting for lock.")
+
+ def _poll_lock(self, op):
+ """Attempt to acquire the lock in a non-blocking manner. Return whether
+ the locking attempt succeeds
+ """
+ try:
+ # Try to get the lock (will raise if not available.)
+ fcntl.lockf(self._file, op | fcntl.LOCK_NB,
+ self._length, self._start, os.SEEK_SET)
+ # help for debugging distributed locking
+ if self.debug:
# All locks read the owner PID and host
- self._read_lock_data()
+ self._read_debug_data()
# Exclusive locks write their PID/host
if op == fcntl.LOCK_EX:
- self._write_lock_data()
+ self._write_debug_data()
- return
-
- except IOError as e:
- if e.errno in (errno.EAGAIN, errno.EACCES):
- # EAGAIN and EACCES == locked by another process
- pass
- else:
- raise
- time.sleep(_sleep_time)
+ return True
- raise LockError("Timed out waiting for lock.")
+ except IOError as e:
+ if e.errno in (errno.EAGAIN, errno.EACCES):
+ # EAGAIN and EACCES == locked by another process
+ pass
+ else:
+ raise
def _ensure_parent_directory(self):
parent = os.path.dirname(self.path)
+
+ # relative paths to lockfiles in the current directory have no parent
+ if not parent:
+ return '.'
+
try:
os.makedirs(parent)
- return True
except OSError as e:
# makedirs can fail when diretory already exists.
if not (e.errno == errno.EEXIST and os.path.isdir(parent) or
e.errno == errno.EISDIR):
raise
+ return parent
- def _read_lock_data(self):
+ def _read_debug_data(self):
"""Read PID and host data out of the file if it is there."""
+ self.old_pid = self.pid
+ self.old_host = self.host
+
line = self._file.read()
if line:
pid, host = line.strip().split(',')
_, _, self.pid = pid.rpartition('=')
_, _, self.host = host.rpartition('=')
+ self.pid = int(self.pid)
- def _write_lock_data(self):
+ def _write_debug_data(self):
"""Write PID and host data to the file, recording old values."""
self.old_pid = self.pid
self.old_host = self.host
@@ -183,7 +232,7 @@ class Lock(object):
self._file.close()
self._file = None
- def acquire_read(self, timeout=_default_timeout):
+ def acquire_read(self, timeout=None):
"""Acquires a recursive, shared lock for reading.
Read and write locks can be acquired and released in arbitrary
@@ -194,19 +243,22 @@ class Lock(object):
the POSIX lock, False if it is a nested transaction.
"""
+ timeout = timeout or self.default_timeout
+
if self._reads == 0 and self._writes == 0:
- tty.debug('READ LOCK: {0.path}[{0._start}:{0._length}] [Acquiring]'
- .format(self))
- self._lock(fcntl.LOCK_SH, timeout=timeout) # can raise LockError.
- tty.debug('READ LOCK: {0.path}[{0._start}:{0._length}] [Acquired]'
- .format(self))
+ self._debug(
+ 'READ LOCK: {0.path}[{0._start}:{0._length}] [Acquiring]'
+ .format(self))
+ # can raise LockError.
+ wait_time, nattempts = self._lock(fcntl.LOCK_SH, timeout=timeout)
+ self._acquired_debug('READ LOCK', wait_time, nattempts)
self._reads += 1
return True
else:
self._reads += 1
return False
- def acquire_write(self, timeout=_default_timeout):
+ def acquire_write(self, timeout=None):
"""Acquires a recursive, exclusive lock for writing.
Read and write locks can be acquired and released in arbitrary
@@ -217,13 +269,15 @@ class Lock(object):
the POSIX lock, False if it is a nested transaction.
"""
+ timeout = timeout or self.default_timeout
+
if self._writes == 0:
- tty.debug(
+ self._debug(
'WRITE LOCK: {0.path}[{0._start}:{0._length}] [Acquiring]'
.format(self))
- self._lock(fcntl.LOCK_EX, timeout=timeout) # can raise LockError.
- tty.debug('WRITE LOCK: {0.path}[{0._start}:{0._length}] [Acquired]'
- .format(self))
+ # can raise LockError.
+ wait_time, nattempts = self._lock(fcntl.LOCK_EX, timeout=timeout)
+ self._acquired_debug('WRITE LOCK', wait_time, nattempts)
self._writes += 1
return True
else:
@@ -243,8 +297,9 @@ class Lock(object):
assert self._reads > 0
if self._reads == 1 and self._writes == 0:
- tty.debug('READ LOCK: {0.path}[{0._start}:{0._length}] [Released]'
- .format(self))
+ self._debug(
+ 'READ LOCK: {0.path}[{0._start}:{0._length}] [Released]'
+ .format(self))
self._unlock() # can raise LockError.
self._reads -= 1
return True
@@ -265,8 +320,9 @@ class Lock(object):
assert self._writes > 0
if self._writes == 1 and self._reads == 0:
- tty.debug('WRITE LOCK: {0.path}[{0._start}:{0._length}] [Released]'
- .format(self))
+ self._debug(
+ 'WRITE LOCK: {0.path}[{0._start}:{0._length}] [Released]'
+ .format(self))
self._unlock() # can raise LockError.
self._writes -= 1
return True
@@ -274,6 +330,21 @@ class Lock(object):
self._writes -= 1
return False
+ def _debug(self, *args):
+ tty.debug(*args)
+
+ def _acquired_debug(self, lock_type, wait_time, nattempts):
+ attempts_format = 'attempt' if nattempts == 1 else 'attempt'
+ if nattempts > 1:
+ acquired_attempts_format = ' after {0:0.2f}s and {1:d} {2}'.format(
+ wait_time, nattempts, attempts_format)
+ else:
+ # Dont print anything if we succeeded immediately
+ acquired_attempts_format = ''
+ self._debug(
+ '{0}: {1.path}[{1._start}:{1._length}] [Acquired{2}]'
+ .format(lock_type, self, acquired_attempts_format))
+
class LockTransaction(object):
"""Simple nested transaction context manager that uses a file lock.
@@ -295,7 +366,7 @@ class LockTransaction(object):
"""
def __init__(self, lock, acquire_fn=None, release_fn=None,
- timeout=_default_timeout):
+ timeout=None):
self._lock = lock
self._timeout = timeout
self._acquire_fn = acquire_fn
@@ -323,7 +394,7 @@ class LockTransaction(object):
class ReadTransaction(LockTransaction):
-
+ """LockTransaction context manager that does a read and releases it."""
def _enter(self):
return self._lock.acquire_read(self._timeout)
@@ -332,7 +403,7 @@ class ReadTransaction(LockTransaction):
class WriteTransaction(LockTransaction):
-
+ """LockTransaction context manager that does a write and releases it."""
def _enter(self):
return self._lock.acquire_write(self._timeout)
@@ -341,4 +412,27 @@ class WriteTransaction(LockTransaction):
class LockError(Exception):
+ """Raised for any errors related to locks."""
+
+
+class LockTimeoutError(LockError):
"""Raised when an attempt to acquire a lock times out."""
+
+
+class LockPermissionError(LockError):
+ """Raised when there are permission issues with a lock."""
+
+
+class LockROFileError(LockPermissionError):
+ """Tried to take an exclusive lock on a read-only file."""
+ def __init__(self, path):
+ msg = "Can't take write lock on read-only file: %s" % path
+ super(LockROFileError, self).__init__(msg)
+
+
+class CantCreateLockError(LockPermissionError):
+ """Attempt to create a lock in an unwritable location."""
+ def __init__(self, path):
+ msg = "cannot create lock '%s': " % path
+ msg += "file does not exist and location is not writable"
+ super(LockError, self).__init__(msg)
diff --git a/lib/spack/spack/util/multiproc.py b/lib/spack/llnl/util/multiproc.py
index 3cbbac4566..9c555112ec 100644
--- a/lib/spack/spack/util/multiproc.py
+++ b/lib/spack/llnl/util/multiproc.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This implements a parallel map operation but it can accept more values
than multiprocessing.Pool.apply() can. For example, apply() will fail
@@ -39,10 +20,10 @@ def spawn(f):
return fun
-def parmap(f, X):
- pipe = [Pipe() for x in X]
+def parmap(f, elements):
+ pipe = [Pipe() for x in elements]
proc = [Process(target=spawn(f), args=(c, x))
- for x, (p, c) in zip(X, pipe)]
+ for x, (p, c) in zip(elements, pipe)]
[p.start() for p in proc]
[p.join() for p in proc]
return [p.recv() for (p, c) in pipe]
diff --git a/lib/spack/llnl/util/tty/__init__.py b/lib/spack/llnl/util/tty/__init__.py
index 1d04787372..49a2187ad3 100644
--- a/lib/spack/llnl/util/tty/__init__.py
+++ b/lib/spack/llnl/util/tty/__init__.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import fcntl
import os
import struct
@@ -246,18 +227,18 @@ def hline(label=None, **kwargs):
def terminal_size():
"""Gets the dimensions of the console: (rows, cols)."""
- def ioctl_GWINSZ(fd):
+ def ioctl_gwinsz(fd):
try:
rc = struct.unpack('hh', fcntl.ioctl(
fd, termios.TIOCGWINSZ, '1234'))
except BaseException:
return
return rc
- rc = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
+ rc = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2)
if not rc:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
- rc = ioctl_GWINSZ(fd)
+ rc = ioctl_gwinsz(fd)
os.close(fd)
except BaseException:
pass
diff --git a/lib/spack/llnl/util/tty/colify.py b/lib/spack/llnl/util/tty/colify.py
index eebb102fb1..b6cf15a574 100644
--- a/lib/spack/llnl/util/tty/colify.py
+++ b/lib/spack/llnl/util/tty/colify.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
Routines for printing columnar output. See ``colify()`` for more information.
"""
@@ -29,7 +10,7 @@ from __future__ import division
import os
import sys
-from six import StringIO
+from six import StringIO, text_type
from llnl.util.tty import terminal_size
from llnl.util.tty.color import clen, cextra
@@ -156,7 +137,7 @@ def colify(elts, **options):
% next(options.iterkeys()))
# elts needs to be an array of strings so we can count the elements
- elts = [str(elt) for elt in elts]
+ elts = [text_type(elt) for elt in elts]
if not elts:
return (0, ())
diff --git a/lib/spack/llnl/util/tty/color.py b/lib/spack/llnl/util/tty/color.py
index c1365a93a0..53a1150ada 100644
--- a/lib/spack/llnl/util/tty/color.py
+++ b/lib/spack/llnl/util/tty/color.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This file implements an expression syntax, similar to ``printf``, for adding
ANSI colors to text.
@@ -190,7 +171,7 @@ class match_to_ansi(object):
string = styles[style]
if color:
if color not in colors:
- raise ColorParseError("invalid color specifier: '%s' in '%s'"
+ raise ColorParseError("Invalid color specifier: '%s' in '%s'"
% (color, match.string))
string += ';' + str(colors[color])
@@ -215,7 +196,9 @@ def colorize(string, **kwargs):
codes, for output to non-console devices.
"""
color = _color_when_value(kwargs.get('color', get_color_when()))
- return re.sub(color_re, match_to_ansi(color), string)
+ string = re.sub(color_re, match_to_ansi(color), string)
+ string = string.replace('}}', '}')
+ return string
def clen(string):
@@ -224,14 +207,14 @@ def clen(string):
def cextra(string):
- """"Length of extra color characters in a string"""
+ """Length of extra color characters in a string"""
return len(''.join(re.findall(r'\033[^m]*m', string)))
def cwrite(string, stream=sys.stdout, color=None):
"""Replace all color expressions in string with ANSI control
codes and write the result to the stream. If color is
- False, this will write plain text with o color. If True,
+ False, this will write plain text with no color. If True,
then it will always write colored output. If not supplied,
then it will be set based on stream.isatty().
"""
@@ -246,8 +229,25 @@ def cprint(string, stream=sys.stdout, color=None):
def cescape(string):
- """Replace all @ with @@ in the string provided."""
- return str(string).replace('@', '@@')
+ """Escapes special characters needed for color codes.
+
+ Replaces the following symbols with their equivalent literal forms:
+
+ ===== ======
+ ``@`` ``@@``
+ ``}`` ``}}``
+ ===== ======
+
+ Parameters:
+ string (str): the string to escape
+
+ Returns:
+ (str): the string with color codes escaped
+ """
+ string = str(string)
+ string = string.replace('@', '@@')
+ string = string.replace('}', '}}')
+ return string
class ColorStream(object):
diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py
index 40edca972e..df2d56cab2 100644
--- a/lib/spack/llnl/util/tty/log.py
+++ b/lib/spack/llnl/util/tty/log.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Utility classes for logging the output of blocks of code.
"""
import multiprocessing
@@ -446,10 +427,9 @@ class log_output(object):
try:
with keyboard_input(stdin):
while True:
- # Without the last parameter (timeout) select will
- # wait until at least one of the two streams are
- # ready. This may cause the function to hang.
- rlist, _, xlist = select.select(istreams, [], [], 0)
+ # No need to set any timeout for select.select
+ # Wait until a key press or an event on in_pipe.
+ rlist, _, _ = select.select(istreams, [], [])
# Allow user to toggle echo with 'v' key.
# Currently ignores other chars.
diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py
index a355b45f96..848dc4f670 100644
--- a/lib/spack/spack/__init__.py
+++ b/lib/spack/spack/__init__.py
@@ -1,266 +1,13 @@
-# flake8: noqa
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import multiprocessing
-import os
-import sys
-import tempfile
-import getpass
-from llnl.util.filesystem import *
-import llnl.util.tty as tty
-
-#-----------------------------------------------------------------------------
-# Variables describing how Spack is laid out in its prefix.
-#-----------------------------------------------------------------------------
-# This file lives in $prefix/lib/spack/spack/__file__
-spack_root = ancestor(__file__, 4)
-
-# The spack script itself
-spack_file = join_path(spack_root, "bin", "spack")
-
-# spack directory hierarchy
-lib_path = join_path(spack_root, "lib", "spack")
-external_path = join_path(lib_path, "external")
-build_env_path = join_path(lib_path, "env")
-module_path = join_path(lib_path, "spack")
-platform_path = join_path(module_path, 'platforms')
-compilers_path = join_path(module_path, "compilers")
-build_systems_path = join_path(module_path, 'build_systems')
-operating_system_path = join_path(module_path, 'operating_systems')
-test_path = join_path(module_path, "test")
-hooks_path = join_path(module_path, "hooks")
-var_path = join_path(spack_root, "var", "spack")
-stage_path = join_path(var_path, "stage")
-repos_path = join_path(var_path, "repos")
-share_path = join_path(spack_root, "share", "spack")
-
-# Paths to built-in Spack repositories.
-packages_path = join_path(repos_path, "builtin")
-mock_packages_path = join_path(repos_path, "builtin.mock")
-
-# User configuration location
-user_config_path = os.path.expanduser('~/.spack')
-
-prefix = spack_root
-opt_path = join_path(prefix, "opt")
-etc_path = join_path(prefix, "etc")
-system_etc_path = '/etc'
-
-# GPG paths.
-gpg_keys_path = join_path(var_path, "gpg")
-mock_gpg_data_path = join_path(var_path, "gpg.mock", "data")
-mock_gpg_keys_path = join_path(var_path, "gpg.mock", "keys")
-gpg_path = join_path(opt_path, "spack", "gpg")
-
-
-#-----------------------------------------------------------------------------
-# Initial imports (only for use in this file -- see __all__ below.)
-#-----------------------------------------------------------------------------
-# These imports depend on the paths above, or on each other
-# Group them here so it's easy to understand the order.
-# TODO: refactor this stuff to be more init order agnostic.
-import spack.repository
-import spack.error
-import spack.config
-import spack.fetch_strategy
-from spack.file_cache import FileCache
-from spack.abi import ABI
-from spack.concretize import DefaultConcretizer
-from spack.version import Version
-from spack.util.path import canonicalize_path
-from spack.package_prefs import PackageTesting
-
-#-----------------------------------------------------------------------------
-# Initialize various data structures & objects at the core of Spack.
-#-----------------------------------------------------------------------------
-# Version information
-spack_version = Version("0.11.1")
-
-
-# Set up the default packages database.
-try:
- repo = spack.repository.RepoPath()
- sys.meta_path.append(repo)
-except spack.error.SpackError as e:
- tty.die('while initializing Spack RepoPath:', e.message)
-
-
-# Tests ABI compatibility between packages
-abi = ABI()
-
-
-# This controls how things are concretized in spack.
-# Replace it with a subclass if you want different
-# policies.
-concretizer = DefaultConcretizer()
-
-#-----------------------------------------------------------------------------
-# config.yaml options
-#-----------------------------------------------------------------------------
-_config = spack.config.get_config('config')
-
-
-# Path where downloaded source code is cached
-cache_path = canonicalize_path(
- _config.get('source_cache', join_path(var_path, "cache")))
-fetch_cache = spack.fetch_strategy.FsCache(cache_path)
-
-
-# cache for miscellaneous stuff.
-misc_cache_path = canonicalize_path(
- _config.get('misc_cache', join_path(user_config_path, 'cache')))
-misc_cache = FileCache(misc_cache_path)
-
-
-binary_cache_retrieved_specs = set()
-
-
-#: Directories where to search for templates
-template_dirs = spack.config.get_config('config')['template_dirs']
-template_dirs = [canonicalize_path(x) for x in template_dirs]
-
-# If this is enabled, tools that use SSL should not verify
-# certifiates. e.g., curl should use the -k option.
-insecure = not _config.get('verify_ssl', True)
-
-
-# Whether spack should allow installation of unsafe versions of software.
-# "Unsafe" versions are ones it doesn't have a checksum for.
-do_checksum = _config.get('checksum', True)
-
-
-# If this is True, spack will not clean the environment to remove
-# potentially harmful variables before builds.
-dirty = _config.get('dirty', False)
-
-
-# The number of jobs to use when building in parallel.
-# By default, use all cores on the machine.
-build_jobs = _config.get('build_jobs', multiprocessing.cpu_count())
-
-
-# Needed for test dependencies
-package_testing = PackageTesting()
-
-
-#-----------------------------------------------------------------------------
-# When packages call 'from spack import *', this extra stuff is brought in.
-#
-# Spack internal code should call 'import spack' and accesses other
-# variables (spack.repo, paths, etc.) directly.
-#
-# TODO: maybe this should be separated out to build_environment.py?
-# TODO: it's not clear where all the stuff that needs to be included in
-# packages should live. This file is overloaded for spack core vs.
-# for packages.
-#
-#-----------------------------------------------------------------------------
-__all__ = []
-
-from spack.package import Package, run_before, run_after, on_package_attributes
-from spack.build_systems.makefile import MakefilePackage
-from spack.build_systems.aspell_dict import AspellDictPackage
-from spack.build_systems.autotools import AutotoolsPackage
-from spack.build_systems.cmake import CMakePackage
-from spack.build_systems.qmake import QMakePackage
-from spack.build_systems.scons import SConsPackage
-from spack.build_systems.waf import WafPackage
-from spack.build_systems.python import PythonPackage
-from spack.build_systems.r import RPackage
-from spack.build_systems.perl import PerlPackage
-from spack.build_systems.intel import IntelPackage
-
-__all__ += [
- 'run_before',
- 'run_after',
- 'on_package_attributes',
- 'Package',
- 'MakefilePackage',
- 'AspellDictPackage',
- 'AutotoolsPackage',
- 'CMakePackage',
- 'QMakePackage',
- 'SConsPackage',
- 'WafPackage',
- 'PythonPackage',
- 'RPackage',
- 'PerlPackage',
- 'IntelPackage',
-]
-
-from spack.version import Version, ver
-__all__ += ['Version', 'ver']
-
-from spack.spec import Spec
-__all__ += ['Spec']
-
-from spack.dependency import all_deptypes
-__all__ += ['all_deptypes']
-
-from spack.multimethod import when
-__all__ += ['when']
-
-import llnl.util.filesystem
-from llnl.util.filesystem import *
-__all__ += llnl.util.filesystem.__all__
-
-import spack.directives
-from spack.directives import *
-__all__ += spack.directives.__all__
-
-import spack.util.executable
-from spack.util.executable import *
-__all__ += spack.util.executable.__all__
-
-
-# Set up the user's editor
-# $EDITOR environment variable has the highest precedence
-editor = os.environ.get('EDITOR')
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-# if editor is not set, use some sensible defaults
-if editor is not None:
- editor = Executable(editor)
-else:
- editor = which('vim', 'vi', 'emacs', 'nano')
-# If there is no editor, only raise an error if we actually try to use it.
-if not editor:
- def editor_not_found(*args, **kwargs):
- raise EnvironmentError(
- 'No text editor found! Please set the EDITOR environment variable '
- 'to your preferred text editor.')
- editor = editor_not_found
+#: major, minor, patch version for Spack, in a tuple
+spack_version_info = (0, 12, 0)
-from spack.package import \
- install_dependency_symlinks, flatten_dependencies, \
- DependencyConflictError, InstallError, ExternalPackageError
-__all__ += [
- 'install_dependency_symlinks', 'flatten_dependencies',
- 'DependencyConflictError', 'InstallError', 'ExternalPackageError']
+#: String containing Spack version joined with .'s
+spack_version = '.'.join(str(v) for v in spack_version_info)
-# Add default values for attributes that would otherwise be modified from
-# Spack main script
-debug = False
-spack_working_dir = None
+__all__ = ['spack_version_info', 'spack_version']
diff --git a/lib/spack/spack/abi.py b/lib/spack/spack/abi.py
index ad46e88e61..490c688911 100644
--- a/lib/spack/spack/abi.py
+++ b/lib/spack/spack/abi.py
@@ -1,36 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
-import spack
+
+from llnl.util.lang import memoized
+
import spack.spec
from spack.build_environment import dso_suffix
from spack.spec import CompilerSpec
from spack.util.executable import Executable, ProcessError
from spack.compilers.clang import Clang
-from llnl.util.lang import memoized
class ABI(object):
@@ -74,7 +55,7 @@ class ABI(object):
return None
if not output:
return None
- libpath = os.readlink(output.strip())
+ libpath = os.path.realpath(output.strip())
if not libpath:
return None
return os.path.basename(libpath)
diff --git a/lib/spack/spack/architecture.py b/lib/spack/spack/architecture.py
index 62e2619d7f..1b7b602121 100644
--- a/lib/spack/spack/architecture.py
+++ b/lib/spack/spack/architecture.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This module contains all the elements that are required to create an
architecture object. These include, the target processor, the operating system,
@@ -79,16 +60,15 @@ import os
import inspect
import platform as py_platform
-from llnl.util.lang import memoized, list_modules, key_ordering
-from llnl.util.filesystem import join_path
+import llnl.util.multiproc as mp
import llnl.util.tty as tty
+from llnl.util.lang import memoized, list_modules, key_ordering
-import spack
+import spack.paths
+import spack.error as serr
from spack.util.naming import mod_to_class
from spack.util.environment import get_path
-from spack.util.multiproc import parmap
from spack.util.spack_yaml import syaml_dict
-import spack.error as serr
class NoPlatformError(serr.SpackError):
@@ -194,14 +174,13 @@ class Platform(object):
return self.operating_sys.get(name, None)
@classmethod
- def setup_platform_environment(self, pkg, env):
+ def setup_platform_environment(cls, pkg, env):
""" Subclass can override this method if it requires any
platform-specific build environment modifications.
"""
- pass
@classmethod
- def detect(self):
+ def detect(cls):
""" Subclass is responsible for implementing this method.
Returns True if the Platform class detects that
it is the current platform
@@ -240,8 +219,8 @@ class OperatingSystem(object):
"""
def __init__(self, name, version):
- self.name = name
- self.version = version
+ self.name = name.replace('-', '_')
+ self.version = str(version).replace('-', '_')
def __str__(self):
return "%s%s" % (self.name, self.version)
@@ -271,7 +250,7 @@ class OperatingSystem(object):
filtered_path.append(p)
# Check for a bin directory, add it if it exists
- bin = join_path(p, 'bin')
+ bin = os.path.join(p, 'bin')
if os.path.isdir(bin):
filtered_path.append(os.path.realpath(bin))
@@ -281,9 +260,9 @@ class OperatingSystem(object):
# NOTE: we import spack.compilers here to avoid init order cycles
import spack.compilers
types = spack.compilers.all_compiler_types()
- compiler_lists = parmap(lambda cmp_cls:
- self.find_compiler(cmp_cls, *filtered_path),
- types)
+ compiler_lists = mp.parmap(
+ lambda cmp_cls: self.find_compiler(cmp_cls, *filtered_path),
+ types)
# ensure all the version calls we made are cached in the parent
# process, as well. This speeds up Spack a lot.
@@ -301,7 +280,7 @@ class OperatingSystem(object):
prefixes, suffixes, and versions. e.g., gcc-mp-4.7 would
be grouped with g++-mp-4.7 and gfortran-mp-4.7.
"""
- dicts = parmap(
+ dicts = mp.parmap(
lambda t: cmp_cls._find_matches_in_path(*t),
[(cmp_cls.cc_names, cmp_cls.cc_version) + tuple(path),
(cmp_cls.cxx_names, cmp_cls.cxx_version) + tuple(path),
@@ -463,7 +442,7 @@ def arch_for_spec(arch_spec):
@memoized
def all_platforms():
classes = []
- mod_path = spack.platform_path
+ mod_path = spack.paths.platform_path
parent_module = "spack.platforms"
for name in list_modules(mod_path):
diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py
index 5a2db06424..ced7447db6 100644
--- a/lib/spack/spack/binary_distribution.py
+++ b/lib/spack/spack/binary_distribution.py
@@ -1,71 +1,84 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import re
import tarfile
-import yaml
import shutil
import platform
+import tempfile
+import hashlib
+from contextlib import closing
+
+import ruamel.yaml as yaml
import llnl.util.tty as tty
-from spack.util.gpg import Gpg
-from llnl.util.filesystem import mkdirp, join_path, install_tree
-from spack.util.web import spider
+from llnl.util.filesystem import mkdirp, install_tree, get_filetype
+
import spack.cmd
-import spack
-from spack.stage import Stage
import spack.fetch_strategy as fs
-from contextlib import closing
import spack.util.gpg as gpg_util
-import hashlib
-from spack.util.executable import ProcessError
import spack.relocate as relocate
+from spack.stage import Stage
+from spack.util.gpg import Gpg
+from spack.util.web import spider
+from spack.util.executable import ProcessError
class NoOverwriteException(Exception):
- pass
+ """
+ Raised when a file exists and must be overwritten.
+ """
+ def __init__(self, file_path):
+ err_msg = "\n%s\nexists\n" % file_path
+ err_msg += "Use -f option to overwrite."
+ super(NoOverwriteException, self).__init__(err_msg)
-class NoGpgException(Exception):
+class NoGpgException(spack.error.SpackError):
+ """
+ Raised when gpg2 is not in PATH
+ """
pass
-class PickKeyException(Exception):
+class NoKeyException(spack.error.SpackError):
+ """
+ Raised when gpg has no default key added.
+ """
pass
-class NoKeyException(Exception):
+class PickKeyException(spack.error.SpackError):
+ """
+ Raised when multiple keys can be used to sign.
+ """
+ def __init__(self, keys):
+ err_msg = "Multi keys available for signing\n%s\n" % keys
+ err_msg += "Use spack buildcache create -k <key hash> to pick a key."
+ super(PickKeyException, self).__init__(err_msg)
+
+
+class NoVerifyException(spack.error.SpackError):
+ """
+ Raised if file fails signature verification.
+ """
pass
-class NoVerifyException(Exception):
+class NoChecksumException(spack.error.SpackError):
+ """
+ Raised if file fails checksum verification.
+ """
pass
-class NoChecksumException(Exception):
+class NewLayoutException(spack.error.SpackError):
+ """
+ Raised if directory layout is different from buildcache.
+ """
pass
@@ -111,18 +124,25 @@ def write_buildinfo_file(prefix, workdir, rel=False):
dirs[:] = [d for d in dirs if d not in blacklist]
for filename in files:
path_name = os.path.join(root, filename)
- filetype = relocate.get_filetype(path_name)
- if relocate.needs_binary_relocation(filetype, os_id):
- rel_path_name = os.path.relpath(path_name, prefix)
- binary_to_relocate.append(rel_path_name)
- elif relocate.needs_text_relocation(filetype):
- rel_path_name = os.path.relpath(path_name, prefix)
- text_to_relocate.append(rel_path_name)
+ # Check if the file contains a string with the installroot.
+ # This cuts down on the number of files added to the list
+ # of files potentially needing relocation
+ if relocate.strings_contains_installroot(
+ path_name, spack.store.layout.root):
+ filetype = get_filetype(path_name)
+ if relocate.needs_binary_relocation(filetype, os_id):
+ rel_path_name = os.path.relpath(path_name, prefix)
+ binary_to_relocate.append(rel_path_name)
+ elif relocate.needs_text_relocation(filetype):
+ rel_path_name = os.path.relpath(path_name, prefix)
+ text_to_relocate.append(rel_path_name)
# Create buildinfo data and write it to disk
buildinfo = {}
buildinfo['relative_rpaths'] = rel
buildinfo['buildpath'] = spack.store.layout.root
+ buildinfo['relative_prefix'] = os.path.relpath(
+ prefix, spack.store.layout.root)
buildinfo['relocate_textfiles'] = text_to_relocate
buildinfo['relocate_binaries'] = binary_to_relocate
filename = buildinfo_file_name(workdir)
@@ -164,29 +184,34 @@ def tarball_path_name(spec, ext):
def checksum_tarball(file):
# calculate sha256 hash of tar file
- BLOCKSIZE = 65536
+ block_size = 65536
hasher = hashlib.sha256()
with open(file, 'rb') as tfile:
- buf = tfile.read(BLOCKSIZE)
+ buf = tfile.read(block_size)
while len(buf) > 0:
hasher.update(buf)
- buf = tfile.read(BLOCKSIZE)
+ buf = tfile.read(block_size)
return hasher.hexdigest()
-def sign_tarball(yes_to_all, key, force, specfile_path):
+def sign_tarball(key, force, specfile_path):
# Sign the packages if keys available
if not has_gnupg2():
- raise NoGpgException()
+ raise NoGpgException(
+ "gpg2 is not available in $PATH .\n"
+ "Use spack install gnupg and spack load gnupg.")
else:
if key is None:
keys = Gpg.signing_keys()
if len(keys) == 1:
key = keys[0]
if len(keys) > 1:
- raise PickKeyException()
+ raise PickKeyException(str(keys))
if len(keys) == 0:
- raise NoKeyException()
+ msg = "No default key available for signing.\n"
+ msg += "Use spack gpg init and spack gpg create"
+ msg += " to create a default key."
+ raise NoKeyException(msg)
if os.path.exists('%s.asc' % specfile_path):
if force:
os.remove('%s.asc' % specfile_path)
@@ -210,17 +235,17 @@ def generate_index(outdir, indexfile_path):
f.close()
-def build_tarball(spec, outdir, force=False, rel=False, yes_to_all=False,
- key=None):
+def build_tarball(spec, outdir, force=False, rel=False, unsigned=False,
+ allow_root=False, key=None):
"""
Build a tarball from given spec and put it into the directory structure
used at the mirror (following <tarball_directory_name>).
"""
# set up some paths
tarfile_name = tarball_name(spec, '.tar.gz')
- tarfile_dir = join_path(outdir, "build_cache",
- tarball_directory_name(spec))
- tarfile_path = join_path(tarfile_dir, tarfile_name)
+ tarfile_dir = os.path.join(outdir, "build_cache",
+ tarball_directory_name(spec))
+ tarfile_path = os.path.join(tarfile_dir, tarfile_name)
mkdirp(tarfile_dir)
spackfile_path = os.path.join(
outdir, "build_cache", tarball_path_name(spec, '.spack'))
@@ -232,20 +257,18 @@ def build_tarball(spec, outdir, force=False, rel=False, yes_to_all=False,
# need to copy the spec file so the build cache can be downloaded
# without concretizing with the current spack packages
# and preferences
- spec_file = join_path(spec.prefix, ".spack", "spec.yaml")
+ spec_file = os.path.join(spec.prefix, ".spack", "spec.yaml")
specfile_name = tarball_name(spec, '.spec.yaml')
specfile_path = os.path.realpath(
- join_path(outdir, "build_cache", specfile_name))
- indexfile_path = join_path(outdir, "build_cache", "index.html")
+ os.path.join(outdir, "build_cache", specfile_name))
+ indexfile_path = os.path.join(outdir, "build_cache", "index.html")
if os.path.exists(specfile_path):
if force:
os.remove(specfile_path)
else:
raise NoOverwriteException(str(specfile_path))
# make a copy of the install directory to work with
- workdir = join_path(outdir, os.path.basename(spec.prefix))
- if os.path.exists(workdir):
- shutil.rmtree(workdir)
+ workdir = os.path.join(tempfile.mkdtemp(), os.path.basename(spec.prefix))
install_tree(spec.prefix, workdir, symlinks=True)
# create info for later relocation and create tar
@@ -254,11 +277,23 @@ def build_tarball(spec, outdir, force=False, rel=False, yes_to_all=False,
# optinally make the paths in the binaries relative to each other
# in the spack install tree before creating tarball
if rel:
- make_package_relative(workdir, spec.prefix)
+ try:
+ make_package_relative(workdir, spec.prefix, allow_root)
+ except Exception as e:
+ shutil.rmtree(workdir)
+ shutil.rmtree(tarfile_dir)
+ tty.die(str(e))
+ else:
+ try:
+ make_package_placeholder(workdir, allow_root)
+ except Exception as e:
+ shutil.rmtree(workdir)
+ shutil.rmtree(tarfile_dir)
+ tty.die(str(e))
# create compressed tarball of the install prefix
with closing(tarfile.open(tarfile_path, 'w:gz')) as tar:
tar.add(name='%s' % workdir,
- arcname='%s' % os.path.basename(workdir))
+ arcname='%s' % os.path.basename(spec.prefix))
# remove copy of install directory
shutil.rmtree(workdir)
@@ -274,31 +309,28 @@ def build_tarball(spec, outdir, force=False, rel=False, yes_to_all=False,
bchecksum['hash_algorithm'] = 'sha256'
bchecksum['hash'] = checksum
spec_dict['binary_cache_checksum'] = bchecksum
+ # Add original install prefix relative to layout root to spec.yaml.
+ # This will be used to determine is the directory layout has changed.
+ buildinfo = {}
+ buildinfo['relative_prefix'] = os.path.relpath(
+ spec.prefix, spack.store.layout.root)
+ spec_dict['buildinfo'] = buildinfo
with open(specfile_path, 'w') as outfile:
outfile.write(yaml.dump(spec_dict))
- signed = False
- if not yes_to_all:
- # sign the tarball and spec file with gpg
- try:
- sign_tarball(yes_to_all, key, force, specfile_path)
- signed = True
- except NoGpgException:
- raise NoGpgException()
- except PickKeyException:
- raise PickKeyException()
- except NoKeyException():
- raise NoKeyException()
+ # sign the tarball and spec file with gpg
+ if not unsigned:
+ sign_tarball(key, force, specfile_path)
# put tarball, spec and signature files in .spack archive
with closing(tarfile.open(spackfile_path, 'w')) as tar:
tar.add(name='%s' % tarfile_path, arcname='%s' % tarfile_name)
tar.add(name='%s' % specfile_path, arcname='%s' % specfile_name)
- if signed:
+ if not unsigned:
tar.add(name='%s.asc' % specfile_path,
arcname='%s.asc' % specfile_name)
# cleanup file moved to archive
os.remove(tarfile_path)
- if signed:
+ if not unsigned:
os.remove('%s.asc' % specfile_path)
# create an index.html for the build_cache directory so specs can be found
@@ -313,7 +345,7 @@ def download_tarball(spec):
Download binary tarball for given package into stage area
Return True if successful
"""
- mirrors = spack.config.get_config('mirrors')
+ mirrors = spack.config.get('mirrors')
if len(mirrors) == 0:
tty.die("Please add a spack mirror to allow " +
"download of pre-compiled packages.")
@@ -330,7 +362,7 @@ def download_tarball(spec):
return None
-def make_package_relative(workdir, prefix):
+def make_package_relative(workdir, prefix, allow_root):
"""
Change paths in binaries to relative paths
"""
@@ -341,26 +373,35 @@ def make_package_relative(workdir, prefix):
for filename in buildinfo['relocate_binaries']:
orig_path_names.append(os.path.join(prefix, filename))
cur_path_names.append(os.path.join(workdir, filename))
- relocate.make_binary_relative(cur_path_names, orig_path_names,
- old_path)
+ relocate.make_binary_relative(cur_path_names, orig_path_names,
+ old_path, allow_root)
+
+
+def make_package_placeholder(workdir, allow_root):
+ """
+ Change paths in binaries to placeholder paths
+ """
+ buildinfo = read_buildinfo_file(workdir)
+ cur_path_names = list()
+ for filename in buildinfo['relocate_binaries']:
+ cur_path_names.append(os.path.join(workdir, filename))
+ relocate.make_binary_placeholder(cur_path_names, allow_root)
-def relocate_package(prefix):
+def relocate_package(workdir, allow_root):
"""
Relocate the given package
"""
- buildinfo = read_buildinfo_file(prefix)
+ buildinfo = read_buildinfo_file(workdir)
new_path = spack.store.layout.root
old_path = buildinfo['buildpath']
rel = buildinfo.get('relative_rpaths', False)
- if new_path == old_path and not rel:
- return
tty.msg("Relocating package from",
"%s to %s." % (old_path, new_path))
path_names = set()
for filename in buildinfo['relocate_textfiles']:
- path_name = os.path.join(prefix, filename)
+ path_name = os.path.join(workdir, filename)
# Don't add backup files generated by filter_file during install step.
if not path_name.endswith('~'):
path_names.add(path_name)
@@ -370,39 +411,47 @@ def relocate_package(prefix):
if not rel:
path_names = set()
for filename in buildinfo['relocate_binaries']:
- path_name = os.path.join(prefix, filename)
+ path_name = os.path.join(workdir, filename)
path_names.add(path_name)
- relocate.relocate_binary(path_names, old_path, new_path)
+ relocate.relocate_binary(path_names, old_path, new_path,
+ allow_root)
-def extract_tarball(spec, filename, yes_to_all=False, force=False):
+def extract_tarball(spec, filename, allow_root=False, unsigned=False,
+ force=False):
"""
extract binary tarball for given package into install area
"""
- installpath = spec.prefix
- if os.path.exists(installpath):
+ if os.path.exists(spec.prefix):
if force:
- shutil.rmtree(installpath)
+ shutil.rmtree(spec.prefix)
else:
- raise NoOverwriteException(str(installpath))
+ raise NoOverwriteException(str(spec.prefix))
+
+ tmpdir = tempfile.mkdtemp()
stagepath = os.path.dirname(filename)
spackfile_name = tarball_name(spec, '.spack')
spackfile_path = os.path.join(stagepath, spackfile_name)
tarfile_name = tarball_name(spec, '.tar.gz')
- tarfile_path = os.path.join(stagepath, tarfile_name)
+ tarfile_path = os.path.join(tmpdir, tarfile_name)
specfile_name = tarball_name(spec, '.spec.yaml')
- specfile_path = os.path.join(stagepath, specfile_name)
+ specfile_path = os.path.join(tmpdir, specfile_name)
with closing(tarfile.open(spackfile_path, 'r')) as tar:
- tar.extractall(stagepath)
-
- if not yes_to_all:
+ tar.extractall(tmpdir)
+ if not unsigned:
if os.path.exists('%s.asc' % specfile_path):
- Gpg.verify('%s.asc' % specfile_path, specfile_path)
- os.remove(specfile_path + '.asc')
+ try:
+ Gpg.verify('%s.asc' % specfile_path, specfile_path)
+ except Exception as e:
+ shutil.rmtree(tmpdir)
+ tty.die(str(e))
else:
- raise NoVerifyException()
-
+ shutil.rmtree(tmpdir)
+ raise NoVerifyException(
+ "Package spec file failed signature verification.\n"
+ "Use spack buildcache keys to download "
+ "and install a key for verification from the mirror.")
# get the sha256 checksum of the tarball
checksum = checksum_tarball(tarfile_path)
@@ -415,28 +464,65 @@ def extract_tarball(spec, filename, yes_to_all=False, force=False):
# if the checksums don't match don't install
if bchecksum['hash'] != checksum:
- raise NoChecksumException()
-
- # delay creating installpath until verification is complete
- mkdirp(installpath)
+ shutil.rmtree(tmpdir)
+ raise NoChecksumException(
+ "Package tarball failed checksum verification.\n"
+ "It cannot be installed.")
+
+ new_relative_prefix = str(os.path.relpath(spec.prefix,
+ spack.store.layout.root))
+ # if the original relative prefix is in the spec file use it
+ buildinfo = spec_dict.get('buildinfo', {})
+ old_relative_prefix = buildinfo.get('relative_prefix', new_relative_prefix)
+ # if the original relative prefix and new relative prefix differ the
+ # directory layout has changed and the buildcache cannot be installed
+ if old_relative_prefix != new_relative_prefix:
+ shutil.rmtree(tmpdir)
+ msg = "Package tarball was created from an install "
+ msg += "prefix with a different directory layout.\n"
+ msg += "It cannot be relocated."
+ raise NewLayoutException(msg)
+
+ # extract the tarball in a temp directory
with closing(tarfile.open(tarfile_path, 'r')) as tar:
- tar.extractall(path=join_path(installpath, '..'))
+ tar.extractall(path=tmpdir)
+ # the base of the install prefix is used when creating the tarball
+ # so the pathname should be the same now that the directory layout
+ # is confirmed
+ workdir = os.path.join(tmpdir, os.path.basename(spec.prefix))
+ # cleanup
os.remove(tarfile_path)
os.remove(specfile_path)
- relocate_package(installpath)
+
+ try:
+ relocate_package(workdir, allow_root)
+ except Exception as e:
+ shutil.rmtree(workdir)
+ tty.die(str(e))
+ # Delay creating spec.prefix until verification is complete
+ # and any relocation has been done.
+ else:
+ install_tree(workdir, spec.prefix, symlinks=True)
+ finally:
+ shutil.rmtree(tmpdir)
+
+
+#: Internal cache for get_specs
+_cached_specs = None
def get_specs(force=False):
"""
Get spec.yaml's for build caches available on mirror
"""
- if spack.binary_cache_retrieved_specs:
+ global _cached_specs
+
+ if _cached_specs:
tty.debug("Using previously-retrieved specs")
- previously_retrieved = spack.binary_cache_retrieved_specs
- return previously_retrieved
+ return _cached_specs
- mirrors = spack.config.get_config('mirrors')
+ mirrors = spack.config.get('mirrors')
if len(mirrors) == 0:
tty.warn("No Spack mirrors are currently configured")
return {}
@@ -448,11 +534,12 @@ def get_specs(force=False):
if url.startswith('file'):
mirror = url.replace('file://', '') + '/build_cache'
tty.msg("Finding buildcaches in %s" % mirror)
- files = os.listdir(mirror)
- for file in files:
- if re.search('spec.yaml', file):
- link = 'file://' + mirror + '/' + file
- urls.add(link)
+ if os.path.exists(mirror):
+ files = os.listdir(mirror)
+ for file in files:
+ if re.search('spec.yaml', file):
+ link = 'file://' + mirror + '/' + file
+ urls.add(link)
else:
tty.msg("Finding buildcaches on %s" % url)
p, links = spider(url + "/build_cache")
@@ -460,7 +547,7 @@ def get_specs(force=False):
if re.search("spec.yaml", link) and re.search(path, link):
urls.add(link)
- specs = set()
+ _cached_specs = set()
for link in urls:
with Stage(link, name="build_cache", keep=True) as stage:
if force and os.path.exists(stage.save_filename):
@@ -476,17 +563,16 @@ def get_specs(force=False):
# we need to mark this spec concrete on read-in.
spec = spack.spec.Spec.from_yaml(f)
spec._mark_concrete()
- specs.add(spec)
+ _cached_specs.add(spec)
- spack.binary_cache_retrieved_specs = specs
- return specs
+ return _cached_specs
-def get_keys(install=False, yes_to_all=False, force=False):
+def get_keys(install=False, trust=False, force=False):
"""
Get pgp public keys available on mirror
"""
- mirrors = spack.config.get_config('mirrors')
+ mirrors = spack.config.get('mirrors')
if len(mirrors) == 0:
tty.die("Please add a spack mirror to allow " +
"download of build caches.")
@@ -519,9 +605,9 @@ def get_keys(install=False, yes_to_all=False, force=False):
continue
tty.msg('Found key %s' % link)
if install:
- if yes_to_all:
+ if trust:
Gpg.trust(stage.save_filename)
tty.msg('Added this key to trusted keys.')
else:
tty.msg('Will not add this key to trusted keys.'
- 'Use -y to override')
+ 'Use -t to install all downloaded keys')
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index dfadabb10c..9ef64a6f7e 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This module contains all routines related to setting up the package
build environment. All of this is set up by package.py just before
@@ -62,13 +43,20 @@ from six import iteritems
from six import StringIO
import llnl.util.tty as tty
-from llnl.util.tty.color import colorize
-from llnl.util.filesystem import join_path, mkdirp, install, install_tree
-
-import spack
+from llnl.util.tty.color import cescape, colorize
+from llnl.util.filesystem import mkdirp, install, install_tree
+
+import spack.build_systems.cmake
+import spack.build_systems.meson
+import spack.config
+import spack.main
+import spack.paths
import spack.store
-from spack.environment import EnvironmentModifications, validate
+from spack.util.string import plural
+from spack.util.environment import EnvironmentModifications, validate
+from spack.util.environment import preserve_environment
from spack.util.environment import env_flag, filter_system_paths, get_path
+from spack.util.environment import system_dirs
from spack.util.executable import Executable
from spack.util.module_cmd import load_module, get_path_from_module
from spack.util.log_parse import parse_log_events, make_log_context
@@ -94,6 +82,8 @@ SPACK_DEBUG = 'SPACK_DEBUG'
SPACK_SHORT_SPEC = 'SPACK_SHORT_SPEC'
SPACK_DEBUG_LOG_ID = 'SPACK_DEBUG_LOG_ID'
SPACK_DEBUG_LOG_DIR = 'SPACK_DEBUG_LOG_DIR'
+SPACK_CCACHE_BINARY = 'SPACK_CCACHE_BINARY'
+SPACK_SYSTEM_DIRS = 'SPACK_SYSTEM_DIRS'
# Platform-specific library suffix.
@@ -101,11 +91,14 @@ dso_suffix = 'dylib' if sys.platform == 'darwin' else 'so'
class MakeExecutable(Executable):
- """Special callable executable object for make so the user can
- specify parallel or not on a per-invocation basis. Using
- 'parallel' as a kwarg will override whatever the package's
- global setting is, so you can either default to true or false
- and override particular calls.
+ """Special callable executable object for make so the user can specify
+ parallelism options on a per-invocation basis. Specifying
+ 'parallel' to the call will override whatever the package's
+ global setting is, so you can either default to true or false and
+ override particular calls. Specifying 'jobs_env' to a particular
+ call will name an environment variable which will be set to the
+ parallelism level (without affecting the normal invocation with
+ -j).
Note that if the SPACK_NO_PARALLEL_MAKE env var is set it overrides
everything.
@@ -116,18 +109,60 @@ class MakeExecutable(Executable):
self.jobs = jobs
def __call__(self, *args, **kwargs):
+ """parallel, and jobs_env from kwargs are swallowed and used here;
+ remaining arguments are passed through to the superclass.
+ """
+
disable = env_flag(SPACK_NO_PARALLEL_MAKE)
- parallel = not disable and kwargs.get('parallel', self.jobs > 1)
+ parallel = (not disable) and kwargs.pop('parallel', self.jobs > 1)
if parallel:
- jobs = "-j%d" % self.jobs
- args = (jobs,) + args
+ args = ('-j{0}'.format(self.jobs),) + args
+ jobs_env = kwargs.pop('jobs_env', None)
+ if jobs_env:
+ # Caller wants us to set an environment variable to
+ # control the parallelism.
+ kwargs['extra_env'] = {jobs_env: str(self.jobs)}
return super(MakeExecutable, self).__call__(*args, **kwargs)
+def clean_environment():
+ # Stuff in here sanitizes the build environment to eliminate
+ # anything the user has set that may interfere. We apply it immediately
+ # unlike the other functions so it doesn't overwrite what the modules load.
+ env = EnvironmentModifications()
+
+ # Remove these vars from the environment during build because they
+ # can affect how some packages find libraries. We want to make
+ # sure that builds never pull in unintended external dependencies.
+ env.unset('LD_LIBRARY_PATH')
+ env.unset('LIBRARY_PATH')
+ env.unset('CPATH')
+ env.unset('LD_RUN_PATH')
+ env.unset('DYLD_LIBRARY_PATH')
+
+ build_lang = spack.config.get('config:build_language')
+ if build_lang:
+ # Override language-related variables. This can be used to force
+ # English compiler messages etc., which allows parse_log_events to
+ # show useful matches.
+ env.set('LC_ALL', build_lang)
+
+ # Remove any macports installs from the PATH. The macports ld can
+ # cause conflicts with the built-in linker on el capitan. Solves
+ # assembler issues, e.g.:
+ # suffix or operands invalid for `movq'"
+ path = get_path('PATH')
+ for p in path:
+ if '/macports/' in p:
+ env.remove_path('PATH', p)
+
+ env.apply_modifications()
+
+
def set_compiler_environment_variables(pkg, env):
- assert(pkg.spec.concrete)
+ assert pkg.spec.concrete
compiler = pkg.compiler
# Set compiler variables used by CMake and autotools
@@ -138,21 +173,21 @@ def set_compiler_environment_variables(pkg, env):
# and return it
# TODO : add additional kwargs for better diagnostics, like requestor,
# ttyout, ttyerr, etc.
- link_dir = spack.build_env_path
+ link_dir = spack.paths.build_env_path
# Set SPACK compiler variables so that our wrapper knows what to call
if compiler.cc:
env.set('SPACK_CC', compiler.cc)
- env.set('CC', join_path(link_dir, compiler.link_paths['cc']))
+ env.set('CC', os.path.join(link_dir, compiler.link_paths['cc']))
if compiler.cxx:
env.set('SPACK_CXX', compiler.cxx)
- env.set('CXX', join_path(link_dir, compiler.link_paths['cxx']))
+ env.set('CXX', os.path.join(link_dir, compiler.link_paths['cxx']))
if compiler.f77:
env.set('SPACK_F77', compiler.f77)
- env.set('F77', join_path(link_dir, compiler.link_paths['f77']))
+ env.set('F77', os.path.join(link_dir, compiler.link_paths['f77']))
if compiler.fc:
env.set('SPACK_FC', compiler.fc)
- env.set('FC', join_path(link_dir, compiler.link_paths['fc']))
+ env.set('FC', os.path.join(link_dir, compiler.link_paths['fc']))
# Set SPACK compiler rpath flags so that our wrapper knows what to use
env.set('SPACK_CC_RPATH_ARG', compiler.cc_rpath_arg)
@@ -197,6 +232,8 @@ def set_compiler_environment_variables(pkg, env):
env.set('SPACK_COMPILER_SPEC', str(pkg.spec.compiler))
+ env.set('SPACK_SYSTEM_DIRS', ':'.join(system_dirs))
+
compiler.setup_custom_environment(pkg, env)
return env
@@ -256,39 +293,24 @@ def set_build_environment_variables(pkg, env, dirty):
# Install root prefix
env.set(SPACK_INSTALL, spack.store.root)
- # Stuff in here sanitizes the build environment to eliminate
- # anything the user has set that may interfere.
- if not dirty:
- # Remove these vars from the environment during build because they
- # can affect how some packages find libraries. We want to make
- # sure that builds never pull in unintended external dependencies.
- env.unset('LD_LIBRARY_PATH')
- env.unset('LIBRARY_PATH')
- env.unset('CPATH')
- env.unset('LD_RUN_PATH')
- env.unset('DYLD_LIBRARY_PATH')
-
- # Remove any macports installs from the PATH. The macports ld can
- # cause conflicts with the built-in linker on el capitan. Solves
- # assembler issues, e.g.:
- # suffix or operands invalid for `movq'"
- path = get_path('PATH')
- for p in path:
- if '/macports/' in p:
- env.remove_path('PATH', p)
-
# Set environment variables if specified for
# the given compiler
compiler = pkg.compiler
environment = compiler.environment
- if 'set' in environment:
- env_to_set = environment['set']
- for key, value in iteritems(env_to_set):
- env.set('SPACK_ENV_SET_%s' % key, value)
- env.set('%s' % key, value)
- # Let shell know which variables to set
- env_variables = ":".join(env_to_set.keys())
- env.set('SPACK_ENV_TO_SET', env_variables)
+
+ for command, variable in iteritems(environment):
+ if command == 'set':
+ for name, value in iteritems(variable):
+ env.set(name, value)
+ elif command == 'unset':
+ for name, _ in iteritems(variable):
+ env.unset(name)
+ elif command == 'prepend-path':
+ for name, value in iteritems(variable):
+ env.prepend_path(name, value)
+ elif command == 'append-path':
+ for name, value in iteritems(variable):
+ env.append_path(name, value)
if compiler.extra_rpaths:
extra_rpaths = ':'.join(compiler.extra_rpaths)
@@ -302,20 +324,21 @@ def set_build_environment_variables(pkg, env, dirty):
env.prepend_path('PATH', bin_dir)
# Add spack build environment path with compiler wrappers first in
- # the path. We add both spack.env_path, which includes default
+ # the path. We add the compiler wrapper path, which includes default
# wrappers (cc, c++, f77, f90), AND a subdirectory containing
# compiler-specific symlinks. The latter ensures that builds that
- # are sensitive to the *name* of the compiler see the right name
- # when we're building with the wrappers.
+ # are sensitive to the *name* of the compiler see the right name when
+ # we're building with the wrappers.
#
# Conflicts on case-insensitive systems (like "CC" and "cc") are
# handled by putting one in the <build_env_path>/case-insensitive
# directory. Add that to the path too.
env_paths = []
- compiler_specific = join_path(spack.build_env_path, pkg.compiler.name)
- for item in [spack.build_env_path, compiler_specific]:
+ compiler_specific = os.path.join(
+ spack.paths.build_env_path, pkg.compiler.name)
+ for item in [spack.paths.build_env_path, compiler_specific]:
env_paths.append(item)
- ci = join_path(item, 'case-insensitive')
+ ci = os.path.join(item, 'case-insensitive')
if os.path.isdir(ci):
env_paths.append(ci)
@@ -324,16 +347,23 @@ def set_build_environment_variables(pkg, env, dirty):
env.set_path(SPACK_ENV_PATH, env_paths)
# Working directory for the spack command itself, for debug logs.
- if spack.debug:
+ if spack.config.get('config:debug'):
env.set(SPACK_DEBUG, 'TRUE')
env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec)
env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('${PACKAGE}-${HASH:7}'))
- env.set(SPACK_DEBUG_LOG_DIR, spack.spack_working_dir)
+ env.set(SPACK_DEBUG_LOG_DIR, spack.main.spack_working_dir)
+
+ # Find ccache binary and hand it to build environment
+ if spack.config.get('config:ccache'):
+ ccache = Executable('ccache')
+ if not ccache:
+ raise RuntimeError("No ccache binary found in PATH")
+ env.set(SPACK_CCACHE_BINARY, ccache)
# Add any pkgconfig directories to PKG_CONFIG_PATH
for prefix in build_link_prefixes:
for directory in ('lib', 'lib64', 'share'):
- pcdir = join_path(prefix, directory, 'pkgconfig')
+ pcdir = os.path.join(prefix, directory, 'pkgconfig')
if os.path.isdir(pcdir):
env.prepend_path('PKG_CONFIG_PATH', pcdir)
@@ -345,7 +375,7 @@ def set_module_variables_for_package(pkg, module):
This makes things easier for package writers.
"""
# number of jobs spack will build with.
- jobs = spack.build_jobs
+ jobs = spack.config.get('config:build_jobs') or multiprocessing.cpu_count()
if not pkg.parallel:
jobs = 1
elif pkg.make_jobs:
@@ -367,18 +397,20 @@ def set_module_variables_for_package(pkg, module):
# Don't use which for this; we want to find it in the current dir.
m.configure = Executable('./configure')
+ m.meson = Executable('meson')
m.cmake = Executable('cmake')
- m.ctest = Executable('ctest')
+ m.ctest = MakeExecutable('ctest', jobs)
# Standard CMake arguments
- m.std_cmake_args = spack.CMakePackage._std_args(pkg)
+ m.std_cmake_args = spack.build_systems.cmake.CMakePackage._std_args(pkg)
+ m.std_meson_args = spack.build_systems.meson.MesonPackage._std_args(pkg)
# Put spack compiler paths in module scope.
- link_dir = spack.build_env_path
- m.spack_cc = join_path(link_dir, pkg.compiler.link_paths['cc'])
- m.spack_cxx = join_path(link_dir, pkg.compiler.link_paths['cxx'])
- m.spack_f77 = join_path(link_dir, pkg.compiler.link_paths['f77'])
- m.spack_fc = join_path(link_dir, pkg.compiler.link_paths['fc'])
+ link_dir = spack.paths.build_env_path
+ m.spack_cc = os.path.join(link_dir, pkg.compiler.link_paths['cc'])
+ m.spack_cxx = os.path.join(link_dir, pkg.compiler.link_paths['cxx'])
+ m.spack_f77 = os.path.join(link_dir, pkg.compiler.link_paths['f77'])
+ m.spack_fc = os.path.join(link_dir, pkg.compiler.link_paths['fc'])
# Emulate some shell commands for convenience
m.pwd = os.getcwd
@@ -465,16 +497,16 @@ def _static_to_shared_library(arch, compiler, static_lib, shared_lib=None,
compiler_args = [
'-dynamiclib',
- '-install_name {0}'.format(install_name),
+ '-install_name', '{0}'.format(install_name),
'-Wl,-force_load,{0}'.format(static_lib)
]
if compat_version:
- compiler_args.append('-compatibility_version {0}'.format(
- compat_version))
+ compiler_args.extend(['-compatibility_version', '{0}'.format(
+ compat_version)])
if version:
- compiler_args.append('-current_version {0}'.format(version))
+ compiler_args.extend(['-current_version', '{0}'.format(version)])
if len(arguments) > 0:
compiler_args.extend(arguments)
@@ -537,15 +569,31 @@ def get_std_cmake_args(pkg):
Returns:
list of str: arguments for cmake
"""
- return spack.CMakePackage._std_args(pkg)
+ return spack.build_systems.cmake.CMakePackage._std_args(pkg)
+
+
+def get_std_meson_args(pkg):
+ """List of standard arguments used if a package is a MesonPackage.
+
+ Returns:
+ list of str: standard arguments that would be used if this
+ package were a MesonPackage instance.
+
+ Args:
+ pkg (PackageBase): package under consideration
+
+ Returns:
+ list of str: arguments for meson
+ """
+ return spack.build_systems.meson.MesonPackage._std_args(pkg)
def parent_class_modules(cls):
"""
- Get list of super class modules that are all descend from spack.Package
+ Get list of superclass modules that descend from spack.package.PackageBase
"""
- if (not issubclass(cls, spack.package.Package) or
- issubclass(spack.package.Package, cls)):
+ if (not issubclass(cls, spack.package.PackageBase) or
+ issubclass(spack.package.PackageBase, cls)):
return []
result = []
module = sys.modules.get(cls.__module__)
@@ -575,18 +623,8 @@ def setup_package(pkg, dirty):
spack_env = EnvironmentModifications()
run_env = EnvironmentModifications()
- # Before proceeding, ensure that specs and packages are consistent
- #
- # This is a confusing behavior due to how packages are
- # constructed. `setup_dependent_package` may set attributes on
- # specs in the DAG for use by other packages' install
- # method. However, spec.package will look up a package via
- # spack.repo, which defensively copies specs into packages. This
- # code ensures that all packages in the DAG have pieces of the
- # same spec object at build time.
- #
- for s in pkg.spec.traverse():
- assert s.package.spec is s
+ if not dirty:
+ clean_environment()
set_compiler_environment_variables(pkg, spack_env)
set_build_environment_variables(pkg, spack_env, dirty)
@@ -594,10 +632,11 @@ def setup_package(pkg, dirty):
# traverse in postorder so package can use vars from its dependencies
spec = pkg.spec
- for dspec in pkg.spec.traverse(order='post', root=False, deptype='build'):
+ for dspec in pkg.spec.traverse(order='post', root=False,
+ deptype=('build', 'test')):
# If a user makes their own package repo, e.g.
- # spack.repos.mystuff.libelf.Libelf, and they inherit from
- # an existing class like spack.repos.original.libelf.Libelf,
+ # spack.pkg.mystuff.libelf.Libelf, and they inherit from
+ # an existing class like spack.pkg.original.libelf.Libelf,
# then set the module variables for both classes so the
# parent class can still use them if it gets called.
spkg = dspec.package
@@ -614,25 +653,33 @@ def setup_package(pkg, dirty):
set_module_variables_for_package(pkg, pkg.module)
pkg.setup_environment(spack_env, run_env)
+ # Loading modules, in particular if they are meant to be used outside
+ # of Spack, can change environment variables that are relevant to the
+ # build of packages. To avoid a polluted environment, preserve the
+ # value of a few, selected, environment variables
+ # With the current ordering of environment modifications, this is strictly
+ # unnecessary. Modules affecting these variables will be overwritten anyway
+ with preserve_environment('CC', 'CXX', 'FC', 'F77'):
+ # All module loads that otherwise would belong in previous
+ # functions have to occur after the spack_env object has its
+ # modifications applied. Otherwise the environment modifications
+ # could undo module changes, such as unsetting LD_LIBRARY_PATH
+ # after a module changes it.
+ for mod in pkg.compiler.modules:
+ # Fixes issue https://github.com/spack/spack/issues/3153
+ if os.environ.get("CRAY_CPU_TARGET") == "mic-knl":
+ load_module("cce")
+ load_module(mod)
+
+ if pkg.architecture.target.module_name:
+ load_module(pkg.architecture.target.module_name)
+
+ load_external_modules(pkg)
+
# Make sure nothing's strange about the Spack environment.
validate(spack_env, tty.warn)
spack_env.apply_modifications()
- # All module loads that otherwise would belong in previous functions
- # have to occur after the spack_env object has its modifications applied.
- # Otherwise the environment modifications could undo module changes, such
- # as unsetting LD_LIBRARY_PATH after a module changes it.
- for mod in pkg.compiler.modules:
- # Fixes issue https://github.com/spack/spack/issues/3153
- if os.environ.get("CRAY_CPU_TARGET") == "mic-knl":
- load_module("cce")
- load_module(mod)
-
- if pkg.architecture.target.module_name:
- load_module(pkg.architecture.target.module_name)
-
- load_external_modules(pkg)
-
def fork(pkg, function, dirty, fake):
"""Fork a child process to do part of a spack build.
@@ -680,7 +727,7 @@ def fork(pkg, function, dirty, fake):
except StopIteration as e:
# StopIteration is used to stop installations
# before the final stage, mainly for debug purposes
- tty.msg(e.message)
+ tty.msg(e)
child_pipe.send(None)
except BaseException:
@@ -783,25 +830,33 @@ def get_package_context(traceback, context=3):
if isinstance(obj, spack.package.PackageBase):
break
- # we found obj, the Package implementation we care about.
- # point out the location in the install method where we failed.
- lines = []
- lines.append("%s:%d, in %s:" % (
- inspect.getfile(frame.f_code), frame.f_lineno, frame.f_code.co_name
- ))
+ # We found obj, the Package implementation we care about.
+ # Point out the location in the install method where we failed.
+ lines = [
+ '{0}:{1:d}, in {2}:'.format(
+ inspect.getfile(frame.f_code),
+ frame.f_lineno - 1, # subtract 1 because f_lineno is 0-indexed
+ frame.f_code.co_name
+ )
+ ]
# Build a message showing context in the install method.
sourcelines, start = inspect.getsourcelines(frame)
- fl = frame.f_lineno - start
- start_ctx = max(0, fl - context)
- sourcelines = sourcelines[start_ctx:fl + context + 1]
+ # Calculate lineno of the error relative to the start of the function.
+ # Subtract 1 because f_lineno is 0-indexed.
+ fun_lineno = frame.f_lineno - start - 1
+ start_ctx = max(0, fun_lineno - context)
+ sourcelines = sourcelines[start_ctx:fun_lineno + context + 1]
+
for i, line in enumerate(sourcelines):
- is_error = start_ctx + i == fl
- mark = ">> " if is_error else " "
- marked = " %s%-6d%s" % (mark, start_ctx + i, line.rstrip())
+ is_error = start_ctx + i == fun_lineno
+ mark = '>> ' if is_error else ' '
+ # Add start to get lineno relative to start of file, not function.
+ marked = ' {0}{1:-6d}{2}'.format(
+ mark, start + start_ctx + i, line.rstrip())
if is_error:
- marked = colorize('@R{%s}' % marked)
+ marked = colorize('@R{%s}' % cescape(marked))
lines.append(marked)
return lines
@@ -869,29 +924,34 @@ class ChildError(InstallError):
if (self.module, self.name) in ChildError.build_errors:
# The error happened in some external executed process. Show
- # the build log with errors highlighted.
- if self.build_log:
+ # the build log with errors or warnings highlighted.
+ if self.build_log and os.path.exists(self.build_log):
errors, warnings = parse_log_events(self.build_log)
nerr = len(errors)
+ nwar = len(warnings)
if nerr > 0:
- if nerr == 1:
- out.write("\n1 error found in build log:\n")
- else:
- out.write("\n%d errors found in build log:\n" % nerr)
+ # If errors are found, only display errors
+ out.write(
+ "\n%s found in build log:\n" % plural(nerr, 'error'))
out.write(make_log_context(errors))
+ elif nwar > 0:
+ # If no errors are found but warnings are, display warnings
+ out.write(
+ "\n%s found in build log:\n" % plural(nwar, 'warning'))
+ out.write(make_log_context(warnings))
else:
# The error happened in in the Python code, so try to show
# some context from the Package itself.
- out.write('%s: %s\n\n' % (self.name, self.message))
if self.context:
+ out.write('\n')
out.write('\n'.join(self.context))
out.write('\n')
if out.getvalue():
out.write('\n')
- if self.build_log:
+ if self.build_log and os.path.exists(self.build_log):
out.write('See build log for details:\n')
out.write(' %s' % self.build_log)
diff --git a/lib/spack/spack/build_systems/README-intel.rst b/lib/spack/spack/build_systems/README-intel.rst
new file mode 100644
index 0000000000..6efbd09dd4
--- /dev/null
+++ b/lib/spack/spack/build_systems/README-intel.rst
@@ -0,0 +1,660 @@
+====================================
+Development Notes on Intel Packages
+====================================
+
+These are notes for concepts and development of
+lib/spack/spack/build_systems/intel.py .
+
+For documentation on how to *use* ``IntelPackage``, see
+lib/spack/docs/build_systems/intelpackage.rst .
+
+-------------------------------------------------------------------------------
+Installation and path handling as implemented in ./intel.py
+-------------------------------------------------------------------------------
+
+
+***************************************************************************
+Prefix differences between Spack-external and Spack-internal installations
+***************************************************************************
+
+
+Problem summary
+~~~~~~~~~~~~~~~~
+
+For Intel packages that were installed external to Spack, ``self.prefix`` will
+be a *component-specific* path (e.g. to an MKL-specific dir hierarchy), whereas
+for a package installed by Spack itself, ``self.prefix`` will be a
+*vendor-level* path that holds one or more components (or parts thereof), and
+must be further qualified down to a particular desired component.
+
+It is possible that a similar conceptual difference is inherent to other
+package families that use a common vendor-style installer.
+
+
+Description
+~~~~~~~~~~~~
+
+Spack makes packages available through two routes, let's call them A and B:
+
+A. Packages pre-installed external to Spack and configured *for* Spack
+B. Packages built and installed *by* Spack.
+
+For a user who is interested in building end-user applications, it should not
+matter through which route any of its dependent packages has been installed.
+Most packages natively support a ``prefix`` concept which unifies the two
+routes just fine.
+
+Intel packages, however, are more complicated because they consist of a number
+of components that are released as a suite of varying extent, like "Intel
+Parallel Studio *Foo* Edition", or subsetted into products like "MKL" or "MPI",
+each of which also contain libraries from other components like the compiler
+runtime and multithreading libraries. For this reason, an Intel package is
+"anchored" during installation at a directory level higher than just the
+user-facing directory that has the conventional hierarchy of ``bin``, ``lib``,
+and others relevant for the end-product.
+
+As a result, internal to Spack, there is a conceptual difference in what
+``self.prefix`` represents for the two routes.
+
+For route A, consider MKL installed outside of Spack. It will likely be one
+product component among other products, at one particular release among others
+that are installed in sibling or cousin directories on the local system.
+Therefore, the path given to Spack in ``packages.yaml`` should be a
+*product-specific and fully version-specific* directory. E.g., for an
+``intel-mkl`` package, ``self.prefix`` should look like::
+
+ /opt/intel/compilers_and_libraries_2018.1.163/linux/mkl
+
+In this route, the interaction point with the user is encapsulated in an
+environment variable which will be (in pseudo-code)::
+
+ MKLROOT := {self.prefix}
+
+For route B, a Spack-based installation of MKL will be placed in the directory
+given to the ``./install.sh`` script of Intel's package distribution. This
+directory is taken to be the *vendor*-specific anchor directory, playing the
+same role as the default ``/opt/intel``. In this case, ``self.prefix`` will
+be::
+
+ $SPACK_ROOT/opt/spack/linux-centos6-x86_64/gcc-4.9.3/intel-mkl-2018.1.163-<HASH>
+
+However, now the environment variable will have to be constructed as *several
+directory levels down*::
+
+ MKLROOT := {self.prefix}/compilers_and_libraries_2018.1.163/linux/mkl
+
+A recent post on the Spack mailing list illustrates the confusion when route A
+was taken while route B was the only one that was coded in Spack:
+https://groups.google.com/d/msg/spack/x28qlmqPAys/Ewx6220uAgAJ
+
+
+Solution
+~~~~~~~~~
+
+Introduce a series of functions which will return the appropriate
+directories, regardless of whether the Intel package has been installed
+external or internal to Spack:
+
+========================== ==================================================
+Function Example return values
+-------------------------- --------------------------------------------------
+normalize_suite_dir() Spack-external installation:
+ /opt/intel/compilers_and_libraries_2018.1.163
+ Spack-internal installation:
+ $SPACK_ROOT/...<HASH>/compilers_and_libraries_2018.1.163
+-------------------------- --------------------------------------------------
+normalize_path('mkl') <suite_dir>/linux/mkl
+component_bin_dir() <suite_dir>/linux/mkl/bin
+component_lib_dir() <suite_dir>/linux/mkl/lib/intel64
+-------------------------- --------------------------------------------------
+normalize_path('mpi') <suite_dir>/linux/mpi
+component_bin_dir('mpi') <suite_dir>/linux/mpi/intel64/bin
+component_lib_dir('mpi') <suite_dir>/linux/mpi/intel64/lib
+========================== ==================================================
+
+
+*********************************
+Analysis of directory layouts
+*********************************
+
+Let's look at some sample directory layouts, using ``ls -lF``,
+but focusing on names and symlinks only.
+
+Spack-born installation of ``intel-mkl@2018.1.163``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ $ ls -l <prefix>
+
+ bin/
+ - compilervars.*sh (symlinked) ONLY
+
+ compilers_and_libraries -> compilers_and_libraries_2018
+ - generically-named entry point, stable across versions (one hopes)
+
+ compilers_and_libraries_2018/
+ - vaguely-versioned dirname, holding a stub hierarchy --ignorable
+
+ $ ls -l compilers_and_libraries_2018/linux/
+ bin - actual compilervars.*sh (reg. files) ONLY
+ documentation -> ../../documentation_2018/
+ lib -> ../../compilers_and_libraries_2018.1.163/linux/compiler/lib/
+ mkl -> ../../compilers_and_libraries_2018.1.163/linux/mkl/
+ pkg_bin -> ../../compilers_and_libraries_2018.1.163/linux/bin/
+ samples -> ../../samples_2018/
+ tbb -> ../../compilers_and_libraries_2018.1.163/linux/tbb/
+
+ compilers_and_libraries_2018.1.163/
+ - Main "product" + a minimal set of libs from related products
+
+ $ ls -l compilers_and_libraries_2018.1.163/linux/
+ bin/ - compilervars.*sh, link_install*sh ONLY
+ mkl/ - Main Product ==> to be assigned to MKLROOT
+ compiler/ - lib/intel64_lin/libiomp5* ONLY
+ tbb/ - tbb/lib/intel64_lin/gcc4.[147]/libtbb*.so* ONLY
+
+ parallel_studio_xe_2018 -> parallel_studio_xe_2018.1.038/
+ parallel_studio_xe_2018.1.038/
+ - Alternate product packaging - ignorable
+
+ $ ls -l parallel_studio_xe_2018.1.038/
+ bin/ - actual psxevars.*sh (reg. files)
+ compilers_and_libraries_2018 -> <full_path>/comp...aries_2018.1.163
+ documentation_2018 -> <full_path_prefix>/documentation_2018
+ samples_2018 -> <full_path_prefix>/samples_2018
+ ...
+
+ documentation_2018/
+ samples_2018/
+ lib -> compilers_and_libraries/linux/lib/
+ mkl -> compilers_and_libraries/linux/mkl/
+ tbb -> compilers_and_libraries/linux/tbb/
+ - auxiliaries and convenience links
+
+Spack-external installation of Intel-MPI 2018
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For MPI, the layout is slightly different than MKL. The prefix will have to
+include an architecture directory (typically ``intel64``), which then contains
+bin/, lib/, ..., all without further architecture branching. The environment
+variable ``I_MPI_ROOT`` from the API documentation, however, must be the
+package's top directory, not including the architecture.
+
+FIXME: For MANPATH, need the parent dir.
+
+::
+
+ $ ls -lF /opt/intel/compilers_and_libraries_2018.1.163/linux/mpi/
+ bin64 -> intel64/bin/
+ etc64 -> intel64/etc/
+ include64 -> intel64/include/
+ lib64 -> intel64/lib/
+
+ benchmarks/
+ binding/
+ intel64/
+ man/
+ test/
+
+The package contains an MPI-2019 preview; Curiously, its release notes contain
+the tag: "File structure clean-up." I could not find further documentation on
+this, however, so it is unclear what, if any, changes will make it to release.
+
+https://software.intel.com/en-us/articles/restoring-legacy-path-structure-on-intel-mpi-library-2019
+
+::
+
+ $ ls -lF /opt/intel/compilers_and_libraries_2018.1.163/linux/mpi_2019/
+ binding/
+ doc/
+ imb/
+ intel64/
+ man/
+ test/
+
+Spack-external installation of Intel Parallel Studio 2018
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the main product bundle that I actually downloaded and installed on my
+system. Its nominal installation directory mostly holds merely symlinks
+to components installed in sibling dirs::
+
+ $ ls -lF /opt/intel/parallel_studio_xe_2018.1.038/
+ advisor_2018 -> /opt/intel/advisor_2018/
+ clck_2018 -> /opt/intel/clck/2018.1/
+ compilers_and_libraries_2018 -> /opt/intel/comp....aries_2018.1.163/
+ documentation_2018 -> /opt/intel/documentation_2018/
+ ide_support_2018 -> /opt/intel/ide_support_2018/
+ inspector_2018 -> /opt/intel/inspector_2018/
+ itac_2018 -> /opt/intel/itac/2018.1.017/
+ man -> /opt/intel/man/
+ samples_2018 -> /opt/intel/samples_2018/
+ vtune_amplifier_2018 -> /opt/intel/vtune_amplifier_2018/
+
+ psxevars.csh -> ./bin/psxevars.csh*
+ psxevars.sh -> ./bin/psxevars.sh*
+ bin/ - *vars.*sh scripts + sshconnectivity.exp ONLY
+
+ licensing/
+ uninstall*
+
+The only relevant regular files are ``*vars.*sh``, but those also just churn
+through the subordinate vars files of the components.
+
+Installation model
+~~~~~~~~~~~~~~~~~~~~
+
+Intel packages come with an ``install.sh`` script that is normally run
+interactively (in either text or GUI mode) but can run unattended with a
+``--silent <file>`` option, which is of course what Spack uses.
+
+Format of configuration file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The configuration file is conventionally called ``silent.cfg`` and has a simple
+``token=value`` syntax. Before using the configuration file, the installer
+calls ``<staging_dir>/pset/check.awk`` to validate it. Example paths to the
+validator are::
+
+ .../l_mkl_2018.1.163/pset/check.awk .
+ .../parallel_studio_xe_2018_update1_cluster_edition/pset/check.awk
+
+The tokens that are accepted in the configuration file vary between packages.
+Tokens not supported for a given package **will cause the installer to stop
+and fail.** This is particularly relevant for license-related tokens, which are
+accepted only for packages that actually require a license.
+
+Reference: [Intel's documentation](https://software.intel.com/en-us/articles/configuration-file-format)
+
+See also: https://software.intel.com/en-us/articles/silent-installation-guide-for-intel-parallel-studio-xe-composer-edition-for-os-x
+
+The following is from ``.../parallel_studio_xe_2018_update1_cluster_edition/pset/check.awk``:
+
+* Tokens valid for all packages encountered::
+
+ ACCEPT_EULA {accept, decline}
+ CONTINUE_WITH_OPTIONAL_ERROR {yes, no}
+ PSET_INSTALL_DIR {/opt/intel, , filepat}
+ CONTINUE_WITH_INSTALLDIR_OVERWRITE {yes, no}
+ COMPONENTS {ALL, DEFAULTS, , anythingpat}
+ PSET_MODE {install, repair, uninstall}
+ NONRPM_DB_DIR {, filepat}
+
+ SIGNING_ENABLED {yes, no}
+ ARCH_SELECTED {IA32, INTEL64, ALL}
+
+* Mentioned but unexplained in ``check.awk``::
+
+ NO_VALIDATE (?!)
+
+* Only for licensed packages::
+
+ ACTIVATION_SERIAL_NUMBER {, snpat}
+ ACTIVATION_LICENSE_FILE {, lspat, filepat}
+ ACTIVATION_TYPE {exist_lic, license_server,
+ license_file, trial_lic,
+
+ PHONEHOME_SEND_USAGE_DATA {yes, no}
+ serial_number}
+
+* Only for Amplifier (obviously)::
+
+ AMPLIFIER_SAMPLING_DRIVER_INSTALL_TYPE {build, kit}
+ AMPLIFIER_DRIVER_ACCESS_GROUP {, anythingpat, vtune}
+ AMPLIFIER_DRIVER_PERMISSIONS {, anythingpat, 666}
+ AMPLIFIER_LOAD_DRIVER {yes, no}
+ AMPLIFIER_C_COMPILER {, filepat, auto, none}
+ AMPLIFIER_KERNEL_SRC_DIR {, filepat, auto, none}
+ AMPLIFIER_MAKE_COMMAND {, filepat, auto, none}
+ AMPLIFIER_INSTALL_BOOT_SCRIPT {yes, no}
+ AMPLIFIER_DRIVER_PER_USER_MODE {yes, no}
+
+* Only for MKL and Studio::
+
+ CLUSTER_INSTALL_REMOTE {yes, no}
+ CLUSTER_INSTALL_TEMP {, filepat}
+ CLUSTER_INSTALL_MACHINES_FILE {, filepat}
+
+* "backward compatibility" (?)::
+
+ INSTALL_MODE {RPM, NONRPM}
+ download_only {yes}
+ download_dir {, filepat}
+
+
+Details for licensing tokens
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Quoted from
+https://software.intel.com/en-us/articles/configuration-file-format,
+for reference:
+
+[ed. note: As of 2018-05, the page incorrectly references ``ACTIVATION``, which
+was used only until about 2012; this is corrected to ``ACTIVATION_TYPE`` here.]
+
+ ...
+
+ ``ACTIVATION_TYPE=exist_lic``
+ This directive tells the install program to look for an existing
+ license during the install process. This is the preferred method for
+ silent installs. Take the time to register your serial number and get
+ a license file (see below). Having a license file on the system
+ simplifies the process. In addition, as an administrator it is good
+ practice to know WHERE your licenses are saved on your system.
+ License files are plain text files with a .lic extension. By default
+ these are saved in /opt/intel/licenses which is searched by default.
+ If you save your license elsewhere, perhaps under an NFS folder, set
+ environment variable **INTEL_LICENSE_FILE** to the full path to your
+ license file prior to starting the installation or use the
+ configuration file directive ``ACTIVATION_LICENSE_FILE`` to specify the
+ full pathname to the license file.
+
+ Options for ``ACTIVATION_TYPE`` are ``{ exist_lic, license_file, server_lic,
+ serial_number, trial_lic }``
+
+ ``exist_lic``
+ directs the installer to search for a valid license on the server.
+ Searches will utilize the environment variable **INTEL_LICENSE_FILE**,
+ search the default license directory /opt/intel/licenses, or use the
+ ``ACTIVATION_LICENSE_FILE`` directive to find a valid license file.
+
+ ``license_file``
+ is similar to exist_lic but directs the installer to use
+ ``ACTIVATION_LICENSE_FILE`` to find the license file.
+
+ ``server_lic``
+ is similar to exist_lic and exist_lic but directs the installer that
+ this is a client installation and a floating license server will be
+ contacted to active the product. This option will contact your
+ floating license server on your network to retrieve the license
+ information. BEFORE using this option make sure your client is
+ correctly set up for your network including all networking, routing,
+ name service, and firewall configuration. Insure that your client has
+ direct access to your floating license server and that firewalls are
+ set up to allow TCP/IP access for the 2 license server ports.
+ server_lic will use **INTEL_LICENSE_FILE** containing a port@host format
+ OR a client license file. The formats for these are described here
+ https://software.intel.com/en-us/articles/licensing-setting-up-the-client-floating-license
+
+ ``serial_number``
+ directs the installer to use directive ``ACTIVATION_SERIAL_NUMBER`` for
+ activation. This method will require the installer to contact an
+ external Intel activation server over the Internet to confirm your
+ serial number. Due to user and company firewalls, this method is more
+ complex and hence error prone of the available activation methods. We
+ highly recommend using a license file or license server for activation
+ instead.
+
+ ``trial_lic``
+ is used only if you do not have an existing license and intend to
+ temporarily evaluate the compiler. This method creates a temporary
+ trial license in Trusted Storage on your system.
+
+ ...
+
+*******************
+vars files
+*******************
+
+Intel's product packages contain a number of shell initialization files let's call them vars files.
+
+There are three kinds:
+
+#. Component-specific vars files, such as `mklvars` or `tbbvars`.
+#. Toplevel vars files such as "psxevars". They will scan for all
+ component-specific vars files associated with the product, and source them
+ if found.
+#. Symbolic links to either of them. Links may appear under a different name
+ for backward compatibility.
+
+At present, IntelPackage class is only concerned with the toplevel vars files,
+generally found in the product's toplevel bin/ directory.
+
+For reference, here is an overview of the names and locations of the vars files
+in the 2018 product releases, as seen for Spack-native installation. NB: May be
+incomplete as some components may have been omitted during installation.
+
+Names of vars files seen::
+
+ $ cd opt/spack/linux-centos6-x86_64
+ $ find intel* -name \*vars.sh -printf '%f\n' | sort -u | nl
+ 1 advixe-vars.sh
+ 2 amplxe-vars.sh
+ 3 apsvars.sh
+ 4 compilervars.sh
+ 5 daalvars.sh
+ 6 debuggervars.sh
+ 7 iccvars.sh
+ 8 ifortvars.sh
+ 9 inspxe-vars.sh
+ 10 ippvars.sh
+ 11 mklvars.sh
+ 12 mpivars.sh
+ 13 pstlvars.sh
+ 14 psxevars.sh
+ 15 sep_vars.sh
+ 16 tbbvars.sh
+
+Names and locations of vars files, sorted by Spack package name::
+
+ $ cd opt/spack/linux-centos6-x86_64
+ $ find intel* -name \*vars.sh -printf '%y\t%-15f\t%h\n' \
+ | cut -d/ -f1,4- \
+ | sed '/iccvars\|ifortvars/d; s,/,\t\t,; s,\.sh,,; s, */\(intel[/-]\),\1,' \
+ | sort -k3,3 -k2,2 \
+ | nl \
+ | awk '{printf "%6i %-2s %-16s %-24s %s\n", $1, $2, $3, $4, $5}'
+
+ --------------------------------------------------------------------------------------------------------
+ item no.
+ file or link
+ name of vars file
+ Spack package name
+ dir relative to Spack install dir
+ --------------------------------------------------------------------------------------------------------
+
+ 1 f mpivars intel compilers_and_libraries_2018.1.163/linux/mpi/intel64/bin
+ 2 f mpivars intel compilers_and_libraries_2018.1.163/linux/mpirt/bin/ia32_lin
+ 3 f tbbvars intel compilers_and_libraries_2018.1.163/linux/tbb/bin
+ 4 f pstlvars intel compilers_and_libraries_2018.1.163/linux/pstl/bin
+ 5 f compilervars intel compilers_and_libraries_2018.1.163/linux/bin
+ 6 f compilervars intel compilers_and_libraries_2018/linux/bin
+ 7 l compilervars intel bin
+ 8 f daalvars intel-daal compilers_and_libraries_2018.2.199/linux/daal/bin
+ 9 f psxevars intel-daal parallel_studio_xe_2018.2.046/bin
+ 10 l psxevars intel-daal parallel_studio_xe_2018.2.046
+ 11 f compilervars intel-daal compilers_and_libraries_2018.2.199/linux/bin
+ 12 f compilervars intel-daal compilers_and_libraries_2018/linux/bin
+ 13 l compilervars intel-daal bin
+ 14 f ippvars intel-ipp compilers_and_libraries_2018.2.199/linux/ipp/bin
+ 15 f psxevars intel-ipp parallel_studio_xe_2018.2.046/bin
+ 16 l psxevars intel-ipp parallel_studio_xe_2018.2.046
+ 17 f compilervars intel-ipp compilers_and_libraries_2018.2.199/linux/bin
+ 18 f compilervars intel-ipp compilers_and_libraries_2018/linux/bin
+ 19 l compilervars intel-ipp bin
+ 20 f mklvars intel-mkl compilers_and_libraries_2018.2.199/linux/mkl/bin
+ 21 f psxevars intel-mkl parallel_studio_xe_2018.2.046/bin
+ 22 l psxevars intel-mkl parallel_studio_xe_2018.2.046
+ 23 f compilervars intel-mkl compilers_and_libraries_2018.2.199/linux/bin
+ 24 f compilervars intel-mkl compilers_and_libraries_2018/linux/bin
+ 25 l compilervars intel-mkl bin
+ 26 f mpivars intel-mpi compilers_and_libraries_2018.2.199/linux/mpi_2019/intel64/bin
+ 27 f mpivars intel-mpi compilers_and_libraries_2018.2.199/linux/mpi/intel64/bin
+ 28 f psxevars intel-mpi parallel_studio_xe_2018.2.046/bin
+ 29 l psxevars intel-mpi parallel_studio_xe_2018.2.046
+ 30 f compilervars intel-mpi compilers_and_libraries_2018.2.199/linux/bin
+ 31 f compilervars intel-mpi compilers_and_libraries_2018/linux/bin
+ 32 l compilervars intel-mpi bin
+ 33 f apsvars intel-parallel-studio vtune_amplifier_2018.1.0.535340
+ 34 l apsvars intel-parallel-studio performance_snapshots_2018.1.0.535340
+ 35 f ippvars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/ipp/bin
+ 36 f ippvars intel-parallel-studio composer_xe_2015.6.233/ipp/bin
+ 37 f mklvars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/mkl/bin
+ 38 f mklvars intel-parallel-studio composer_xe_2015.6.233/mkl/bin
+ 39 f mpivars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/mpi/intel64/bin
+ 40 f mpivars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/mpirt/bin/ia32_lin
+ 41 f tbbvars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/tbb/bin
+ 42 f tbbvars intel-parallel-studio composer_xe_2015.6.233/tbb/bin
+ 43 f daalvars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/daal/bin
+ 44 f pstlvars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/pstl/bin
+ 45 f psxevars intel-parallel-studio parallel_studio_xe_2018.1.038/bin
+ 46 l psxevars intel-parallel-studio parallel_studio_xe_2018.1.038
+ 47 f sep_vars intel-parallel-studio vtune_amplifier_2018.1.0.535340
+ 48 f sep_vars intel-parallel-studio vtune_amplifier_2018.1.0.535340/target/android_v4.1_x86_64
+ 49 f advixe-vars intel-parallel-studio advisor_2018.1.1.535164
+ 50 f amplxe-vars intel-parallel-studio vtune_amplifier_2018.1.0.535340
+ 51 f inspxe-vars intel-parallel-studio inspector_2018.1.1.535159
+ 52 f compilervars intel-parallel-studio compilers_and_libraries_2018.1.163/linux/bin
+ 53 f compilervars intel-parallel-studio compilers_and_libraries_2018/linux/bin
+ 54 l compilervars intel-parallel-studio bin
+ 55 f debuggervars intel-parallel-studio debugger_2018/bin
+
+
+********************
+MPI linkage
+********************
+
+
+Library selection
+~~~~~~~~~~~~~~~~~~~~~
+
+In the Spack code so far, the library selections for MPI are:
+
+::
+
+ libnames = ['libmpifort', 'libmpi']
+ if 'cxx' in self.spec.last_query.extra_parameters:
+ libnames = ['libmpicxx'] + libnames
+ return find_libraries(libnames,
+ root=self.component_lib_dir('mpi'),
+ shared=True, recursive=False)
+
+The problem is that there are multiple library versions under ``component_lib_dir``::
+
+ $ cd $I_MPI_ROOT
+ $ find . -name libmpi.so | sort
+ ./intel64/lib/debug/libmpi.so
+ ./intel64/lib/debug_mt/libmpi.so
+ ./intel64/lib/libmpi.so
+ ./intel64/lib/release/libmpi.so
+ ./intel64/lib/release_mt/libmpi.so
+
+"mt" refers to multi-threading, not in the explicit sense but in the sense of being thread-safe::
+
+ $ mpiifort -help | grep mt
+ -mt_mpi link the thread safe version of the Intel(R) MPI Library
+
+Well, why should we not inspect what the canonical script does? The wrapper
+has its own hardcoded "prefix=..." and can thus tell us what it will do, from a
+*wiped environment* no less!::
+
+ $ env - intel64/bin/mpiicc -show hello.c | ld-unwrap-args
+ icc 'hello.c' \
+ -I/opt/intel/compilers_and_libraries_2018.1.163/linux/mpi/intel64/include \
+ -L/opt/intel/compilers_and_libraries_2018.1.163/linux/mpi/intel64/lib/release_mt \
+ -L/opt/intel/compilers_and_libraries_2018.1.163/linux/mpi/intel64/lib \
+ -Xlinker --enable-new-dtags \
+ -Xlinker -rpath=/opt/intel/compilers_and_libraries_2018.1.163/linux/mpi/intel64/lib/release_mt \
+ -Xlinker -rpath=/opt/intel/compilers_and_libraries_2018.1.163/linux/mpi/intel64/lib \
+ -Xlinker -rpath=/opt/intel/mpi-rt/2017.0.0/intel64/lib/release_mt \
+ -Xlinker -rpath=/opt/intel/mpi-rt/2017.0.0/intel64/lib \
+ -lmpifort \
+ -lmpi \
+ -lmpigi \
+ -ldl \
+ -lrt \
+ -lpthread
+
+
+MPI Wrapper options
+~~~~~~~~~~~~~~~~~~~~~
+
+For reference, here's the wrapper's builtin help output::
+
+ $ mpiifort -help
+ Simple script to compile and/or link MPI programs.
+ Usage: mpiifort [options] <files>
+ ----------------------------------------------------------------------------
+ The following options are supported:
+ -fc=<name> | -f90=<name>
+ specify a FORTRAN compiler name: i.e. -fc=ifort
+ -echo print the scripts during their execution
+ -show show command lines without real calling
+ -config=<name> specify a configuration file: i.e. -config=ifort for mpif90-ifort.conf file
+ -v print version info of mpiifort and its native compiler
+ -profile=<name> specify a profile configuration file (an MPI profiling
+ library): i.e. -profile=myprofile for the myprofile.cfg file.
+ As a special case, lib<name>.so or lib<name>.a may be used
+ if the library is found
+ -check_mpi link against the Intel(R) Trace Collector (-profile=vtmc).
+ -static_mpi link the Intel(R) MPI Library statically
+ -mt_mpi link the thread safe version of the Intel(R) MPI Library
+ -ilp64 link the ILP64 support of the Intel(R) MPI Library
+ -no_ilp64 disable ILP64 support explicitly
+ -fast the same as -static_mpi + pass -fast option to a compiler.
+ -t or -trace
+ link against the Intel(R) Trace Collector
+ -trace-imbalance
+ link against the Intel(R) Trace Collector imbalance library
+ (-profile=vtim)
+ -dynamic_log link against the Intel(R) Trace Collector dynamically
+ -static use static linkage method
+ -nostrip turn off the debug information stripping during static linking
+ -O enable optimization
+ -link_mpi=<name>
+ link against the specified version of the Intel(R) MPI Library
+ All other options will be passed to the compiler without changing.
+ ----------------------------------------------------------------------------
+ The following environment variables are used:
+ I_MPI_ROOT the Intel(R) MPI Library installation directory path
+ I_MPI_F90 or MPICH_F90
+ the path/name of the underlying compiler to be used
+ I_MPI_FC_PROFILE or I_MPI_F90_PROFILE or MPIF90_PROFILE
+ the name of profile file (without extension)
+ I_MPI_COMPILER_CONFIG_DIR
+ the folder which contains configuration files *.conf
+ I_MPI_TRACE_PROFILE
+ specify a default profile for the -trace option
+ I_MPI_CHECK_PROFILE
+ specify a default profile for the -check_mpi option
+ I_MPI_CHECK_COMPILER
+ enable compiler setup checks
+ I_MPI_LINK specify the version of the Intel(R) MPI Library
+ I_MPI_DEBUG_INFO_STRIP
+ turn on/off the debug information stripping during static linking
+ I_MPI_FCFLAGS
+ special flags needed for compilation
+ I_MPI_LDFLAGS
+ special flags needed for linking
+ ----------------------------------------------------------------------------
+
+
+Side Note: MPI version divergence in 2015 release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The package `intel-parallel-studio@cluster.2015.6` contains both a full MPI
+development version in `$prefix/impi` and an MPI Runtime under the
+`composer_xe*` suite directory. Curiously, these have *different versions*,
+with a release date nearly 1 year apart::
+
+ $ $SPACK_ROOT/...uaxaw7/impi/5.0.3.049/intel64/bin/mpiexec --version
+ Intel(R) MPI Library for Linux* OS, Version 5.0 Update 3 Build 20150804 (build id: 12452)
+ Copyright (C) 2003-2015, Intel Corporation. All rights reserved.
+
+ $ $SPACK_ROOT/...uaxaw7/composer_xe_2015.6.233/mpirt/bin/intel64/mpiexec --version
+ Intel(R) MPI Library for Linux* OS, Version 5.0 Update 1 Build 20140709
+ Copyright (C) 2003-2014, Intel Corporation. All rights reserved.
+
+I'm not sure what to make of it.
+
+
+**************
+macOS support
+**************
+
+- On macOS, the Spack methods here only include support to integrate an
+ externally installed MKL.
+
+- URLs in child packages will be Linux-specific; macOS download packages
+ are located in differently numbered dirs and are named m_*.dmg.
diff --git a/lib/spack/spack/build_systems/__init__.py b/lib/spack/spack/build_systems/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/spack/build_systems/__init__.py
+++ b/lib/spack/spack/build_systems/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/spack/build_systems/aspell_dict.py b/lib/spack/spack/build_systems/aspell_dict.py
index edf9bdb5da..437983e8a7 100644
--- a/lib/spack/spack/build_systems/aspell_dict.py
+++ b/lib/spack/spack/build_systems/aspell_dict.py
@@ -1,32 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
# Why doesn't this work for me?
# from spack import *
from llnl.util.filesystem import filter_file
from spack.build_systems.autotools import AutotoolsPackage
from spack.directives import extends
+from spack.package import ExtensionError
from spack.util.executable import which
@@ -38,10 +20,21 @@ from spack.util.executable import which
# They aren't really an Autotools package, but it's close enough
# that this works if we override configure().
class AspellDictPackage(AutotoolsPackage):
- """Specialized class for builing aspell dictionairies."""
+ """Specialized class for building aspell dictionairies."""
extends('aspell')
+ def view_destination(self, view):
+ aspell_spec = self.spec['aspell']
+ if view.root != aspell_spec.prefix:
+ raise ExtensionError(
+ 'aspell does not support non-global extensions')
+ aspell = aspell_spec.command
+ return aspell('dump', 'config', 'dict-dir', output=str).strip()
+
+ def view_source(self):
+ return self.prefix.lib
+
def patch(self):
filter_file(r'^dictdir=.*$', 'dictdir=/lib', 'configure')
filter_file(r'^datadir=.*$', 'datadir=/lib', 'configure')
diff --git a/lib/spack/spack/build_systems/autotools.py b/lib/spack/spack/build_systems/autotools.py
index 01a59feeba..a26c7f56bb 100644
--- a/lib/spack/spack/build_systems/autotools.py
+++ b/lib/spack/spack/build_systems/autotools.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
import os
@@ -32,7 +13,7 @@ from subprocess import PIPE
from subprocess import check_call
import llnl.util.tty as tty
-from llnl.util.filesystem import working_dir, join_path, force_remove
+from llnl.util.filesystem import working_dir, force_remove
from spack.package import PackageBase, run_after, run_before
from spack.util.executable import Executable
@@ -94,15 +75,20 @@ class AutotoolsPackage(PackageBase):
#: Options to be passed to autoreconf when using the default implementation
autoreconf_extra_args = []
+ @property
+ def archive_files(self):
+ """Files to archive for packages based on autotools"""
+ return [os.path.join(self.build_directory, 'config.log')]
+
@run_after('autoreconf')
def _do_patch_config_guess(self):
"""Some packages ship with an older config.guess and need to have
this updated when installed on a newer architecture. In particular,
config.guess fails for PPC64LE for version prior to a 2013-06-10
- build date (automake 1.13.4)."""
+ build date (automake 1.13.4) and for ARM (aarch64)."""
- if not self.patch_config_guess or not self.spec.satisfies(
- 'target=ppc64le'
+ if not self.patch_config_guess or (not self.spec.satisfies(
+ 'target=ppc64le') and not self.spec.satisfies('target=aarch64')
):
return
my_config_guess = None
@@ -172,7 +158,7 @@ class AutotoolsPackage(PackageBase):
@property
def configure_abs_path(self):
# Absolute path to configure
- configure_abs_path = join_path(
+ configure_abs_path = os.path.join(
os.path.abspath(self.configure_directory), 'configure'
)
return configure_abs_path
@@ -212,10 +198,10 @@ class AutotoolsPackage(PackageBase):
# This line is what is needed most of the time
# --install, --verbose, --force
autoreconf_args = ['-ivf']
- if 'pkg-config' in spec:
+ if 'pkgconfig' in spec:
autoreconf_args += [
'-I',
- join_path(spec['pkg-config'].prefix, 'share', 'aclocal'),
+ os.path.join(spec['pkgconfig'].prefix, 'share', 'aclocal'),
]
autoreconf_args += self.autoreconf_extra_args
m.autoreconf(*autoreconf_args)
diff --git a/lib/spack/spack/build_systems/cmake.py b/lib/spack/spack/build_systems/cmake.py
index 13c752eb2e..6f46643f83 100644
--- a/lib/spack/spack/build_systems/cmake.py
+++ b/lib/spack/spack/build_systems/cmake.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
import os
import platform
import spack.build_environment
-from llnl.util.filesystem import working_dir, join_path
+from llnl.util.filesystem import working_dir
from spack.util.environment import filter_system_paths
from spack.directives import depends_on, variant
from spack.package import PackageBase, InstallError, run_after
@@ -91,6 +72,11 @@ class CMakePackage(PackageBase):
depends_on('cmake', type='build')
@property
+ def archive_files(self):
+ """Files to archive for packages based on CMake"""
+ return [os.path.join(self.build_directory, 'CMakeCache.txt')]
+
+ @property
def root_cmakelists_dir(self):
"""The relative path to the directory containing CMakeLists.txt
@@ -142,11 +128,14 @@ class CMakePackage(PackageBase):
]
if platform.mac_ver()[0]:
- args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST')
+ args.extend([
+ '-DCMAKE_FIND_FRAMEWORK:STRING=LAST',
+ '-DCMAKE_FIND_APPBUNDLE:STRING=LAST'
+ ])
# Set up CMake rpath
args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE')
- rpaths = ':'.join(spack.build_environment.get_rpaths(pkg))
+ rpaths = ';'.join(spack.build_environment.get_rpaths(pkg))
args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths))
# CMake's find_package() looks in CMAKE_PREFIX_PATH first, help CMake
# to find immediate link dependencies in right places:
@@ -200,7 +189,7 @@ class CMakePackage(PackageBase):
:return: directory where to build the package
"""
- return join_path(self.stage.source_path, 'spack-build')
+ return os.path.join(self.stage.source_path, 'spack-build')
def cmake_args(self):
"""Produces a list containing all the arguments that must be passed to
@@ -247,9 +236,13 @@ class CMakePackage(PackageBase):
"""
with working_dir(self.build_directory):
if self.generator == 'Unix Makefiles':
- self._if_make_target_execute('test')
+ self._if_make_target_execute('test',
+ jobs_env='CTEST_PARALLEL_LEVEL')
+ self._if_make_target_execute('check')
elif self.generator == 'Ninja':
- self._if_ninja_target_execute('test')
+ self._if_ninja_target_execute('test',
+ jobs_env='CTEST_PARALLEL_LEVEL')
+ self._if_ninja_target_execute('check')
# Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix)
diff --git a/lib/spack/spack/build_systems/cuda.py b/lib/spack/spack/build_systems/cuda.py
new file mode 100644
index 0000000000..2e395fe9dd
--- /dev/null
+++ b/lib/spack/spack/build_systems/cuda.py
@@ -0,0 +1,72 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.package import PackageBase
+from spack.directives import depends_on, variant, conflicts
+import platform
+
+
+class CudaPackage(PackageBase):
+ """Auxiliary class which contains CUDA variant, dependencies and conflicts
+ and is meant to unify and facilitate its usage.
+ """
+
+ # FIXME: keep cuda and cuda_arch separate to make usage easier untill
+ # Spack has depends_on(cuda, when='cuda_arch!=None') or alike
+ variant('cuda', default=False,
+ description='Build with CUDA')
+ # see http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#gpu-feature-list
+ # https://developer.nvidia.com/cuda-gpus
+ variant('cuda_arch', default=None,
+ description='CUDA architecture',
+ values=('20', '30', '32', '35', '50', '52', '53', '60', '61',
+ '62', '70'),
+ multi=True)
+
+ # see http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#nvcc-examples
+ # and http://llvm.org/docs/CompileCudaWithLLVM.html#compiling-cuda-code
+ @staticmethod
+ def cuda_flags(arch_list):
+ return [('--generate-code arch=compute_{0},code=sm_{0} '
+ '--generate-code arch=compute_{0},code=compute_{0}').format(s)
+ for s in arch_list]
+
+ depends_on("cuda@7:", when='+cuda')
+
+ # CUDA version vs Architecture
+ depends_on("cuda@8:", when='cuda_arch=60')
+ depends_on("cuda@8:", when='cuda_arch=61')
+ depends_on("cuda@8:", when='cuda_arch=62')
+ depends_on("cuda@9:", when='cuda_arch=70')
+
+ depends_on('cuda@:8', when='cuda_arch=20')
+
+ # Compiler conflicts:
+ # https://gist.github.com/ax3l/9489132
+ conflicts('%gcc@5:', when='+cuda ^cuda@:7.5')
+ conflicts('%gcc@6:', when='+cuda ^cuda@:8')
+ conflicts('%gcc@7:', when='+cuda ^cuda@:9.1')
+ conflicts('%gcc@8:', when='+cuda ^cuda@:9.99')
+ if (platform.system() != "Darwin"):
+ conflicts('%clang@:3.4,3.7:', when='+cuda ^cuda@7.5')
+ conflicts('%clang@:3.7,4:', when='+cuda ^cuda@8:9.0')
+ conflicts('%clang@:3.7,5:', when='+cuda ^cuda@9.1')
+ conflicts('%clang@:3.7,6:', when='+cuda ^cuda@9.2')
+ conflicts('%intel@:14,16:', when='+cuda ^cuda@7.5')
+ conflicts('%intel@:14,17:', when='+cuda ^cuda@8.0.44')
+ conflicts('%intel@:14,18:', when='+cuda ^cuda@8.0.61:9')
+
+ # Make sure cuda_arch can not be used without +cuda
+ conflicts('~cuda', when='cuda_arch=20')
+ conflicts('~cuda', when='cuda_arch=30')
+ conflicts('~cuda', when='cuda_arch=32')
+ conflicts('~cuda', when='cuda_arch=35')
+ conflicts('~cuda', when='cuda_arch=50')
+ conflicts('~cuda', when='cuda_arch=52')
+ conflicts('~cuda', when='cuda_arch=53')
+ conflicts('~cuda', when='cuda_arch=60')
+ conflicts('~cuda', when='cuda_arch=61')
+ conflicts('~cuda', when='cuda_arch=62')
+ conflicts('~cuda', when='cuda_arch=70')
diff --git a/lib/spack/spack/build_systems/intel.py b/lib/spack/spack/build_systems/intel.py
index d9ad0da2fa..fcab73e0a1 100644
--- a/lib/spack/spack/build_systems/intel.py
+++ b/lib/spack/spack/build_systems/intel.py
@@ -1,45 +1,83 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the LICENSE file for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
+import sys
+import glob
+import tempfile
+import re
+import inspect
import xml.etree.ElementTree as ET
+import llnl.util.tty as tty
+
+from llnl.util.filesystem import \
+ install, ancestor, filter_file, \
+ HeaderList, find_headers, \
+ LibraryList, find_libraries, find_system_libraries
-from llnl.util.filesystem import install, join_path
-from spack.package import PackageBase, run_after
+from spack.version import Version, ver
+from spack.package import PackageBase, run_after, InstallError
+from spack.util.environment import EnvironmentModifications
from spack.util.executable import Executable
+from spack.util.prefix import Prefix
+from spack.build_environment import dso_suffix
+
+
+# A couple of utility functions that might be useful in general. If so, they
+# should really be defined elsewhere, unless deemed heretical.
+# (Or na"ive on my part).
+
+def debug_print(msg, *args):
+ '''Prints a message (usu. a variable) and the callers' names for a couple
+ of stack frames.
+ '''
+ # https://docs.python.org/2/library/inspect.html#the-interpreter-stack
+ stack = inspect.stack()
+ _func_name = 3
+ tty.debug("%s.%s:\t%s" % (stack[2][_func_name], stack[1][_func_name], msg),
+ *args)
+
+
+def raise_lib_error(*args):
+ '''Bails out with an error message. Shows args after the first as one per
+ line, tab-indented, useful for long paths to line up and stand out.
+ '''
+ raise InstallError("\n\t".join(str(i) for i in args))
+
+
+def _expand_fields(s):
+ '''[Experimental] Expand arch-related fields in a string, typically a
+ filename.
+ Supported fields and their typical expansions are::
-def _valid_components():
- """A generator that yields valid components."""
+ {platform} linux, mac
+ {arch} intel64 (including on Mac)
+ {libarch} intel64, empty on Mac
+ {bits} 64
- tree = ET.parse('pset/mediaconfig.xml')
- root = tree.getroot()
+ '''
+ # Python-native string formatting requires arg list counts to match the
+ # replacement field count; optional fields are far easier with regexes.
- components = root.findall('.//Abbr')
- for component in components:
- yield component.text
+ _bits = '64'
+ _arch = 'intel64' # TBD: ia32
+
+ if 'linux' in sys.platform: # NB: linux2 vs. linux
+ s = re.sub('{platform}', 'linux', s)
+ s = re.sub('{libarch}', _arch, s)
+ elif 'darwin' in sys.platform:
+ s = re.sub('{platform}', 'mac', s)
+ s = re.sub('{libarch}', '', s) # no arch dirs are used (as of 2018)
+ # elif 'win' in sys.platform: # TBD
+ # s = re.sub('{platform}', 'windows', s)
+
+ s = re.sub('{arch}', _arch, s)
+ s = re.sub('{bits}', _bits, s)
+ return s
class IntelPackage(PackageBase):
@@ -51,7 +89,7 @@ class IntelPackage(PackageBase):
2. :py:meth:`~.IntelPackage.install`
They both have sensible defaults and for many packages the
- only thing necessary will be to override ``setup_environment``
+ only thing necessary will be to override setup_environment
to set the appropriate environment variables.
"""
#: Phases of an Intel package
@@ -61,15 +99,31 @@ class IntelPackage(PackageBase):
#: system base class
build_system_class = 'IntelPackage'
- #: By default, we assume that all Intel software requires a license.
- #: This can be overridden for packages that do not require a license.
- license_required = True
+ #: A dict that maps Spack version specs to release years, needed to infer
+ #: the installation directory layout for pre-2016 versions in the family of
+ #: Intel packages.
+ #
+ # Like any property, it can be overridden in client packages, should older
+ # versions ever be added there. The initial dict here contains the
+ # packages defined in Spack as of 2018-04. Keys could conceivably overlap
+ # but preferably should not - only the first key in hash traversal order
+ # that satisfies self.spec will be used.
+ version_years = {
+ # intel-daal is versioned 2016 and later, no divining is needed
+ 'intel-ipp@9.0:9.99': 2016,
+ 'intel-mkl@11.3.0:11.3.999': 2016,
+ 'intel-mpi@5.1:5.99': 2016,
+ }
- #: Comment symbol used in the ``license.lic`` file
- license_comment = '#'
+ @property
+ def license_required(self):
+ # The Intel libraries are provided without requiring a license as of
+ # version 2017.2. Trying to specify one anyway will fail. See:
+ # https://software.intel.com/en-us/articles/free-ipsxe-tools-and-libraries
+ return self._has_compilers or self.version < ver('2017.2')
- #: Location where Intel searches for a license file
- license_files = ['Licenses/license.lic']
+ #: Comment symbol used in the license.lic file
+ license_comment = '#'
#: Environment variables that Intel searches for a license file
license_vars = ['INTEL_LICENSE_FILE']
@@ -77,116 +131,1115 @@ class IntelPackage(PackageBase):
#: URL providing information on how to acquire a license key
license_url = 'https://software.intel.com/en-us/articles/intel-license-manager-faq'
- #: Components of the package to install.
- #: By default, install 'ALL' components.
- components = ['ALL']
+ #: Location where Intel searches for a license file
+ @property
+ def license_files(self):
+ dirs = ['Licenses']
+
+ if self._has_compilers:
+ dirs.append(self.component_bin_dir('compiler'))
+
+ for variant, component_suite_dir in {
+ '+advisor': 'advisor',
+ '+inspector': 'inspector',
+ '+itac': 'itac',
+ '+vtune': 'vtune_amplifier',
+ }.items():
+ if variant in self.spec:
+ dirs.append(self.normalize_path(
+ 'licenses', component_suite_dir, relative=True))
+ files = [os.path.join(d, 'license.lic') for d in dirs]
+ return files
+
+ #: Components to install (list of name patterns from pset/mediaconfig.xml)
+ # NB: Renamed from plain components() for coding and maintainability.
@property
- def _filtered_components(self):
- """Returns a list or set of valid components that match
- the requested components from ``components``."""
+ def pset_components(self):
+ # Do not detail single-purpose client packages.
+ if not self._has_compilers:
+ return ['ALL']
+
+ # tty.warn('DEBUG: installing ALL components')
+ # return ['ALL']
- # Don't filter 'ALL'
- if self.components == ['ALL']:
- return self.components
+ # Always include compilers and closely related components.
+ # Pre-2016 compiler components have different names - throw in all.
+ # Later releases have overlapping minor parts that differ by "edition".
+ # NB: The spack package 'intel' is a subset of
+ # 'intel-parallel-studio@composer' without the lib variants.
+ c = ' intel-icc intel-ifort' \
+ ' intel-ccomp intel-fcomp intel-comp-' \
+ ' intel-compilerproc intel-compilerprof intel-compilerpro-' \
+ ' intel-psxe intel-openmp'
+
+ additions_for = {
+ 'cluster': ' intel-icsxe',
+ 'professional': ' intel-ips-',
+ 'composer': ' intel-compxe',
+ }
+ if self._edition in additions_for:
+ c += additions_for[self._edition]
+
+ for variant, components_to_add in {
+ '+daal': ' intel-daal', # Data Analytics Acceleration Lib
+ '+gdb': ' intel-gdb', # Integrated Performance Primitives
+ '+ipp': ' intel-ipp intel-crypto-ipp',
+ '+mkl': ' intel-mkl', # Math Kernel Library
+ '+mpi': ' intel-mpi intel-imb', # MPI runtime, SDK, benchm.
+ '+tbb': ' intel-tbb', # Threading Building Blocks
+ '+advisor': ' intel-advisor',
+ '+clck': ' intel_clck', # Cluster Checker
+ '+inspector': ' intel-inspector',
+ '+itac': ' intel-itac intel-ta intel-tc'
+ ' intel-trace-analyzer intel-trace-collector',
+ # Trace Analyzer and Collector
+ '+vtune': ' intel-vtune-amplifier', # VTune
+ }.items():
+ if variant in self.spec:
+ c += components_to_add
+
+ debug_print(c)
+ return c.split()
+
+ # ---------------------------------------------------------------------
+ # Utilities
+ # ---------------------------------------------------------------------
+ @property
+ def _filtered_components(self):
+ '''Expands the list of desired component patterns to the exact names
+ present in the given download.
+ '''
+ c = self.pset_components
+ if 'ALL' in c or 'DEFAULTS' in c: # No filter needed
+ return c
# mediaconfig.xml is known to contain duplicate components.
# If more than one copy of the same component is used, you
# will get an error message about invalid components.
- # Use a set to store components to prevent duplicates.
- matches = set()
+ # Use sets to prevent duplicates and for efficient traversal.
+ requested = set(c)
+ confirmed = set()
+
+ # NB: To get a reasonable overview in pretty much the documented way:
+ #
+ # grep -E '<Product|<Abbr|<Name>..[a-z]' pset/mediaconfig.xml
+ #
+ # https://software.intel.com/en-us/articles/configuration-file-format
+ #
+ xmltree = ET.parse('pset/mediaconfig.xml')
+ for entry in xmltree.getroot().findall('.//Abbr'): # XPath expression
+ name_present = entry.text
+ for name_requested in requested:
+ if name_present.startswith(name_requested):
+ confirmed.add(name_present)
+
+ return list(confirmed)
+
+ @property
+ def intel64_int_suffix(self):
+ '''Provide the suffix for Intel library names to match a client
+ application's desired int size, conveyed by the active spec variant.
+ The possible suffixes and their meanings are:
+
+ ``ilp64`` all of int, long, and pointer are 64 bit,
+ `` lp64`` only long and pointer are 64 bit; int will be 32bit.
+ '''
+ if '+ilp64' in self.spec:
+ return 'ilp64'
+ else:
+ return 'lp64'
+
+ @property
+ def _has_compilers(self):
+ return self.name in ['intel', 'intel-parallel-studio']
+
+ @property
+ def _edition(self):
+ if self.name == 'intel-parallel-studio':
+ return self.version[0] # clearer than .up_to(1), I think.
+ elif self.name == 'intel':
+ return 'composer'
+ else:
+ return ''
+
+ @property
+ def version_yearlike(self):
+ '''Return the version in a unified style, suitable for Version class
+ conditionals.
+ '''
+ # Input data for this routine: self.version
+ # Returns: YYYY.Nupdate[.Buildseq]
+ #
+ # Specifics by package:
+ #
+ # Package Format of self.version
+ # ------------------------------------------------------------
+ # 'intel-parallel-studio' <edition>.YYYY.Nupdate
+ # 'intel' YY.0.Nupdate (some assigned ad-hoc)
+ # Recent lib packages YYYY.Nupdate.Buildseq
+ # Early lib packages Major.Minor.Patch.Buildseq
+ # ------------------------------------------------------------
+ #
+ # Package Output
+ # ------------------------------------------------------------
+ # 'intel-parallel-studio' YYYY.Nupdate
+ # 'intel' YYYY.Nupdate
+ # Recent lib packages YYYY.Nupdate.Buildseq
+ # Known early lib packages YYYY.Minor.Patch.Buildseq (*)
+ # Unknown early lib packages (2000 + Major).Minor.Patch.Buildseq
+ # ----------------------------------------------------------------
+ #
+ # (*) YYYY is taken from @property "version_years" (a dict of specs)
+ #
+ try:
+ if self.name == 'intel':
+ # Has a "Minor" version element, but it is always set as 0. To
+ # be useful for comparisons, drop it and get YYYY.Nupdate.
+ v_tail = self.version[2:] # coerced just fine via __getitem__
+ else:
+ v_tail = self.version[1:]
+ except IndexError:
+ # Hmm - this happens on "spack install intel-mkl@11".
+ # I thought concretization picks an actual version??
+ return self.version # give up
+
+ if self.name == 'intel-parallel-studio':
+ return v_tail
+
+ v_year = self.version[0]
+ if v_year < 2000:
+ # Shoehorn Major into release year until we know better.
+ v_year += 2000
+ for spec, year in self.version_years.items():
+ if self.spec.satisfies(spec):
+ v_year = year
+ break
+
+ return ver('%s.%s' % (v_year, v_tail))
+
+ # ---------------------------------------------------------------------
+ # Directory handling common to all Intel components
+ # ---------------------------------------------------------------------
+ # For reference: classes using IntelPackage, as of Spack-0.11:
+ #
+ # intel/ intel-ipp/ intel-mpi/
+ # intel-daal/ intel-mkl/ intel-parallel-studio/
+ #
+ # Not using class IntelPackage:
+ # intel-gpu-tools/ intel-mkl-dnn/ intel-tbb/
+ #
+ def normalize_suite_dir(self, suite_dir_name, version_globs=['*.*.*']):
+ '''Returns the version-specific and absolute path to the directory of
+ an Intel product or a suite of product components.
+
+ Parameters:
+
+ suite_dir_name (str):
+ Name of the product directory, without numeric version.
+
+ - Examples::
+
+ composer_xe, parallel_studio_xe, compilers_and_libraries
+
+ The following will work as well, even though they are not
+ directly targets for Spack installation::
+
+ advisor_xe, inspector_xe, vtune_amplifier_xe,
+ performance_snapshots (new name for vtune as of 2018)
+
+ These are single-component products without subordinate
+ components and are normally made available to users by a
+ toplevel psxevars.sh or equivalent file to source (and thus by
+ the modulefiles that Spack produces).
+
+ version_globs (list of str): Suffix glob patterns (most specific
+ first) expected to qualify suite_dir_name to its fully
+ version-specific install directory (as opposed to a
+ compatibility directory or symlink).
+ '''
+ # See ./README-intel.rst for background and analysis of dir layouts.
+
+ d = self.prefix
+
+ # Distinguish between product installations that were done external to
+ # Spack (integrated via packages.yaml) and Spack-internal ones. The
+ # resulting prefixes may differ in directory depth and specificity.
+ unversioned_dirname = ''
+ if suite_dir_name and suite_dir_name in d:
+ # If e.g. MKL was installed outside of Spack, it is likely just one
+ # product or product component among possibly many other Intel
+ # products and their releases that were installed in sibling or
+ # cousin directories. In such cases, the prefix given to Spack
+ # will inevitably be a highly product-specific and preferably fully
+ # version-specific directory. This is what we want and need, and
+ # nothing more specific than that, i.e., if needed, convert, e.g.:
+ # .../compilers_and_libraries*/* -> .../compilers_and_libraries*
+ d = re.sub('(%s%s.*?)%s.*' %
+ (os.sep, re.escape(suite_dir_name), os.sep), r'\1', d)
+
+ # The Intel installer scripts try hard to place compatibility links
+ # named like this in the install dir to convey upgrade benefits to
+ # traditional client apps. But such a generic name can be trouble
+ # when given to Spack: the link target is bound to change outside
+ # of Spack's purview and when it does, the outcome of subsequent
+ # builds of dependent packages may be affected. (Though Intel has
+ # been remarkably good at backward compatibility.)
+ # I'm not sure if Spack's package hashing includes link targets.
+ if d.endswith(suite_dir_name):
+ # NB: This could get tiresome without a seen++ test.
+ # tty.warn('Intel product found in a version-neutral directory'
+ # ' - future builds may not be reproducible.')
+ #
+ # Simply doing realpath() would not be enough, because:
+ # compilers_and_libraries -> compilers_and_libraries_2018
+ # which is mostly a staging directory for symlinks (see next).
+ unversioned_dirname = d
+ else:
+ # By contrast, a Spack-internal MKL installation will inherit its
+ # prefix from install.sh of Intel's package distribution, where it
+ # means the high-level installation directory that is specific to
+ # the *vendor* (think of the default "/opt/intel"). We must now
+ # step down into the *product* directory to get the usual
+ # hierarchy. But let's not do that in haste ...
+ #
+ # For a Spack-born install, the fully-qualified release directory
+ # desired above may seem less important since product upgrades
+ # won't land in the same parent. However, only the fully qualified
+ # directory contains the regular files for the compiler commands:
+ #
+ # $ ls -lF <HASH>/compilers_and_libraries*/linux/bin/intel64/icc
+ #
+ # <HASH>/compilers_and_libraries_2018.1.163/linux/bin/intel64/icc*
+ # A regular file in the actual release directory. Bingo!
+ #
+ # <HASH>/compilers_and_libraries_2018/linux/bin/intel64/icc -> ...
+ # A symlink - no good. Note that "compilers_and_libraries_2018/"
+ # is itself a directory (not symlink) but it merely holds a
+ # compatibility dir hierarchy with lots of symlinks into the
+ # release dir.
+ #
+ # <HASH>/compilers_and_libraries/linux/bin/intel64/icc -> ...
+ # Ditto.
+ #
+ # Now, the Spack packages for MKL and MPI packges use version
+ # triplets, but the one for intel-parallel-studio does not.
+ # So, we can't have it quite as easy as:
+ # d = Prefix(d.append('compilers_and_libraries_' + self.version))
+ # Alright, let's see what we can find instead:
+ unversioned_dirname = os.path.join(d, suite_dir_name)
+
+ if unversioned_dirname:
+ for g in version_globs:
+ try_glob = unversioned_dirname + g
+ debug_print('trying %s' % try_glob)
+
+ matching_dirs = sorted(glob.glob(try_glob))
+ # NB: Python glob() returns results in arbitrary order - ugh!
+ # NB2: sorted() is a shortcut that is NOT number-aware.
+
+ if matching_dirs:
+ debug_print('found %d:' % len(matching_dirs),
+ matching_dirs)
+ # Take the highest and thus presumably newest match, which
+ # better be the sole one anyway.
+ d = matching_dirs[-1]
+ break
+
+ if not matching_dirs:
+ # No match -- this *will* happen during pre-build call to
+ # setup_environment() when the destination dir is still empty.
+ # Return a sensible value anyway.
+ d = unversioned_dirname
+
+ debug_print(d)
+ return Prefix(d)
+
+ def normalize_path(self, component_path, component_suite_dir=None,
+ relative=False):
+ '''Returns the absolute or relative path to a component or file under a
+ component suite directory.
+
+ Intel's product names, scope, and directory layout changed over the
+ years. This function provides a unified interface to their directory
+ names.
+
+ Parameters:
+
+ component_path (str): a component name like 'mkl', or 'mpi', or a
+ deeper relative path.
+
+ component_suite_dir (str): _Unversioned_ name of the expected
+ parent directory of component_path. When absent or `None`, an
+ appropriate default will be used. A present but empty string
+ `""` requests that `component_path` refer to `self.prefix`
+ directly.
+
+ Typical values: `compilers_and_libraries`, `composer_xe`,
+ `parallel_studio_xe`.
+
+ Also supported: `advisor`, `inspector`, `vtune`. The actual
+ directory name for these suites varies by release year. The
+ name will be corrected as needed for use in the return value.
+
+ relative (bool): When True, return path relative to self.prefix,
+ otherwise, return an absolute path (the default).
+ '''
+ # Design note: Choosing the default for `component_suite_dir` was a bit
+ # tricky since there better be a sensible means to specify direct
+ # parentage under self.prefix (even though you normally shouldn't need
+ # a function for that). I chose "" to allow that case be represented,
+ # and 'None' or the absence of the kwarg to represent the most relevant
+ # case for the time of writing.
+ #
+ # In the 2015 releases (the earliest in Spack as of 2018), there were
+ # nominally two separate products that provided the compilers:
+ # "Composer" as lower tier, and "Parallel Studio" as upper tier. In
+ # Spack, we justifiably retcon both as "intel-parallel-studio@composer"
+ # and "...@cluster", respectively. Both of these use the older
+ # "composer_xe" dir layout, as do their virtual package personas.
+ #
+ # All other "intel-foo" packages in Spack as of 2018-04 use the
+ # "compilers_and_libraries" layout, including the 2016 releases that
+ # are not natively versioned by year.
+
+ cs = component_suite_dir
+ if cs is None and component_path.startswith('ism'):
+ cs = 'parallel_studio_xe'
+
+ v = self.version_yearlike
+
+ # Glob variants to complete component_suite_dir.
+ # Helper var for older MPI versions - those are reparented, with each
+ # version in their own version-named dir.
+ standalone_glob = '[1-9]*.*.*'
+
+ # Most other components; try most specific glob first.
+ # flake8 is far too opinionated about lists - ugh.
+ normalize_kwargs = {
+ 'version_globs': [
+ '_%s' % self.version,
+ '_%s.*' % v.up_to(2), # should be: YYYY.Nupdate
+ '_*.*.*', # last resort
+ ]
+ }
+ for rename_rule in [
+ # cs given as arg, in years, dir actually used, [version_globs]
+ [None, ':2015', 'composer_xe'],
+ [None, '2016:', 'compilers_and_libraries'],
+ ['advisor', ':2016', 'advisor_xe'],
+ ['inspector', ':2016', 'inspector_xe'],
+ ['vtune_amplifier', ':2017', 'vtune_amplifier_xe'],
+ ['vtune', ':2017', 'vtune_amplifier_xe'], # alt.
+ ['itac', ':', 'itac', [os.sep + standalone_glob]],
+ ]:
+ if cs == rename_rule[0] and v.satisfies(ver(rename_rule[1])):
+ cs = rename_rule[2]
+ if len(rename_rule) > 3:
+ normalize_kwargs = {'version_globs': rename_rule[3]}
+ break
+
+ d = self.normalize_suite_dir(cs, **normalize_kwargs)
+
+ # Help find components not located directly under d.
+ # NB: ancestor() not well suited if version_globs may contain os.sep .
+ parent_dir = re.sub(os.sep + re.escape(cs) + '.*', '', d)
+
+ reparent_as = {}
+ if cs == 'compilers_and_libraries': # must qualify further
+ d = os.path.join(d, _expand_fields('{platform}'))
+ elif cs == 'composer_xe':
+ reparent_as = {'mpi': 'impi'}
+ # ignore 'imb' (MPI Benchmarks)
+
+ for nominal_p, actual_p in reparent_as.items():
+ if component_path.startswith(nominal_p):
+ dirs = glob.glob(
+ os.path.join(parent_dir, actual_p, standalone_glob))
+ debug_print('reparent dirs: %s' % dirs)
+ # Brazenly assume last match is the most recent version;
+ # convert back to relative of parent_dir, and re-assemble.
+ rel_dir = dirs[-1].split(parent_dir + os.sep, 1)[-1]
+ component_path = component_path.replace(nominal_p, rel_dir, 1)
+ d = parent_dir
+
+ d = os.path.join(d, component_path)
+
+ if relative:
+ d = os.path.relpath(os.path.realpath(d), parent_dir)
+
+ debug_print(d)
+ return d
+
+ def component_bin_dir(self, component, **kwargs):
+ d = self.normalize_path(component, **kwargs)
+
+ if component == 'compiler': # bin dir is always under PARENT
+ d = os.path.join(ancestor(d), 'bin', _expand_fields('{libarch}'))
+ d = d.rstrip(os.sep) # cosmetics, when {libarch} is empty
+ # NB: Works fine even with relative=True, e.g.:
+ # composer_xe/compiler -> composer_xe/bin/intel64
+ elif component == 'mpi':
+ d = os.path.join(d, _expand_fields('{libarch}'), 'bin')
+ else:
+ d = os.path.join(d, 'bin')
+ debug_print(d)
+ return d
+
+ def component_lib_dir(self, component, **kwargs):
+ '''Provide directory suitable for find_libraries() and
+ SPACK_COMPILER_EXTRA_RPATHS.
+ '''
+ d = self.normalize_path(component, **kwargs)
+
+ if component == 'mpi':
+ d = os.path.join(d, _expand_fields('{libarch}'), 'lib')
+ else:
+ d = os.path.join(d, 'lib', _expand_fields('{libarch}'))
+ d = d.rstrip(os.sep) # cosmetics, when {libarch} is empty
+
+ if component == 'tbb': # must qualify further for abi
+ d = os.path.join(d, self._tbb_abi)
+
+ debug_print(d)
+ return d
+
+ def component_include_dir(self, component, **kwargs):
+ d = self.normalize_path(component, **kwargs)
+
+ if component == 'mpi':
+ d = os.path.join(d, _expand_fields('{libarch}'), 'include')
+ else:
+ d = os.path.join(d, 'include')
+
+ debug_print(d)
+ return d
- for valid in _valid_components():
- for requested in self.components:
- if valid.startswith(requested):
- matches.add(valid)
+ @property
+ def file_to_source(self):
+ '''Full path of file to source for initializing an Intel package.
+ A client package could override as follows:
+ ` @property`
+ ` def file_to_source(self):`
+ ` return self.normalize_path("apsvars.sh", "vtune_amplifier")`
+ '''
+ vars_file_info_for = {
+ # key (usu. spack package name) -> [rel_path, component_suite_dir]
+ # Extension note: handle additions by Spack name or ad-hoc keys.
+ '@early_compiler': ['bin/compilervars', None],
+ 'intel-parallel-studio': ['bin/psxevars', 'parallel_studio_xe'],
+ 'intel': ['bin/compilervars', None],
+ 'intel-daal': ['daal/bin/daalvars', None],
+ 'intel-ipp': ['ipp/bin/ippvars', None],
+ 'intel-mkl': ['mkl/bin/mklvars', None],
+ 'intel-mpi': ['mpi/{libarch}/bin/mpivars', None],
+ }
+ key = self.name
+ if self.version_yearlike.satisfies(ver(':2015')):
+ # Same file as 'intel' but 'None' for component_suite_dir will
+ # resolve differently. Listed as a separate entry to serve as
+ # example and to avoid pitfalls upon possible refactoring.
+ key = '@early_compiler'
+
+ f, component_suite_dir = vars_file_info_for[key]
+ f = _expand_fields(f) + '.sh'
+ # TODO?? win32 would have to handle os.sep, '.bat' (unless POSIX??)
+
+ f = self.normalize_path(f, component_suite_dir)
+ return f
+
+ # ---------------------------------------------------------------------
+ # Threading, including (WIP) support for virtual 'tbb'
+ # ---------------------------------------------------------------------
+ @property
+ def openmp_libs(self):
+ '''Supply LibraryList for linking OpenMP'''
+
+ if '%intel' in self.spec:
+ # NB: Hunting down explicit library files may be the Spack way of
+ # doing things, but be aware that "{icc|ifort} --help openmp"
+ # steers us towards options instead: -qopenmp-link={dynamic,static}
+
+ omp_libnames = ['libiomp5']
+ omp_libs = find_libraries(
+ omp_libnames,
+ root=self.component_lib_dir('compiler'),
+ shared=('+shared' in self.spec))
+ # Note about search root here: For MKL, the directory
+ # "$MKLROOT/../compiler" will be present even for an MKL-only
+ # product installation (as opposed to one being ghosted via
+ # packages.yaml), specificially to provide the 'iomp5' libs.
+
+ elif '%gcc' in self.spec:
+ gcc = Executable(self.compiler.cc)
+ omp_lib_path = gcc(
+ '--print-file-name', 'libgomp.%s' % dso_suffix, output=str)
+ omp_libs = LibraryList(omp_lib_path)
+
+ if len(omp_libs) < 1:
+ raise_lib_error('Cannot locate OpenMP libraries:', omp_libnames)
+
+ debug_print(omp_libs)
+ return omp_libs
+
+ @property
+ def tbb_libs(self):
+ '''Supply LibraryList for linking TBB'''
+
+ # TODO: When is 'libtbbmalloc' needed?
+ tbb_lib = find_libraries(
+ ['libtbb'], root=self.component_lib_dir('tbb'))
+ # NB: Like icc with -qopenmp, so does icpc steer us towards using an
+ # option: "icpc -tbb"
+
+ # TODO: clang(?)
+ gcc = Executable('gcc') # must be gcc, not self.compiler.cc
+ cxx_lib_path = gcc(
+ '--print-file-name', 'libstdc++.%s' % dso_suffix, output=str)
+
+ libs = tbb_lib + LibraryList(cxx_lib_path)
+ debug_print(libs)
+ return libs
+
+ @property
+ def _tbb_abi(self):
+ '''Select the ABI needed for linking TBB'''
+ # Match the available gcc, as it's done in tbbvars.sh.
+ gcc = Executable('gcc')
+ matches = re.search(r'(gcc|LLVM).* ([0-9]+\.[0-9]+\.[0-9]+).*',
+ gcc('--version', output=str), re.I | re.M)
+ abi = ''
+ if sys.platform == 'darwin':
+ pass
+ elif matches:
+ # TODO: Confirm that this covers clang (needed on Linux only)
+ gcc_version = Version(matches.groups()[1])
+ if gcc_version >= ver('4.7'):
+ abi = 'gcc4.7'
+ elif gcc_version >= ver('4.4'):
+ abi = 'gcc4.4'
+ else:
+ abi = 'gcc4.1' # unlikely, one hopes.
+
+ # Alrighty then ...
+ debug_print(abi)
+ return abi
+
+ # ---------------------------------------------------------------------
+ # Support for virtual 'blas/lapack/scalapack'
+ # ---------------------------------------------------------------------
+ @property
+ def blas_libs(self):
+ # Main magic here.
+ # For reference, see The Intel Math Kernel Library Link Line Advisor:
+ # https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor/
+
+ mkl_integer = 'libmkl_intel_' + self.intel64_int_suffix
+
+ if self.spec.satisfies('threads=openmp'):
+ if '%intel' in self.spec:
+ mkl_threading = 'libmkl_intel_thread'
+ elif '%gcc' in self.spec:
+ mkl_threading = 'libmkl_gnu_thread'
+ threading_engine_libs = self.openmp_libs()
+ elif self.spec.satisfies('threads=tbb'):
+ mkl_threading = 'libmkl_tbb_thread'
+ threading_engine_libs = self.tbb_libs()
+ elif self.spec.satisfies('threads=none'):
+ mkl_threading = 'libmkl_sequential'
+ threading_engine_libs = LibraryList([])
+ else:
+ raise_lib_error('Cannot determine MKL threading libraries.')
+
+ mkl_libnames = [mkl_integer, mkl_threading, 'libmkl_core']
+ mkl_libs = find_libraries(
+ mkl_libnames,
+ root=self.component_lib_dir('mkl'),
+ shared=('+shared' in self.spec))
+ debug_print(mkl_libs)
+
+ if len(mkl_libs) < 3:
+ raise_lib_error('Cannot locate core MKL libraries:', mkl_libnames)
+
+ # The Intel MKL link line advisor recommends these system libraries
+ system_libs = find_system_libraries(
+ 'libpthread libm libdl'.split(),
+ shared=('+shared' in self.spec))
+ debug_print(system_libs)
- return matches
+ return mkl_libs + threading_engine_libs + system_libs
@property
+ def lapack_libs(self):
+ return self.blas_libs
+
+ @property
+ def scalapack_libs(self):
+ # Intel MKL does not directly depend on MPI but the BLACS library
+ # which underlies ScaLapack does. It comes in several personalities;
+ # we must supply a personality matching the MPI implementation that
+ # is active for the root package that asked for ScaLapack.
+ spec_root = self.spec.root
+ if sys.platform == 'darwin' and '^mpich' in spec_root:
+ # The only supported choice for MKL 2018 on Mac.
+ blacs_lib = 'libmkl_blacs_mpich'
+ elif '^openmpi' in spec_root:
+ blacs_lib = 'libmkl_blacs_openmpi'
+ elif '^mpich@1' in spec_root:
+ # Was supported only up to 2015.
+ blacs_lib = 'libmkl_blacs'
+ elif ('^mpich@2:' in spec_root or
+ '^mvapich2' in spec_root or
+ '^intel-mpi' in spec_root):
+ blacs_lib = 'libmkl_blacs_intelmpi'
+ elif '^mpt' in spec_root:
+ blacs_lib = 'libmkl_blacs_sgimpt'
+ else:
+ raise_lib_error('Cannot find a BLACS library for the given MPI.')
+
+ int_suff = '_' + self.intel64_int_suffix
+ scalapack_libnames = [
+ 'libmkl_scalapack' + int_suff,
+ blacs_lib + int_suff,
+ ]
+ sca_libs = find_libraries(
+ scalapack_libnames,
+ root=self.component_lib_dir('mkl'),
+ shared=('+shared' in self.spec))
+ debug_print(sca_libs)
+
+ if len(sca_libs) < 2:
+ raise_lib_error(
+ 'Cannot locate ScaLapack/BLACS libraries:', scalapack_libnames)
+ # NB: ScaLapack is installed as "cluster" components within MKL or
+ # MKL-encompassing products. But those were *optional* for the ca.
+ # 2015/2016 product releases, which was easy to overlook, and I have
+ # been bitten by that. Thus, complain early because it'd be a sore
+ # disappointment to have missing ScaLapack libs show up as a link error
+ # near the end phase of a client package's build phase.
+
+ return sca_libs
+
+ # ---------------------------------------------------------------------
+ # Support for virtual 'mpi'
+ # ---------------------------------------------------------------------
+ @property
+ def mpi_compiler_wrappers(self):
+ '''Return paths to compiler wrappers as a dict of env-like names
+ '''
+ # Intel comes with 2 different flavors of MPI wrappers:
+ #
+ # * mpiicc, mpiicpc, and mpiifort are hardcoded to wrap around
+ # the Intel compilers.
+ # * mpicc, mpicxx, mpif90, and mpif77 allow you to set which
+ # compilers to wrap using I_MPI_CC and friends. By default,
+ # wraps around the GCC compilers.
+ #
+ # In theory, these should be equivalent as long as I_MPI_CC
+ # and friends are set to point to the Intel compilers, but in
+ # practice, mpicc fails to compile some applications while
+ # mpiicc works.
+ bindir = self.component_bin_dir('mpi')
+ if self.compiler.name == 'intel':
+ wrapper_vars = {
+ # eschew Prefix objects -- emphasize the command strings.
+ 'MPICC': os.path.join(bindir, 'mpiicc'),
+ 'MPICXX': os.path.join(bindir, 'mpiicpc'),
+ 'MPIF77': os.path.join(bindir, 'mpiifort'),
+ 'MPIF90': os.path.join(bindir, 'mpiifort'),
+ 'MPIFC': os.path.join(bindir, 'mpiifort'),
+ }
+ else:
+ wrapper_vars = {
+ 'MPICC': os.path.join(bindir, 'mpicc'),
+ 'MPICXX': os.path.join(bindir, 'mpicxx'),
+ 'MPIF77': os.path.join(bindir, 'mpif77'),
+ 'MPIF90': os.path.join(bindir, 'mpif90'),
+ 'MPIFC': os.path.join(bindir, 'mpif90'),
+ }
+ # debug_print("wrapper_vars =", wrapper_vars)
+ return wrapper_vars
+
+ def mpi_setup_dependent_environment(
+ self, spack_env, run_env, dependent_spec, compilers_of_client={}):
+ '''Unified back-end for setup_dependent_environment() of Intel packages
+ that provide 'mpi'.
+
+ Parameters:
+
+ spack_env, run_env, dependent_spec: same as in
+ setup_dependent_environment().
+
+ compilers_of_client (dict): Conveys spack_cc, spack_cxx, etc.,
+ from the scope of dependent packages; constructed in caller.
+ '''
+ # See also: setup_dependent_package()
+ wrapper_vars = {
+ 'I_MPI_CC': compilers_of_client['CC'],
+ 'I_MPI_CXX': compilers_of_client['CXX'],
+ 'I_MPI_F77': compilers_of_client['F77'],
+ 'I_MPI_F90': compilers_of_client['F90'],
+ 'I_MPI_FC': compilers_of_client['FC'],
+ # NB: Normally set by the modulefile, but that is not active here:
+ 'I_MPI_ROOT': self.normalize_path('mpi'),
+ }
+
+ # CAUTION - SIMILAR code in:
+ # var/spack/repos/builtin/packages/mpich/package.py
+ # var/spack/repos/builtin/packages/openmpi/package.py
+ # var/spack/repos/builtin/packages/mvapich2/package.py
+ #
+ # On Cray, the regular compiler wrappers *are* the MPI wrappers.
+ if 'platform=cray' in self.spec:
+ # TODO: Confirm
+ wrapper_vars.update({
+ 'MPICC': compilers_of_client['CC'],
+ 'MPICXX': compilers_of_client['CXX'],
+ 'MPIF77': compilers_of_client['F77'],
+ 'MPIF90': compilers_of_client['F90'],
+ })
+ else:
+ compiler_wrapper_commands = self.mpi_compiler_wrappers
+ wrapper_vars.update({
+ 'MPICC': compiler_wrapper_commands['MPICC'],
+ 'MPICXX': compiler_wrapper_commands['MPICXX'],
+ 'MPIF77': compiler_wrapper_commands['MPIF77'],
+ 'MPIF90': compiler_wrapper_commands['MPIF90'],
+ })
+
+ for key, value in wrapper_vars.items():
+ spack_env.set(key, value)
+
+ debug_print("adding to spack_env:", wrapper_vars)
+
+ # ---------------------------------------------------------------------
+ # General support for child packages
+ # ---------------------------------------------------------------------
+ @property
+ def headers(self):
+ result = HeaderList([])
+ if '+mpi' in self.spec or self.provides('mpi'):
+ result += find_headers(
+ ['mpi'],
+ root=self.component_include_dir('mpi'),
+ recursive=False)
+ if '+mkl' in self.spec or self.provides('mkl'):
+ result += find_headers(
+ ['mkl_cblas', 'mkl_lapacke'],
+ root=self.component_include_dir('mkl'),
+ recursive=False)
+ debug_print(result)
+ return result
+
+ @property
+ def libs(self):
+ result = LibraryList([])
+ if '+mpi' in self.spec or self.provides('mpi'):
+ # If prefix is too general, recursive searches may get files from
+ # supported but inappropriate sub-architectures like 'mic'.
+ libnames = ['libmpifort', 'libmpi']
+ if 'cxx' in self.spec.last_query.extra_parameters:
+ libnames = ['libmpicxx'] + libnames
+ result += find_libraries(
+ libnames,
+ root=self.component_lib_dir('mpi'),
+ shared=True, recursive=True)
+
+ # NB: MKL uses domain-specifics: blas_libs/lapack_libs/scalapack_libs
+
+ debug_print(result)
+ return result
+
+ def setup_environment(self, spack_env, run_env):
+ """Adds environment variables to the generated module file.
+
+ These environment variables come from running:
+
+ .. code-block:: console
+
+ $ source parallel_studio_xe_2017/bin/psxevars.sh intel64
+ [and likewise for MKL, MPI, and other components]
+ """
+ # https://spack.readthedocs.io/en/latest/spack.html#spack.package.PackageBase.setup_environment
+ #
+ # spack_env -> Applied when dependent is built within Spack.
+ # Not used here.
+ # run_env -> Applied to the modulefile of dependent.
+ #
+ # NOTE: Spack runs setup_environment twice, once pre-build to set up
+ # the build environment, and once post-installation to determine
+ # the environment variables needed at run-time to add to the module
+ # file. The script we need to source is only present post-installation,
+ # so check for its existence before sourcing.
+ # TODO: At some point we should split setup_environment into
+ # setup_build_environment and setup_run_environment to get around
+ # this problem.
+ f = self.file_to_source
+ if not f or not os.path.isfile(f):
+ return
+
+ tty.debug("sourcing " + f)
+
+ # All Intel packages expect at least the architecture as argument.
+ # Some accept more args, but those are not (yet?) handled here.
+ args = (_expand_fields('{arch}'),)
+
+ # On Mac, the platform is *also required*, at least as of 2018.
+ # I am not sure about earlier versions.
+ # if sys.platform == 'darwin':
+ # args = ()
+
+ run_env.extend(EnvironmentModifications.from_sourcing_file(f, *args))
+
+ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
+ # https://spack.readthedocs.io/en/latest/spack.html#spack.package.PackageBase.setup_dependent_environment
+ #
+ # spack_env -> Applied when dependent is built within Spack.
+ # run_env -> Applied to the modulefile of dependent.
+ # Not used here.
+ #
+ # NB: This function is overwritten by 'mpi' provider packages:
+ #
+ # var/spack/repos/builtin/packages/intel-mpi/package.py
+ # var/spack/repos/builtin/packages/intel-parallel-studio/package.py
+ #
+ # They call _setup_dependent_env_callback() as well, but with the
+ # dictionary kwarg compilers_of_client{} present and populated.
+
+ # Handle everything in a callback version.
+ self._setup_dependent_env_callback(spack_env, run_env, dependent_spec)
+
+ def _setup_dependent_env_callback(
+ self, spack_env, run_env, dependent_spec, compilers_of_client={}):
+ # Expected to be called from a client's setup_dependent_environment(),
+ # with args extended to convey the client's compilers as needed.
+
+ if '+mkl' in self.spec or self.provides('mkl'):
+ # Spack's env philosophy demands that we replicate some of the
+ # settings normally handled by file_to_source ...
+ #
+ # TODO: Why is setup_environment() [which uses file_to_source()]
+ # not called as a matter of course upon entering the current
+ # function? (guarding against multiple calls notwithstanding)
+ #
+ # Use a local dict to facilitate debug_print():
+ env_mods = {
+ 'MKLROOT': self.normalize_path('mkl'),
+ 'SPACK_COMPILER_EXTRA_RPATHS': self.component_lib_dir('mkl'),
+ }
+
+ spack_env.set('MKLROOT', env_mods['MKLROOT'])
+ spack_env.append_path('SPACK_COMPILER_EXTRA_RPATHS',
+ env_mods['SPACK_COMPILER_EXTRA_RPATHS'])
+
+ debug_print("adding/modifying spack_env:", env_mods)
+
+ if '+mpi' in self.spec or self.provides('mpi'):
+ if compilers_of_client:
+ self.mpi_setup_dependent_environment(
+ spack_env, run_env, dependent_spec, compilers_of_client)
+ # We could forego this nonce function and inline its code here,
+ # but (a) it sisters mpi_compiler_wrappers() [needed twice]
+ # which performs dizzyingly similar but necessarily different
+ # actions, and (b) function code leaves a bit more breathing
+ # room within the suffocating corset of flake8 line length.
+ else:
+ raise InstallError('compilers_of_client arg required for MPI')
+
+ def setup_dependent_package(self, module, dep_spec):
+ # https://spack.readthedocs.io/en/latest/spack.html#spack.package.PackageBase.setup_dependent_package
+ # Reminder: "module" refers to Python module.
+ # Called before the install() method of dependents.
+
+ if '+mpi' in self.spec or self.provides('mpi'):
+ compiler_wrapper_commands = self.mpi_compiler_wrappers
+ self.spec.mpicc = compiler_wrapper_commands['MPICC']
+ self.spec.mpicxx = compiler_wrapper_commands['MPICXX']
+ self.spec.mpif77 = compiler_wrapper_commands['MPIF77']
+ self.spec.mpifc = compiler_wrapper_commands['MPIFC']
+ debug_print(("spec '%s' received .mpi* properties:" % self.spec),
+ compiler_wrapper_commands)
+
+ # ---------------------------------------------------------------------
+ # Specifics for installation phase
+ # ---------------------------------------------------------------------
+ @property
def global_license_file(self):
- """Returns the path where a global license file should be stored.
+ """Returns the path where a Spack-global license file should be stored.
All Intel software shares the same license, so we store it in a
common 'intel' directory."""
- return join_path(self.global_license_dir, 'intel',
- os.path.basename(self.license_files[0]))
+ return os.path.join(self.global_license_dir, 'intel', 'license.lic')
+
+ @property
+ def _determine_license_type(self):
+ '''Provide appropriate license tokens for the installer (silent.cfg).
+ '''
+ # See:
+ # ./README-intel.rst, section "Details for licensing tokens".
+ # ./build_systems/README-intel.rst, section "Licenses"
+ #
+ # Ideally, we just tell the installer to look around on the system.
+ # Thankfully, we neither need to care nor emulate where it looks:
+ license_type = {'ACTIVATION_TYPE': 'exist_lic', }
+
+ # However (and only), if the spack-internal Intel license file has been
+ # populated beyond its templated explanatory comments, proffer it to
+ # the installer instead:
+ f = self.global_license_file
+ if os.path.isfile(f):
+ # The file will have been created upon self.license_required AND
+ # self.license_files having been populated, so the "if" is usually
+ # true by the time the present function runs; ../hooks/licensing.py
+ with open(f) as fh:
+ if re.search(r'^[ \t]*[^' + self.license_comment + '\n]',
+ fh.read(), re.MULTILINE):
+ license_type = {
+ 'ACTIVATION_TYPE': 'license_file',
+ 'ACTIVATION_LICENSE_FILE': f,
+ }
+
+ debug_print(license_type)
+ return license_type
def configure(self, spec, prefix):
- """Writes the ``silent.cfg`` file used to configure the installation.
+ '''Generates the silent.cfg file to pass to installer.sh.
See https://software.intel.com/en-us/articles/configuration-file-format
- """
- # Patterns used to check silent configuration file
- #
- # anythingpat - any string
- # filepat - the file location pattern (/path/to/license.lic)
- # lspat - the license server address pattern (0123@hostname)
- # snpat - the serial number pattern (ABCD-01234567)
- config = {
- # Accept EULA, valid values are: {accept, decline}
- 'ACCEPT_EULA': 'accept',
+ '''
- # Optional error behavior, valid values are: {yes, no}
- 'CONTINUE_WITH_OPTIONAL_ERROR': 'yes',
-
- # Install location, valid values are: {/opt/intel, filepat}
- 'PSET_INSTALL_DIR': prefix,
+ # Both tokens AND values of the configuration file are validated during
+ # the run of the underlying binary installer. Any unknown token or
+ # unacceptable value will cause that installer to fail. Notably, this
+ # applies to trying to specify a license for a product that does not
+ # require one.
+ #
+ # Fortunately, the validator is a script from a solid code base that is
+ # only lightly adapted to the token vocabulary of each product and
+ # release. Let's get that script so we can preempt its objections.
+ #
+ # Rather than running the script on a trial file and dissecting its
+ # pronouncements, let's brazenly skim it for supported tokens and build
+ # our configuration accordingly. We can do this because the tokens are
+ # quite long and specific.
- # Continue with overwrite of existing installation directory,
- # valid values are: {yes, no}
- 'CONTINUE_WITH_INSTALLDIR_OVERWRITE': 'yes',
+ validator_code = open('pset/check.awk', 'r').read()
+ # Let's go a little further and distill the tokens (plus some noise).
+ tokenlike_words = set(re.findall(r'[A-Z_]{4,}', validator_code))
- # List of components to install,
- # valid values are: {ALL, DEFAULTS, anythingpat}
- 'COMPONENTS': ';'.join(self._filtered_components),
+ # NB: .cfg files generated with the "--duplicate filename" option have
+ # the COMPONENTS string begin with a separator - do not worry about it.
+ components_joined = ';'.join(self._filtered_components)
+ nonrpm_db_dir = os.path.join(prefix, 'nonrpm-db')
- # Installation mode, valid values are: {install, repair, uninstall}
- 'PSET_MODE': 'install',
+ config_draft = {
+ # Basics first - these should be accepted in all products.
+ 'ACCEPT_EULA': 'accept',
+ 'PSET_MODE': 'install',
+ 'CONTINUE_WITH_OPTIONAL_ERROR': 'yes',
+ 'CONTINUE_WITH_INSTALLDIR_OVERWRITE': 'yes',
+ 'SIGNING_ENABLED': 'no',
- # Directory for non-RPM database, valid values are: {filepat}
- 'NONRPM_DB_DIR': prefix,
+ # Highly variable package specifics:
+ 'PSET_INSTALL_DIR': prefix,
+ 'NONRPM_DB_DIR': nonrpm_db_dir,
+ 'COMPONENTS': components_joined,
- # Perform validation of digital signatures of RPM files,
- # valid values are: {yes, no}
- 'SIGNING_ENABLED': 'no',
+ # Conditional tokens; the first is supported post-2015 only.
+ # Ignore ia32; most recent products don't even provide it.
+ 'ARCH_SELECTED': 'INTEL64', # was: 'ALL'
- # Select target architecture of your applications,
- # valid values are: {IA32, INTEL64, ALL}
- 'ARCH_SELECTED': 'ALL',
+ # 'ism' component -- see uninstall_ism(); also varies by release.
+ 'PHONEHOME_SEND_USAGE_DATA': 'no',
+ # Ah, as of 2018.2, that somewhat loaded term got replaced by one
+ # in business-speak. We uphold our preference, both out of general
+ # principles and for technical reasons like overhead and non-routed
+ # compute nodes.
+ 'INTEL_SW_IMPROVEMENT_PROGRAM_CONSENT': 'no',
}
+ # Deal with licensing only if truly needed.
+ # NB: Token was 'ACTIVATION' pre ~2013, so basically irrelevant here.
+ if 'ACTIVATION_TYPE' in tokenlike_words:
+ config_draft.update(self._determine_license_type)
- # Not all Intel software requires a license. Trying to specify
- # one anyway will cause the installation to fail.
- if self.license_required:
- config.update({
- # License file or license server,
- # valid values are: {lspat, filepat}
- 'ACTIVATION_LICENSE_FILE': self.global_license_file,
-
- # Activation type, valid values are: {exist_lic,
- # license_server, license_file, trial_lic, serial_number}
- 'ACTIVATION_TYPE': 'license_file',
-
- # Intel(R) Software Improvement Program opt-in,
- # valid values are: {yes, no}
- 'PHONEHOME_SEND_USAGE_DATA': 'no',
- })
-
- with open('silent.cfg', 'w') as cfg:
- for key in config:
- cfg.write('{0}={1}\n'.format(key, config[key]))
+ # Write sorted *by token* so the file looks less like a hash dump.
+ f = open('silent.cfg', 'w')
+ for token, value in sorted(config_draft.items()):
+ if token in tokenlike_words:
+ f.write('%s=%s\n' % (token, value))
+ f.close()
def install(self, spec, prefix):
- """Runs the ``install.sh`` installation script."""
+ '''Runs Intel's install.sh installation script. Afterwards, save the
+ installer config and logs to <prefix>/.spack
+ '''
+ # prepare
+ tmpdir = tempfile.mkdtemp(prefix='spack-intel-')
install_script = Executable('./install.sh')
+ install_script.add_default_env('TMPDIR', tmpdir)
+
+ # perform
install_script('--silent', 'silent.cfg')
+ # preserve config and logs
+ dst = os.path.join(self.prefix, '.spack')
+ install('silent.cfg', dst)
+ for f in glob.glob('%s/intel*log' % tmpdir):
+ install(f, dst)
+
+ @run_after('install')
+ def configure_rpath(self):
+ if '+rpath' not in self.spec:
+ return
+
+ # https://software.intel.com/en-us/cpp-compiler-18.0-developer-guide-and-reference-using-configuration-files
+ compilers_bin_dir = self.component_bin_dir('compiler')
+ compilers_lib_dir = self.component_lib_dir('compiler')
+
+ for compiler_name in 'icc icpc ifort'.split():
+ f = os.path.join(compilers_bin_dir, compiler_name)
+ if not os.path.isfile(f):
+ raise InstallError(
+ 'Cannot find compiler command to configure rpath:\n\t' + f)
+
+ compiler_cfg = os.path.abspath(f + '.cfg')
+ with open(compiler_cfg, 'w') as fh:
+ fh.write('-Xlinker -rpath={0}\n'.format(compilers_lib_dir))
+
@run_after('install')
- def save_silent_cfg(self):
- """Copies the silent.cfg configuration file to ``<prefix>/.spack``."""
- install('silent.cfg', join_path(self.prefix, '.spack'))
+ def filter_compiler_wrappers(self):
+ if (('+mpi' in self.spec or self.provides('mpi')) and
+ '~newdtags' in self.spec):
+ bin_dir = self.component_bin_dir('mpi')
+ for f in 'mpif77 mpif90 mpigcc mpigxx mpiicc mpiicpc ' \
+ 'mpiifort'.split():
+ f = os.path.join(bin_dir, f)
+ filter_file('-Xlinker --enable-new-dtags', ' ', f, string=True)
+
+ @run_after('install')
+ def uninstall_ism(self):
+ # The "Intel(R) Software Improvement Program" [ahem] gets installed,
+ # apparently regardless of PHONEHOME_SEND_USAGE_DATA.
+ #
+ # https://software.intel.com/en-us/articles/software-improvement-program
+ # https://software.intel.com/en-us/forums/intel-c-compiler/topic/506959
+ # Hubert H. (Intel) Mon, 03/10/2014 - 03:02 wrote:
+ # "... you can also uninstall the Intel(R) Software Manager
+ # completely: <installdir>/intel/ism/uninstall.sh"
+
+ f = os.path.join(self.normalize_path('ism'), 'uninstall.sh')
+ if os.path.isfile(f):
+ tty.warn('Uninstalling "Intel Software Improvement Program"'
+ 'component')
+ uninstall = Executable(f)
+ uninstall('--silent')
+
+ # TODO? also try
+ # ~/intel/ism/uninstall --silent
+
+ debug_print(os.getcwd())
+ return
# Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix)
diff --git a/lib/spack/spack/build_systems/makefile.py b/lib/spack/spack/build_systems/makefile.py
index 286b702fc9..1dd25bbd08 100644
--- a/lib/spack/spack/build_systems/makefile.py
+++ b/lib/spack/spack/build_systems/makefile.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
diff --git a/lib/spack/spack/build_systems/meson.py b/lib/spack/spack/build_systems/meson.py
new file mode 100644
index 0000000000..929248d7f9
--- /dev/null
+++ b/lib/spack/spack/build_systems/meson.py
@@ -0,0 +1,171 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
+import inspect
+import os
+
+from llnl.util.filesystem import working_dir
+from spack.directives import depends_on, variant
+from spack.package import PackageBase, run_after
+
+
+class MesonPackage(PackageBase):
+ """Specialized class for packages built using Meson
+
+ For more information on the Meson build system, see:
+ https://mesonbuild.com/
+
+ This class provides three phases that can be overridden:
+
+ 1. :py:meth:`~.MesonPackage.meson`
+ 2. :py:meth:`~.MesonPackage.build`
+ 3. :py:meth:`~.MesonPackage.install`
+
+ They all have sensible defaults and for many packages the only thing
+ necessary will be to override :py:meth:`~.MesonPackage.meson_args`.
+ For a finer tuning you may also override:
+
+ +-----------------------------------------------+--------------------+
+ | **Method** | **Purpose** |
+ +===============================================+====================+
+ | :py:meth:`~.MesonPackage.root_mesonlists_dir` | Location of the |
+ | | root MesonLists.txt|
+ +-----------------------------------------------+--------------------+
+ | :py:meth:`~.MesonPackage.build_directory` | Directory where to |
+ | | build the package |
+ +-----------------------------------------------+--------------------+
+
+
+ """
+ #: Phases of a Meson package
+ phases = ['meson', 'build', 'install']
+ #: This attribute is used in UI queries that need to know the build
+ #: system base class
+ build_system_class = 'MesonPackage'
+
+ build_targets = []
+ install_targets = ['install']
+
+ build_time_test_callbacks = ['check']
+
+ variant('buildtype', default='release',
+ description='Meson build type',
+ values=('plain', 'debug', 'debugoptimized', 'release', 'minsize'))
+
+ depends_on('meson', type='build')
+ depends_on('ninja', type='build')
+
+ @property
+ def archive_files(self):
+ """Files to archive for packages based on Meson"""
+ return [os.path.join(self.build_directory, 'meson-logs/meson-log.txt')]
+
+ @property
+ def root_mesonlists_dir(self):
+ """The relative path to the directory containing meson.build
+
+ This path is relative to the root of the extracted tarball,
+ not to the ``build_directory``. Defaults to the current directory.
+
+ :return: directory containing meson.build
+ """
+ return self.stage.source_path
+
+ @property
+ def std_meson_args(self):
+ """Standard meson arguments provided as a property for
+ convenience of package writers
+
+ :return: standard meson arguments
+ """
+ # standard Meson arguments
+ std_meson_args = MesonPackage._std_args(self)
+ std_meson_args += getattr(self, 'meson_flag_args', [])
+ return std_meson_args
+
+ @staticmethod
+ def _std_args(pkg):
+ """Computes the standard meson arguments for a generic package"""
+
+ try:
+ build_type = pkg.spec.variants['buildtype'].value
+ except KeyError:
+ build_type = 'release'
+
+ args = [
+ '--prefix={0}'.format(pkg.prefix),
+ # If we do not specify libdir explicitly, Meson chooses something
+ # like lib/x86_64-linux-gnu, which causes problems when trying to
+ # find libraries and pkg-config files.
+ # See https://github.com/mesonbuild/meson/issues/2197
+ '--libdir={0}'.format(pkg.prefix.lib),
+ '--buildtype={0}'.format(build_type),
+ '--strip',
+ ]
+
+ return args
+
+ def flags_to_build_system_args(self, flags):
+ """Produces a list of all command line arguments to pass the specified
+ compiler flags to meson."""
+ # Has to be dynamic attribute due to caching
+ setattr(self, 'meson_flag_args', [])
+
+ @property
+ def build_directory(self):
+ """Returns the directory to use when building the package
+
+ :return: directory where to build the package
+ """
+ return os.path.join(self.stage.source_path, 'spack-build')
+
+ def meson_args(self):
+ """Produces a list containing all the arguments that must be passed to
+ meson, except:
+
+ * ``--prefix``
+ * ``--libdir``
+ * ``--buildtype``
+ * ``--strip``
+
+ which will be set automatically.
+
+ :return: list of arguments for meson
+ """
+ return []
+
+ def meson(self, spec, prefix):
+ """Runs ``meson`` in the build directory"""
+ options = [os.path.abspath(self.root_mesonlists_dir)]
+ options += self.std_meson_args
+ options += self.meson_args()
+ with working_dir(self.build_directory, create=True):
+ inspect.getmodule(self).meson(*options)
+
+ def build(self, spec, prefix):
+ """Make the build targets"""
+ options = ['-v']
+ options += self.build_targets
+ with working_dir(self.build_directory):
+ inspect.getmodule(self).ninja(*options)
+
+ def install(self, spec, prefix):
+ """Make the install targets"""
+ with working_dir(self.build_directory):
+ inspect.getmodule(self).ninja(*self.install_targets)
+
+ run_after('build')(PackageBase._run_default_build_time_test_callbacks)
+
+ def check(self):
+ """Searches the Meson-generated file for the target ``test``
+ and runs it if found.
+ """
+ with working_dir(self.build_directory):
+ self._if_ninja_target_execute('test')
+ self._if_ninja_target_execute('check')
+
+ # Check that self.prefix is there after installation
+ run_after('install')(PackageBase.sanity_check_prefix)
diff --git a/lib/spack/spack/build_systems/octave.py b/lib/spack/spack/build_systems/octave.py
new file mode 100644
index 0000000000..ffcbb98c2a
--- /dev/null
+++ b/lib/spack/spack/build_systems/octave.py
@@ -0,0 +1,52 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import inspect
+
+from spack.directives import depends_on, extends
+from spack.package import PackageBase, run_after
+
+
+class OctavePackage(PackageBase):
+ """Specialized class for Octave packages. See
+ https://www.gnu.org/software/octave/doc/v4.2.0/Installing-and-Removing-Packages.html
+ for more information.
+
+ This class provides the following phases that can be overridden:
+
+ 1. :py:meth:`~.OctavePackage.install`
+
+ """
+ # Default phases
+ phases = ['install']
+
+ # To be used in UI queries that require to know which
+ # build-system class we are using
+ build_system_class = 'OctavePackage'
+
+ extends('octave')
+ depends_on('octave', type=('build', 'run'))
+
+ def setup_environment(self, spack_env, run_env):
+ """Set up the compile and runtime environments for a package."""
+ # octave does not like those environment variables to be set:
+ spack_env.unset('CC')
+ spack_env.unset('CXX')
+ spack_env.unset('FC')
+
+ def install(self, spec, prefix):
+ """Install the package from the archive file"""
+ inspect.getmodule(self).octave(
+ '--quiet',
+ '--norc',
+ '--built-in-docstrings-file=/dev/null',
+ '--texi-macros-file=/dev/null',
+ '--eval', 'pkg prefix %s; pkg install %s' %
+ (prefix, self.stage.archive_file))
+
+ # Testing
+
+ # Check that self.prefix is there after installation
+ run_after('install')(PackageBase.sanity_check_prefix)
diff --git a/lib/spack/spack/build_systems/perl.py b/lib/spack/spack/build_systems/perl.py
index fe845a45db..f2b088f25d 100644
--- a/lib/spack/spack/build_systems/perl.py
+++ b/lib/spack/spack/build_systems/perl.py
@@ -1,32 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
import os
-from llnl.util.filesystem import join_path
from spack.directives import depends_on, extends
from spack.package import PackageBase, run_after
from spack.util.executable import Executable
@@ -88,7 +68,7 @@ class PerlPackage(PackageBase):
elif os.path.isfile('Build.PL'):
self.build_method = 'Build.PL'
self.build_executable = Executable(
- join_path(self.stage.source_path, 'Build'))
+ os.path.join(self.stage.source_path, 'Build'))
else:
raise RuntimeError('Unknown build_method for perl package')
diff --git a/lib/spack/spack/build_systems/python.py b/lib/spack/spack/build_systems/python.py
index b07a196fff..bf469cee23 100644
--- a/lib/spack/spack/build_systems/python.py
+++ b/lib/spack/spack/build_systems/python.py
@@ -1,35 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
import os
+import shutil
from spack.directives import depends_on, extends
from spack.package import PackageBase, run_after
-from llnl.util.filesystem import working_dir
+from llnl.util.filesystem import (working_dir, get_filetype, filter_file,
+ path_contains_subdirectory, same_path)
+from llnl.util.lang import match_predicate
class PythonPackage(PackageBase):
@@ -75,7 +59,7 @@ class PythonPackage(PackageBase):
.. code-block:: console
- $ python setup.py --no-user-cfg <phase>
+ $ python -s setup.py --no-user-cfg <phase>
Each phase also has a <phase_args> function that can pass arguments to
this call. All of these functions are empty except for the ``install_args``
@@ -116,6 +100,8 @@ class PythonPackage(PackageBase):
depends_on('python', type=('build', 'run'))
+ py_namespace = None
+
def setup_file(self):
"""Returns the name of the setup file to use."""
return 'setup.py'
@@ -132,7 +118,7 @@ class PythonPackage(PackageBase):
setup = self.setup_file()
with working_dir(self.build_directory):
- self.python(setup, '--no-user-cfg', *args, **kwargs)
+ self.python('-s', setup, '--no-user-cfg', *args, **kwargs)
def _setup_command_available(self, command):
"""Determines whether or not a setup.py command exists.
@@ -152,7 +138,7 @@ class PythonPackage(PackageBase):
python = inspect.getmodule(self).python
setup = self.setup_file()
- python(setup, '--no-user-cfg', command, '--help', **kwargs)
+ python('-s', setup, '--no-user-cfg', command, '--help', **kwargs)
return python.returncode == 0
# The following phases and their descriptions come from:
@@ -237,9 +223,15 @@ class PythonPackage(PackageBase):
# Spack manages the package directory on its own by symlinking
# extensions into the site-packages directory, so we don't really
# need the .pth files or egg directories, anyway.
+ #
+ # We need to make sure this is only for build dependencies. A package
+ # such as py-basemap will not build properly with this flag since
+ # it does not use setuptools to build and those does not recognize
+ # the --single-version-externally-managed flag
if ('py-setuptools' == spec.name or # this is setuptools, or
- 'py-setuptools' in spec._dependencies): # it's an immediate dep
- args += ['--single-version-externally-managed', '--root=/']
+ 'py-setuptools' in spec._dependencies and # it's an immediate dep
+ 'build' in spec._dependencies['py-setuptools'].deptypes):
+ args += ['--single-version-externally-managed', '--root=/']
return args
@@ -389,7 +381,7 @@ class PythonPackage(PackageBase):
# Make sure we are importing the installed modules,
# not the ones in the current directory
- with working_dir('..'):
+ with working_dir('spack-test', create=True):
for module in self.import_modules:
self.python('-c', 'import {0}'.format(module))
@@ -397,3 +389,66 @@ class PythonPackage(PackageBase):
# Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix)
+
+ def view_file_conflicts(self, view, merge_map):
+ """Report all file conflicts, excepting special cases for python.
+ Specifically, this does not report errors for duplicate
+ __init__.py files for packages in the same namespace.
+ """
+ conflicts = list(dst for src, dst in merge_map.items()
+ if os.path.exists(dst))
+
+ if conflicts and self.py_namespace:
+ ext_map = view.extensions_layout.extension_map(self.extendee_spec)
+ namespaces = set(
+ x.package.py_namespace for x in ext_map.values())
+ namespace_re = (
+ r'site-packages/{0}/__init__.py'.format(self.py_namespace))
+ find_namespace = match_predicate(namespace_re)
+ if self.py_namespace in namespaces:
+ conflicts = list(
+ x for x in conflicts if not find_namespace(x))
+
+ return conflicts
+
+ def add_files_to_view(self, view, merge_map):
+ bin_dir = self.spec.prefix.bin
+ python_prefix = self.extendee_spec.prefix
+ global_view = same_path(python_prefix, view.root)
+ for src, dst in merge_map.items():
+ if os.path.exists(dst):
+ continue
+ elif global_view or not path_contains_subdirectory(src, bin_dir):
+ view.link(src, dst)
+ elif not os.path.islink(src):
+ shutil.copy2(src, dst)
+ if 'script' in get_filetype(src):
+ filter_file(
+ python_prefix, os.path.abspath(view.root), dst)
+ else:
+ orig_link_target = os.path.realpath(src)
+ new_link_target = os.path.abspath(merge_map[orig_link_target])
+ view.link(new_link_target, dst)
+
+ def remove_files_from_view(self, view, merge_map):
+ ignore_namespace = False
+ if self.py_namespace:
+ ext_map = view.extensions_layout.extension_map(self.extendee_spec)
+ remaining_namespaces = set(
+ spec.package.py_namespace for name, spec in ext_map.items()
+ if name != self.name)
+ if self.py_namespace in remaining_namespaces:
+ namespace_init = match_predicate(
+ r'site-packages/{0}/__init__.py'.format(self.py_namespace))
+ ignore_namespace = True
+
+ bin_dir = self.spec.prefix.bin
+ global_view = self.extendee_spec.prefix == view.root
+ for src, dst in merge_map.items():
+ if ignore_namespace and namespace_init(dst):
+ continue
+
+ if global_view or not path_contains_subdirectory(src, bin_dir):
+ view.remove_file(src, dst)
+ else:
+ os.remove(dst)
diff --git a/lib/spack/spack/build_systems/qmake.py b/lib/spack/spack/build_systems/qmake.py
index 70b53664dc..054d84f4b8 100644
--- a/lib/spack/spack/build_systems/qmake.py
+++ b/lib/spack/spack/build_systems/qmake.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
diff --git a/lib/spack/spack/build_systems/r.py b/lib/spack/spack/build_systems/r.py
index 05a66427ec..32bad7bac6 100644
--- a/lib/spack/spack/build_systems/r.py
+++ b/lib/spack/spack/build_systems/r.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
diff --git a/lib/spack/spack/build_systems/scons.py b/lib/spack/spack/build_systems/scons.py
index 0476362e17..a7bc5c6374 100644
--- a/lib/spack/spack/build_systems/scons.py
+++ b/lib/spack/spack/build_systems/scons.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
diff --git a/lib/spack/spack/build_systems/waf.py b/lib/spack/spack/build_systems/waf.py
index 2097e1680f..ee00d175b0 100644
--- a/lib/spack/spack/build_systems/waf.py
+++ b/lib/spack/spack/build_systems/waf.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
diff --git a/lib/spack/spack/caches.py b/lib/spack/spack/caches.py
new file mode 100644
index 0000000000..1d74e9dc3b
--- /dev/null
+++ b/lib/spack/spack/caches.py
@@ -0,0 +1,51 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Caches used by Spack to store data"""
+import os
+
+import llnl.util.lang
+
+import spack.paths
+import spack.config
+import spack.fetch_strategy
+import spack.util.file_cache
+from spack.util.path import canonicalize_path
+
+
+def _misc_cache():
+ """The ``misc_cache`` is Spack's cache for small data.
+
+ Currently the ``misc_cache`` stores indexes for virtual dependency
+ providers and for which packages provide which tags.
+ """
+ path = spack.config.get('config:misc_cache')
+ if not path:
+ path = os.path.join(spack.paths.user_config_path, 'cache')
+ path = canonicalize_path(path)
+
+ return spack.util.file_cache.FileCache(path)
+
+
+#: Spack's cache for small data
+misc_cache = llnl.util.lang.Singleton(_misc_cache)
+
+
+def _fetch_cache():
+ """Filesystem cache of downloaded archives.
+
+ This prevents Spack from repeatedly fetch the same files when
+ building the same package different ways or multiple times.
+ """
+ path = spack.config.get('config:source_cache')
+ if not path:
+ path = os.path.join(spack.paths.var_path, "cache")
+ path = canonicalize_path(path)
+
+ return spack.fetch_strategy.FsCache(path)
+
+
+#: Spack's local cache for downloaded source archives
+fetch_cache = llnl.util.lang.Singleton(_fetch_cache)
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index 39eb4c2ae1..2963c053e4 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import os
@@ -34,19 +15,12 @@ from llnl.util.tty.colify import colify
from llnl.util.tty.color import colorize
from llnl.util.filesystem import working_dir
-import spack
import spack.config
+import spack.paths
import spack.spec
import spack.store
+from spack.error import SpackError
-#
-# Settings for commands that modify configuration
-#
-# Commands that modify configuration by default modify the *highest*
-# priority scope.
-default_modify_scope = spack.config.highest_precedence_scope().name
-# Commands that list configuration list *all* scopes by default.
-default_list_scope = None
# cmd has a submodule called "list" so preserve the python list module
python_list = list
@@ -57,14 +31,40 @@ ignore_files = r'^\.|^__init__.py$|^#'
SETUP_PARSER = "setup_parser"
DESCRIPTION = "description"
-command_path = os.path.join(spack.lib_path, "spack", "cmd")
+#: Names of all commands
+all_commands = []
+
+
+def python_name(cmd_name):
+ """Convert ``-`` to ``_`` in command name, to make a valid identifier."""
+ return cmd_name.replace("-", "_")
-commands = []
-for file in os.listdir(command_path):
- if file.endswith(".py") and not re.search(ignore_files, file):
- cmd = re.sub(r'.py$', '', file)
- commands.append(cmd)
-commands.sort()
+
+def cmd_name(python_name):
+ """Convert module name (with ``_``) to command name (with ``-``)."""
+ return python_name.replace('_', '-')
+
+
+#: global, cached list of all commands -- access through all_commands()
+_all_commands = None
+
+
+def all_commands():
+ """Get a sorted list of all spack commands.
+
+ This will list the lib/spack/spack/cmd directory and find the
+ commands there to construct the list. It does not actually import
+ the python files -- just gets the names.
+ """
+ global _all_commands
+ if _all_commands is None:
+ _all_commands = []
+ for file in os.listdir(spack.paths.command_path):
+ if file.endswith(".py") and not re.search(ignore_files, file):
+ cmd = re.sub(r'.py$', '', file)
+ _all_commands.append(cmd_name(cmd))
+ _all_commands.sort()
+ return _all_commands
def remove_options(parser, *options):
@@ -76,33 +76,38 @@ def remove_options(parser, *options):
break
-def get_python_name(name):
- """Commands can have '-' in their names, unlike Python identifiers."""
- return name.replace("-", "_")
-
+def get_module(cmd_name):
+ """Imports the module for a particular command name and returns it.
-def get_module(name):
- """Imports the module for a particular command name and returns it."""
- module_name = "%s.%s" % (__name__, name)
+ Args:
+ cmd_name (str): name of the command for which to get a module
+ (contains ``-``, not ``_``).
+ """
+ pname = python_name(cmd_name)
+ module_name = "%s.%s" % (__name__, pname)
module = __import__(module_name,
- fromlist=[name, SETUP_PARSER, DESCRIPTION],
+ fromlist=[pname, SETUP_PARSER, DESCRIPTION],
level=0)
attr_setdefault(module, SETUP_PARSER, lambda *args: None) # null-op
attr_setdefault(module, DESCRIPTION, "")
- fn_name = get_python_name(name)
- if not hasattr(module, fn_name):
+ if not hasattr(module, pname):
tty.die("Command module %s (%s) must define function '%s'." %
- (module.__name__, module.__file__, fn_name))
+ (module.__name__, module.__file__, pname))
return module
-def get_command(name):
- """Imports the command's function from a module and returns it."""
- python_name = get_python_name(name)
- return getattr(get_module(python_name), python_name)
+def get_command(cmd_name):
+ """Imports the command's function from a module and returns it.
+
+ Args:
+ cmd_name (str): name of the command for which to get a module
+ (contains ``-``, not ``_``).
+ """
+ pname = python_name(cmd_name)
+ return getattr(get_module(pname), pname)
def parse_specs(args, **kwargs):
@@ -111,24 +116,30 @@ def parse_specs(args, **kwargs):
"""
concretize = kwargs.get('concretize', False)
normalize = kwargs.get('normalize', False)
+ tests = kwargs.get('tests', False)
try:
specs = spack.spec.parse(args)
for spec in specs:
if concretize:
- spec.concretize() # implies normalize
+ spec.concretize(tests=tests) # implies normalize
elif normalize:
- spec.normalize()
+ spec.normalize(tests=tests)
return specs
- except spack.parse.ParseError as e:
- tty.error(e.message, e.string, e.pos * " " + "^")
- sys.exit(1)
+ except spack.spec.SpecParseError as e:
+ msg = e.message + "\n" + str(e.string) + "\n"
+ msg += (e.pos + 2) * " " + "^"
+ raise SpackError(msg)
except spack.spec.SpecError as e:
- tty.error(e.message)
- sys.exit(1)
+
+ msg = e.message
+ if e.long_message:
+ msg += e.long_message
+
+ raise SpackError(msg)
def elide_list(line_list, max_num=10):
@@ -164,7 +175,8 @@ def disambiguate_spec(spec):
def gray_hash(spec, length):
- return colorize('@K{%s}' % spec.dag_hash(length))
+ h = spec.dag_hash(length) if spec.concrete else '-' * length
+ return colorize('@K{%s}' % h)
def display_specs(specs, args=None, **kwargs):
@@ -197,7 +209,10 @@ def display_specs(specs, args=None, **kwargs):
namespace (bool): Print namespaces along with names
show_flags (bool): Show compiler flags with specs
variants (bool): Show variants with specs
-
+ indent (int): indent each line this much
+ decorators (dict): dictionary mappng specs to decorators
+ header_callback (function): called at start of arch/compiler sections
+ all_headers (bool): show headers even when arch/compiler aren't defined
"""
def get_arg(name, default=None):
"""Prefer kwargs, then args, then default."""
@@ -208,19 +223,27 @@ def display_specs(specs, args=None, **kwargs):
else:
return default
- mode = get_arg('mode', 'short')
- hashes = get_arg('long', False)
- namespace = get_arg('namespace', False)
- flags = get_arg('show_flags', False)
+ mode = get_arg('mode', 'short')
+ hashes = get_arg('long', False)
+ namespace = get_arg('namespace', False)
+ flags = get_arg('show_flags', False)
full_compiler = get_arg('show_full_compiler', False)
- variants = get_arg('variants', False)
+ variants = get_arg('variants', False)
+ all_headers = get_arg('all_headers', False)
+
+ decorator = get_arg('decorator', None)
+ if decorator is None:
+ decorator = lambda s, f: f
+
+ indent = get_arg('indent', 0)
+ ispace = indent * ' '
hlen = 7
if get_arg('very_long', False):
hashes = True
hlen = None
- nfmt = '.' if namespace else '_'
+ nfmt = '{fullpackage}' if namespace else '{package}'
ffmt = ''
if full_compiler or flags:
ffmt += '$%'
@@ -232,30 +255,46 @@ def display_specs(specs, args=None, **kwargs):
# Make a dict with specs keyed by architecture and compiler.
index = index_by(specs, ('architecture', 'compiler'))
+ transform = {'package': decorator, 'fullpackage': decorator}
# Traverse the index and print out each package
for i, (architecture, compiler) in enumerate(sorted(index)):
if i > 0:
print()
- header = "%s{%s} / %s{%s}" % (spack.spec.architecture_color,
- architecture, spack.spec.compiler_color,
- compiler)
- tty.hline(colorize(header), char='-')
+ header = "%s{%s} / %s{%s}" % (
+ spack.spec.architecture_color,
+ architecture if architecture else 'no arch',
+ spack.spec.compiler_color,
+ compiler if compiler else 'no compiler')
+
+ # Sometimes we want to display specs that are not yet concretized.
+ # If they don't have a compiler / architecture attached to them,
+ # then skip the header
+ if all_headers or (architecture is not None or compiler is not None):
+ sys.stdout.write(ispace)
+ tty.hline(colorize(header), char='-')
specs = index[(architecture, compiler)]
specs.sort()
- abbreviated = [s.cformat(format_string) for s in specs]
if mode == 'paths':
# Print one spec per line along with prefix path
+ abbreviated = [s.cformat(format_string, transform=transform)
+ for s in specs]
width = max(len(s) for s in abbreviated)
width += 2
- format = " %%-%ds%%s" % width
for abbrv, spec in zip(abbreviated, specs):
- prefix = gray_hash(spec, hlen) if hashes else ''
- print(prefix + (format % (abbrv, spec.prefix)))
+ # optional hash prefix for paths
+ h = gray_hash(spec, hlen) if hashes else ''
+
+ # only show prefix for concrete specs
+ prefix = spec.prefix if spec.concrete else ''
+
+ # print it all out at once
+ fmt = "%%s%%s %%-%ds%%s" % width
+ print(fmt % (ispace, h, abbrv, prefix))
elif mode == 'deps':
for spec in specs:
@@ -265,24 +304,25 @@ def display_specs(specs, args=None, **kwargs):
prefix=(lambda s: gray_hash(s, hlen)) if hashes else None))
elif mode == 'short':
- # Print columns of output if not printing flags
- if not flags and not full_compiler:
+ def fmt(s):
+ string = ""
+ if hashes:
+ string += gray_hash(s, hlen) + ' '
+ string += s.cformat(
+ '$%s$@%s' % (nfmt, vfmt), transform=transform)
+ return string
- def fmt(s):
- string = ""
- if hashes:
- string += gray_hash(s, hlen) + ' '
- string += s.cformat('$-%s$@%s' % (nfmt, vfmt))
-
- return string
+ if not flags and not full_compiler:
+ # Print columns of output if not printing flags
+ colify((fmt(s) for s in specs), indent=indent)
- colify(fmt(s) for s in specs)
- # Print one entry per line if including flags
else:
+ # Print one entry per line if including flags
for spec in specs:
# Print the hash if necessary
hsh = gray_hash(spec, hlen) + ' ' if hashes else ''
- print(hsh + spec.cformat(format_string) + '\n')
+ print(ispace + hsh + spec.cformat(
+ format_string, transform=transform))
else:
raise ValueError(
@@ -292,5 +332,5 @@ def display_specs(specs, args=None, **kwargs):
def spack_is_git_repo():
"""Ensure that this instance of Spack is a git clone."""
- with working_dir(spack.prefix):
+ with working_dir(spack.paths.prefix):
return os.path.isdir('.git')
diff --git a/lib/spack/spack/cmd/activate.py b/lib/spack/spack/cmd/activate.py
index a5909df9fb..de6bbc3ecc 100644
--- a/lib/spack/spack/cmd/activate.py
+++ b/lib/spack/spack/cmd/activate.py
@@ -1,32 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
+
import llnl.util.tty as tty
-import spack
+
import spack.cmd
-from spack.directory_layout import YamlViewExtensionsLayout
+from spack.filesystem_view import YamlFilesystemView
description = "activate a package extension"
section = "extensions"
@@ -54,11 +36,17 @@ def activate(parser, args):
if not spec.package.is_extension:
tty.die("%s is not an extension." % spec.name)
- layout = spack.store.extensions
- if args.view is not None:
- layout = YamlViewExtensionsLayout(args.view, spack.store.layout)
+ if args.view:
+ target = args.view
+ else:
+ target = spec.package.extendee_spec.prefix
+
+ view = YamlFilesystemView(target, spack.store.layout)
- if spec.package.is_activated(extensions_layout=layout):
- tty.die("Package %s is already activated." % specs[0].short_spec)
+ if spec.package.is_activated(view):
+ tty.msg("Package %s is already activated." % specs[0].short_spec)
+ return
- spec.package.do_activate(extensions_layout=layout)
+ # TODO: refactor FilesystemView.add_extension and use that here (so there
+ # aren't two ways of activating extensions)
+ spec.package.do_activate(view, with_dependencies=not args.force)
diff --git a/lib/spack/spack/cmd/add.py b/lib/spack/spack/cmd/add.py
new file mode 100644
index 0000000000..6dc903ae68
--- /dev/null
+++ b/lib/spack/spack/cmd/add.py
@@ -0,0 +1,33 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import argparse
+
+import llnl.util.tty as tty
+
+import spack.cmd
+import spack.environment as ev
+
+
+description = 'add a spec to an environment'
+section = "environments"
+level = "long"
+
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ 'specs', nargs=argparse.REMAINDER, help="specs of packages to add")
+
+
+def add(parser, args):
+ env = ev.get_env(args, 'add')
+
+ for spec in spack.cmd.parse_specs(args.specs):
+ if not env.add(spec):
+ tty.msg("Package {0} was already added to {1}"
+ .format(spec.name, env.name))
+ else:
+ tty.msg('Adding %s to environment %s' % (spec, env.name))
+ env.write()
diff --git a/lib/spack/spack/cmd/arch.py b/lib/spack/spack/cmd/arch.py
index c8f844e4c1..46a2306ed5 100644
--- a/lib/spack/spack/cmd/arch.py
+++ b/lib/spack/spack/cmd/arch.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import spack.architecture as architecture
@@ -35,11 +16,24 @@ def setup_parser(subparser):
parts = subparser.add_mutually_exclusive_group()
parts.add_argument(
'-p', '--platform', action='store_true', default=False,
- help="print only the platform")
+ help='print only the platform')
+ parts.add_argument(
+ '-o', '--operating-system', action='store_true', default=False,
+ help='print only the operating system')
+ parts.add_argument(
+ '-t', '--target', action='store_true', default=False,
+ help='print only the target')
def arch(parser, args):
+ arch = architecture.Arch(
+ architecture.platform(), 'default_os', 'default_target')
+
if args.platform:
- print(architecture.platform())
+ print(arch.platform)
+ elif args.operating_system:
+ print(arch.platform_os)
+ elif args.target:
+ print(arch.target)
else:
- print(architecture.sys_type())
+ print(arch)
diff --git a/lib/spack/spack/cmd/blame.py b/lib/spack/spack/cmd/blame.py
index a4f75da19a..a385817f9f 100644
--- a/lib/spack/spack/cmd/blame.py
+++ b/lib/spack/spack/cmd/blame.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import re
@@ -30,7 +11,8 @@ from llnl.util.lang import pretty_date
from llnl.util.filesystem import working_dir
from llnl.util.tty.colify import colify_table
-import spack
+import spack.paths
+import spack.repo
from spack.util.executable import which
from spack.cmd import spack_is_git_repo
@@ -67,7 +49,7 @@ def blame(parser, args):
blame_file = None
if os.path.isfile(args.package_name):
path = os.path.realpath(args.package_name)
- if path.startswith(spack.prefix):
+ if path.startswith(spack.paths.prefix):
blame_file = path
if not blame_file:
@@ -75,7 +57,7 @@ def blame(parser, args):
blame_file = pkg.module.__file__.rstrip('c') # .pyc -> .py
# get git blame for the package
- with working_dir(spack.prefix):
+ with working_dir(spack.paths.prefix):
if args.view == 'git':
git('blame', blame_file)
return
diff --git a/lib/spack/spack/cmd/bootstrap.py b/lib/spack/spack/cmd/bootstrap.py
index b41b568fb3..ee09298cb2 100644
--- a/lib/spack/spack/cmd/bootstrap.py
+++ b/lib/spack/spack/cmd/bootstrap.py
@@ -1,30 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import llnl.util.tty as tty
-import spack
-import spack.cmd
+
+import spack.repo
+import spack.spec
import spack.cmd.common.arguments as arguments
description = "Bootstrap packages needed for spack to run smoothly"
@@ -35,16 +17,14 @@ level = "long"
def setup_parser(subparser):
subparser.add_argument(
'-j', '--jobs', action='store', type=int,
- help="explicitly set number of make jobs. default is #cpus")
+ help="explicitly set number of make jobs (default: #cpus)")
subparser.add_argument(
'--keep-prefix', action='store_true', dest='keep_prefix',
help="don't remove the install prefix if installation fails")
subparser.add_argument(
'--keep-stage', action='store_true', dest='keep_stage',
help="don't remove the build stage if installation succeeds")
- subparser.add_argument(
- '-n', '--no-checksum', action='store_true', dest='no_checksum',
- help="do not check packages against checksum")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'-v', '--verbose', action='store_true', dest='verbose',
help="display verbose build output while installing")
@@ -52,11 +32,6 @@ def setup_parser(subparser):
cd_group = subparser.add_mutually_exclusive_group()
arguments.add_common_arguments(cd_group, ['clean', 'dirty'])
- subparser.add_argument(
- '--run-tests', action='store_true', dest='run_tests',
- help="run package level tests during installation"
- )
-
def bootstrap(parser, args, **kwargs):
kwargs.update({
@@ -64,7 +39,6 @@ def bootstrap(parser, args, **kwargs):
'keep_stage': args.keep_stage,
'install_deps': 'dependencies',
'make_jobs': args.jobs,
- 'run_tests': args.run_tests,
'verbose': args.verbose,
'dirty': args.dirty
})
@@ -81,7 +55,7 @@ def bootstrap(parser, args, **kwargs):
"package %s" % (requirement, installed_specs[0]))
else:
# Install requirement
- spec_to_install = spack.Spec(requirement_dict[requirement])
+ spec_to_install = spack.spec.Spec(requirement_dict[requirement])
spec_to_install.concretize()
tty.msg("Installing %s to satisfy requirement for %s" %
(spec_to_install, requirement))
diff --git a/lib/spack/spack/cmd/build.py b/lib/spack/spack/cmd/build.py
index 08fb9f1350..13b5621cd4 100644
--- a/lib/spack/spack/cmd/build.py
+++ b/lib/spack/spack/cmd/build.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import spack.cmd.configure as cfg
from spack.build_systems.autotools import AutotoolsPackage
@@ -31,6 +12,7 @@ from spack.build_systems.scons import SConsPackage
from spack.build_systems.waf import WafPackage
from spack.build_systems.python import PythonPackage
from spack.build_systems.perl import PerlPackage
+from spack.build_systems.meson import MesonPackage
description = 'stops at build stage when installing a package, if possible'
section = "build"
@@ -45,6 +27,7 @@ build_system_to_phase = {
WafPackage: 'build',
PythonPackage: 'build',
PerlPackage: 'build',
+ MesonPackage: 'build',
}
diff --git a/lib/spack/spack/cmd/build_env.py b/lib/spack/spack/cmd/build_env.py
new file mode 100644
index 0000000000..cb87bbc620
--- /dev/null
+++ b/lib/spack/spack/cmd/build_env.py
@@ -0,0 +1,59 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from __future__ import print_function
+
+import argparse
+import os
+
+import llnl.util.tty as tty
+import spack.build_environment as build_environment
+import spack.cmd
+import spack.cmd.common.arguments as arguments
+
+description = "show install environment for a spec, and run commands"
+section = "build"
+level = "long"
+
+
+def setup_parser(subparser):
+ arguments.add_common_arguments(subparser, ['clean', 'dirty'])
+ subparser.add_argument(
+ 'spec', nargs=argparse.REMAINDER,
+ help="specs of package environment to emulate")
+
+
+def build_env(parser, args):
+ if not args.spec:
+ tty.die("spack build-env requires a spec.")
+
+ # Specs may have spaces in them, so if they do, require that the
+ # caller put a '--' between the spec and the command to be
+ # executed. If there is no '--', assume that the spec is the
+ # first argument.
+ sep = '--'
+ if sep in args.spec:
+ s = args.spec.index(sep)
+ spec = args.spec[:s]
+ cmd = args.spec[s + 1:]
+ else:
+ spec = args.spec[0]
+ cmd = args.spec[1:]
+
+ specs = spack.cmd.parse_specs(spec, concretize=True)
+ if len(specs) > 1:
+ tty.die("spack build-env only takes one spec.")
+ spec = specs[0]
+
+ build_environment.setup_package(spec.package, args.dirty)
+
+ if not cmd:
+ # If no command act like the "env" command and print out env vars.
+ for key, val in os.environ.items():
+ print("%s=%s" % (key, val))
+
+ else:
+ # Otherwise execute the command with the new environment
+ os.execvp(cmd[0], cmd)
diff --git a/lib/spack/spack/cmd/buildcache.py b/lib/spack/spack/cmd/buildcache.py
index 653c59074a..dc9f736a7e 100644
--- a/lib/spack/spack/cmd/buildcache.py
+++ b/lib/spack/spack/cmd/buildcache.py
@@ -1,41 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the LICENSE file for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License (as published by
-# the Free Software Foundation) version 2.1 dated February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
-import os
import llnl.util.tty as tty
-import spack
import spack.cmd
+import spack.repo
+import spack.store
+import spack.spec
import spack.binary_distribution as bindist
-from spack.binary_distribution import NoOverwriteException, NoGpgException
-from spack.binary_distribution import NoKeyException, PickKeyException
-from spack.binary_distribution import NoVerifyException, NoChecksumException
-description = "Create, download and install build cache files."
-section = "caching"
+description = "create, download and install binary packages"
+section = "packaging"
level = "long"
@@ -43,15 +22,18 @@ def setup_parser(subparser):
setup_parser.parser = subparser
subparsers = subparser.add_subparsers(help='buildcache sub-commands')
- create = subparsers.add_parser('create')
+ create = subparsers.add_parser('create', help=createtarball.__doc__)
create.add_argument('-r', '--rel', action='store_true',
help="make all rpaths relative" +
" before creating tarballs.")
create.add_argument('-f', '--force', action='store_true',
help="overwrite tarball if it exists.")
- create.add_argument('-y', '--yes-to-all', action='store_true',
- help="answer yes to all create unsigned " +
- "buildcache questions")
+ create.add_argument('-u', '--unsigned', action='store_true',
+ help="create unsigned buildcache" +
+ " tarballs for testing")
+ create.add_argument('-a', '--allow_root', action='store_true',
+ help="allow install root string in binary files " +
+ "after RPATH substitution")
create.add_argument('-k', '--key', metavar='key',
type=str, default=None,
help="Key for signing.")
@@ -63,18 +45,23 @@ def setup_parser(subparser):
help="specs of packages to create buildcache for")
create.set_defaults(func=createtarball)
- install = subparsers.add_parser('install')
+ install = subparsers.add_parser('install', help=installtarball.__doc__)
install.add_argument('-f', '--force', action='store_true',
help="overwrite install directory if it exists.")
- install.add_argument('-y', '--yes-to-all', action='store_true',
- help="answer yes to all install unsigned " +
- "buildcache questions")
+ install.add_argument('-m', '--multiple', action='store_true',
+ help="allow all matching packages ")
+ install.add_argument('-a', '--allow_root', action='store_true',
+ help="allow install root string in binary files " +
+ "after RPATH substitution")
+ install.add_argument('-u', '--unsigned', action='store_true',
+ help="install unsigned buildcache" +
+ " tarballs for testing")
install.add_argument(
'packages', nargs=argparse.REMAINDER,
- help="specs of packages to install biuldache for")
+ help="specs of packages to install buildcache for")
install.set_defaults(func=installtarball)
- listcache = subparsers.add_parser('list')
+ listcache = subparsers.add_parser('list', help=listspecs.__doc__)
listcache.add_argument('-f', '--force', action='store_true',
help="force new download of specs")
listcache.add_argument(
@@ -82,13 +69,13 @@ def setup_parser(subparser):
help="specs of packages to search for")
listcache.set_defaults(func=listspecs)
- dlkeys = subparsers.add_parser('keys')
+ dlkeys = subparsers.add_parser('keys', help=getkeys.__doc__)
dlkeys.add_argument(
'-i', '--install', action='store_true',
help="install Keys pulled from mirror")
dlkeys.add_argument(
- '-y', '--yes-to-all', action='store_true',
- help="answer yes to all trust questions")
+ '-t', '--trust', action='store_true',
+ help="trust all downloaded keys")
dlkeys.add_argument('-f', '--force', action='store_true',
help="force new download of keys")
dlkeys.set_defaults(func=getkeys)
@@ -179,26 +166,18 @@ def match_downloaded_specs(pkgs, allow_multiple_matches=False, force=False):
def createtarball(args):
+ """create a binary package from an existing install"""
if not args.packages:
tty.die("build cache file creation requires at least one" +
" installed package argument")
pkgs = set(args.packages)
specs = set()
- outdir = os.getcwd()
+ outdir = '.'
if args.directory:
outdir = args.directory
signkey = None
if args.key:
signkey = args.key
- yes_to_all = False
- force = False
- relative = False
- if args.yes_to_all:
- yes_to_all = True
- if args.force:
- force = True
- if args.rel:
- relative = True
matches = find_matching_specs(pkgs, False, False)
for match in matches:
@@ -219,38 +198,21 @@ def createtarball(args):
tty.msg('adding dependency %s' % node.format())
specs.add(node)
+ tty.msg('writing tarballs to %s/build_cache' % outdir)
+
for spec in specs:
tty.msg('creating binary cache file for package %s ' % spec.format())
- try:
- bindist.build_tarball(spec, outdir, force,
- relative, yes_to_all, signkey)
- except NoOverwriteException as e:
- tty.warn("%s exists, use -f to force overwrite." % e)
- except NoGpgException:
- tty.die("gpg2 is not available,"
- " use -y to create unsigned build caches")
- except NoKeyException:
- tty.die("no default key available for signing,"
- " use -y to create unsigned build caches"
- " or spack gpg init to create a default key")
- except PickKeyException:
- tty.die("multi keys available for signing,"
- " use -y to create unsigned build caches"
- " or -k <key hash> to pick a key")
+ bindist.build_tarball(spec, outdir, args.force, args.rel,
+ args.unsigned, args.allow_root, signkey)
def installtarball(args):
+ """install from a binary package"""
if not args.packages:
tty.die("build cache file installation requires" +
" at least one package spec argument")
pkgs = set(args.packages)
- yes_to_all = False
- if args.yes_to_all:
- yes_to_all = True
- force = False
- if args.force:
- force = True
- matches = match_downloaded_specs(pkgs, yes_to_all, force)
+ matches = match_downloaded_specs(pkgs, args.multiple, args.force)
for match in matches:
install_tarball(match, args)
@@ -261,41 +223,27 @@ def install_tarball(spec, args):
if s.external or s.virtual:
tty.warn("Skipping external or virtual package %s" % spec.format())
return
- yes_to_all = False
- if args.yes_to_all:
- yes_to_all = True
- force = False
- if args.force:
- force = True
for d in s.dependencies(deptype=('link', 'run')):
tty.msg("Installing buildcache for dependency spec %s" % d)
install_tarball(d, args)
package = spack.repo.get(spec)
- if s.concrete and package.installed and not force:
- tty.warn("Package for spec %s already installed." % spec.format(),
- " Use -f flag to overwrite.")
+ if s.concrete and package.installed and not args.force:
+ tty.warn("Package for spec %s already installed." % spec.format())
else:
tarball = bindist.download_tarball(spec)
if tarball:
tty.msg('Installing buildcache for spec %s' % spec.format())
- try:
- bindist.extract_tarball(spec, tarball, yes_to_all, force)
- except NoOverwriteException as e:
- tty.warn("%s exists. use -f to force overwrite." % e.args)
- except NoVerifyException:
- tty.die("Package spec file failed signature verification,"
- " use -y flag to install build cache")
- except NoChecksumException:
- tty.die("Package tarball failed checksum verification,"
- " use -y flag to install build cache")
- finally:
- spack.store.db.reindex(spack.store.layout)
+ bindist.extract_tarball(spec, tarball, args.allow_root,
+ args.unsigned, args.force)
+ spack.hooks.post_install(spec)
+ spack.store.store.reindex()
else:
tty.die('Download of binary cache file for spec %s failed.' %
spec.format())
def listspecs(args):
+ """list binary packages available from mirrors"""
specs = bindist.get_specs(args.force)
if args.packages:
pkgs = set(args.packages)
@@ -318,16 +266,8 @@ def listspecs(args):
def getkeys(args):
- install = False
- if args.install:
- install = True
- yes_to_all = False
- if args.yes_to_all:
- yes_to_all = True
- force = False
- if args.force:
- force = True
- bindist.get_keys(install, yes_to_all, force)
+ """get public keys available on mirrors"""
+ bindist.get_keys(args.install, args.trust, args.force)
def buildcache(parser, args):
diff --git a/lib/spack/spack/cmd/cd.py b/lib/spack/spack/cmd/cd.py
index bf86ba573d..b2dae30fd8 100644
--- a/lib/spack/spack/cmd/cd.py
+++ b/lib/spack/spack/cmd/cd.py
@@ -1,32 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.cmd.common import print_module_placeholder_help
+
import spack.cmd.location
-import spack.modules
description = "cd to spack directories in the shell"
-section = "environment"
+section = "developer"
level = "long"
@@ -38,4 +20,4 @@ def setup_parser(subparser):
def cd(parser, args):
- spack.modules.print_help()
+ print_module_placeholder_help()
diff --git a/lib/spack/spack/cmd/checksum.py b/lib/spack/spack/cmd/checksum.py
index 4a930ac5d0..19bfde49bd 100644
--- a/lib/spack/spack/cmd/checksum.py
+++ b/lib/spack/spack/cmd/checksum.py
@@ -1,34 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import argparse
import llnl.util.tty as tty
-import spack
+
import spack.cmd
+import spack.repo
import spack.util.crypto
import spack.util.web
from spack.util.naming import valid_fully_qualified_module_name
@@ -54,8 +36,7 @@ def setup_parser(subparser):
def checksum(parser, args):
# Make sure the user provided a package and not a URL
if not valid_fully_qualified_module_name(args.package):
- tty.die("`spack checksum` accepts package names, not URLs. "
- "Use `spack md5 <url>` instead.")
+ tty.die("`spack checksum` accepts package names, not URLs.")
# Get the package we're going to generate checksums for
pkg = spack.repo.get(args.package)
diff --git a/lib/spack/spack/cmd/clean.py b/lib/spack/spack/cmd/clean.py
index 62359aaa42..5d3d39997f 100644
--- a/lib/spack/spack/cmd/clean.py
+++ b/lib/spack/spack/cmd/clean.py
@@ -1,33 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
+import os
+import shutil
import llnl.util.tty as tty
-import spack
+import spack.caches
import spack.cmd
+import spack.repo
+import spack.stage
+from spack.paths import lib_path, var_path
+
description = "remove temporary build files and/or downloaded archives"
section = "build"
@@ -35,9 +22,9 @@ level = "long"
class AllClean(argparse.Action):
- """Activates flags -s -d and -m simultaneously"""
+ """Activates flags -s -d -m and -p simultaneously"""
def __call__(self, parser, namespace, values, option_string=None):
- parser.parse_args(['-sdm'], namespace=namespace)
+ parser.parse_args(['-sdmp'], namespace=namespace)
def setup_parser(subparser):
@@ -51,7 +38,10 @@ def setup_parser(subparser):
'-m', '--misc-cache', action='store_true',
help="remove long-lived caches, like the virtual package index")
subparser.add_argument(
- '-a', '--all', action=AllClean, help="equivalent to -sdm", nargs=0
+ '-p', '--python-cache', action='store_true',
+ help="remove .pyc, .pyo files and __pycache__ folders")
+ subparser.add_argument(
+ '-a', '--all', action=AllClean, help="equivalent to -sdmp", nargs=0
)
subparser.add_argument(
'specs',
@@ -61,9 +51,9 @@ def setup_parser(subparser):
def clean(parser, args):
-
# If nothing was set, activate the default
- if not any([args.specs, args.stage, args.downloads, args.misc_cache]):
+ if not any([args.specs, args.stage, args.downloads, args.misc_cache,
+ args.python_cache]):
args.stage = True
# Then do the cleaning falling through the cases
@@ -81,8 +71,23 @@ def clean(parser, args):
if args.downloads:
tty.msg('Removing cached downloads')
- spack.fetch_cache.destroy()
+ spack.caches.fetch_cache.destroy()
if args.misc_cache:
tty.msg('Removing cached information on repositories')
- spack.misc_cache.destroy()
+ spack.caches.misc_cache.destroy()
+
+ if args.python_cache:
+ tty.msg('Removing python cache files')
+ for directory in [lib_path, var_path]:
+ for root, dirs, files in os.walk(directory):
+ for f in files:
+ if f.endswith('.pyc') or f.endswith('.pyo'):
+ fname = os.path.join(root, f)
+ tty.debug('Removing {0}'.format(fname))
+ os.remove(fname)
+ for d in dirs:
+ if d == '__pycache__':
+ dname = os.path.join(root, d)
+ tty.debug('Removing {0}'.format(dname))
+ shutil.rmtree(dname)
diff --git a/lib/spack/spack/cmd/clone.py b/lib/spack/spack/cmd/clone.py
index 1394368f0b..9926bf016e 100644
--- a/lib/spack/spack/cmd/clone.py
+++ b/lib/spack/spack/cmd/clone.py
@@ -1,33 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the LICENSE file for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import llnl.util.tty as tty
from llnl.util.filesystem import mkdirp, working_dir
-import spack
+import spack.paths
from spack.util.executable import ProcessError, which
_SPACK_UPSTREAM = 'https://github.com/spack/spack'
@@ -43,11 +24,11 @@ def setup_parser(subparser):
help="name of the remote to clone from", default='origin')
subparser.add_argument(
'prefix',
- help="names of prefix where we should install spack")
+ help="name of prefix where we should install spack")
def get_origin_info(remote):
- git_dir = os.path.join(spack.prefix, '.git')
+ git_dir = os.path.join(spack.paths.prefix, '.git')
git = which('git', required=True)
try:
branch = git('symbolic-ref', '--short', 'HEAD', output=str)
diff --git a/lib/spack/spack/cmd/commands.py b/lib/spack/spack/cmd/commands.py
new file mode 100644
index 0000000000..bf29b3f096
--- /dev/null
+++ b/lib/spack/spack/cmd/commands.py
@@ -0,0 +1,123 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from __future__ import print_function
+
+import sys
+import re
+import argparse
+
+from llnl.util.argparsewriter import ArgparseWriter, ArgparseRstWriter
+
+import spack.main
+from spack.main import section_descriptions
+
+
+description = "list available spack commands"
+section = "developer"
+level = "long"
+
+
+#: list of command formatters
+formatters = {}
+
+
+def formatter(func):
+ """Decorator used to register formatters"""
+ formatters[func.__name__] = func
+ return func
+
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ '--format', default='names', choices=formatters,
+ help='format to be used to print the output (default: names)')
+ subparser.add_argument(
+ 'documented_commands', nargs=argparse.REMAINDER,
+ help='list of documented commands to cross-references')
+
+
+class SpackArgparseRstWriter(ArgparseRstWriter):
+ """RST writer tailored for spack documentation."""
+
+ def __init__(self, documented_commands, out=sys.stdout):
+ super(SpackArgparseRstWriter, self).__init__(out)
+ self.documented = documented_commands if documented_commands else []
+
+ def usage(self, *args):
+ super(SpackArgparseRstWriter, self).usage(*args)
+ cmd = re.sub(' ', '-', self.parser.prog)
+ if cmd in self.documented:
+ self.line()
+ self.line(':ref:`More documentation <cmd-%s>`' % cmd)
+
+
+class SubcommandWriter(ArgparseWriter):
+ def begin_command(self, prog):
+ print(' ' * self.level + prog)
+
+
+@formatter
+def subcommands(args):
+ parser = spack.main.make_argument_parser()
+ spack.main.add_all_commands(parser)
+ SubcommandWriter().write(parser)
+
+
+def rst_index(out=sys.stdout):
+ out.write('\n')
+
+ index = spack.main.index_commands()
+ sections = index['long']
+
+ dmax = max(len(section_descriptions.get(s, s)) for s in sections) + 2
+ cmax = max(len(c) for _, c in sections.items()) + 60
+
+ row = "%s %s\n" % ('=' * dmax, '=' * cmax)
+ line = '%%-%ds %%s\n' % dmax
+
+ out.write(row)
+ out.write(line % (" Category ", " Commands "))
+ out.write(row)
+ for section, commands in sorted(sections.items()):
+ description = section_descriptions.get(section, section)
+
+ for i, cmd in enumerate(sorted(commands)):
+ description = description.capitalize() if i == 0 else ''
+ ref = ':ref:`%s <spack-%s>`' % (cmd, cmd)
+ comma = ',' if i != len(commands) - 1 else ''
+ bar = '| ' if i % 8 == 0 else ' '
+ out.write(line % (description, bar + ref + comma))
+ out.write(row)
+
+
+@formatter
+def rst(args):
+ # print an index to each command
+ rst_index()
+ print()
+
+ # create a parser with all commands
+ parser = spack.main.make_argument_parser()
+ spack.main.add_all_commands(parser)
+
+ # get documented commands from the command line
+ documented_commands = set(args.documented_commands)
+
+ # print sections for each command and subcommand
+ SpackArgparseRstWriter(documented_commands).write(parser, root=1)
+
+
+@formatter
+def names(args):
+ for cmd in spack.cmd.all_commands():
+ print(cmd)
+
+
+def commands(parser, args):
+
+ # Print to stdout
+ formatters[args.format](args)
+ return
diff --git a/lib/spack/spack/cmd/common/__init__.py b/lib/spack/spack/cmd/common/__init__.py
index bb4e45438e..40fee516d1 100644
--- a/lib/spack/spack/cmd/common/__init__.py
+++ b/lib/spack/spack/cmd/common/__init__.py
@@ -1,46 +1,37 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import spack
+
+import spack.paths
from llnl.util import tty
+shell_init_instructions = [
+ "To initialize spack's shell commands:",
+ "",
+ " # for bash and zsh",
+ " . %s/setup-env.sh" % spack.paths.share_path,
+ "",
+ " # for csh and tcsh",
+ " setenv SPACK_ROOT %s" % spack.paths.prefix,
+ " source %s/setup-env.csh" % spack.paths.share_path, ""
+]
+
+
def print_module_placeholder_help():
"""
For use by commands to tell user how to activate shell support.
"""
- tty.msg("This command requires spack's shell integration.", "",
- "To initialize spack's shell commands, you must run one of",
- "the commands below. Choose the right command for your shell.",
- "", "For bash and zsh:",
- " . %s/setup-env.sh" % spack.share_path, "",
- "For csh and tcsh:", " setenv SPACK_ROOT %s" % spack.prefix,
- " source %s/setup-env.csh" % spack.share_path, "",
- "This exposes a 'spack' shell function, which you can use like",
- " $ spack load package-foo", "",
- "Running the Spack executable directly (for example, invoking",
- "./bin/spack) will bypass the shell function and print this",
- "placeholder message, even if you have sourced one of the above",
- "shell integration scripts.")
+ msg = [
+ "This command requires spack's shell integration.", ""
+ ] + shell_init_instructions + [
+ "This exposes a 'spack' shell function, which you can use like",
+ " $ spack load package-foo", "",
+ "Running the Spack executable directly (for example, invoking",
+ "./bin/spack) will bypass the shell function and print this",
+ "placeholder message, even if you have sourced one of the above",
+ "shell integration scripts."
+ ]
+ tty.msg(*msg)
diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py
index 6628ec4190..b3b8773e00 100644
--- a/lib/spack/spack/cmd/common/arguments.py
+++ b/lib/spack/spack/cmd/common/arguments.py
@@ -1,31 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import spack.cmd
+import spack.config
+import spack.environment as ev
import spack.modules
import spack.spec
import spack.store
@@ -52,7 +35,7 @@ def add_common_arguments(parser, list_of_arguments):
class ConstraintAction(argparse.Action):
- """Constructs a list of specs based on a constraint given on the command line
+ """Constructs a list of specs based on constraints from the command line
An instance of this class is supposed to be used as an argument action
in a parser. It will read a constraint and will attach a function to the
@@ -60,7 +43,6 @@ class ConstraintAction(argparse.Action):
To obtain the specs from a command the function must be called.
"""
-
def __call__(self, parser, namespace, values, option_string=None):
# Query specs from command line
self.values = values
@@ -70,45 +52,30 @@ class ConstraintAction(argparse.Action):
def _specs(self, **kwargs):
qspecs = spack.cmd.parse_specs(self.values)
+ # If an environment is provided, we'll restrict the search to
+ # only its installed packages.
+ env = ev._active_environment
+ if env:
+ kwargs['hashes'] = set(env.all_hashes())
+
# return everything for an empty query.
if not qspecs:
return spack.store.db.query(**kwargs)
# Return only matching stuff otherwise.
- specs = set()
+ specs = {}
for spec in qspecs:
for s in spack.store.db.query(spec, **kwargs):
- specs.add(s)
- return sorted(specs)
+ # This is fast for already-concrete specs
+ specs[s.dag_hash()] = s
-
-class CleanOrDirtyAction(argparse.Action):
- """Sets the dirty flag in the current namespace"""
-
- def __init__(self, *args, **kwargs):
- kwargs['default'] = spack.dirty
- super(CleanOrDirtyAction, self).__init__(*args, **kwargs)
-
- def __call__(self, parser, namespace, values, option_string=None):
- if option_string == '--clean':
- setattr(namespace, self.dest, False)
- elif option_string == '--dirty':
- setattr(namespace, self.dest, True)
- else:
- msg = 'expected "--dirty" or "--clean" [got {0} instead]'
- raise argparse.ArgumentError(msg.format(option_string))
+ return sorted(specs.values())
_arguments['constraint'] = Args(
'constraint', nargs=argparse.REMAINDER, action=ConstraintAction,
help='constraint to select a subset of installed packages')
-_arguments['module_type'] = Args(
- '-m', '--module-type',
- choices=spack.modules.module_types.keys(),
- action='append',
- help='type of module file. More than one choice is allowed [default: tcl]') # NOQA: ignore=E501
-
_arguments['yes_to_all'] = Args(
'-y', '--yes-to-all', action='store_true', dest='yes_to_all',
help='assume "yes" is the answer to every confirmation request')
@@ -117,22 +84,24 @@ _arguments['recurse_dependencies'] = Args(
'-r', '--dependencies', action='store_true', dest='recurse_dependencies',
help='recursively traverse spec dependencies')
+_arguments['recurse_dependents'] = Args(
+ '-R', '--dependents', action='store_true', dest='dependents',
+ help='also uninstall any packages that depend on the ones given '
+ 'via command line')
+
_arguments['clean'] = Args(
'--clean',
- action=CleanOrDirtyAction,
+ action='store_false',
+ default=spack.config.get('config:dirty'),
dest='dirty',
- help='sanitize the environment from variables that can affect how ' +
- ' packages find libraries or headers',
- nargs=0
-)
+ help='unset harmful variables in the build environment (default)')
_arguments['dirty'] = Args(
'--dirty',
- action=CleanOrDirtyAction,
+ action='store_true',
+ default=spack.config.get('config:dirty'),
dest='dirty',
- help='maintain the current environment without trying to sanitize it',
- nargs=0
-)
+ help='preserve user environment in the spack build environment (danger!)')
_arguments['long'] = Args(
'-l', '--long', action='store_true',
@@ -142,6 +111,24 @@ _arguments['very_long'] = Args(
'-L', '--very-long', action='store_true',
help='show full dependency hashes as well as versions')
+_arguments['jobs'] = Args(
+ '-j', '--jobs', action='store', type=int, dest='jobs',
+ help="explicitely set number of make jobs. default is #cpus")
+
_arguments['tags'] = Args(
'-t', '--tags', action='append',
help='filter a package query by tags')
+
+_arguments['jobs'] = Args(
+ '-j', '--jobs', action='store', type=int, dest="jobs",
+ help="explicitly set number of make jobs, default is #cpus.")
+
+_arguments['install_status'] = Args(
+ '-I', '--install-status', action='store_true', default=False,
+ help='show install status of packages. packages can be: '
+ 'installed [+], missing and needed by an installed package [-], '
+ 'or not installed (no annotation)')
+
+_arguments['no_checksum'] = Args(
+ '-n', '--no-checksum', action='store_true', default=False,
+ help="do not use checksums to verify downloadeded files (unsafe)")
diff --git a/lib/spack/spack/cmd/compiler.py b/lib/spack/spack/cmd/compiler.py
index e7be196b1f..bf2e1687f8 100644
--- a/lib/spack/spack/cmd/compiler.py
+++ b/lib/spack/spack/cmd/compiler.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import argparse
@@ -46,7 +27,8 @@ def setup_parser(subparser):
sp = subparser.add_subparsers(
metavar='SUBCOMMAND', dest='compiler_command')
- scopes = spack.config.config_scopes
+ scopes = spack.config.scopes()
+ scopes_metavar = spack.config.scopes_metavar
# Find
find_parser = sp.add_parser(
@@ -54,7 +36,8 @@ def setup_parser(subparser):
help='search the system for compilers to add to Spack configuration')
find_parser.add_argument('add_paths', nargs=argparse.REMAINDER)
find_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_modify_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_modify_scope(),
help="configuration scope to modify")
# Remove
@@ -65,20 +48,23 @@ def setup_parser(subparser):
help='remove ALL compilers that match spec')
remove_parser.add_argument('compiler_spec')
remove_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_modify_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_modify_scope(),
help="configuration scope to modify")
# List
list_parser = sp.add_parser('list', help='list available compilers')
list_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_list_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_list_scope(),
help="configuration scope to read from")
# Info
info_parser = sp.add_parser('info', help='show compiler paths')
info_parser.add_argument('compiler_spec')
info_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_list_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_list_scope(),
help="configuration scope to read from")
@@ -109,7 +95,9 @@ def compiler_find(args):
init_config=False)
n = len(new_compilers)
s = 's' if n > 1 else ''
- filename = spack.config.get_config_filename(args.scope, 'compilers')
+
+ config = spack.config.config
+ filename = config.get_config_filename(args.scope, 'compilers')
tty.msg("Added %d new compiler%s to %s" % (n, s, filename))
colify(reversed(sorted(c.spec for c in new_compilers)), indent=4)
else:
diff --git a/lib/spack/spack/cmd/compilers.py b/lib/spack/spack/cmd/compilers.py
index 7895d11d94..7510e24b7e 100644
--- a/lib/spack/spack/cmd/compilers.py
+++ b/lib/spack/spack/cmd/compilers.py
@@ -1,28 +1,9 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import spack
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import spack.config
from spack.cmd.compiler import compiler_list
description = "list available compilers"
@@ -31,8 +12,12 @@ level = "short"
def setup_parser(subparser):
- subparser.add_argument('--scope', choices=spack.config.config_scopes,
- help="configuration scope to read/modify")
+ scopes = spack.config.scopes()
+ scopes_metavar = spack.config.scopes_metavar
+
+ subparser.add_argument(
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ help="configuration scope to read/modify")
def compilers(parser, args):
diff --git a/lib/spack/spack/cmd/concretize.py b/lib/spack/spack/cmd/concretize.py
new file mode 100644
index 0000000000..728718e502
--- /dev/null
+++ b/lib/spack/spack/cmd/concretize.py
@@ -0,0 +1,22 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import spack.environment as ev
+
+description = 'concretize an environment and write a lockfile'
+section = "environments"
+level = "long"
+
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ '-f', '--force', action='store_true',
+ help="Re-concretize even if already concretized.")
+
+
+def concretize(parser, args):
+ env = ev.get_env(args, 'concretize')
+ env.concretize(force=args.force)
+ env.write()
diff --git a/lib/spack/spack/cmd/config.py b/lib/spack/spack/cmd/config.py
index f2325e73e0..4fd21768c8 100644
--- a/lib/spack/spack/cmd/config.py
+++ b/lib/spack/spack/cmd/config.py
@@ -1,28 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from __future__ import print_function
+import os
+
+import llnl.util.tty as tty
+
import spack.config
+import spack.environment as ev
+
+from spack.util.editor import editor
description = "get and set configuration options"
section = "config"
@@ -30,9 +19,13 @@ level = "long"
def setup_parser(subparser):
+ scopes = spack.config.scopes()
+ scopes_metavar = spack.config.scopes_metavar
+
# User can only choose one
- subparser.add_argument('--scope', choices=spack.config.config_scopes,
- help="configuration scope to read/modify")
+ subparser.add_argument(
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ help="configuration scope to read/modify")
sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='config_command')
@@ -40,34 +33,102 @@ def setup_parser(subparser):
get_parser.add_argument('section',
help="configuration section to print. "
"options: %(choices)s",
+ nargs='?',
metavar='SECTION',
choices=spack.config.section_schemas)
+ blame_parser = sp.add_parser(
+ 'blame', help='print configuration annotated with source file:line')
+ blame_parser.add_argument('section',
+ help="configuration section to print. "
+ "options: %(choices)s",
+ metavar='SECTION',
+ choices=spack.config.section_schemas)
+
edit_parser = sp.add_parser('edit', help='edit configuration file')
edit_parser.add_argument('section',
help="configuration section to edit. "
"options: %(choices)s",
metavar='SECTION',
+ nargs='?',
choices=spack.config.section_schemas)
+ edit_parser.add_argument(
+ '--print-file', action='store_true',
+ help="print the file name that would be edited")
+
+
+def _get_scope_and_section(args):
+ """Extract config scope and section from arguments."""
+ scope = args.scope
+ section = args.section
+
+ # w/no args and an active environment, point to env manifest
+ if not args.section:
+ env = ev.get_env(args, 'config edit', required=False)
+ if env:
+ scope = env.env_file_config_scope_name()
+
+ # set scope defaults
+ elif not args.scope:
+ if section == 'compilers':
+ scope = spack.config.default_modify_scope()
+ else:
+ scope = 'user'
+
+ return scope, section
def config_get(args):
- spack.config.print_section(args.section)
+ """Dump merged YAML configuration for a specific section.
+ With no arguments and an active environment, print the contents of
+ the environment's manifest file (spack.yaml).
-def config_edit(args):
- if not args.scope:
- if args.section == 'compilers':
- args.scope = spack.cmd.default_modify_scope
+ """
+ scope, section = _get_scope_and_section(args)
+
+ if scope and scope.startswith('env:'):
+ config_file = spack.config.config.get_config_filename(scope, section)
+ if os.path.exists(config_file):
+ with open(config_file) as f:
+ print(f.read())
else:
- args.scope = 'user'
- if not args.section:
- args.section = None
- config_file = spack.config.get_config_filename(args.scope, args.section)
- spack.editor(config_file)
+ tty.die('environment has no %s file' % ev.manifest_name)
+
+ elif section is not None:
+ spack.config.config.print_section(section)
+
+ else:
+ tty.die('`spack config get` requires a section argument '
+ 'or an active environment.')
+
+
+def config_blame(args):
+ """Print out line-by-line blame of merged YAML."""
+ spack.config.config.print_section(args.section, blame=True)
+
+
+def config_edit(args):
+ """Edit the configuration file for a specific scope and config section.
+
+ With no arguments and an active environment, edit the spack.yaml for
+ the active environment.
+
+ """
+ scope, section = _get_scope_and_section(args)
+ if not scope and not section:
+ tty.die('`spack config edit` requires a section argument '
+ 'or an active environment.')
+
+ config_file = spack.config.config.get_config_filename(scope, section)
+ if args.print_file:
+ print(config_file)
+ else:
+ editor(config_file)
def config(parser, args):
action = {'get': config_get,
+ 'blame': config_blame,
'edit': config_edit}
action[args.config_command](args)
diff --git a/lib/spack/spack/cmd/configure.py b/lib/spack/spack/cmd/configure.py
index 346fc71bdc..668d16dafd 100644
--- a/lib/spack/spack/cmd/configure.py
+++ b/lib/spack/spack/cmd/configure.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
@@ -34,6 +15,7 @@ from spack.build_systems.qmake import QMakePackage
from spack.build_systems.waf import WafPackage
from spack.build_systems.perl import PerlPackage
from spack.build_systems.intel import IntelPackage
+from spack.build_systems.meson import MesonPackage
description = 'stage and configure a package but do not install'
section = "build"
@@ -47,6 +29,7 @@ build_system_to_phase = {
WafPackage: 'configure',
PerlPackage: 'configure',
IntelPackage: 'configure',
+ MesonPackage: 'meson',
}
@@ -79,7 +62,7 @@ def _stop_at_phase_during_install(args, calling_fn, phase_mapping):
# Install package dependencies if needed
parser = argparse.ArgumentParser()
inst.setup_parser(parser)
- tty.msg('Checking dependencies for {0}'.format(args.package))
+ tty.msg('Checking dependencies for {0}'.format(args.package[0]))
cli_args = ['-v'] if args.verbose else []
install_args = parser.parse_args(cli_args + ['--only=dependencies'])
install_args.package = args.package
diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py
index 2e67b7648b..880bdb05a8 100644
--- a/lib/spack/spack/cmd/create.py
+++ b/lib/spack/spack/cmd/create.py
@@ -1,39 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import os
import re
import llnl.util.tty as tty
-import spack
+from llnl.util.filesystem import mkdirp
+
import spack.cmd
import spack.util.web
-from llnl.util.filesystem import mkdirp
-from spack.repository import Repo
+import spack.repo
from spack.spec import Spec
+from spack.util.editor import editor
from spack.util.executable import which, ProcessError
from spack.util.naming import mod_to_class
from spack.util.naming import simplify_name, valid_fully_qualified_module_name
@@ -46,30 +28,14 @@ level = "short"
package_template = '''\
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+# ----------------------------------------------------------------------------
+# If you submit this package back to Spack as a pull request,
+# please first remove this boilerplate and all FIXME comments.
#
# This is a template package file for Spack. We've put "FIXME"
# next to all the things you'll want to change. Once you've handled
@@ -82,9 +48,8 @@ package_template = '''\
# spack edit {name}
#
# See the Spack documentation for more information on packaging.
-# If you submit this package back to Spack as a pull request,
-# please first remove this boilerplate and all FIXME comments.
-#
+# ----------------------------------------------------------------------------
+
from spack import *
@@ -194,6 +159,18 @@ class CMakePackageTemplate(PackageTemplate):
return args"""
+class MesonPackageTemplate(PackageTemplate):
+ """Provides appropriate overrides for meson-based packages"""
+
+ base_class_name = 'MesonPackage'
+
+ body = """\
+ def meson_args(self):
+ # FIXME: If not needed delete this function
+ args = []
+ return args"""
+
+
class QMakePackageTemplate(PackageTemplate):
"""Provides appropriate overrides for QMake-based packages"""
@@ -332,21 +309,14 @@ class PerlbuildPackageTemplate(PerlmakePackageTemplate):
class OctavePackageTemplate(PackageTemplate):
"""Provides appropriate overrides for octave packages"""
+ base_class_name = 'OctavePackage'
+
dependencies = """\
extends('octave')
# FIXME: Add additional dependencies if required.
# depends_on('octave-foo', type=('build', 'run'))"""
- body = """\
- def install(self, spec, prefix):
- # FIXME: Add logic to build and install here.
- octave('--quiet', '--norc',
- '--built-in-docstrings-file=/dev/null',
- '--texi-macros-file=/dev/null',
- '--eval', 'pkg prefix {0}; pkg install {1}'.format(
- prefix, self.stage.archive_file))"""
-
def __init__(self, name, *args):
# If the user provided `--name octave-splines`, don't rename it
# octave-octave-splines
@@ -395,6 +365,7 @@ templates = {
'octave': OctavePackageTemplate,
'makefile': MakefilePackageTemplate,
'intel': IntelPackageTemplate,
+ 'meson': MesonPackageTemplate,
'generic': PackageTemplate,
}
@@ -464,6 +435,8 @@ class BuildSystemGuesser:
(r'/Makefile\.PL$', 'perlmake'),
(r'/.*\.pro$', 'qmake'),
(r'/(GNU)?[Mm]akefile$', 'makefile'),
+ (r'/DESCRIPTION$', 'octave'),
+ (r'/meson\.build$', 'meson'),
]
# Peek inside the compressed file.
@@ -654,17 +627,17 @@ def get_repository(args, name):
# Figure out where the new package should live
repo_path = args.repo
if repo_path is not None:
- repo = Repo(repo_path)
+ repo = spack.repo.Repo(repo_path)
if spec.namespace and spec.namespace != repo.namespace:
tty.die("Can't create package with namespace {0} in repo with "
- "namespace {0}".format(spec.namespace, repo.namespace))
+ "namespace {1}".format(spec.namespace, repo.namespace))
else:
if spec.namespace:
- repo = spack.repo.get_repo(spec.namespace, None)
+ repo = spack.repo.path.get_repo(spec.namespace, None)
if not repo:
tty.die("Unknown namespace: '{0}'".format(spec.namespace))
else:
- repo = spack.repo.first_repo()
+ repo = spack.repo.path.first_repo()
# Set the namespace on the spec if it's not there already
if not spec.namespace:
@@ -681,8 +654,8 @@ def create(parser, args):
build_system = get_build_system(args, guesser)
# Create the package template object
- PackageClass = templates[build_system]
- package = PackageClass(name, url, versions)
+ package_class = templates[build_system]
+ package = package_class(name, url, versions)
tty.msg("Created template for {0} package".format(package.name))
# Create a directory for the new package
@@ -699,4 +672,4 @@ def create(parser, args):
tty.msg("Created package file: {0}".format(pkg_path))
# Open up the new package file in your $EDITOR
- spack.editor(pkg_path)
+ editor(pkg_path)
diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py
index ae5241dfe8..ef450b1c94 100644
--- a/lib/spack/spack/cmd/deactivate.py
+++ b/lib/spack/spack/cmd/deactivate.py
@@ -1,34 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
-import spack
import spack.cmd
import spack.store
-from spack.directory_layout import YamlViewExtensionsLayout
+from spack.filesystem_view import YamlFilesystemView
from spack.graph import topological_sort
description = "deactivate a package extension"
@@ -60,24 +40,29 @@ def deactivate(parser, args):
spec = spack.cmd.disambiguate_spec(specs[0])
pkg = spec.package
- layout = spack.store.extensions
- if args.view is not None:
- layout = YamlViewExtensionsLayout(args.view, spack.store.layout)
+ if args.view:
+ target = args.view
+ elif pkg.is_extension:
+ target = pkg.extendee_spec.prefix
+ elif pkg.extendable:
+ target = spec.prefix
+
+ view = YamlFilesystemView(target, spack.store.layout)
if args.all:
if pkg.extendable:
tty.msg("Deactivating all extensions of %s" % pkg.spec.short_spec)
ext_pkgs = spack.store.db.activated_extensions_for(
- spec, extensions_layout=layout)
+ spec, view.extensions_layout)
for ext_pkg in ext_pkgs:
ext_pkg.spec.normalize()
- if ext_pkg.is_activated():
- ext_pkg.do_deactivate(force=True, extensions_layout=layout)
+ if ext_pkg.is_activated(view):
+ ext_pkg.do_deactivate(view, force=True)
elif pkg.is_extension:
if not args.force and \
- not spec.package.is_activated(extensions_layout=layout):
+ not spec.package.is_activated(view):
tty.die("%s is not activated." % pkg.spec.short_spec)
tty.msg("Deactivating %s and all dependencies." %
@@ -90,11 +75,8 @@ def deactivate(parser, args):
espec = index[name]
epkg = espec.package
if epkg.extends(pkg.extendee_spec):
- if epkg.is_activated(extensions_layout=layout) or \
- args.force:
-
- epkg.do_deactivate(
- force=args.force, extensions_layout=layout)
+ if epkg.is_activated(view) or args.force:
+ epkg.do_deactivate(view, force=args.force)
else:
tty.die(
@@ -107,7 +89,7 @@ def deactivate(parser, args):
"Did you mean 'spack deactivate --all'?")
if not args.force and \
- not spec.package.is_activated(extensions_layout=layout):
+ not spec.package.is_activated(view):
tty.die("Package %s is not activated." % specs[0].short_spec)
- spec.package.do_deactivate(force=args.force, extensions_layout=layout)
+ spec.package.do_deactivate(view, force=args.force)
diff --git a/lib/spack/spack/cmd/debug.py b/lib/spack/spack/cmd/debug.py
index 1d3e645a29..e1fa227371 100644
--- a/lib/spack/spack/cmd/debug.py
+++ b/lib/spack/spack/cmd/debug.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import re
from datetime import datetime
@@ -30,7 +11,7 @@ from glob import glob
import llnl.util.tty as tty
from llnl.util.filesystem import working_dir
-import spack
+import spack.paths
from spack.util.executable import which
description = "debugging commands for troubleshooting Spack"
@@ -52,7 +33,7 @@ def _debug_tarball_suffix():
if not git:
return 'nobranch-nogit-%s' % suffix
- with working_dir(spack.spack_root):
+ with working_dir(spack.paths.prefix):
if not os.path.isdir('.git'):
return 'nobranch.nogit.%s' % suffix
@@ -76,14 +57,14 @@ def create_db_tarball(args):
tarball_name = "spack-db.%s.tar.gz" % _debug_tarball_suffix()
tarball_path = os.path.abspath(tarball_name)
- base = os.path.basename(spack.store.root)
+ base = os.path.basename(str(spack.store.root))
transform_args = []
if 'GNU' in tar('--version', output=str):
transform_args = ['--transform', 's/^%s/%s/' % (base, tarball_name)]
else:
transform_args = ['-s', '/^%s/%s/' % (base, tarball_name)]
- wd = os.path.dirname(spack.store.root)
+ wd = os.path.dirname(str(spack.store.root))
with working_dir(wd):
files = [spack.store.db._index_path]
files += glob('%s/*/*/*/.spack/spec.yaml' % base)
diff --git a/lib/spack/spack/cmd/dependencies.py b/lib/spack/spack/cmd/dependencies.py
index 95183fa318..fe66bef1df 100644
--- a/lib/spack/spack/cmd/dependencies.py
+++ b/lib/spack/spack/cmd/dependencies.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the LICENSE file for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
-import spack
import spack.store
+import spack.repo
import spack.cmd
description = "show dependencies of a package"
@@ -43,7 +24,10 @@ def setup_parser(subparser):
"instead of possible dependencies of a package.")
subparser.add_argument(
'-t', '--transitive', action='store_true', default=False,
- help="Show all transitive dependencies.")
+ help="show all transitive dependencies")
+ subparser.add_argument(
+ '-V', '--no-expand-virtuals', action='store_false', default=True,
+ dest="expand_virtuals", help="do not expand virtual dependencies")
subparser.add_argument(
'spec', nargs=argparse.REMAINDER, help="spec or package name")
@@ -70,13 +54,15 @@ def dependencies(parser, args):
if not spec.virtual:
packages = [spec.package]
else:
- packages = [spack.repo.get(s.name)
- for s in spack.repo.providers_for(spec)]
+ packages = [
+ spack.repo.get(s.name)
+ for s in spack.repo.path.providers_for(spec)]
dependencies = set()
for pkg in packages:
dependencies.update(
- set(pkg.possible_dependencies(args.transitive)))
+ set(pkg.possible_dependencies(
+ args.transitive, args.expand_virtuals)))
if spec.name in dependencies:
dependencies.remove(spec.name)
diff --git a/lib/spack/spack/cmd/dependents.py b/lib/spack/spack/cmd/dependents.py
index 1ad3c0a3b9..46397ed5f0 100644
--- a/lib/spack/spack/cmd/dependents.py
+++ b/lib/spack/spack/cmd/dependents.py
@@ -1,33 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
-import spack
+import spack.repo
import spack.store
import spack.cmd
@@ -57,14 +38,14 @@ def inverted_dependencies():
actual dependents.
"""
dag = {}
- for pkg in spack.repo.all_packages():
+ for pkg in spack.repo.path.all_packages():
dag.setdefault(pkg.name, set())
for dep in pkg.dependencies:
deps = [dep]
# expand virtuals if necessary
- if spack.repo.is_virtual(dep):
- deps += [s.name for s in spack.repo.providers_for(dep)]
+ if spack.repo.path.is_virtual(dep):
+ deps += [s.name for s in spack.repo.path.providers_for(dep)]
for d in deps:
dag.setdefault(d, set()).add(pkg.name)
diff --git a/lib/spack/spack/cmd/diy.py b/lib/spack/spack/cmd/diy.py
index ba5c7eb954..39282b3b2d 100644
--- a/lib/spack/spack/cmd/diy.py
+++ b/lib/spack/spack/cmd/diy.py
@@ -1,47 +1,34 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import sys
import os
import argparse
import llnl.util.tty as tty
-import spack
+import spack.config
import spack.cmd
+import spack.repo
import spack.cmd.common.arguments as arguments
from spack.stage import DIYStage
description = "do-it-yourself: build from an existing source directory"
-section = "developer"
+section = "build"
level = "long"
def setup_parser(subparser):
+ arguments.add_common_arguments(subparser, ['jobs'])
+ subparser.add_argument(
+ '-d', '--source-path', dest='source_path', default=None,
+ help="path to source directory. defaults to the current directory")
subparser.add_argument(
'-i', '--ignore-dependencies', action='store_true', dest='ignore_deps',
help="don't try to install dependencies of requested packages")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'--keep-prefix', action='store_true',
help="do not remove the install prefix if installation fails")
@@ -63,12 +50,16 @@ def diy(self, args):
if not args.spec:
tty.die("spack diy requires a package spec argument.")
+ if args.jobs is not None:
+ if args.jobs <= 0:
+ tty.die("the -j option must be a positive integer")
+
specs = spack.cmd.parse_specs(args.spec)
if len(specs) > 1:
tty.die("spack diy only takes one spec.")
spec = specs[0]
- if not spack.repo.exists(spec.name):
+ if not spack.repo.path.exists(spec.name):
tty.die("No package for '{0}' was found.".format(spec.name),
" Use `spack create` to create a new package")
@@ -85,13 +76,20 @@ def diy(self, args):
tty.msg("Uninstall or try adding a version suffix for this DIY build.")
sys.exit(1)
+ source_path = args.source_path
+ if source_path is None:
+ source_path = os.getcwd()
+ source_path = os.path.abspath(source_path)
+
# Forces the build to run out of the current directory.
- package.stage = DIYStage(os.getcwd())
+ package.stage = DIYStage(source_path)
- # TODO: make this an argument, not a global.
- spack.do_checksum = False
+ # disable checksumming if requested
+ if args.no_checksum:
+ spack.config.set('config:checksum', False, scope='command_line')
package.do_install(
+ make_jobs=args.jobs,
keep_prefix=args.keep_prefix,
install_deps=not args.ignore_deps,
verbose=not args.quiet,
diff --git a/lib/spack/spack/cmd/docs.py b/lib/spack/spack/cmd/docs.py
index 02096a0020..9af6a37d7c 100644
--- a/lib/spack/spack/cmd/docs.py
+++ b/lib/spack/spack/cmd/docs.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import webbrowser
description = 'open spack documentation in a web browser'
diff --git a/lib/spack/spack/cmd/edit.py b/lib/spack/spack/cmd/edit.py
index 48d423a97e..ddc49753af 100644
--- a/lib/spack/spack/cmd/edit.py
+++ b/lib/spack/spack/cmd/edit.py
@@ -1,36 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
+import glob
import llnl.util.tty as tty
-from llnl.util.filesystem import join_path
-import spack
import spack.cmd
+import spack.paths
+import spack.repo
from spack.spec import Spec
-from spack.repository import Repo
+from spack.util.editor import editor
description = "open package files in $EDITOR"
section = "packaging"
@@ -47,11 +29,11 @@ def edit_package(name, repo_path, namespace):
"""
# Find the location of the package
if repo_path:
- repo = Repo(repo_path)
+ repo = spack.repo.Repo(repo_path)
elif namespace:
- repo = spack.repo.get_repo(namespace)
+ repo = spack.repo.path.get_repo(namespace)
else:
- repo = spack.repo
+ repo = spack.repo.path
path = repo.filename_for_package_name(name)
spec = Spec(name)
@@ -64,7 +46,7 @@ def edit_package(name, repo_path, namespace):
tty.die("No package for '{0}' was found.".format(spec.name),
" Use `spack create` to create a new package")
- spack.editor(path)
+ editor(path)
def setup_parser(subparser):
@@ -74,19 +56,23 @@ def setup_parser(subparser):
# Edits package files by default
excl_args.add_argument(
'-b', '--build-system', dest='path', action='store_const',
- const=spack.build_systems_path,
+ const=spack.paths.build_systems_path,
help="Edit the build system with the supplied name.")
excl_args.add_argument(
'-c', '--command', dest='path', action='store_const',
- const=spack.cmd.command_path,
+ const=spack.paths.command_path,
help="edit the command with the supplied name")
excl_args.add_argument(
+ '-d', '--docs', dest='path', action='store_const',
+ const=os.path.join(spack.paths.lib_path, 'docs'),
+ help="edit the docs with the supplied name")
+ excl_args.add_argument(
'-t', '--test', dest='path', action='store_const',
- const=spack.test_path,
+ const=spack.paths.test_path,
help="edit the test with the supplied name")
excl_args.add_argument(
'-m', '--module', dest='path', action='store_const',
- const=spack.module_path,
+ const=spack.paths.module_path,
help="edit the main spack module with the supplied name")
# Options for editing packages
@@ -106,18 +92,36 @@ def edit(parser, args):
name = args.name
# By default, edit package files
- path = spack.packages_path
+ path = spack.paths.packages_path
# If `--command`, `--test`, or `--module` is chosen, edit those instead
if args.path:
path = args.path
if name:
- path = join_path(path, name + ".py")
+ # convert command names to python module name
+ if path == spack.paths.command_path:
+ name = spack.cmd.python_name(name)
+
+ path = os.path.join(path, name)
if not os.path.exists(path):
- tty.die("No command for '{0}' was found.".format(name))
- spack.editor(path)
+ files = glob.glob(path + '*')
+ blacklist = ['.pyc', '~'] # blacklist binaries and backups
+ files = list(filter(
+ lambda x: all(s not in x for s in blacklist), files))
+ if len(files) > 1:
+ m = 'Multiple files exist with the name {0}.'.format(name)
+ m += ' Please specify a suffix. Files are:\n\n'
+ for f in files:
+ m += ' ' + os.path.basename(f) + '\n'
+ tty.die(m)
+ if not files:
+ tty.die("No file for '{0}' was found in {1}".format(name,
+ path))
+ path = files[0] # already confirmed only one entry in files
+
+ editor(path)
elif name:
edit_package(name, args.repo, args.namespace)
else:
# By default open the directory where packages live
- spack.editor(path)
+ editor(path)
diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py
index 14432c4dd0..c8b9c169b5 100644
--- a/lib/spack/spack/cmd/env.py
+++ b/lib/spack/spack/cmd/env.py
@@ -1,78 +1,364 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+import sys
+
+import llnl.util.tty as tty
+import llnl.util.filesystem as fs
+from llnl.util.tty.colify import colify
+from llnl.util.tty.color import colorize
+
+import spack.config
+import spack.schema.env
+import spack.cmd.install
+import spack.cmd.uninstall
+import spack.cmd.modules
+import spack.cmd.common.arguments as arguments
+import spack.environment as ev
+import spack.util.string as string
+
+description = "manage virtual environments"
+section = "environments"
+level = "short"
+
+
+#: List of subcommands of `spack env`
+subcommands = [
+ 'activate',
+ 'deactivate',
+ 'create',
+ ['remove', 'rm'],
+ ['list', 'ls'],
+ ['status', 'st'],
+ 'loads',
+]
+
+
#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
+# env activate
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
+def env_activate_setup_parser(subparser):
+ """set the current environment"""
+ shells = subparser.add_mutually_exclusive_group()
+ shells.add_argument(
+ '--sh', action='store_const', dest='shell', const='sh',
+ help="print sh commands to activate the environment")
+ shells.add_argument(
+ '--csh', action='store_const', dest='shell', const='csh',
+ help="print csh commands to activate the environment")
+ shells.add_argument(
+ '-d', '--dir', action='store_true', default=False,
+ help="force spack to treat env as a directory, not a name")
+
+ subparser.add_argument(
+ '-p', '--prompt', action='store_true', default=False,
+ help="decorate the command line prompt when activating")
+ subparser.add_argument(
+ metavar='env', dest='activate_env',
+ help='name of environment to activate')
+
+
+def env_activate(args):
+ env = args.activate_env
+ if not args.shell:
+ msg = [
+ "This command works best with Spack's shell support",
+ ""
+ ] + spack.cmd.common.shell_init_instructions + [
+ 'Or, if you want to use `spack env activate` without initializing',
+ 'shell support, you can run one of these:',
+ '',
+ ' eval `spack env activate --sh %s` # for bash/sh' % env,
+ ' eval `spack env activate --csh %s` # for csh/tcsh' % env,
+ ]
+ tty.msg(*msg)
+ return 1
+
+ if ev.exists(env) and not args.dir:
+ spack_env = ev.root(env)
+ short_name = env
+ env_prompt = '[%s]' % env
+
+ elif ev.is_env_dir(env):
+ spack_env = os.path.abspath(env)
+ short_name = os.path.basename(os.path.abspath(env))
+ env_prompt = '[%s]' % short_name
+
+ else:
+ tty.die("No such environment: '%s'" % env)
+
+ if spack_env == os.environ.get('SPACK_ENV'):
+ tty.die("Environment %s is already active" % args.activate_env)
+
+ if args.shell == 'csh':
+ # TODO: figure out how to make color work for csh
+ sys.stdout.write('setenv SPACK_ENV %s;\n' % spack_env)
+ sys.stdout.write('alias despacktivate "spack env deactivate";\n')
+ if args.prompt:
+ sys.stdout.write('if (! $?SPACK_OLD_PROMPT ) '
+ 'setenv SPACK_OLD_PROMPT "${prompt}";\n')
+ sys.stdout.write('set prompt="%s ${prompt}";\n' % env_prompt)
+
+ else:
+ if 'color' in os.environ['TERM']:
+ env_prompt = colorize('@G{%s} ' % env_prompt, color=True)
+
+ sys.stdout.write('export SPACK_ENV=%s;\n' % spack_env)
+ sys.stdout.write("alias despacktivate='spack env deactivate';\n")
+ if args.prompt:
+ sys.stdout.write('if [ -z "${SPACK_OLD_PS1}" ]; then\n')
+ sys.stdout.write('export SPACK_OLD_PS1="${PS1}"; fi;\n')
+ sys.stdout.write('export PS1="%s ${PS1}";\n' % env_prompt)
+
+
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
+# env deactivate
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-from __future__ import print_function
+def env_deactivate_setup_parser(subparser):
+ """deactivate any active environment in the shell"""
+ shells = subparser.add_mutually_exclusive_group()
+ shells.add_argument(
+ '--sh', action='store_const', dest='shell', const='sh',
+ help="print sh commands to deactivate the environment")
+ shells.add_argument(
+ '--csh', action='store_const', dest='shell', const='csh',
+ help="print csh commands to deactivate the environment")
-import argparse
-import os
-import llnl.util.tty as tty
-import spack.build_environment as build_env
-import spack.cmd
-import spack.cmd.common.arguments as arguments
+def env_deactivate(args):
+ if not args.shell:
+ msg = [
+ "This command works best with Spack's shell support",
+ ""
+ ] + spack.cmd.common.shell_init_instructions + [
+ 'Or, if you want to use `spack env activate` without initializing',
+ 'shell support, you can run one of these:',
+ '',
+ ' eval `spack env deactivate --sh` # for bash/sh',
+ ' eval `spack env deactivate --csh` # for csh/tcsh',
+ ]
+ tty.msg(*msg)
+ return 1
-description = "show install environment for a spec, and run commands"
-section = "build"
-level = "long"
+ if 'SPACK_ENV' not in os.environ:
+ tty.die('No environment is currently active.')
+ if args.shell == 'csh':
+ sys.stdout.write('unsetenv SPACK_ENV;\n')
+ sys.stdout.write('if ( $?SPACK_OLD_PROMPT ) '
+ 'set prompt="$SPACK_OLD_PROMPT" && '
+ 'unsetenv SPACK_OLD_PROMPT;\n')
+ sys.stdout.write('unalias despacktivate;\n')
-def setup_parser(subparser):
- arguments.add_common_arguments(subparser, ['clean', 'dirty'])
+ else:
+ sys.stdout.write('unset SPACK_ENV; export SPACK_ENV;\n')
+ sys.stdout.write('unalias despacktivate;\n')
+ sys.stdout.write('if [ -n "$SPACK_OLD_PS1" ]; then\n')
+ sys.stdout.write('export PS1="$SPACK_OLD_PS1";\n')
+ sys.stdout.write('unset SPACK_OLD_PS1; export SPACK_OLD_PS1;\n')
+ sys.stdout.write('fi;\n')
+
+
+#
+# env create
+#
+def env_create_setup_parser(subparser):
+ """create a new environment"""
+ subparser.add_argument(
+ 'create_env', metavar='ENV', help='name of environment to create')
+ subparser.add_argument(
+ '-d', '--dir', action='store_true',
+ help='create an environment in a specific directory')
subparser.add_argument(
- 'spec', nargs=argparse.REMAINDER,
- help="specs of package environment to emulate")
+ 'envfile', nargs='?', default=None,
+ help='optional init file; can be spack.yaml or spack.lock')
-def env(parser, args):
- if not args.spec:
- tty.die("spack env requires a spec.")
-
- # Specs may have spaces in them, so if they do, require that the
- # caller put a '--' between the spec and the command to be
- # executed. If there is no '--', assume that the spec is the
- # first argument.
- sep = '--'
- if sep in args.spec:
- s = args.spec.index(sep)
- spec = args.spec[:s]
- cmd = args.spec[s + 1:]
+def env_create(args):
+ if args.envfile:
+ with open(args.envfile) as f:
+ _env_create(args.create_env, f, args.dir)
else:
- spec = args.spec[0]
- cmd = args.spec[1:]
+ _env_create(args.create_env, None, args.dir)
+
+
+def _env_create(name_or_path, init_file=None, dir=False):
+ """Create a new environment, with an optional yaml description.
+
+ Arguments:
+ name_or_path (str): name of the environment to create, or path to it
+ init_file (str or file): optional initialization file -- can be
+ spack.yaml or spack.lock
+ dir (bool): if True, create an environment in a directory instead
+ of a named environment
+ """
+ if dir:
+ env = ev.Environment(name_or_path, init_file)
+ env.write()
+ tty.msg("Created environment in %s" % env.path)
+ else:
+ env = ev.create(name_or_path, init_file)
+ env.write()
+ tty.msg("Created environment '%s' in %s" % (name_or_path, env.path))
+ return env
+
+
+#
+# env remove
+#
+def env_remove_setup_parser(subparser):
+ """remove an existing environment"""
+ subparser.add_argument(
+ 'rm_env', metavar='ENV', nargs='+',
+ help='environment(s) to remove')
+ arguments.add_common_arguments(subparser, ['yes_to_all'])
+
+
+def env_remove(args):
+ """Remove a *named* environment.
+
+ This removes an environment managed by Spack. Directory environments
+ and `spack.yaml` files embedded in repositories should be removed
+ manually.
+ """
+ read_envs = []
+ for env_name in args.rm_env:
+ env = ev.read(env_name)
+ read_envs.append(env)
+
+ if not args.yes_to_all:
+ answer = tty.get_yes_or_no(
+ 'Really remove %s %s?' % (
+ string.plural(len(args.rm_env), 'environment', show_n=False),
+ string.comma_and(args.rm_env)),
+ default=False)
+ if not answer:
+ tty.die("Will not remove any environments")
+
+ for env in read_envs:
+ if env.active:
+ tty.die("Environment %s can't be removed while activated.")
+
+ env.destroy()
+ tty.msg("Successfully removed environment '%s'" % env.name)
+
+
+#
+# env list
+#
+def env_list_setup_parser(subparser):
+ """list available environments"""
- specs = spack.cmd.parse_specs(spec, concretize=True)
- if len(specs) > 1:
- tty.die("spack env only takes one spec.")
- spec = specs[0]
- build_env.setup_package(spec.package, args.dirty)
+def env_list(args):
+ names = ev.all_environment_names()
- if not cmd:
- # If no command act like the "env" command and print out env vars.
- for key, val in os.environ.items():
- print("%s=%s" % (key, val))
+ color_names = []
+ for name in names:
+ if ev.active(name):
+ name = colorize('@*g{%s}' % name)
+ color_names.append(name)
+ # say how many there are if writing to a tty
+ if sys.stdout.isatty():
+ if not names:
+ tty.msg('No environments')
+ else:
+ tty.msg('%d environments' % len(names))
+
+ colify(color_names, indent=4)
+
+
+#
+# env status
+#
+def env_status_setup_parser(subparser):
+ """print whether there is an active environment"""
+
+
+def env_status(args):
+ env = ev.get_env(args, 'env status', required=False)
+ if env:
+ if env.path == os.getcwd():
+ tty.msg('Using %s in current directory: %s'
+ % (ev.manifest_name, env.path))
+ else:
+ tty.msg('In environment %s' % env.name)
else:
- # Otherwise execute the command with the new environment
- os.execvp(cmd[0], cmd)
+ tty.msg('No active environment')
+
+
+#
+# env loads
+#
+def env_loads_setup_parser(subparser):
+ """list modules for an installed environment '(see spack module loads)'"""
+ subparser.add_argument(
+ 'env', nargs='?', help='name of env to generate loads file for')
+ subparser.add_argument(
+ '-m', '--module-type', choices=('tcl', 'lmod'),
+ help='type of module system to generate loads for')
+ spack.cmd.modules.add_loads_arguments(subparser)
+
+
+def env_loads(args):
+ env = ev.get_env(args, 'env loads')
+
+ # Set the module types that have been selected
+ module_type = args.module_type
+ if module_type is None:
+ # If no selection has been made select all of them
+ module_type = 'tcl'
+
+ recurse_dependencies = args.recurse_dependencies
+ args.recurse_dependencies = False
+
+ loads_file = fs.join_path(env.path, 'loads')
+ with open(loads_file, 'w') as f:
+ specs = env._get_environment_specs(
+ recurse_dependencies=recurse_dependencies)
+
+ spack.cmd.modules.loads(module_type, specs, args, f)
+
+ print('To load this environment, type:')
+ print(' source %s' % loads_file)
+
+
+#: Dictionary mapping subcommand names and aliases to functions
+subcommand_functions = {}
+
+
+#
+# spack env
+#
+def setup_parser(subparser):
+ sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='env_command')
+
+ for name in subcommands:
+ if isinstance(name, (list, tuple)):
+ name, aliases = name[0], name[1:]
+ else:
+ aliases = []
+
+ # add commands to subcommands dict
+ function_name = 'env_%s' % name
+ function = globals()[function_name]
+ for alias in [name] + aliases:
+ subcommand_functions[alias] = function
+
+ # make a subparser and run the command's setup function on it
+ setup_parser_cmd_name = 'env_%s_setup_parser' % name
+ setup_parser_cmd = globals()[setup_parser_cmd_name]
+
+ subsubparser = sp.add_parser(
+ name, aliases=aliases, help=setup_parser_cmd.__doc__)
+ setup_parser_cmd(subsubparser)
+
+
+def env(parser, args):
+ """Look for a function called environment_<name> and call it."""
+ action = subcommand_functions[args.env_command]
+ action(args)
diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py
index 6d36511691..a564248d63 100644
--- a/lib/spack/spack/cmd/extensions.py
+++ b/lib/spack/spack/cmd/extensions.py
@@ -1,37 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
-import spack
import spack.cmd
import spack.cmd.find
+import spack.repo
import spack.store
-from spack.directory_layout import YamlViewExtensionsLayout
+from spack.filesystem_view import YamlFilesystemView
description = "list extensions for package"
section = "extensions"
@@ -105,7 +86,7 @@ def extensions(parser, args):
if show_packages:
#
# List package names of extensions
- extensions = spack.repo.extensions_for(spec)
+ extensions = spack.repo.path.extensions_for(spec)
if not extensions:
tty.msg("%s has no extensions." % spec.cshort_spec)
else:
@@ -113,16 +94,19 @@ def extensions(parser, args):
tty.msg("%d extensions:" % len(extensions))
colify(ext.name for ext in extensions)
- layout = spack.store.extensions
- if args.view is not None:
- layout = YamlViewExtensionsLayout(args.view, spack.store.layout)
+ if args.view:
+ target = args.view
+ else:
+ target = spec.prefix
+
+ view = YamlFilesystemView(target, spack.store.layout)
if show_installed:
#
# List specs of installed extensions.
#
- installed = [s.spec
- for s in spack.store.db.installed_extensions_for(spec)]
+ installed = [
+ s.spec for s in spack.store.db.installed_extensions_for(spec)]
if show_all:
print
@@ -136,7 +120,7 @@ def extensions(parser, args):
#
# List specs of activated extensions.
#
- activated = layout.extension_map(spec)
+ activated = view.extensions_layout.extension_map(spec)
if show_all:
print
if not activated:
diff --git a/lib/spack/spack/cmd/fetch.py b/lib/spack/spack/cmd/fetch.py
index e3956b125a..6682cfaaa8 100644
--- a/lib/spack/spack/cmd/fetch.py
+++ b/lib/spack/spack/cmd/fetch.py
@@ -1,33 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
-import spack
import spack.cmd
+import spack.config
+import spack.repo
+import spack.cmd.common.arguments as arguments
description = "fetch archives for packages"
section = "build"
@@ -35,9 +18,7 @@ level = "long"
def setup_parser(subparser):
- subparser.add_argument(
- '-n', '--no-checksum', action='store_true', dest='no_checksum',
- help="do not check packages against checksum")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'-m', '--missing', action='store_true',
help="fetch only missing (not yet installed) dependencies")
@@ -54,7 +35,7 @@ def fetch(parser, args):
tty.die("fetch requires at least one package argument")
if args.no_checksum:
- spack.do_checksum = False
+ spack.config.set('config:checksum', False, scope='command_line')
specs = spack.cmd.parse_specs(args.packages, concretize=True)
for spec in specs:
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index 71102563c3..b1ea65dfc1 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -1,33 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import sys
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+from __future__ import print_function
import llnl.util.tty as tty
-import spack
+import llnl.util.tty.color as color
+import llnl.util.lang
+
+import spack.environment as ev
+import spack.repo
import spack.cmd.common.arguments as arguments
from spack.cmd import display_specs
+from spack.util.string import plural
description = "list and search installed packages"
section = "basic"
@@ -54,8 +39,12 @@ def setup_parser(subparser):
const='deps',
help='show full dependency DAG of installed packages')
- arguments.add_common_arguments(subparser, ['long', 'very_long', 'tags'])
+ arguments.add_common_arguments(
+ subparser, ['long', 'very_long', 'tags'])
+ subparser.add_argument('-c', '--show-concretized',
+ action='store_true',
+ help='show concretized specs in an environment')
subparser.add_argument('-f', '--show-flags',
action='store_true',
dest='show_flags',
@@ -66,11 +55,11 @@ def setup_parser(subparser):
help='show full compiler specs')
implicit_explicit = subparser.add_mutually_exclusive_group()
implicit_explicit.add_argument(
- '-e', '--explicit',
+ '-x', '--explicit',
action='store_true',
help='show only specs that were installed explicitly')
implicit_explicit.add_argument(
- '-E', '--implicit',
+ '-X', '--implicit',
action='store_true',
help='show only specs that were installed as dependencies')
subparser.add_argument(
@@ -96,6 +85,14 @@ def setup_parser(subparser):
action='store_true',
help='show fully qualified package names')
+ subparser.add_argument(
+ '--start-date',
+ help='earliest date of installation [YYYY-MM-DD]'
+ )
+ subparser.add_argument(
+ '--end-date', help='latest date of installation [YYYY-MM-DD]'
+ )
+
arguments.add_common_arguments(subparser, ['constraint'])
@@ -114,15 +111,52 @@ def query_arguments(args):
if args.implicit:
explicit = False
q_args = {'installed': installed, 'known': known, "explicit": explicit}
+
+ # Time window of installation
+ for attribute in ('start_date', 'end_date'):
+ date = getattr(args, attribute)
+ if date:
+ q_args[attribute] = llnl.util.lang.pretty_string_to_date(date)
+
return q_args
+def setup_env(env):
+ """Create a function for decorating specs when in an environment."""
+
+ def strip_build(seq):
+ return set(s.copy(deps=('link', 'run')) for s in seq)
+
+ added = set(strip_build(env.added_specs()))
+ roots = set(strip_build(env.roots()))
+ removed = set(strip_build(env.removed_specs()))
+
+ def decorator(spec, fmt):
+ # add +/-/* to show added/removed/root specs
+ if any(spec.dag_hash() == r.dag_hash() for r in roots):
+ return color.colorize('@*{%s}' % fmt)
+ elif spec in removed:
+ return color.colorize('@K{%s}' % fmt)
+ else:
+ return '%s' % fmt
+
+ return decorator, added, roots, removed
+
+
def find(parser, args):
q_args = query_arguments(args)
- query_specs = args.specs(**q_args)
+ results = args.specs(**q_args)
+
+ decorator = lambda s, f: f
+ added = set()
+ removed = set()
+
+ env = ev.get_env(args, 'find', required=False)
+ if env:
+ decorator, added, roots, removed = setup_env(env)
# Exit early if no package matches the constraint
- if not query_specs and args.constraint:
+ if not results and args.constraint:
msg = "No package matches the query: {0}"
msg = msg.format(' '.join(args.constraint))
tty.msg(msg)
@@ -130,11 +164,28 @@ def find(parser, args):
# If tags have been specified on the command line, filter by tags
if args.tags:
- packages_with_tags = spack.repo.packages_with_tags(*args.tags)
- query_specs = [x for x in query_specs if x.name in packages_with_tags]
+ packages_with_tags = spack.repo.path.packages_with_tags(*args.tags)
+ results = [x for x in results if x.name in packages_with_tags]
# Display the result
- if sys.stdout.isatty():
- tty.msg("%d installed packages." % len(query_specs))
+ if env:
+ tty.msg('In environment %s' % env.name)
+
+ if not env.user_specs:
+ tty.msg('No root specs')
+ else:
+ tty.msg('Root specs')
+ display_specs(
+ env.user_specs, args,
+ decorator=lambda s, f: color.colorize('@*{%s}' % f))
+ print()
+
+ if args.show_concretized:
+ tty.msg('Concretized roots')
+ display_specs(
+ env.specs_by_hash.values(), args, decorator=decorator)
+ print()
+
+ tty.msg("%s" % plural(len(results), 'installed package'))
- display_specs(query_specs, args)
+ display_specs(results, args, decorator=decorator, all_headers=True)
diff --git a/lib/spack/spack/cmd/flake8.py b/lib/spack/spack/cmd/flake8.py
index 887348e9f6..7049d622f2 100644
--- a/lib/spack/spack/cmd/flake8.py
+++ b/lib/spack/spack/cmd/flake8.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import re
@@ -33,7 +14,7 @@ import argparse
from llnl.util.filesystem import working_dir, mkdirp
-import spack
+import spack.paths
from spack.util.executable import which
@@ -53,7 +34,7 @@ def is_package(f):
#: List of directories to exclude from checks.
-exclude_directories = [spack.external_path]
+exclude_directories = [spack.paths.external_path]
#: This is a dict that maps:
@@ -226,7 +207,7 @@ def setup_parser(subparser):
help="send filtered files to stdout as well as temp files")
subparser.add_argument(
'-r', '--root-relative', action='store_true', default=False,
- help="print root-relative paths (default is cwd-relative)")
+ help="print root-relative paths (default: cwd-relative)")
subparser.add_argument(
'-U', '--no-untracked', dest='untracked', action='store_false',
default=True, help="exclude untracked files from checks")
@@ -243,11 +224,12 @@ def flake8(parser, args):
if file_list:
def prefix_relative(path):
return os.path.relpath(
- os.path.abspath(os.path.realpath(path)), spack.prefix)
+ os.path.abspath(os.path.realpath(path)),
+ spack.paths.prefix)
file_list = [prefix_relative(p) for p in file_list]
- with working_dir(spack.prefix):
+ with working_dir(spack.paths.prefix):
if not file_list:
file_list = changed_files(args)
@@ -261,7 +243,7 @@ def flake8(parser, args):
# filter files into a temporary directory with exemptions added.
for filename in file_list:
- src_path = os.path.join(spack.prefix, filename)
+ src_path = os.path.join(spack.paths.prefix, filename)
dest_path = os.path.join(temp, filename)
filter_file(src_path, dest_path, args.output)
@@ -275,13 +257,14 @@ def flake8(parser, args):
if file_list:
output += flake8(
'--format', 'pylint',
- '--config=%s' % os.path.join(spack.prefix, '.flake8'),
+ '--config=%s' % os.path.join(spack.paths.prefix,
+ '.flake8'),
*file_list, fail_on_error=False, output=str)
returncode |= flake8.returncode
if package_file_list:
output += flake8(
'--format', 'pylint',
- '--config=%s' % os.path.join(spack.prefix,
+ '--config=%s' % os.path.join(spack.paths.prefix,
'.flake8_packages'),
*package_file_list, fail_on_error=False, output=str)
returncode |= flake8.returncode
@@ -293,7 +276,8 @@ def flake8(parser, args):
# print results relative to current working directory
def cwd_relative(path):
return '{0}: ['.format(os.path.relpath(
- os.path.join(spack.prefix, path.group(1)), os.getcwd()))
+ os.path.join(
+ spack.paths.prefix, path.group(1)), os.getcwd()))
for line in output.split('\n'):
print(re.sub(r'^(.*): \[', cwd_relative, line))
diff --git a/lib/spack/spack/cmd/gpg.py b/lib/spack/spack/cmd/gpg.py
index b16df52e8f..6b81ce885d 100644
--- a/lib/spack/spack/cmd/gpg.py
+++ b/lib/spack/spack/cmd/gpg.py
@@ -1,34 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-from spack.util.gpg import Gpg
-import argparse
-import spack
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
+import argparse
+
+import spack.paths
+from spack.util.gpg import Gpg
description = "handle GPG actions for spack"
-section = "developer"
+section = "packaging"
level = "long"
@@ -148,7 +130,7 @@ def gpg_trust(args):
def gpg_init(args):
import_dir = args.import_dir
if import_dir is None:
- import_dir = spack.gpg_keys_path
+ import_dir = spack.paths.gpg_keys_path
for root, _, filenames in os.walk(import_dir):
for filename in filenames:
diff --git a/lib/spack/spack/cmd/graph.py b/lib/spack/spack/cmd/graph.py
index 16bd6a38a1..6830c90bae 100644
--- a/lib/spack/spack/cmd/graph.py
+++ b/lib/spack/spack/cmd/graph.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import argparse
import llnl.util.tty as tty
-import spack
import spack.cmd
+import spack.config
import spack.store
from spack.dependency import all_deptypes, canonical_deptype
from spack.graph import graph_dot, graph_ascii
@@ -98,7 +79,8 @@ def graph(parser, args):
graph_dot(specs, static=args.static, deptype=deptype)
elif specs: # ascii is default: user doesn't need to provide it explicitly
- graph_ascii(specs[0], debug=spack.debug, deptype=deptype)
+ debug = spack.config.get('config:debug')
+ graph_ascii(specs[0], debug=debug, deptype=deptype)
for spec in specs[1:]:
print() # extra line bt/w independent graphs
- graph_ascii(spec, debug=spack.debug)
+ graph_ascii(spec, debug=debug)
diff --git a/lib/spack/spack/cmd/help.py b/lib/spack/spack/cmd/help.py
index a76ef3a083..ab1a5b5c45 100644
--- a/lib/spack/spack/cmd/help.py
+++ b/lib/spack/spack/cmd/help.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import sys
from llnl.util.tty.color import colorize
@@ -59,9 +40,9 @@ spec expression syntax:
@B{variant=value1,value2,value3} set multi-value <variant> values
architecture variants:
- @m{target=target} specific <target> processor
- @m{os=operating_system} specific <operating_system>
@m{platform=platform} linux, darwin, cray, bgq, etc.
+ @m{os=operating_system} specific <operating_system>
+ @m{target=target} specific <target> processor
@m{arch=platform-os-target} shortcut for all three above
cross-compiling:
diff --git a/lib/spack/spack/cmd/info.py b/lib/spack/spack/cmd/info.py
index e53d607704..d4e1f9e5d3 100644
--- a/lib/spack/spack/cmd/info.py
+++ b/lib/spack/spack/cmd/info.py
@@ -1,39 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import textwrap
-
from six.moves import zip_longest
+import llnl.util.tty.color as color
from llnl.util.tty.colify import colify
-import llnl.util.tty.color as color
-import spack
-import spack.fetch_strategy as fs
+import spack.repo
import spack.spec
+import spack.fetch_strategy as fs
+
description = 'get detailed information on a particular package'
section = 'basic'
@@ -156,7 +137,7 @@ def print_text_info(pkg):
color.cprint('')
color.cprint(section_title('Description:'))
if pkg.__doc__:
- color.cprint(pkg.format_doc(indent=4))
+ color.cprint(color.cescape(pkg.format_doc(indent=4)))
else:
color.cprint(" None")
@@ -195,14 +176,14 @@ def print_text_info(pkg):
preferred = sorted(pkg.versions, key=key_fn).pop()
f = fs.for_package_version(pkg, preferred)
- line = version(' {0}'.format(pad(preferred))) + str(f)
+ line = version(' {0}'.format(pad(preferred))) + color.cescape(f)
color.cprint(line)
color.cprint('')
color.cprint(section_title('Safe versions: '))
for v in reversed(sorted(pkg.versions)):
f = fs.for_package_version(pkg, v)
- line = version(' {0}'.format(pad(v))) + str(f)
+ line = version(' {0}'.format(pad(v))) + color.cescape(f)
color.cprint(line)
color.cprint('')
diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py
index 86acd580d7..d42988303f 100644
--- a/lib/spack/spack/cmd/install.py
+++ b/lib/spack/spack/cmd/install.py
@@ -1,52 +1,55 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
-import codecs
-import functools
import os
-import platform
import shutil
import sys
-import time
-import xml.dom.minidom
-import xml.etree.ElementTree as ET
import llnl.util.filesystem as fs
import llnl.util.tty as tty
-import spack
+
+import spack.build_environment
import spack.cmd
import spack.cmd.common.arguments as arguments
-from spack.build_environment import InstallError
-from spack.fetch_strategy import FetchError
-from spack.package import PackageBase
+import spack.environment as ev
+import spack.fetch_strategy
+import spack.paths
+import spack.report
+from spack.error import SpackError
+
description = "build and install packages"
section = "build"
level = "short"
+def update_kwargs_from_args(args, kwargs):
+ """Parse cli arguments and construct a dictionary
+ that will be passed to Package.do_install API"""
+
+ kwargs.update({
+ 'keep_prefix': args.keep_prefix,
+ 'keep_stage': args.keep_stage,
+ 'restage': not args.dont_restage,
+ 'install_source': args.install_source,
+ 'make_jobs': args.jobs,
+ 'verbose': args.verbose,
+ 'fake': args.fake,
+ 'dirty': args.dirty,
+ 'use_cache': args.use_cache
+ })
+ if hasattr(args, 'setup'):
+ setups = set()
+ for arglist_s in args.setup:
+ for arg in [x.strip() for x in arglist_s.split(',')]:
+ setups.add(arg)
+ kwargs['setup'] = setups
+ tty.msg('Setup={0}'.format(kwargs['setup']))
+
+
def setup_parser(subparser):
subparser.add_argument(
'--only',
@@ -58,9 +61,7 @@ the default is to install the package along with all its dependencies.
alternatively one can decide to install only the package or only
the dependencies"""
)
- subparser.add_argument(
- '-j', '--jobs', action='store', type=int,
- help="explicitly set number of make jobs. default is #cpus")
+ arguments.add_common_arguments(subparser, ['jobs', 'install_status'])
subparser.add_argument(
'--overwrite', action='store_true',
help="reinstall an existing spec, even if it has dependents")
@@ -71,20 +72,24 @@ the dependencies"""
'--keep-stage', action='store_true',
help="don't remove the build stage if installation succeeds")
subparser.add_argument(
- '--restage', action='store_true',
- help="if a partial install is detected, delete prior state")
- subparser.add_argument(
- '--use-cache', action='store_true', dest='use_cache',
- help="check for pre-built Spack packages in mirrors")
+ '--dont-restage', action='store_true',
+ help="if a partial install is detected, don't delete prior state")
+
+ cache_group = subparser.add_mutually_exclusive_group()
+ cache_group.add_argument(
+ '--use-cache', action='store_true', dest='use_cache', default=True,
+ help="check for pre-built Spack packages in mirrors (default)")
+ cache_group.add_argument(
+ '--no-cache', action='store_false', dest='use_cache', default=True,
+ help="do not check for pre-built Spack packages in mirrors")
+
subparser.add_argument(
'--show-log-on-error', action='store_true',
help="print full build log to stderr if build fails")
subparser.add_argument(
'--source', action='store_true', dest='install_source',
help="install source files in prefix")
- subparser.add_argument(
- '-n', '--no-checksum', action='store_true',
- help="do not check packages against checksum")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'-v', '--verbose', action='store_true',
help="display verbose build output while installing")
@@ -92,7 +97,11 @@ the dependencies"""
'--fake', action='store_true',
help="fake install for debug purposes.")
subparser.add_argument(
- '-f', '--file', action='store_true',
+ '--only-concrete', action='store_true', default=False,
+ help='(with environment) only install already concretized specs')
+ subparser.add_argument(
+ '-f', '--file', action='append', default=[],
+ dest='specfiles', metavar='SPEC_YAML_FILE',
help="install from file. Read specs to install from .yaml files")
cd_group = subparser.add_mutually_exclusive_group()
@@ -119,7 +128,7 @@ packages. If neither are chosen, don't run tests for any packages."""
subparser.add_argument(
'--log-format',
default=None,
- choices=['junit'],
+ choices=spack.report.valid_formats,
help="format to be used for log files"
)
subparser.add_argument(
@@ -127,237 +136,49 @@ packages. If neither are chosen, don't run tests for any packages."""
default=None,
help="filename for the log file. if not passed a default will be used"
)
+ subparser.add_argument(
+ '--cdash-upload-url',
+ default=None,
+ help="CDash URL where reports will be uploaded"
+ )
arguments.add_common_arguments(subparser, ['yes_to_all'])
-# Needed for test cases
-class TestResult(object):
- PASSED = 0
- FAILED = 1
- SKIPPED = 2
- ERRORED = 3
-
-
-class TestSuite(object):
- def __init__(self, spec):
- self.root = ET.Element('testsuite')
- self.tests = []
- self.spec = spec
-
- def append(self, item):
- if not isinstance(item, TestCase):
- raise TypeError(
- 'only TestCase instances may be appended to TestSuite'
- )
- self.tests.append(item) # Append the item to the list of tests
-
- def dump(self, filename):
- # Prepare the header for the entire test suite
- number_of_errors = sum(
- x.result_type == TestResult.ERRORED for x in self.tests
- )
- self.root.set('errors', str(number_of_errors))
- number_of_failures = sum(
- x.result_type == TestResult.FAILED for x in self.tests
- )
- self.root.set('failures', str(number_of_failures))
- self.root.set('tests', str(len(self.tests)))
- self.root.set('name', self.spec.short_spec)
- self.root.set('hostname', platform.node())
-
- for item in self.tests:
- self.root.append(item.element)
-
- with codecs.open(filename, 'wb', 'utf-8') as file:
- xml_string = ET.tostring(self.root)
- xml_string = xml.dom.minidom.parseString(xml_string).toprettyxml()
- file.write(xml_string)
-
-
-class TestCase(object):
-
- results = {
- TestResult.PASSED: None,
- TestResult.SKIPPED: 'skipped',
- TestResult.FAILED: 'failure',
- TestResult.ERRORED: 'error',
- }
-
- def __init__(self, classname, name):
- self.element = ET.Element('testcase')
- self.element.set('classname', str(classname))
- self.element.set('name', str(name))
- self.result_type = None
-
- def set_duration(self, duration):
- self.element.set('time', str(duration))
-
- def set_result(self, result_type,
- message=None, error_type=None, text=None):
- self.result_type = result_type
- result = TestCase.results[self.result_type]
- if result is not None and result is not TestResult.PASSED:
- subelement = ET.SubElement(self.element, result)
- if error_type is not None:
- subelement.set('type', error_type)
- if message is not None:
- subelement.set('message', str(message))
- if text is not None:
- subelement.text = text
-
-
-def fetch_text(path):
- if not os.path.exists(path):
- return ''
-
- with codecs.open(path, 'rb', 'utf-8') as f:
- return '\n'.join(
- list(line.strip() for line in f.readlines())
- )
-
-
-def junit_output(spec, test_suite):
- # Cycle once and for all on the dependencies and skip
- # the ones that are already installed. This ensures that
- # for the same spec, the same number of entries will be
- # displayed in the XML report
- for x in spec.traverse(order='post'):
- package = spack.repo.get(x)
- if package.installed:
- test_case = TestCase(package.name, x.short_spec)
- test_case.set_duration(0.0)
- test_case.set_result(
- TestResult.SKIPPED,
- message='Skipped [already installed]',
- error_type='already_installed'
- )
- test_suite.append(test_case)
-
- def decorator(func):
- @functools.wraps(func)
- def wrapper(self, *args, ** kwargs):
-
- # Check if the package has been installed already
- if self.installed:
- return
-
- test_case = TestCase(self.name, self.spec.short_spec)
- # Try to install the package
- try:
- # If already installed set the spec as skipped
- start_time = time.time()
- # PackageBase.do_install
- func(self, *args, **kwargs)
- duration = time.time() - start_time
- test_case.set_duration(duration)
- test_case.set_result(TestResult.PASSED)
- except InstallError:
- # Check if the package relies on dependencies that
- # did not install
- duration = time.time() - start_time
- test_case.set_duration(duration)
- if [x for x in self.spec.dependencies(('link', 'run')) if not spack.repo.get(x).installed]: # NOQA: ignore=E501
- test_case.set_duration(0.0)
- test_case.set_result(
- TestResult.SKIPPED,
- message='Skipped [failed dependencies]',
- error_type='dep_failed'
- )
- else:
- # An InstallError is considered a failure (the recipe
- # didn't work correctly)
- text = fetch_text(self.build_log_path)
- test_case.set_result(
- TestResult.FAILED,
- message='Installation failure',
- text=text
- )
- except FetchError:
- # A FetchError is considered an error as
- # we didn't even start building
- duration = time.time() - start_time
- test_case.set_duration(duration)
- text = fetch_text(self.build_log_path)
- test_case.set_result(
- TestResult.FAILED,
- message='Unable to fetch package',
- text=text
- )
- except Exception:
- # Anything else is also an error
- duration = time.time() - start_time
- test_case.set_duration(duration)
- text = fetch_text(self.build_log_path)
- test_case.set_result(
- TestResult.FAILED,
- message='Unexpected exception thrown during install',
- text=text
- )
- except BaseException:
- # Anything else is also an error
- duration = time.time() - start_time
- test_case.set_duration(duration)
- text = fetch_text(self.build_log_path)
- test_case.set_result(
- TestResult.FAILED,
- message='Unknown error',
- text=text
- )
-
- # Try to get the log
- test_suite.append(test_case)
- return wrapper
- return decorator
-
-
def default_log_file(spec):
"""Computes the default filename for the log file and creates
the corresponding directory if not present
"""
fmt = 'test-{x.name}-{x.version}-{hash}.xml'
basename = fmt.format(x=spec, hash=spec.dag_hash())
- dirname = fs.join_path(spack.var_path, 'junit-report')
+ dirname = fs.os.path.join(spack.paths.var_path, 'junit-report')
fs.mkdirp(dirname)
- return fs.join_path(dirname, basename)
-
+ return fs.os.path.join(dirname, basename)
-def install_spec(cli_args, kwargs, spec):
- saved_do_install = PackageBase.do_install
- decorator = lambda fn: fn
+def install_spec(cli_args, kwargs, abstract_spec, spec):
+ """Do the actual installation."""
- # Check if we were asked to produce some log for dashboards
- if cli_args.log_format is not None:
- # Compute the filename for logging
- log_filename = cli_args.log_file
- if not log_filename:
- log_filename = default_log_file(spec)
-
- # Create the test suite in which to log results
- test_suite = TestSuite(spec)
-
- # Temporarily decorate PackageBase.do_install to monitor
- # recursive calls.
- decorator = junit_output(spec, test_suite)
+ # handle active environment, if any
+ def install(spec, kwargs):
+ env = ev.get_env(cli_args, 'install', required=False)
+ if env:
+ env.install(abstract_spec, spec, **kwargs)
+ env.write()
+ else:
+ spec.package.do_install(**kwargs)
- # Do the actual installation
try:
- # decorate the install if necessary
- PackageBase.do_install = decorator(PackageBase.do_install)
-
if cli_args.things_to_install == 'dependencies':
# Install dependencies as-if they were installed
# for root (explicit=False in the DB)
kwargs['explicit'] = False
for s in spec.dependencies():
- p = spack.repo.get(s)
- p.do_install(**kwargs)
+ install(s, kwargs)
else:
- package = spack.repo.get(spec)
kwargs['explicit'] = True
- package.do_install(**kwargs)
+ install(spec, kwargs)
- except InstallError as e:
+ except spack.build_environment.InstallError as e:
if cli_args.show_log_on_error:
e.print_context()
if not os.path.exists(e.pkg.build_log_path):
@@ -368,94 +189,114 @@ def install_spec(cli_args, kwargs, spec):
shutil.copyfileobj(log, sys.stderr)
raise
- finally:
- PackageBase.do_install = saved_do_install
-
- # Dump test output if asked to
- if cli_args.log_format is not None:
- test_suite.dump(log_filename)
-
def install(parser, args, **kwargs):
- if not args.package:
- tty.die("install requires at least one package argument")
+ if not args.package and not args.specfiles:
+ # if there are no args but an active environment or spack.yaml file
+ # then install the packages from it.
+ env = ev.get_env(args, 'install', required=False)
+ if env:
+ if not args.only_concrete:
+ env.concretize()
+ env.write()
+ tty.msg("Installing environment %s" % env.name)
+ env.install_all(args)
+ return
+ else:
+ tty.die("install requires a package argument or a spack.yaml file")
if args.jobs is not None:
if args.jobs <= 0:
tty.die("The -j option must be a positive integer!")
if args.no_checksum:
- spack.do_checksum = False # TODO: remove this global.
+ spack.config.set('config:checksum', False, scope='command_line')
# Parse cli arguments and construct a dictionary
# that will be passed to Package.do_install API
+ update_kwargs_from_args(args, kwargs)
kwargs.update({
- 'keep_prefix': args.keep_prefix,
- 'keep_stage': args.keep_stage,
- 'restage': args.restage,
- 'install_source': args.install_source,
- 'install_deps': 'dependencies' in args.things_to_install,
- 'make_jobs': args.jobs,
- 'verbose': args.verbose,
- 'fake': args.fake,
- 'dirty': args.dirty,
- 'use_cache': args.use_cache
+ 'install_dependencies': ('dependencies' in args.things_to_install),
+ 'install_package': ('package' in args.things_to_install)
})
if args.run_tests:
tty.warn("Deprecated option: --run-tests: use --test=all instead")
- specs = spack.cmd.parse_specs(args.package)
+ # 1. Abstract specs from cli
+ reporter = spack.report.collect_info(args.log_format,
+ ' '.join(args.package),
+ args.cdash_upload_url)
+ if args.log_file:
+ reporter.filename = args.log_file
+
+ abstract_specs = spack.cmd.parse_specs(args.package)
+ tests = False
if args.test == 'all' or args.run_tests:
- spack.package_testing.test_all()
+ tests = True
elif args.test == 'root':
- for spec in specs:
- spack.package_testing.test(spec.name)
-
- # Spec from cli
- specs = []
- if args.file:
- for file in args.package:
- with open(file, 'r') as f:
- specs.append(spack.spec.Spec.from_yaml(f))
- else:
- specs = spack.cmd.parse_specs(args.package, concretize=True)
+ tests = [spec.name for spec in abstract_specs]
+ kwargs['tests'] = tests
+
+ try:
+ specs = spack.cmd.parse_specs(
+ args.package, concretize=True, tests=tests)
+ except SpackError as e:
+ reporter.concretization_report(e.message)
+ raise
+
+ # 2. Concrete specs from yaml files
+ for file in args.specfiles:
+ with open(file, 'r') as f:
+ s = spack.spec.Spec.from_yaml(f)
+
+ if s.concretized().dag_hash() != s.dag_hash():
+ msg = 'skipped invalid file "{0}". '
+ msg += 'The file does not contain a concrete spec.'
+ tty.warn(msg.format(file))
+ continue
+
+ specs.append(s.concretized())
+
if len(specs) == 0:
- tty.error('The `spack install` command requires a spec to install.')
-
- if args.overwrite:
- # If we asked to overwrite an existing spec we must ensure that:
- # 1. We have only one spec
- # 2. The spec is already installed
- assert len(specs) == 1, \
- "only one spec is allowed when overwriting an installation"
-
- spec = specs[0]
- t = spack.store.db.query(spec)
- assert len(t) == 1, "to overwrite a spec you must install it first"
-
- # Give the user a last chance to think about overwriting an already
- # existing installation
- if not args.yes_to_all:
- tty.msg('The following package will be reinstalled:\n')
-
- display_args = {
- 'long': True,
- 'show_flags': True,
- 'variants': True
- }
-
- spack.cmd.display_specs(t, **display_args)
- answer = tty.get_yes_or_no(
- 'Do you want to proceed?', default=False
- )
- if not answer:
- tty.die('Reinstallation aborted.')
-
- with fs.replace_directory_transaction(specs[0].prefix):
- install_spec(args, kwargs, specs[0])
-
- else:
-
- for spec in specs:
- install_spec(args, kwargs, spec)
+ tty.die('The `spack install` command requires a spec to install.')
+
+ if not args.log_file and not reporter.filename:
+ reporter.filename = default_log_file(specs[0])
+ reporter.specs = specs
+ with reporter:
+ if args.overwrite:
+ # If we asked to overwrite an existing spec we must ensure that:
+ # 1. We have only one spec
+ # 2. The spec is already installed
+ assert len(specs) == 1, \
+ "only one spec is allowed when overwriting an installation"
+
+ spec = specs[0]
+ t = spack.store.db.query(spec)
+ assert len(t) == 1, "to overwrite a spec you must install it first"
+
+ # Give the user a last chance to think about overwriting an already
+ # existing installation
+ if not args.yes_to_all:
+ tty.msg('The following package will be reinstalled:\n')
+
+ display_args = {
+ 'long': True,
+ 'show_flags': True,
+ 'variants': True
+ }
+
+ spack.cmd.display_specs(t, **display_args)
+ answer = tty.get_yes_or_no(
+ 'Do you want to proceed?', default=False
+ )
+ if not answer:
+ tty.die('Reinstallation aborted.')
+
+ with fs.replace_directory_transaction(specs[0].prefix):
+ install_spec(args, kwargs, abstract_specs[0], specs[0])
+
+ else:
+ for abstract, concrete in zip(abstract_specs, specs):
+ install_spec(args, kwargs, abstract, concrete)
diff --git a/lib/spack/spack/cmd/license.py b/lib/spack/spack/cmd/license.py
new file mode 100644
index 0000000000..df208d8bbe
--- /dev/null
+++ b/lib/spack/spack/cmd/license.py
@@ -0,0 +1,156 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from __future__ import print_function
+
+import os
+import re
+
+import llnl.util.tty as tty
+
+import spack.paths
+from spack.util.executable import which
+
+description = 'list and check license headers on files in spack'
+section = "developer"
+level = "long"
+
+#: need the git command to check new files
+git = which('git')
+
+#: SPDX license id must appear in the first <license_lines> lines of a file
+license_lines = 6
+
+#: Spack's license identifier
+apache2_mit_spdx = "(Apache-2.0 OR MIT)"
+
+#: regular expressions for licensed files.
+licensed_files = [
+ # spack scripts
+ r'^bin/spack$',
+ r'^bin/spack-python$',
+ r'^bin/sbang$',
+
+ # all of spack core
+ r'^lib/spack/spack/.*\.py$',
+ r'^lib/spack/spack/.*\.sh$',
+ r'^lib/spack/llnl/.*\.py$',
+ r'^lib/spack/env/cc$',
+
+ # rst files in documentation
+ r'^lib/spack/docs/(?!command_index|spack|llnl).*\.rst$',
+ r'^lib/spack/docs/.*\.py$',
+
+ # 2 files in external
+ r'^lib/spack/external/__init__.py$',
+ r'^lib/spack/external/ordereddict_backport.py$',
+
+ # shell scripts in share
+ r'^share/spack/.*\.sh$',
+ r'^share/spack/.*\.bash$',
+ r'^share/spack/.*\.csh$',
+ r'^share/spack/qa/run-[^/]*$',
+
+ # all packages
+ r'^var/spack/repos/.*/package.py$'
+]
+
+#: licensed files that can have LGPL language in them
+#: so far, just this command -- so it can find LGPL things elsewhere
+lgpl_exceptions = [
+ r'lib/spack/spack/cmd/license.py',
+ r'lib/spack/spack/test/cmd/license.py',
+]
+
+
+def _all_spack_files(root=spack.paths.prefix):
+ """Generates root-relative paths of all files in the spack repository."""
+ for cur_root, folders, files in os.walk(root):
+ for filename in files:
+ path = os.path.join(cur_root, filename)
+ yield os.path.relpath(path, root)
+
+
+def _licensed_files(root=spack.paths.prefix):
+ for relpath in _all_spack_files(root):
+ if any(regex.match(relpath) for regex in licensed_files):
+ yield relpath
+
+
+def list_files(args):
+ """list files in spack that should have license headers"""
+ for relpath in _licensed_files():
+ print(os.path.join(spack.paths.spack_root, relpath))
+
+
+def verify(args):
+ """verify that files in spack have the right license header"""
+ errors = 0
+ missing = 0
+ old_license = 0
+
+ for relpath in _licensed_files(args.root):
+ path = os.path.join(args.root, relpath)
+ with open(path) as f:
+ lines = [line for line in f]
+
+ if not any(re.match(regex, relpath) for regex in lgpl_exceptions):
+ if any(re.match(r'^# This program is free software', line)
+ for line in lines):
+ print('%s: has old LGPL license header' % path)
+ old_license += 1
+ continue
+
+ # how we'll find licenses in files
+ spdx_expr = r'SPDX-License-Identifier: ([^\n]*)'
+
+ # check first <license_lines> lines for required header
+ first_n_lines = ''.join(lines[:license_lines])
+ match = re.search(spdx_expr, first_n_lines)
+
+ if not match:
+ print('%s: no license header' % path)
+ missing += 1
+ continue
+
+ correct = apache2_mit_spdx
+ actual = match.group(1)
+ if actual != correct:
+ print("%s: labeled as '%s', but should be '%s'"
+ % (path, actual, correct))
+ errors += 1
+ continue
+
+ if any([errors, missing, old_license]):
+ tty.die(
+ '%d improperly licensed files' % (errors + missing + old_license),
+ 'files with no SPDX-License-Identifier: %d' % missing,
+ 'files with wrong SPDX-License-Identifier: %d' % errors,
+ 'files with old license header: %d' % old_license)
+ else:
+ tty.msg('No license issues found.')
+
+
+def setup_parser(subparser):
+ sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='license_command')
+ sp.add_parser('list-files', help=list_files.__doc__)
+
+ verify_parser = sp.add_parser('verify', help=verify.__doc__)
+ verify_parser.add_argument(
+ '--root', action='store', default=spack.paths.prefix,
+ help='scan a different prefix for license issues')
+
+
+def license(parser, args):
+ if not git:
+ tty.die('spack license requires git in your environment')
+
+ licensed_files[:] = [re.compile(regex) for regex in licensed_files]
+
+ commands = {
+ 'list-files': list_files,
+ 'verify': verify,
+ }
+ return commands[args.license_command](args)
diff --git a/lib/spack/spack/cmd/list.py b/lib/spack/spack/cmd/list.py
index 3549de361a..f486f46a4f 100644
--- a/lib/spack/spack/cmd/list.py
+++ b/lib/spack/spack/cmd/list.py
@@ -1,41 +1,25 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
+from __future__ import division
import argparse
import cgi
import fnmatch
import re
import sys
+import math
from six import StringIO
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
-import spack
+import spack.dependency
+import spack.repo
import spack.cmd.common.arguments as arguments
description = "list and search available packages"
@@ -113,23 +97,35 @@ def name_only(pkgs):
colify(pkgs, indent=indent)
-@formatter
-def rst(pkgs):
- """Print out information on all packages in restructured text."""
+def github_url(pkg):
+ """Link to a package file on github."""
+ url = 'https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/{0}/package.py'
+ return url.format(pkg.name)
+
- def github_url(pkg):
- """Link to a package file on github."""
- url = 'https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/{0}/package.py'
- return url.format(pkg.name)
+def rst_table(elts):
+ """Print out a RST-style table."""
+ cols = StringIO()
+ ncol, widths = colify(elts, output=cols, tty=True)
+ header = ' '.join('=' * (w - 1) for w in widths)
+ return '%s\n%s%s' % (header, cols.getvalue(), header)
- def rst_table(elts):
- """Print out a RST-style table."""
- cols = StringIO()
- ncol, widths = colify(elts, output=cols, tty=True)
- header = ' '.join('=' * (w - 1) for w in widths)
- return '%s\n%s%s' % (header, cols.getvalue(), header)
- pkg_names = pkgs
+def rows_for_ncols(elts, ncols):
+ """Print out rows in a table with ncols of elts laid out vertically."""
+ clen = int(math.ceil(len(elts) / ncols))
+ for r in range(clen):
+ row = []
+ for c in range(ncols):
+ i = c * clen + r
+ row.append(elts[i] if i < len(elts) else None)
+ yield row
+
+
+@formatter
+def rst(pkg_names):
+ """Print out information on all packages in restructured text."""
+
pkgs = [spack.repo.get(name) for name in pkg_names]
print('.. _package-list:')
@@ -170,7 +166,7 @@ def rst(pkgs):
reversed(sorted(pkg.versions))))
print()
- for deptype in spack.all_deptypes:
+ for deptype in spack.dependency.all_deptypes:
deps = pkg.dependencies_of_type(deptype)
if deps:
print('%s Dependencies' % deptype.capitalize())
@@ -183,6 +179,102 @@ def rst(pkgs):
print()
+@formatter
+def html(pkg_names):
+ """Print out information on all packages in Sphinx HTML.
+
+ This is intended to be inlined directly into Sphinx documentation.
+ We write HTML instead of RST for speed; generating RST from *all*
+ packages causes the Sphinx build to take forever. Including this as
+ raw HTML is much faster.
+ """
+
+ # Read in all packages
+ pkgs = [spack.repo.get(name) for name in pkg_names]
+
+ # Start at 2 because the title of the page from Sphinx is id1.
+ span_id = 2
+
+ # HTML header with an increasing id span
+ def head(n, span_id, title, anchor=None):
+ if anchor is None:
+ anchor = title
+ print(('<span id="id%d"></span>'
+ '<h1>%s<a class="headerlink" href="#%s" '
+ 'title="Permalink to this headline">&para;</a>'
+ '</h1>') % (span_id, title, anchor))
+
+ # Start with the number of packages, skipping the title and intro
+ # blurb, which we maintain in the RST file.
+ print('<p>')
+ print('Spack currently has %d mainline packages:' % len(pkgs))
+ print('</p>')
+
+ # Table of links to all packages
+ print('<table border="1" class="docutils">')
+ print('<tbody valign="top">')
+ for i, row in enumerate(rows_for_ncols(pkg_names, 3)):
+ print('<tr class="row-odd">' if i % 2 == 0 else
+ '<tr class="row-even">')
+ for name in row:
+ print('<td>')
+ print('<a class="reference internal" href="#%s">%s</a></td>'
+ % (name, name))
+ print('</td>')
+ print('</tr>')
+ print('</tbody>')
+ print('</table>')
+ print('<hr class="docutils"/>')
+
+ # Output some text for each package.
+ for pkg in pkgs:
+ print('<div class="section" id="%s">' % pkg.name)
+ head(2, span_id, pkg.name)
+ span_id += 1
+
+ print('<dl class="docutils">')
+
+ print('<dt>Homepage:</dt>')
+ print('<dd><ul class="first last simple">')
+ print(('<li>'
+ '<a class="reference external" href="%s">%s</a>'
+ '</li>') % (pkg.homepage, cgi.escape(pkg.homepage)))
+ print('</ul></dd>')
+
+ print('<dt>Spack package:</dt>')
+ print('<dd><ul class="first last simple">')
+ print(('<li>'
+ '<a class="reference external" href="%s">%s/package.py</a>'
+ '</li>') % (github_url(pkg), pkg.name))
+ print('</ul></dd>')
+
+ if pkg.versions:
+ print('<dt>Versions:</dt>')
+ print('<dd>')
+ print(', '.join(str(v) for v in reversed(sorted(pkg.versions))))
+ print('</dd>')
+
+ for deptype in spack.dependency.all_deptypes:
+ deps = pkg.dependencies_of_type(deptype)
+ if deps:
+ print('<dt>%s Dependencies:</dt>' % deptype.capitalize())
+ print('<dd>')
+ print(', '.join(
+ d if d not in pkg_names else
+ '<a class="reference internal" href="#%s">%s</a>' % (d, d)
+ for d in deps))
+ print('</dd>')
+
+ print('<dt>Description:</dt>')
+ print('<dd>')
+ print(cgi.escape(pkg.format_doc(indent=2)))
+ print('</dd>')
+ print('</dl>')
+
+ print('<hr class="docutils"/>')
+ print('</div>')
+
+
def list(parser, args):
# Retrieve the names of all the packages
pkgs = set(spack.repo.all_package_names())
@@ -191,7 +283,8 @@ def list(parser, args):
# Filter by tags
if args.tags:
- packages_with_tags = set(spack.repo.packages_with_tags(*args.tags))
+ packages_with_tags = set(
+ spack.repo.path.packages_with_tags(*args.tags))
sorted_packages = set(sorted_packages) & packages_with_tags
sorted_packages = sorted(sorted_packages)
diff --git a/lib/spack/spack/cmd/load.py b/lib/spack/spack/cmd/load.py
index 61c7003855..87822edb25 100644
--- a/lib/spack/spack/cmd/load.py
+++ b/lib/spack/spack/cmd/load.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
-from spack.cmd.common import print_module_placeholder_help
+from spack.cmd.common import print_module_placeholder_help, arguments
description = "add package to environment using `module load`"
-section = "environment"
+section = "modules"
level = "short"
@@ -36,7 +17,8 @@ def setup_parser(subparser):
subparser.add_argument(
'spec', nargs=argparse.REMAINDER,
help="spec of package to load with modules "
- "(if -, read specs from STDIN)")
+ )
+ arguments.add_common_arguments(subparser, ['recurse_dependencies'])
def load(parser, args):
diff --git a/lib/spack/spack/cmd/location.py b/lib/spack/spack/cmd/location.py
index 99ce4d4fc3..a878f63df8 100644
--- a/lib/spack/spack/cmd/location.py
+++ b/lib/spack/spack/cmd/location.py
@@ -1,37 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
+import os
import argparse
import llnl.util.tty as tty
-import spack
import spack.cmd
+import spack.environment
+import spack.paths
+import spack.repo
-description = "print out locations of various directories used by Spack"
-section = "environment"
+description = "print out locations of packages and spack directories"
+section = "basic"
level = "long"
@@ -65,6 +49,9 @@ def setup_parser(subparser):
'-b', '--build-dir', action='store_true',
help="checked out or expanded source directory for a spec "
"(requires it to be staged first)")
+ directories.add_argument(
+ '-e', '--env', action='store',
+ help="location of an environment managed by spack")
subparser.add_argument(
'spec', nargs=argparse.REMAINDER,
@@ -73,16 +60,22 @@ def setup_parser(subparser):
def location(parser, args):
if args.module_dir:
- print(spack.module_path)
+ print(spack.paths.module_path)
elif args.spack_root:
- print(spack.prefix)
+ print(spack.paths.prefix)
+
+ elif args.env:
+ path = spack.environment.root(args.env)
+ if not os.path.isdir(path):
+ tty.die("no such environment: '%s'" % args.env)
+ print(path)
elif args.packages:
- print(spack.repo.first_repo().root)
+ print(spack.repo.path.first_repo().root)
elif args.stages:
- print(spack.stage_path)
+ print(spack.paths.stage_path)
else:
specs = spack.cmd.parse_specs(args.spec)
@@ -101,7 +94,7 @@ def location(parser, args):
if args.package_dir:
# This one just needs the spec name.
- print(spack.repo.dirname_for_package_name(spec.name))
+ print(spack.repo.path.dirname_for_package_name(spec.name))
else:
# These versions need concretized specs.
diff --git a/lib/spack/spack/cmd/log_parse.py b/lib/spack/spack/cmd/log_parse.py
new file mode 100644
index 0000000000..ac7db768bf
--- /dev/null
+++ b/lib/spack/spack/cmd/log_parse.py
@@ -0,0 +1,63 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import sys
+
+import llnl.util.tty as tty
+from spack.util.log_parse import parse_log_events, make_log_context
+
+description = "filter errors and warnings from build logs"
+section = "build"
+level = "long"
+
+event_types = ('errors', 'warnings')
+
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ '--show', action='store', default='errors',
+ help="comma-separated list of what to show; options: errors, warnings")
+ subparser.add_argument(
+ '-c', '--context', action='store', type=int, default=3,
+ help="lines of context to show around lines of interest")
+ subparser.add_argument(
+ '-p', '--profile', action='store_true',
+ help="print out a profile of time spent in regexes during parse")
+ subparser.add_argument(
+ '-w', '--width', action='store', type=int, default=None,
+ help="wrap width: auto-size to terminal by default; 0 for no wrap")
+ subparser.add_argument(
+ '-j', '--jobs', action='store', type=int, default=None,
+ help="number of jobs to parse log file (default: 1 for short logs, "
+ "ncpus for long logs)")
+
+ subparser.add_argument(
+ 'file', help="a log file containing build output, or - for stdin")
+
+
+def log_parse(parser, args):
+ input = args.file
+ if args.file == '-':
+ input = sys.stdin
+
+ errors, warnings = parse_log_events(
+ input, args.context, args.jobs, args.profile)
+ if args.profile:
+ return
+
+ types = [s.strip() for s in args.show.split(',')]
+ for e in types:
+ if e not in event_types:
+ tty.die('Invalid event type: %s' % e)
+
+ events = []
+ if 'errors' in types:
+ events.extend(errors)
+ print('%d errors' % len(errors))
+ if 'warnings' in types:
+ events.extend(warnings)
+ print('%d warnings' % len(warnings))
+
+ print(make_log_context(events, args.width))
diff --git a/lib/spack/spack/cmd/md5.py b/lib/spack/spack/cmd/md5.py
deleted file mode 100644
index 824e88373c..0000000000
--- a/lib/spack/spack/cmd/md5.py
+++ /dev/null
@@ -1,92 +0,0 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import argparse
-import hashlib
-import os
-from six.moves.urllib.parse import urlparse
-
-import llnl.util.tty as tty
-import spack.util.crypto
-from spack.stage import Stage, FailedDownloadError
-
-description = "calculate md5 checksums for files/urls"
-section = "packaging"
-level = "long"
-
-
-def setup_parser(subparser):
- setup_parser.parser = subparser
- subparser.add_argument('files', nargs=argparse.REMAINDER,
- help="files/urls to checksum")
-
-
-def compute_checksum(url, algo):
- algo = getattr(hashlib, algo)
-
- if not os.path.isfile(url):
- with Stage(url) as stage:
- stage.fetch()
- value = spack.util.crypto.checksum(algo, stage.archive_file)
- else:
- value = spack.util.crypto.checksum(algo, url)
- return value
-
-
-def normalized(files):
- for p in files:
- result = urlparse(p)
- value = p
- if not result.scheme:
- value = os.path.abspath(p)
- yield value
-
-
-def do_checksum(parser, args, algo):
- if not args.files:
- setup_parser.parser.print_help()
- return 1
-
- urls = [x for x in normalized(args.files)]
- results = []
- for url in urls:
- try:
- checksum = compute_checksum(url, algo)
- results.append((checksum, url))
- except FailedDownloadError as e:
- tty.warn("Failed to fetch %s" % url)
- tty.warn("%s" % e)
- except IOError as e:
- tty.warn("Error when reading %s" % url)
- tty.warn("%s" % e)
-
- # Dump the hashes last, without interleaving them with downloads
- checksum = 'checksum' if len(results) == 1 else 'checksums'
- tty.msg("%d %s %s:" % (len(results), algo, checksum))
- for checksum, url in results:
- print("{0} {1}".format(checksum, url))
-
-
-def md5(parser, args):
- do_checksum(parser, args, 'md5')
diff --git a/lib/spack/spack/cmd/mirror.py b/lib/spack/spack/cmd/mirror.py
index 35d31adb2d..4d70df431b 100644
--- a/lib/spack/spack/cmd/mirror.py
+++ b/lib/spack/spack/cmd/mirror.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
from datetime import datetime
@@ -29,23 +10,23 @@ import argparse
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
-import spack
import spack.cmd
+import spack.concretize
import spack.config
import spack.mirror
+import spack.repo
+import spack.cmd.common.arguments as arguments
from spack.spec import Spec
from spack.error import SpackError
from spack.util.spack_yaml import syaml_dict
-description = "manage mirrors"
+description = "manage mirrors (source and binary)"
section = "config"
level = "long"
def setup_parser(subparser):
- subparser.add_argument(
- '-n', '--no-checksum', action='store_true', dest='no_checksum',
- help="do not check fetched packages against checksum")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
sp = subparser.add_subparsers(
metavar='SUBCOMMAND', dest='mirror_command')
@@ -67,7 +48,9 @@ def setup_parser(subparser):
const=1, default=0,
help="only fetch one 'preferred' version per spec, not all known")
- scopes = spack.config.config_scopes
+ # used to construct scope arguments below
+ scopes = spack.config.scopes()
+ scopes_metavar = spack.config.scopes_metavar
# Add
add_parser = sp.add_parser('add', help=mirror_add.__doc__)
@@ -75,7 +58,8 @@ def setup_parser(subparser):
add_parser.add_argument(
'url', help="url of mirror directory from 'spack mirror create'")
add_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_modify_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_modify_scope(),
help="configuration scope to modify")
# Remove
@@ -83,13 +67,15 @@ def setup_parser(subparser):
help=mirror_remove.__doc__)
remove_parser.add_argument('name')
remove_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_modify_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_modify_scope(),
help="configuration scope to modify")
# List
list_parser = sp.add_parser('list', help=mirror_list.__doc__)
list_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_list_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_list_scope(),
help="configuration scope to read from")
@@ -99,7 +85,7 @@ def mirror_add(args):
if url.startswith('/'):
url = 'file://' + url
- mirrors = spack.config.get_config('mirrors', scope=args.scope)
+ mirrors = spack.config.get('mirrors', scope=args.scope)
if not mirrors:
mirrors = syaml_dict()
@@ -113,14 +99,14 @@ def mirror_add(args):
items = [(n, u) for n, u in mirrors.items()]
items.insert(0, (args.name, url))
mirrors = syaml_dict(items)
- spack.config.update_config('mirrors', mirrors, scope=args.scope)
+ spack.config.set('mirrors', mirrors, scope=args.scope)
def mirror_remove(args):
"""Remove a mirror by name."""
name = args.name
- mirrors = spack.config.get_config('mirrors', scope=args.scope)
+ mirrors = spack.config.get('mirrors', scope=args.scope)
if not mirrors:
mirrors = syaml_dict()
@@ -128,13 +114,13 @@ def mirror_remove(args):
tty.die("No mirror with name %s" % name)
old_value = mirrors.pop(name)
- spack.config.update_config('mirrors', mirrors, scope=args.scope)
+ spack.config.set('mirrors', mirrors, scope=args.scope)
tty.msg("Removed mirror %s with url %s" % (name, old_value))
def mirror_list(args):
"""Print out available mirrors to the console."""
- mirrors = spack.config.get_config('mirrors', scope=args.scope)
+ mirrors = spack.config.get('mirrors', scope=args.scope)
if not mirrors:
tty.msg("No mirrors configured.")
return
@@ -164,56 +150,61 @@ def mirror_create(args):
"""Create a directory to be used as a spack mirror, and fill it with
package archives."""
# try to parse specs from the command line first.
- specs = spack.cmd.parse_specs(args.specs, concretize=True)
-
- # If there is a file, parse each line as a spec and add it to the list.
- if args.file:
- if specs:
- tty.die("Cannot pass specs on the command line with --file.")
- specs = _read_specs_from_file(args.file)
-
- # If nothing is passed, use all packages.
- if not specs:
- specs = [Spec(n) for n in spack.repo.all_package_names()]
- specs.sort(key=lambda s: s.format("$_$@").lower())
-
- # If the user asked for dependencies, traverse spec DAG get them.
- if args.dependencies:
- new_specs = set()
- for spec in specs:
- spec.concretize()
- for s in spec.traverse():
- new_specs.add(s)
- specs = list(new_specs)
-
- # Default name for directory is spack-mirror-<DATESTAMP>
- directory = args.directory
- if not directory:
- timestamp = datetime.now().strftime("%Y-%m-%d")
- directory = 'spack-mirror-' + timestamp
-
- # Make sure nothing is in the way.
- existed = False
- if os.path.isfile(directory):
- tty.error("%s already exists and is a file." % directory)
- elif os.path.isdir(directory):
- existed = True
-
- # Actually do the work to create the mirror
- present, mirrored, error = spack.mirror.create(
- directory, specs, num_versions=args.one_version_per_spec)
- p, m, e = len(present), len(mirrored), len(error)
-
- verb = "updated" if existed else "created"
- tty.msg(
- "Successfully %s mirror in %s" % (verb, directory),
- "Archive stats:",
- " %-4d already present" % p,
- " %-4d added" % m,
- " %-4d failed to fetch." % e)
- if error:
- tty.error("Failed downloads:")
- colify(s.cformat("$_$@") for s in error)
+ with spack.concretize.concretizer.disable_compiler_existence_check():
+ specs = spack.cmd.parse_specs(args.specs, concretize=True)
+
+ # If there is a file, parse each line as a spec and add it to the list.
+ if args.file:
+ if specs:
+ tty.die("Cannot pass specs on the command line with --file.")
+ specs = _read_specs_from_file(args.file)
+
+ # If nothing is passed, use all packages.
+ if not specs:
+ specs = [Spec(n) for n in spack.repo.all_package_names()]
+ specs.sort(key=lambda s: s.format("$_$@").lower())
+
+ # If the user asked for dependencies, traverse spec DAG get them.
+ if args.dependencies:
+ new_specs = set()
+ for spec in specs:
+ spec.concretize()
+ for s in spec.traverse():
+ new_specs.add(s)
+ specs = list(new_specs)
+
+ # Skip external specs, as they are already installed
+ external_specs = [s for s in specs if s.external]
+ specs = [s for s in specs if not s.external]
+
+ for spec in external_specs:
+ msg = 'Skipping {0} as it is an external spec.'
+ tty.msg(msg.format(spec.cshort_spec))
+
+ # Default name for directory is spack-mirror-<DATESTAMP>
+ directory = args.directory
+ if not directory:
+ timestamp = datetime.now().strftime("%Y-%m-%d")
+ directory = 'spack-mirror-' + timestamp
+
+ # Make sure nothing is in the way.
+ existed = os.path.isdir(directory)
+
+ # Actually do the work to create the mirror
+ present, mirrored, error = spack.mirror.create(
+ directory, specs, num_versions=args.one_version_per_spec)
+ p, m, e = len(present), len(mirrored), len(error)
+
+ verb = "updated" if existed else "created"
+ tty.msg(
+ "Successfully %s mirror in %s" % (verb, directory),
+ "Archive stats:",
+ " %-4d already present" % p,
+ " %-4d added" % m,
+ " %-4d failed to fetch." % e)
+ if error:
+ tty.error("Failed downloads:")
+ colify(s.cformat("$_$@") for s in error)
def mirror(parser, args):
diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py
index 1ebead1f58..c71f84ef7d 100644
--- a/lib/spack/spack/cmd/module.py
+++ b/lib/spack/spack/cmd/module.py
@@ -1,357 +1,67 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-from __future__ import print_function
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import collections
-import os
-import shutil
-import spack.modules
+import argparse
-import spack.cmd
-from llnl.util import filesystem, tty
-from spack.cmd.common import arguments
+import llnl.util.tty as tty
+
+import spack.cmd.modules.dotkit
+import spack.cmd.modules.lmod
+import spack.cmd.modules.tcl
description = "manipulate module files"
-section = "environment"
+section = "modules"
level = "short"
-#: Dictionary that will be populated with the list of sub-commands
-#: Each sub-command must be callable and accept 3 arguments:
-#:
-#: - mtype : the type of the module file
-#: - specs : the list of specs to be processed
-#: - args : namespace containing the parsed command line arguments
-callbacks = {}
-
+_subcommands = {}
-def subcommand(subparser_name):
- """Registers a function in the callbacks dictionary"""
- def decorator(callback):
- callbacks[subparser_name] = callback
- return callback
- return decorator
+_deprecated_commands = ('refresh', 'find', 'rm', 'loads')
def setup_parser(subparser):
- sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='subparser_name')
+ sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command')
+ spack.cmd.modules.dotkit.add_command(sp, _subcommands)
+ spack.cmd.modules.lmod.add_command(sp, _subcommands)
+ spack.cmd.modules.tcl.add_command(sp, _subcommands)
- # spack module refresh
- refresh_parser = sp.add_parser('refresh', help='regenerate module files')
- refresh_parser.add_argument(
- '--delete-tree',
- help='delete the module file tree before refresh',
- action='store_true'
- )
- arguments.add_common_arguments(
- refresh_parser, ['constraint', 'module_type', 'yes_to_all']
- )
+ for name in _deprecated_commands:
+ add_deprecated_command(sp, name)
- # spack module find
- find_parser = sp.add_parser('find', help='find module files for packages')
- arguments.add_common_arguments(find_parser, ['constraint', 'module_type'])
- # spack module rm
- rm_parser = sp.add_parser('rm', help='remove module files')
- arguments.add_common_arguments(
- rm_parser, ['constraint', 'module_type', 'yes_to_all']
+def add_deprecated_command(subparser, name):
+ parser = subparser.add_parser(name)
+ parser.add_argument(
+ '-m', '--module-type', help=argparse.SUPPRESS,
+ choices=spack.modules.module_types.keys(), action='append'
)
- # spack module loads
- loads_parser = sp.add_parser(
- 'loads',
- help='prompt the list of modules associated with a constraint'
- )
- loads_parser.add_argument(
- '--input-only', action='store_false', dest='shell',
- help='generate input for module command (instead of a shell script)'
- )
- loads_parser.add_argument(
- '-p', '--prefix', dest='prefix', default='',
- help='prepend to module names when issuing module load commands'
- )
- loads_parser.add_argument(
- '-x', '--exclude', dest='exclude', action='append', default=[],
- help="exclude package from output; may be specified multiple times"
- )
- arguments.add_common_arguments(
- loads_parser, ['constraint', 'module_type', 'recurse_dependencies']
- )
-
-
-class MultipleSpecsMatch(Exception):
- """Raised when multiple specs match a constraint, in a context where
- this is not allowed.
- """
-
-
-class NoSpecMatches(Exception):
- """Raised when no spec matches a constraint, in a context where
- this is not allowed.
- """
-
-
-class MultipleModuleTypes(Exception):
- """Raised when multiple module types match a cli request, in a context
- where this is not allowed.
- """
-
-
-def one_module_or_raise(module_types):
- """Ensures exactly one module type has been selected, or raises the
- appropriate exception.
- """
- # Ensure a single module type has been selected
- if len(module_types) > 1:
- raise MultipleModuleTypes()
- return module_types[0]
-
-
-def one_spec_or_raise(specs):
- """Ensures exactly one spec has been selected, or raises the appropriate
- exception.
- """
- # Ensure a single spec matches the constraint
- if len(specs) == 0:
- raise NoSpecMatches()
- if len(specs) > 1:
- raise MultipleSpecsMatch()
-
- # Get the spec and module type
- return specs[0]
-
-
-@subcommand('loads')
-def loads(module_types, specs, args):
- """Prompt the list of modules associated with a list of specs"""
-
- module_type = one_module_or_raise(module_types)
-
- # Get a comprehensive list of specs
- if args.recurse_dependencies:
- specs_from_user_constraint = specs[:]
- specs = []
- # FIXME : during module file creation nodes seem to be visited
- # FIXME : multiple times even if cover='nodes' is given. This
- # FIXME : work around permits to get a unique list of spec anyhow.
- # FIXME : (same problem as in spack/modules.py)
- seen = set()
- seen_add = seen.add
- for spec in specs_from_user_constraint:
- specs.extend(
- [item for item in spec.traverse(order='post', cover='nodes')
- if not (item in seen or seen_add(item))]
- )
-
- module_cls = spack.modules.module_types[module_type]
- modules = [
- (spec, module_cls(spec).layout.use_name)
- for spec in specs if os.path.exists(module_cls(spec).layout.filename)
- ]
-
- module_commands = {
- 'tcl': 'module load ',
- 'lmod': 'module load ',
- 'dotkit': 'dotkit use '
- }
-
- d = {
- 'command': '' if not args.shell else module_commands[module_type],
- 'prefix': args.prefix
- }
-
- exclude_set = set(args.exclude)
- prompt_template = '{comment}{exclude}{command}{prefix}{name}'
- for spec, mod in modules:
- d['exclude'] = '## ' if spec.name in exclude_set else ''
- d['comment'] = '' if not args.shell else '# {0}\n'.format(
- spec.format())
- d['name'] = mod
- print(prompt_template.format(**d))
-
-
-@subcommand('find')
-def find(module_types, specs, args):
- """Returns the module file "use" name if there's a single match. Raises
- error messages otherwise.
- """
-
- spec = one_spec_or_raise(specs)
- module_type = one_module_or_raise(module_types)
-
- # Check if the module file is present
- writer = spack.modules.module_types[module_type](spec)
- if not os.path.isfile(writer.layout.filename):
- msg = 'Even though {1} is installed, '
- msg += 'no {0} module has been generated for it.'
- tty.die(msg.format(module_type, spec))
-
- # ... and if it is print its use name
- print(writer.layout.use_name)
-
-
-@subcommand('rm')
-def rm(module_types, specs, args):
- """Deletes the module files associated with every spec in specs, for every
- module type in module types.
- """
- for module_type in module_types:
-
- module_cls = spack.modules.module_types[module_type]
- module_exist = lambda x: os.path.exists(module_cls(x).layout.filename)
-
- specs_with_modules = [spec for spec in specs if module_exist(spec)]
-
- modules = [module_cls(spec) for spec in specs_with_modules]
-
- if not modules:
- tty.die('No module file matches your query')
-
- # Ask for confirmation
- if not args.yes_to_all:
- msg = 'You are about to remove {0} module files for:\n'
- tty.msg(msg.format(module_type))
- spack.cmd.display_specs(specs_with_modules, long=True)
- print('')
- answer = tty.get_yes_or_no('Do you want to proceed?')
- if not answer:
- tty.die('Will not remove any module files')
-
- # Remove the module files
- for s in modules:
- s.remove()
-
-
-@subcommand('refresh')
-def refresh(module_types, specs, args):
- """Regenerates the module files for every spec in specs and every module
- type in module types.
- """
-
- # Prompt a message to the user about what is going to change
- if not specs:
- tty.msg('No package matches your query')
- return
-
- if not args.yes_to_all:
- msg = 'You are about to regenerate {types} module files for:\n'
- types = ', '.join(module_types)
- tty.msg(msg.format(types=types))
- spack.cmd.display_specs(specs, long=True)
- print('')
- answer = tty.get_yes_or_no('Do you want to proceed?')
- if not answer:
- tty.die('Module file regeneration aborted.')
-
- # Cycle over the module types and regenerate module files
- for module_type in module_types:
-
- cls = spack.modules.module_types[module_type]
-
- writers = [
- cls(spec) for spec in specs if spack.repo.exists(spec.name)
- ] # skip unknown packages.
-
- # Filter blacklisted packages early
- writers = [x for x in writers if not x.conf.blacklisted]
-
- # Detect name clashes in module files
- file2writer = collections.defaultdict(list)
- for item in writers:
- file2writer[item.layout.filename].append(item)
-
- if len(file2writer) != len(writers):
- message = 'Name clashes detected in module files:\n'
- for filename, writer_list in file2writer.items():
- if len(writer_list) > 1:
- message += '\nfile: {0}\n'.format(filename)
- for x in writer_list:
- message += 'spec: {0}\n'.format(x.spec.format())
- tty.error(message)
- tty.error('Operation aborted')
- raise SystemExit(1)
-
- if len(writers) == 0:
- msg = 'Nothing to be done for {0} module files.'
- tty.msg(msg.format(module_type))
- continue
-
- # If we arrived here we have at least one writer
- module_type_root = writers[0].layout.dirname()
- # Proceed regenerating module files
- tty.msg('Regenerating {name} module files'.format(name=module_type))
- if os.path.isdir(module_type_root) and args.delete_tree:
- shutil.rmtree(module_type_root, ignore_errors=False)
- filesystem.mkdirp(module_type_root)
- for x in writers:
- try:
- x.write(overwrite=True)
- except Exception as e:
- msg = 'Could not write module file [{0}]'
- tty.warn(msg.format(x.layout.filename))
- tty.warn('\t--> {0} <--'.format(str(e)))
-
-
-def module(parser, args):
-
- # Qualifiers to be used when querying the db for specs
- constraint_qualifiers = {
- 'refresh': {
- 'installed': True,
- 'known': True
- },
- }
- query_args = constraint_qualifiers.get(args.subparser_name, {})
- # Get the specs that match the query from the DB
- specs = args.specs(**query_args)
+def handle_deprecated_command(args, unknown_args):
+ command = args.module_command
+ unknown = ' '.join(unknown_args)
- # Set the module types that have been selected
- module_types = args.module_type
- if module_types is None:
- # If no selection has been made select all of them
- module_types = ['tcl']
+ module_types = args.module_type or ['tcl']
- module_types = list(set(module_types))
+ msg = '`spack module {0} {1}` has moved. Use these commands instead:\n'
+ msg = msg.format(command, ' '.join('-m ' + x for x in module_types))
+ for x in module_types:
+ msg += '\n\t$ spack module {0} {1} {2}'.format(x, command, unknown)
+ msg += '\n'
+ tty.die(msg)
- try:
- callbacks[args.subparser_name](module_types, specs, args)
+def module(parser, args, unknown_args):
- except MultipleSpecsMatch:
- msg = "the constraint '{query}' matches multiple packages:\n"
- for s in specs:
- msg += '\t' + s.cformat() + '\n'
- tty.error(msg.format(query=args.constraint))
- tty.die('In this context exactly **one** match is needed: please specify your constraints better.') # NOQA: ignore=E501
+ # Here we permit unknown arguments to intercept deprecated calls
+ if args.module_command in _deprecated_commands:
+ handle_deprecated_command(args, unknown_args)
- except NoSpecMatches:
- msg = "the constraint '{query}' matches no package."
- tty.error(msg.format(query=args.constraint))
- tty.die('In this context exactly **one** match is needed: please specify your constraints better.') # NOQA: ignore=E501
+ # Fail if unknown arguments are present, once we excluded a deprecated
+ # command
+ if unknown_args:
+ tty.die('unrecognized arguments: {0}'.format(' '.join(unknown_args)))
- except MultipleModuleTypes:
- msg = "this command needs exactly **one** module type active."
- tty.die(msg)
+ _subcommands[args.module_command](parser, args)
diff --git a/lib/spack/spack/cmd/modules/__init__.py b/lib/spack/spack/cmd/modules/__init__.py
new file mode 100644
index 0000000000..f8f883e42e
--- /dev/null
+++ b/lib/spack/spack/cmd/modules/__init__.py
@@ -0,0 +1,335 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Implementation details of the ``spack module`` command."""
+
+import collections
+import os.path
+import shutil
+import sys
+
+from llnl.util import filesystem, tty
+
+import spack.cmd
+import spack.modules
+import spack.repo
+
+import spack.cmd.common.arguments as arguments
+
+description = "manipulate module files"
+section = "environment"
+level = "short"
+
+
+def setup_parser(subparser):
+ sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='subparser_name')
+
+ refresh_parser = sp.add_parser('refresh', help='regenerate module files')
+ refresh_parser.add_argument(
+ '--delete-tree',
+ help='delete the module file tree before refresh',
+ action='store_true'
+ )
+ arguments.add_common_arguments(
+ refresh_parser, ['constraint', 'yes_to_all']
+ )
+
+ find_parser = sp.add_parser('find', help='find module files for packages')
+ find_parser.add_argument(
+ '--full-path',
+ help='display full path to module file',
+ action='store_true'
+ )
+ arguments.add_common_arguments(
+ find_parser, ['constraint', 'recurse_dependencies']
+ )
+
+ rm_parser = sp.add_parser('rm', help='remove module files')
+ arguments.add_common_arguments(
+ rm_parser, ['constraint', 'yes_to_all']
+ )
+
+ loads_parser = sp.add_parser(
+ 'loads',
+ help='prompt the list of modules associated with a constraint'
+ )
+ add_loads_arguments(loads_parser)
+ arguments.add_common_arguments(loads_parser, ['constraint'])
+
+ return sp
+
+
+def add_loads_arguments(subparser):
+ subparser.add_argument(
+ '--input-only', action='store_false', dest='shell',
+ help='generate input for module command (instead of a shell script)'
+ )
+ subparser.add_argument(
+ '-p', '--prefix', dest='prefix', default='',
+ help='prepend to module names when issuing module load commands'
+ )
+ subparser.add_argument(
+ '-x', '--exclude', dest='exclude', action='append', default=[],
+ help="exclude package from output; may be specified multiple times"
+ )
+ arguments.add_common_arguments(
+ subparser, ['recurse_dependencies']
+ )
+
+
+class MultipleSpecsMatch(Exception):
+ """Raised when multiple specs match a constraint, in a context where
+ this is not allowed.
+ """
+
+
+class NoSpecMatches(Exception):
+ """Raised when no spec matches a constraint, in a context where
+ this is not allowed.
+ """
+
+
+def one_spec_or_raise(specs):
+ """Ensures exactly one spec has been selected, or raises the appropriate
+ exception.
+ """
+ # Ensure a single spec matches the constraint
+ if len(specs) == 0:
+ raise NoSpecMatches()
+ if len(specs) > 1:
+ raise MultipleSpecsMatch()
+
+ # Get the spec and module type
+ return specs[0]
+
+
+def loads(module_type, specs, args, out=sys.stdout):
+ """Prompt the list of modules associated with a list of specs"""
+
+ # Get a comprehensive list of specs
+ if args.recurse_dependencies:
+ specs_from_user_constraint = specs[:]
+ specs = []
+ # FIXME : during module file creation nodes seem to be visited
+ # FIXME : multiple times even if cover='nodes' is given. This
+ # FIXME : work around permits to get a unique list of spec anyhow.
+ # FIXME : (same problem as in spack/modules.py)
+ seen = set()
+ seen_add = seen.add
+ for spec in specs_from_user_constraint:
+ specs.extend(
+ [item for item in spec.traverse(order='post', cover='nodes')
+ if not (item in seen or seen_add(item))]
+ )
+
+ module_cls = spack.modules.module_types[module_type]
+ modules = [
+ (spec, module_cls(spec).layout.use_name)
+ for spec in specs if os.path.exists(module_cls(spec).layout.filename)
+ ]
+
+ module_commands = {
+ 'tcl': 'module load ',
+ 'lmod': 'module load ',
+ 'dotkit': 'use '
+ }
+
+ d = {
+ 'command': '' if not args.shell else module_commands[module_type],
+ 'prefix': args.prefix
+ }
+
+ exclude_set = set(args.exclude)
+ prompt_template = '{comment}{exclude}{command}{prefix}{name}'
+ for spec, mod in modules:
+ d['exclude'] = '## ' if spec.name in exclude_set else ''
+ d['comment'] = '' if not args.shell else '# {0}\n'.format(
+ spec.format())
+ d['name'] = mod
+ out.write(prompt_template.format(**d))
+ out.write('\n')
+
+
+def find(module_type, specs, args):
+ """Returns the module file "use" name if there's a single match. Raises
+ error messages otherwise.
+ """
+
+ spec = one_spec_or_raise(specs)
+
+ # Check if the module file is present
+ def module_exists(spec):
+ writer = spack.modules.module_types[module_type](spec)
+ return os.path.isfile(writer.layout.filename)
+
+ if not module_exists(spec):
+ msg = 'Even though {1} is installed, '
+ msg += 'no {0} module has been generated for it.'
+ tty.die(msg.format(module_type, spec))
+
+ # Check if we want to recurse and load all dependencies. In that case
+ # modify the list of specs adding all the dependencies in post order
+ if args.recurse_dependencies:
+ specs = [
+ item for item in spec.traverse(order='post', cover='nodes')
+ if module_exists(item)
+ ]
+
+ # ... and if it is print its use name or full-path if requested
+ def module_str(specs):
+ modules = []
+ for x in specs:
+ writer = spack.modules.module_types[module_type](x)
+ if args.full_path:
+ modules.append(writer.layout.filename)
+ else:
+ modules.append(writer.layout.use_name)
+
+ return ' '.join(modules)
+
+ print(module_str(specs))
+
+
+def rm(module_type, specs, args):
+ """Deletes the module files associated with every spec in specs, for every
+ module type in module types.
+ """
+
+ module_cls = spack.modules.module_types[module_type]
+ module_exist = lambda x: os.path.exists(module_cls(x).layout.filename)
+
+ specs_with_modules = [spec for spec in specs if module_exist(spec)]
+
+ modules = [module_cls(spec) for spec in specs_with_modules]
+
+ if not modules:
+ tty.die('No module file matches your query')
+
+ # Ask for confirmation
+ if not args.yes_to_all:
+ msg = 'You are about to remove {0} module files for:\n'
+ tty.msg(msg.format(module_type))
+ spack.cmd.display_specs(specs_with_modules, long=True)
+ print('')
+ answer = tty.get_yes_or_no('Do you want to proceed?')
+ if not answer:
+ tty.die('Will not remove any module files')
+
+ # Remove the module files
+ for s in modules:
+ s.remove()
+
+
+def refresh(module_type, specs, args):
+ """Regenerates the module files for every spec in specs and every module
+ type in module types.
+ """
+
+ # Prompt a message to the user about what is going to change
+ if not specs:
+ tty.msg('No package matches your query')
+ return
+
+ if not args.yes_to_all:
+ msg = 'You are about to regenerate {types} module files for:\n'
+ tty.msg(msg.format(types=module_type))
+ spack.cmd.display_specs(specs, long=True)
+ print('')
+ answer = tty.get_yes_or_no('Do you want to proceed?')
+ if not answer:
+ tty.die('Module file regeneration aborted.')
+
+ # Cycle over the module types and regenerate module files
+
+ cls = spack.modules.module_types[module_type]
+
+ # Skip unknown packages.
+ writers = [
+ cls(spec) for spec in specs
+ if spack.repo.path.exists(spec.name)]
+
+ # Filter blacklisted packages early
+ writers = [x for x in writers if not x.conf.blacklisted]
+
+ # Detect name clashes in module files
+ file2writer = collections.defaultdict(list)
+ for item in writers:
+ file2writer[item.layout.filename].append(item)
+
+ if len(file2writer) != len(writers):
+ message = 'Name clashes detected in module files:\n'
+ for filename, writer_list in file2writer.items():
+ if len(writer_list) > 1:
+ message += '\nfile: {0}\n'.format(filename)
+ for x in writer_list:
+ message += 'spec: {0}\n'.format(x.spec.format())
+ tty.error(message)
+ tty.error('Operation aborted')
+ raise SystemExit(1)
+
+ if len(writers) == 0:
+ msg = 'Nothing to be done for {0} module files.'
+ tty.msg(msg.format(module_type))
+ return
+
+ # If we arrived here we have at least one writer
+ module_type_root = writers[0].layout.dirname()
+ # Proceed regenerating module files
+ tty.msg('Regenerating {name} module files'.format(name=module_type))
+ if os.path.isdir(module_type_root) and args.delete_tree:
+ shutil.rmtree(module_type_root, ignore_errors=False)
+ filesystem.mkdirp(module_type_root)
+ for x in writers:
+ try:
+ x.write(overwrite=True)
+ except Exception as e:
+ msg = 'Could not write module file [{0}]'
+ tty.warn(msg.format(x.layout.filename))
+ tty.warn('\t--> {0} <--'.format(str(e)))
+
+
+#: Dictionary populated with the list of sub-commands.
+#: Each sub-command must be callable and accept 3 arguments:
+#:
+#: - module_type: the type of module it refers to
+#: - specs : the list of specs to be processed
+#: - args : namespace containing the parsed command line arguments
+callbacks = {
+ 'refresh': refresh,
+ 'rm': rm,
+ 'find': find,
+ 'loads': loads
+}
+
+
+def modules_cmd(parser, args, module_type, callbacks=callbacks):
+
+ # Qualifiers to be used when querying the db for specs
+ constraint_qualifiers = {
+ 'refresh': {
+ 'installed': True,
+ 'known': True
+ },
+ }
+ query_args = constraint_qualifiers.get(args.subparser_name, {})
+
+ # Get the specs that match the query from the DB
+ specs = args.specs(**query_args)
+
+ try:
+
+ callbacks[args.subparser_name](module_type, specs, args)
+
+ except MultipleSpecsMatch:
+ msg = "the constraint '{query}' matches multiple packages:\n"
+ for s in specs:
+ msg += '\t' + s.cformat(format_string='$/ $_$@$+$%@+$+$=') + '\n'
+ tty.error(msg.format(query=args.constraint))
+ tty.die('In this context exactly **one** match is needed: please specify your constraints better.') # NOQA: ignore=E501
+
+ except NoSpecMatches:
+ msg = "the constraint '{query}' matches no package."
+ tty.error(msg.format(query=args.constraint))
+ tty.die('In this context exactly **one** match is needed: please specify your constraints better.') # NOQA: ignore=E501
diff --git a/lib/spack/spack/cmd/modules/dotkit.py b/lib/spack/spack/cmd/modules/dotkit.py
new file mode 100644
index 0000000000..159defe3a6
--- /dev/null
+++ b/lib/spack/spack/cmd/modules/dotkit.py
@@ -0,0 +1,19 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import functools
+
+import spack.cmd.modules
+
+
+def add_command(parser, command_dict):
+ dotkit_parser = parser.add_parser(
+ 'dotkit', help='manipulate dotkit module files'
+ )
+ spack.cmd.modules.setup_parser(dotkit_parser)
+
+ command_dict['dotkit'] = functools.partial(
+ spack.cmd.modules.modules_cmd, module_type='dotkit'
+ )
diff --git a/lib/spack/spack/cmd/modules/lmod.py b/lib/spack/spack/cmd/modules/lmod.py
new file mode 100644
index 0000000000..33be5bc85b
--- /dev/null
+++ b/lib/spack/spack/cmd/modules/lmod.py
@@ -0,0 +1,50 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import functools
+import os
+
+import llnl.util.filesystem
+import spack.cmd.common.arguments
+import spack.cmd.modules
+
+
+def add_command(parser, command_dict):
+ lmod_parser = parser.add_parser(
+ 'lmod', help='manipulate hierarchical module files'
+ )
+ sp = spack.cmd.modules.setup_parser(lmod_parser)
+
+ # Set default module file for a package
+ setdefault_parser = sp.add_parser(
+ 'setdefault', help='set the default module file for a package'
+ )
+ spack.cmd.common.arguments.add_common_arguments(
+ setdefault_parser, ['constraint']
+ )
+
+ callbacks = dict(spack.cmd.modules.callbacks.items())
+ callbacks['setdefault'] = setdefault
+
+ command_dict['lmod'] = functools.partial(
+ spack.cmd.modules.modules_cmd, module_type='lmod', callbacks=callbacks
+ )
+
+
+def setdefault(module_type, specs, args):
+ """Set the default module file, when multiple are present"""
+ # For details on the underlying mechanism see:
+ #
+ # https://lmod.readthedocs.io/en/latest/060_locating.html#marking-a-version-as-default
+ #
+ spack.cmd.modules.one_spec_or_raise(specs)
+ writer = spack.modules.module_types['lmod'](specs[0])
+
+ module_folder = os.path.dirname(writer.layout.filename)
+ module_basename = os.path.basename(writer.layout.filename)
+ with llnl.util.filesystem.working_dir(module_folder):
+ if os.path.exists('default') and os.path.islink('default'):
+ os.remove('default')
+ os.symlink(module_basename, 'default')
diff --git a/lib/spack/spack/cmd/modules/tcl.py b/lib/spack/spack/cmd/modules/tcl.py
new file mode 100644
index 0000000000..c300584505
--- /dev/null
+++ b/lib/spack/spack/cmd/modules/tcl.py
@@ -0,0 +1,19 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import functools
+
+import spack.cmd.modules
+
+
+def add_command(parser, command_dict):
+ tcl_parser = parser.add_parser(
+ 'tcl', help='manipulate non-hierarchical module files'
+ )
+ spack.cmd.modules.setup_parser(tcl_parser)
+
+ command_dict['tcl'] = functools.partial(
+ spack.cmd.modules.modules_cmd, module_type='tcl'
+ )
diff --git a/lib/spack/spack/cmd/patch.py b/lib/spack/spack/cmd/patch.py
index b19acfcde4..6de45cccb5 100644
--- a/lib/spack/spack/cmd/patch.py
+++ b/lib/spack/spack/cmd/patch.py
@@ -1,32 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
+
+import spack.repo
import spack.cmd
-import spack
+import spack.cmd.common.arguments as arguments
description = "patch expanded archive sources in preparation for install"
@@ -35,9 +18,7 @@ level = "long"
def setup_parser(subparser):
- subparser.add_argument(
- '-n', '--no-checksum', action='store_true', dest='no_checksum',
- help="do not check downloaded packages against checksum")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'packages', nargs=argparse.REMAINDER,
help="specs of packages to stage")
@@ -48,7 +29,7 @@ def patch(parser, args):
tty.die("patch requires at least one package argument")
if args.no_checksum:
- spack.do_checksum = False
+ spack.config.set('config:checksum', False, scope='command_line')
specs = spack.cmd.parse_specs(args.packages, concretize=True)
for spec in specs:
diff --git a/lib/spack/spack/cmd/pkg.py b/lib/spack/spack/cmd/pkg.py
index 9591b58acd..e73c1ec61e 100644
--- a/lib/spack/spack/cmd/pkg.py
+++ b/lib/spack/spack/cmd/pkg.py
@@ -1,37 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import os
-
import argparse
+
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
from llnl.util.filesystem import working_dir
-import spack
+import spack.paths
+import spack.repo
from spack.util.executable import which
from spack.cmd import spack_is_git_repo
@@ -78,11 +60,11 @@ def setup_parser(subparser):
def list_packages(rev):
- pkgpath = os.path.join(spack.packages_path, 'packages')
- relpath = pkgpath[len(spack.prefix + os.path.sep):] + os.path.sep
+ pkgpath = os.path.join(spack.paths.packages_path, 'packages')
+ relpath = pkgpath[len(spack.paths.prefix + os.path.sep):] + os.path.sep
git = which('git', required=True)
- with working_dir(spack.prefix):
+ with working_dir(spack.paths.prefix):
output = git('ls-tree', '--full-tree', '--name-only', rev, relpath,
output=str)
return sorted(line[len(relpath):] for line in output.split('\n') if line)
@@ -90,14 +72,14 @@ def list_packages(rev):
def pkg_add(args):
for pkg_name in args.packages:
- filename = spack.repo.filename_for_package_name(pkg_name)
+ filename = spack.repo.path.filename_for_package_name(pkg_name)
if not os.path.isfile(filename):
tty.die("No such package: %s. Path does not exist:" %
pkg_name, filename)
git = which('git', required=True)
- with working_dir(spack.prefix):
- git('-C', spack.packages_path, 'add', filename)
+ with working_dir(spack.paths.prefix):
+ git('-C', spack.paths.packages_path, 'add', filename)
def pkg_list(args):
diff --git a/lib/spack/spack/cmd/providers.py b/lib/spack/spack/cmd/providers.py
index de45e20ec5..f20966c4d3 100644
--- a/lib/spack/spack/cmd/providers.py
+++ b/lib/spack/spack/cmd/providers.py
@@ -1,33 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import argparse
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import six
+import sys
-from llnl.util.tty.colify import colify
+import llnl.util.tty.colify as colify
-import spack
import spack.cmd
+import spack.repo
description = "list packages that provide a particular virtual package"
section = "basic"
@@ -35,11 +17,46 @@ level = "long"
def setup_parser(subparser):
+ subparser.epilog = 'If called without argument returns ' \
+ 'the list of all valid virtual packages'
subparser.add_argument(
- 'vpkg_spec', metavar='VPACKAGE_SPEC', nargs=argparse.REMAINDER,
- help='find packages that provide this virtual package')
+ 'virtual_package',
+ nargs='*',
+ help='find packages that provide this virtual package'
+ )
def providers(parser, args):
- for spec in spack.cmd.parse_specs(args.vpkg_spec):
- colify(sorted(spack.repo.providers_for(spec)), indent=4)
+ valid_virtuals = sorted(spack.repo.path.provider_index.providers.keys())
+
+ buffer = six.StringIO()
+ isatty = sys.stdout.isatty()
+ if isatty:
+ buffer.write('Virtual packages:\n')
+ colify.colify(valid_virtuals, output=buffer, tty=isatty, indent=4)
+ valid_virtuals_str = buffer.getvalue()
+
+ # If called without arguments, list all the virtual packages
+ if not args.virtual_package:
+ print(valid_virtuals_str)
+ return
+
+ # Otherwise, parse the specs from command line
+ specs = spack.cmd.parse_specs(args.virtual_package)
+
+ # Check prerequisites
+ non_virtual = [
+ str(s) for s in specs if not s.virtual or s.name not in valid_virtuals
+ ]
+ if non_virtual:
+ msg = 'non-virtual specs cannot be part of the query '
+ msg += '[{0}]\n'.format(', '.join(non_virtual))
+ msg += valid_virtuals_str
+ raise ValueError(msg)
+
+ # Display providers
+ for spec in specs:
+ if sys.stdout.isatty():
+ print("{0}:".format(spec))
+ spack.cmd.display_specs(sorted(spack.repo.path.providers_for(spec)))
+ print('')
diff --git a/lib/spack/spack/cmd/pydoc.py b/lib/spack/spack/cmd/pydoc.py
index 093b16f66a..e17d548475 100644
--- a/lib/spack/spack/cmd/pydoc.py
+++ b/lib/spack/spack/cmd/pydoc.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
description = "run pydoc from within spack"
section = "developer"
diff --git a/lib/spack/spack/cmd/python.py b/lib/spack/spack/cmd/python.py
index 8bdb796efa..fbd5c788fe 100644
--- a/lib/spack/spack/cmd/python.py
+++ b/lib/spack/spack/cmd/python.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import sys
import code
@@ -30,7 +11,6 @@ import platform
import spack
-
description = "launch an interpreter as spack would launch a command"
section = "developer"
level = "long"
diff --git a/lib/spack/spack/cmd/reindex.py b/lib/spack/spack/cmd/reindex.py
index 6babec60d5..4dcae1c678 100644
--- a/lib/spack/spack/cmd/reindex.py
+++ b/lib/spack/spack/cmd/reindex.py
@@ -1,34 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import spack
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import spack.store
-description = "rebuild Spack's package database"
+description = "rebuild Spack's package database"
section = "admin"
level = "long"
def reindex(parser, args):
- spack.store.db.reindex(spack.store.layout)
+ spack.store.store.reindex()
diff --git a/lib/spack/spack/cmd/remove.py b/lib/spack/spack/cmd/remove.py
new file mode 100644
index 0000000000..ec0b2cd218
--- /dev/null
+++ b/lib/spack/spack/cmd/remove.py
@@ -0,0 +1,39 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import argparse
+
+import llnl.util.tty as tty
+
+import spack.cmd
+import spack.environment as ev
+
+
+description = 'remove specs from an environment'
+section = "environments"
+level = "long"
+
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ '-a', '--all', action='store_true',
+ help="remove all specs from (clear) the environment")
+ subparser.add_argument(
+ '-f', '--force', action='store_true',
+ help="remove concretized spec (if any) immediately")
+ subparser.add_argument(
+ 'specs', nargs=argparse.REMAINDER, help="specs to be removed")
+
+
+def remove(parser, args):
+ env = ev.get_env(args, 'remove')
+
+ if args.all:
+ env.clear()
+ else:
+ for spec in spack.cmd.parse_specs(args.specs):
+ tty.msg('Removing %s from environment %s' % (spec, env.name))
+ env.remove(spec, force=args.force)
+ env.write()
diff --git a/lib/spack/spack/cmd/repo.py b/lib/spack/spack/cmd/repo.py
index 0b5ced1642..8ce9ea9351 100644
--- a/lib/spack/spack/cmd/repo.py
+++ b/lib/spack/spack/cmd/repo.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import os
@@ -30,7 +11,7 @@ import llnl.util.tty as tty
import spack.spec
import spack.config
-from spack.repository import Repo, create_repo, canonicalize_path, RepoError
+from spack.repo import Repo, create_repo, canonicalize_path, RepoError
description = "manage package source repositories"
section = "config"
@@ -39,7 +20,8 @@ level = "long"
def setup_parser(subparser):
sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='repo_command')
- scopes = spack.config.config_scopes
+ scopes = spack.config.scopes()
+ scopes_metavar = spack.config.scopes_metavar
# Create
create_parser = sp.add_parser('create', help=repo_create.__doc__)
@@ -52,7 +34,8 @@ def setup_parser(subparser):
# List
list_parser = sp.add_parser('list', help=repo_list.__doc__)
list_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_list_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_list_scope(),
help="configuration scope to read from")
# Add
@@ -60,7 +43,8 @@ def setup_parser(subparser):
add_parser.add_argument(
'path', help="path to a Spack package repository directory")
add_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_modify_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_modify_scope(),
help="configuration scope to modify")
# Remove
@@ -70,7 +54,8 @@ def setup_parser(subparser):
'path_or_namespace',
help="path or namespace of a Spack package repository")
remove_parser.add_argument(
- '--scope', choices=scopes, default=spack.cmd.default_modify_scope,
+ '--scope', choices=scopes, metavar=scopes_metavar,
+ default=spack.config.default_modify_scope(),
help="configuration scope to modify")
@@ -101,7 +86,7 @@ def repo_add(args):
repo = Repo(canon_path)
# If that succeeds, finally add it to the configuration.
- repos = spack.config.get_config('repos', args.scope)
+ repos = spack.config.get('repos', scope=args.scope)
if not repos:
repos = []
@@ -109,13 +94,13 @@ def repo_add(args):
tty.die("Repository is already registered with Spack: %s" % path)
repos.insert(0, canon_path)
- spack.config.update_config('repos', repos, args.scope)
+ spack.config.set('repos', repos, args.scope)
tty.msg("Added repo with namespace '%s'." % repo.namespace)
def repo_remove(args):
"""Remove a repository from Spack's configuration."""
- repos = spack.config.get_config('repos', args.scope)
+ repos = spack.config.get('repos', scope=args.scope)
path_or_namespace = args.path_or_namespace
# If the argument is a path, remove that repository from config.
@@ -124,7 +109,7 @@ def repo_remove(args):
repo_canon_path = canonicalize_path(repo_path)
if canon_path == repo_canon_path:
repos.remove(repo_path)
- spack.config.update_config('repos', repos, args.scope)
+ spack.config.set('repos', repos, args.scope)
tty.msg("Removed repository %s" % repo_path)
return
@@ -134,7 +119,7 @@ def repo_remove(args):
repo = Repo(path)
if repo.namespace == path_or_namespace:
repos.remove(path)
- spack.config.update_config('repos', repos, args.scope)
+ spack.config.set('repos', repos, args.scope)
tty.msg("Removed repository %s with namespace '%s'."
% (repo.root, repo.namespace))
return
@@ -147,7 +132,7 @@ def repo_remove(args):
def repo_list(args):
"""Show registered repositories and their namespaces."""
- roots = spack.config.get_config('repos', args.scope)
+ roots = spack.config.get('repos', scope=args.scope)
repos = []
for r in roots:
try:
diff --git a/lib/spack/spack/cmd/restage.py b/lib/spack/spack/cmd/restage.py
index 992aa40951..e2b77167b1 100644
--- a/lib/spack/spack/cmd/restage.py
+++ b/lib/spack/spack/cmd/restage.py
@@ -1,33 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
-import spack
import spack.cmd
+import spack.repo
description = "revert checked out package source code"
section = "build"
diff --git a/lib/spack/spack/cmd/setup.py b/lib/spack/spack/cmd/setup.py
index 01b40dda80..5620f8904c 100644
--- a/lib/spack/spack/cmd/setup.py
+++ b/lib/spack/spack/cmd/setup.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import copy
import os
@@ -29,17 +10,20 @@ import string
import sys
import llnl.util.tty as tty
-import spack
+from llnl.util.filesystem import set_executable
+
+import spack.repo
import spack.store
+import spack.build_systems.cmake
import spack.cmd
import spack.cmd.install as install
import spack.cmd.common.arguments as arguments
-from llnl.util.filesystem import set_executable
-from spack import which
+from spack.util.executable import which
+
from spack.stage import DIYStage
description = "create a configuration script and module, but don't build"
-section = "developer"
+section = "build"
level = "long"
@@ -47,6 +31,7 @@ def setup_parser(subparser):
subparser.add_argument(
'-i', '--ignore-dependencies', action='store_true', dest='ignore_deps',
help="do not try to install dependencies of requested packages")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'-v', '--verbose', action='store_true', dest='verbose',
help="display verbose build output while installing")
@@ -134,7 +119,7 @@ def setup(self, args):
# Take a write lock before checking for existence.
with spack.store.db.write_transaction():
spec = specs[0]
- if not spack.repo.exists(spec.name):
+ if not spack.repo.path.exists(spec.name):
tty.die("No package for '{0}' was found.".format(spec.name),
" Use `spack create` to create a new package")
if not spec.versions.concrete:
@@ -144,20 +129,19 @@ def setup(self, args):
spec.concretize()
package = spack.repo.get(spec)
- if not isinstance(package, spack.CMakePackage):
+ if not isinstance(package, spack.build_systems.cmake.CMakePackage):
tty.die(
'Support for {0} derived packages not yet implemented'.format(
- package.build_system_class
- )
- )
+ package.build_system_class))
# It's OK if the package is already installed.
# Forces the build to run out of the current directory.
package.stage = DIYStage(os.getcwd())
- # TODO: make this an argument, not a global.
- spack.do_checksum = False
+ # disable checksumming if requested
+ if args.no_checksum:
+ spack.config.set('config:checksum', False, scope='command_line')
# Install dependencies if requested to do so
if not args.ignore_deps:
@@ -169,12 +153,14 @@ def setup(self, args):
namespace=inst_args
)
install.install(parser, inst_args)
+
# Generate spconfig.py
tty.msg(
'Generating spconfig.py [{0}]'.format(package.spec.cshort_spec)
)
dirty = args.dirty
write_spconfig(package, dirty)
+
# Install this package to register it in the DB and permit
# module file regeneration
inst_args = copy.deepcopy(args)
diff --git a/lib/spack/spack/cmd/sha256.py b/lib/spack/spack/cmd/sha256.py
deleted file mode 100644
index 9b9b962e46..0000000000
--- a/lib/spack/spack/cmd/sha256.py
+++ /dev/null
@@ -1,40 +0,0 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import argparse
-from spack.cmd.md5 import do_checksum
-
-description = "calculate sha256 checksums for files/urls"
-section = "packaging"
-level = "long"
-
-
-def setup_parser(subparser):
- setup_parser.parser = subparser
- subparser.add_argument('files', nargs=argparse.REMAINDER,
- help="files/urls to checksum")
-
-
-def sha256(parser, args):
- do_checksum(parser, args, 'sha256')
diff --git a/lib/spack/spack/cmd/spec.py b/lib/spack/spack/cmd/spec.py
index 722987c35e..cc5172beb6 100644
--- a/lib/spack/spack/cmd/spec.py
+++ b/lib/spack/spack/cmd/spec.py
@@ -1,30 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import argparse
+import sys
+
+import llnl.util.tty as tty
+
import spack
import spack.cmd
import spack.cmd.common.arguments as arguments
@@ -35,7 +20,8 @@ level = "short"
def setup_parser(subparser):
- arguments.add_common_arguments(subparser, ['long', 'very_long'])
+ arguments.add_common_arguments(
+ subparser, ['long', 'very_long', 'install_status'])
subparser.add_argument(
'-y', '--yaml', action='store_true', default=False,
help='print concrete spec as YAML')
@@ -46,11 +32,7 @@ def setup_parser(subparser):
subparser.add_argument(
'-N', '--namespaces', action='store_true', default=False,
help='show fully qualified package names')
- subparser.add_argument(
- '-I', '--install-status', action='store_true', default=False,
- help='show install status of packages. packages can be: '
- 'installed [+], missing and needed by an installed package [-], '
- 'or not installed (no annotation)')
+
subparser.add_argument(
'-t', '--types', action='store_true', default=False,
help='show dependency types')
@@ -62,29 +44,29 @@ def spec(parser, args):
name_fmt = '$.' if args.namespaces else '$_'
kwargs = {'cover': args.cover,
'format': name_fmt + '$@$%@+$+$=',
- 'hashes': args.long or args.very_long,
'hashlen': None if args.very_long else 7,
'show_types': args.types,
'install_status': args.install_status}
+ if not args.specs:
+ tty.die("spack spec requires at least one spec")
+
for spec in spack.cmd.parse_specs(args.specs):
# With -y, just print YAML to output.
if args.yaml:
- if spec.name in spack.repo:
+ if spec.name in spack.repo.path or spec.virtual:
spec.concretize()
- print(spec.to_yaml())
+
+ # use write because to_yaml already has a newline.
+ sys.stdout.write(spec.to_yaml())
continue
- # Print some diagnostic info by default.
+ kwargs['hashes'] = False # Always False for input spec
print("Input spec")
print("--------------------------------")
print(spec.tree(**kwargs))
- print("Normalized")
- print("--------------------------------")
- spec.normalize()
- print(spec.tree(**kwargs))
-
+ kwargs['hashes'] = args.long or args.very_long
print("Concretized")
print("--------------------------------")
spec.concretize()
diff --git a/lib/spack/spack/cmd/stage.py b/lib/spack/spack/cmd/stage.py
index 3456e9290e..68f2486b0d 100644
--- a/lib/spack/spack/cmd/stage.py
+++ b/lib/spack/spack/cmd/stage.py
@@ -1,32 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import llnl.util.tty as tty
-import spack
+
+import spack.environment as ev
+import spack.repo
import spack.cmd
+import spack.cmd.common.arguments as arguments
description = "expand downloaded archive in preparation for install"
section = "build"
@@ -34,9 +18,7 @@ level = "long"
def setup_parser(subparser):
- subparser.add_argument(
- '-n', '--no-checksum', action='store_true', dest='no_checksum',
- help="do not check downloaded packages against checksum")
+ arguments.add_common_arguments(subparser, ['no_checksum'])
subparser.add_argument(
'-p', '--path', dest='path',
help="path to stage package, does not add to spack tree")
@@ -47,10 +29,18 @@ def setup_parser(subparser):
def stage(parser, args):
if not args.specs:
- tty.die("stage requires at least one package argument")
+ env = ev.get_env(args, 'stage', required=False)
+ if env:
+ tty.msg("Staging specs from environment %s" % env.name)
+ for spec in env.specs_by_hash.values():
+ for dep in spec.traverse():
+ dep.package.do_stage()
+ return
+ else:
+ tty.die("`spack stage` requires a spec or an active environment")
if args.no_checksum:
- spack.do_checksum = False
+ spack.config.set('config:checksum', False, scope='command_line')
specs = spack.cmd.parse_specs(args.specs, concretize=True)
for spec in specs:
diff --git a/lib/spack/spack/cmd/test.py b/lib/spack/spack/cmd/test.py
index d25a851237..40f2d6f8b2 100644
--- a/lib/spack/spack/cmd/test.py
+++ b/lib/spack/spack/cmd/test.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import sys
@@ -34,7 +15,7 @@ from six import StringIO
from llnl.util.filesystem import working_dir
from llnl.util.tty.colify import colify
-import spack
+import spack.paths
description = "run spack's unit tests"
section = "developer"
@@ -96,8 +77,8 @@ def test(parser, args, unknown_args):
pytest.main(['-h'])
return
- # pytest.ini lives in the root of the spack repository.
- with working_dir(spack.prefix):
+ # pytest.ini lives in lib/spack/spack/test
+ with working_dir(spack.paths.test_path):
# --list and --long-list print the test output better.
if args.list or args.long_list:
do_list(args, unknown_args)
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index 0cb79340eb..81e8437999 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -1,37 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import argparse
-import spack
import spack.cmd
+import spack.environment as ev
+import spack.package
+import spack.cmd.common.arguments as arguments
+import spack.repo
import spack.store
-import spack.repository
from llnl.util import tty
+from llnl.util.tty.colify import colify
description = "remove installed packages"
section = "build"
@@ -46,31 +30,30 @@ error_message = """You can either:
display_args = {
'long': True,
'show_flags': True,
- 'variants': True
+ 'variants': True,
+ 'indent': 4,
}
-def setup_parser(subparser):
+def add_common_arguments(subparser):
subparser.add_argument(
'-f', '--force', action='store_true', dest='force',
- help="remove regardless of whether other packages depend on this one")
-
- subparser.add_argument(
- '-a', '--all', action='store_true', dest='all',
- help="USE CAREFULLY. remove ALL installed packages that match each "
- "supplied spec. i.e., if you say uninstall `libelf`,"
- " ALL versions of `libelf` are uninstalled. if no spec is "
- "supplied all installed software will be uninstalled. this "
- "is both useful and dangerous, like rm -r")
+ help="remove regardless of whether other packages or environments "
+ "depend on this one")
+ arguments.add_common_arguments(
+ subparser, ['recurse_dependents', 'yes_to_all'])
- subparser.add_argument(
- '-R', '--dependents', action='store_true', dest='dependents',
- help='also uninstall any packages that depend on the ones given '
- 'via command line')
+def setup_parser(subparser):
+ add_common_arguments(subparser)
subparser.add_argument(
- '-y', '--yes-to-all', action='store_true', dest='yes_to_all',
- help='assume "yes" is the answer to every confirmation requested')
+ '-a', '--all', action='store_true', dest='all',
+ help="USE CAREFULLY. Remove ALL installed packages that match each "
+ "supplied spec. i.e., if you `uninstall --all libelf`,"
+ " ALL versions of `libelf` are uninstalled. If no spec is "
+ "supplied, all installed packages will be uninstalled. "
+ "If used in an environment, all packages in the environment "
+ "will be uninstalled.")
subparser.add_argument(
'packages',
@@ -78,22 +61,26 @@ def setup_parser(subparser):
help="specs of packages to uninstall")
-def find_matching_specs(specs, allow_multiple_matches=False, force=False):
+def find_matching_specs(env, specs, allow_multiple_matches=False, force=False):
"""Returns a list of specs matching the not necessarily
concretized specs given from cli
Args:
- specs: list of specs to be matched against installed packages
- allow_multiple_matches : if True multiple matches are admitted
+ env (Environment): active environment, or ``None`` if there is not one
+ specs (list): list of specs to be matched against installed packages
+ allow_multiple_matches (bool): if True multiple matches are admitted
Return:
list of specs
"""
+ # constrain uninstall resolution to current environment if one is active
+ hashes = env.all_hashes() if env else None
+
# List of specs that match expressions given via command line
specs_from_cli = []
has_errors = False
for spec in specs:
- matching = spack.store.db.query(spec)
+ matching = spack.store.db.query(spec, hashes=hashes)
# For each spec provided, make sure it refers to only one package.
# Fail and ask user to be unambiguous if it doesn't
if not allow_multiple_matches and len(matching) > 1:
@@ -105,54 +92,125 @@ def find_matching_specs(specs, allow_multiple_matches=False, force=False):
# No installed package matches the query
if len(matching) == 0 and spec is not any:
- tty.error('{0} does not match any installed packages.'.format(
- spec))
- has_errors = True
+ if env:
+ pkg_type = "packages in environment '%s'" % env.name
+ else:
+ pkg_type = 'installed packages'
+ tty.die('{0} does not match any {1}.'.format(spec, pkg_type))
specs_from_cli.extend(matching)
+
if has_errors:
tty.die(error_message)
return specs_from_cli
-def installed_dependents(specs):
- """Returns a dictionary that maps a spec with a list of its
- installed dependents
+def installed_dependents(specs, env):
+ """Map each spec to a list of its installed dependents.
Args:
- specs: list of specs to be checked for dependents
+ specs (list): list of Specs
+ env (Environment): the active environment, or None
+
+ Returns:
+ (tuple of dicts): two mappings: one from specs to their dependent
+ environments in the active environment (or global scope if
+ there is no environment), and one from specs to their
+ dependents in *inactive* environments (empty if there is no
+ environment
+
+ """
+ active_dpts = {}
+ inactive_dpts = {}
+
+ env_hashes = set(env.all_hashes()) if env else set()
+
+ for spec in specs:
+ installed = spack.store.db.installed_relatives(
+ spec, direction='parents', transitive=True)
+
+ # separate installed dependents into dpts in this environment and
+ # dpts that are outside this environment
+ for dpt in installed:
+ if dpt not in specs:
+ if not env or dpt.dag_hash() in env_hashes:
+ active_dpts.setdefault(spec, set()).add(dpt)
+ else:
+ inactive_dpts.setdefault(spec, set()).add(dpt)
+
+ return active_dpts, inactive_dpts
+
+def dependent_environments(specs):
+ """Map each spec to environments that depend on it.
+
+ Args:
+ specs (list): list of Specs
Returns:
- dictionary of installed dependents
+ (dict): mapping from spec to lists of dependent Environments
+
"""
dependents = {}
- for item in specs:
- installed = spack.store.db.installed_relatives(item, 'parents', True)
- lst = [x for x in installed if x not in specs]
- if lst:
- lst = list(set(lst))
- dependents[item] = lst
+ for env in ev.all_environments():
+ hashes = set(env.all_hashes())
+ for spec in specs:
+ if spec.dag_hash() in hashes:
+ dependents.setdefault(spec, []).append(env)
return dependents
-def do_uninstall(specs, force):
+def inactive_dependent_environments(spec_envs):
+ """Strip the active environment from a dependent map.
+
+ Take the output of ``dependent_environment()`` and remove the active
+ environment from all mappings. Remove any specs in the map that now
+ have no dependent environments. Return the result.
+
+ Args:
+ (dict): mapping from spec to lists of dependent Environments
+ Returns:
+ (dict): mapping from spec to lists of *inactive* dependent Environments
"""
- Uninstalls all the specs in a list.
+ spec_inactive_envs = {}
+ for spec, de_list in spec_envs.items():
+ inactive = [de for de in de_list if not de.active]
+ if inactive:
+ spec_inactive_envs[spec] = inactive
+
+ return spec_inactive_envs
+
+
+def _remove_from_env(spec, env):
+ """Remove a spec from an environment if it is a root."""
+ try:
+ # try removing the spec from the current active
+ # environment. this will fail if the spec is not a root
+ env.remove(spec, force=True)
+ except ev.SpackEnvironmentError:
+ pass # ignore non-root specs
+
+
+def do_uninstall(env, specs, force):
+ """Uninstalls all the specs in a list.
Args:
- specs: list of specs to be uninstalled
- force: force uninstallation (boolean)
+ env (Environment): active environment, or ``None`` if there is not one
+ specs (list): list of specs to be uninstalled
+ force (bool): force uninstallation (boolean)
"""
packages = []
for item in specs:
try:
# should work if package is known to spack
packages.append(item.package)
- except spack.repository.UnknownEntityError:
+ except spack.repo.UnknownEntityError:
# The package.py file has gone away -- but still
# want to uninstall.
- spack.Package.uninstall_by_spec(item, force=True)
+ spack.package.Package.uninstall_by_spec(item, force=True)
+
+ if env:
+ _remove_from_env(item, env)
# Sort packages to be uninstalled by the number of installed dependents
# This ensures we do things in the right order
@@ -165,57 +223,113 @@ def do_uninstall(specs, force):
for item in packages:
item.do_uninstall(force=force)
+ # write any changes made to the active environment
+ if env:
+ env.write()
-def get_uninstall_list(args):
- specs = [any]
- if args.packages:
- specs = spack.cmd.parse_specs(args.packages)
+def get_uninstall_list(args, specs, env):
# Gets the list of installed specs that match the ones give via cli
- # takes care of '-a' is given in the cli
- uninstall_list = find_matching_specs(specs, args.all, args.force)
-
- # Takes care of '-d'
- dependent_list = installed_dependents(uninstall_list)
-
- # Process dependent_list and update uninstall_list
- has_error = False
- if dependent_list and not args.dependents and not args.force:
- for spec, lst in dependent_list.items():
- tty.error("Will not uninstall %s" % spec.cformat("$_$@$%@$/"))
- print('')
- print('The following packages depend on it:')
- spack.cmd.display_specs(lst, **display_args)
- print('')
- has_error = True
+ # args.all takes care of the case where '-a' is given in the cli
+ uninstall_list = find_matching_specs(env, specs, args.all, args.force)
+
+ # Takes care of '-R'
+ active_dpts, inactive_dpts = installed_dependents(uninstall_list, env)
+
+ # if we are in the global scope, we complain if you try to remove a
+ # spec that's in an environment. If we're in an environment, we'll
+ # just *remove* it from the environment, so we ignore this
+ # error when *in* an environment
+ spec_envs = dependent_environments(uninstall_list)
+ spec_envs = inactive_dependent_environments(spec_envs)
+
+ # Process spec_dependents and update uninstall_list
+ has_error = not args.force and (
+ (active_dpts and not args.dependents) # dependents in the current env
+ or (not env and spec_envs) # there are environments that need specs
+ )
+
+ # say why each problem spec is needed
+ if has_error:
+ specs = set(active_dpts)
+ if not env:
+ specs.update(set(spec_envs)) # environments depend on this
+
+ for i, spec in enumerate(sorted(specs)):
+ # space out blocks of reasons
+ if i > 0:
+ print()
+
+ tty.info("Will not uninstall %s" % spec.cformat("$_$@$%@$/"),
+ format='*r')
+
+ dependents = active_dpts.get(spec)
+ if dependents:
+ print('The following packages depend on it:')
+ spack.cmd.display_specs(dependents, **display_args)
+
+ if not env:
+ envs = spec_envs.get(spec)
+ if envs:
+ print('It is used by the following environments:')
+ colify([e.name for e in envs], indent=4)
+
+ msgs = []
+ if active_dpts:
+ msgs.append(
+ 'use `spack uninstall --dependents` to remove dependents too')
+ if spec_envs:
+ msgs.append('use `spack env remove` to remove from environments')
+ print()
+ tty.die('There are still dependents.', *msgs)
+
elif args.dependents:
- for key, lst in dependent_list.items():
+ for spec, lst in active_dpts.items():
uninstall_list.extend(lst)
uninstall_list = list(set(uninstall_list))
- if has_error:
- tty.die('Use `spack uninstall --dependents` '
- 'to uninstall these dependencies as well.')
- return uninstall_list
+ # only force-remove (don't completely uninstall) specs that still
+ # have external dependent envs or pkgs
+ removes = set(inactive_dpts)
+ if env:
+ removes.update(spec_envs)
+ # remove anything in removes from the uninstall list
+ uninstall_list = set(uninstall_list) - removes
-def uninstall(parser, args):
- if not args.packages and not args.all:
- tty.die('uninstall requires at least one package argument.',
- ' Use `spack uninstall --all` to uninstall ALL packages.')
+ return uninstall_list, removes
- uninstall_list = get_uninstall_list(args)
- if not uninstall_list:
+def uninstall_specs(args, specs):
+ env = ev.get_env(args, 'uninstall', required=False)
+
+ uninstall_list, remove_list = get_uninstall_list(args, specs, env)
+ anything_to_do = set(uninstall_list).union(set(remove_list))
+
+ if not anything_to_do:
tty.warn('There are no package to uninstall.')
return
if not args.yes_to_all:
tty.msg('The following packages will be uninstalled:\n')
- spack.cmd.display_specs(uninstall_list, **display_args)
+ spack.cmd.display_specs(anything_to_do, **display_args)
answer = tty.get_yes_or_no('Do you want to proceed?', default=False)
if not answer:
tty.die('Will not uninstall any packages.')
+ # just force-remove things in the remove list
+ for spec in remove_list:
+ _remove_from_env(spec, env)
+
# Uninstall everything on the list
- do_uninstall(uninstall_list, args.force)
+ do_uninstall(env, uninstall_list, args.force)
+
+
+def uninstall(parser, args):
+ if not args.packages and not args.all:
+ tty.die('uninstall requires at least one package argument.',
+ ' Use `spack uninstall --all` to uninstall ALL packages.')
+
+ # [any] here handles the --all case by forcing all specs to be returned
+ uninstall_specs(
+ args, spack.cmd.parse_specs(args.packages) if args.packages else [any])
diff --git a/lib/spack/spack/cmd/unload.py b/lib/spack/spack/cmd/unload.py
index 9820ff52d3..d8730aea92 100644
--- a/lib/spack/spack/cmd/unload.py
+++ b/lib/spack/spack/cmd/unload.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
from spack.cmd.common import print_module_placeholder_help
description = "remove package from environment using `module unload`"
-section = "environment"
+section = "modules"
level = "short"
diff --git a/lib/spack/spack/cmd/unuse.py b/lib/spack/spack/cmd/unuse.py
index 14ca4227d2..4aab78b17b 100644
--- a/lib/spack/spack/cmd/unuse.py
+++ b/lib/spack/spack/cmd/unuse.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
from spack.cmd.common import print_module_placeholder_help
description = "remove package from environment using dotkit"
-section = "environment"
+section = "modules"
level = "long"
diff --git a/lib/spack/spack/cmd/url.py b/lib/spack/spack/cmd/url.py
index a445810b69..8168ffe45f 100644
--- a/lib/spack/spack/cmd/url.py
+++ b/lib/spack/spack/cmd/url.py
@@ -1,32 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-from __future__ import division, print_function
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+from __future__ import division, print_function
from collections import defaultdict
+try:
+ from urllib.parse import urlparse
+except ImportError:
+ from urlparse import urlparse
-import spack
+import spack.fetch_strategy as fs
+import spack.repo
+import spack.util.crypto as crypto
from llnl.util import tty
from spack.url import parse_version_offset, parse_name_offset
@@ -87,12 +73,18 @@ def setup_parser(subparser):
'summary',
help='print a summary of how well we are parsing package urls')
+ # Stats
+ sp.add_parser(
+ 'stats',
+ help='print statistics on versions and checksums for all packages')
+
def url(parser, args):
action = {
'parse': url_parse,
'list': url_list,
- 'summary': url_summary
+ 'summary': url_summary,
+ 'stats': url_stats,
}
action[args.subcommand](args)
@@ -144,7 +136,7 @@ def url_list(args):
urls = set()
# Gather set of URLs from all packages
- for pkg in spack.repo.all_packages():
+ for pkg in spack.repo.path.all_packages():
url = getattr(pkg.__class__, 'url', None)
urls = url_list_parsing(args, urls, url, pkg)
@@ -178,7 +170,7 @@ def url_summary(args):
tty.msg('Generating a summary of URL parsing in Spack...')
# Loop through all packages
- for pkg in spack.repo.all_packages():
+ for pkg in spack.repo.path.all_packages():
urls = set()
url = getattr(pkg.__class__, 'url', None)
@@ -227,7 +219,7 @@ def url_summary(args):
print()
print(' Index Count Regular Expression')
- for ni in name_regex_dict:
+ for ni in sorted(name_regex_dict.keys()):
print(' {0:>3}: {1:>6} r{2!r}'.format(
ni, name_count_dict[ni], name_regex_dict[ni]))
print()
@@ -236,7 +228,7 @@ def url_summary(args):
print()
print(' Index Count Regular Expression')
- for vi in version_regex_dict:
+ for vi in sorted(version_regex_dict.keys()):
print(' {0:>3}: {1:>6} r{2!r}'.format(
vi, version_count_dict[vi], version_regex_dict[vi]))
print()
@@ -246,6 +238,77 @@ def url_summary(args):
name_count_dict, version_count_dict)
+def url_stats(args):
+ stats = {} # stats about fetchers in packages.
+ nvers = 0 # total number of versions
+ npkgs = 0 # total number of packages
+
+ def inc(fstype, category, attr=None):
+ """Increment statistics in the stats dict."""
+ categories = stats.setdefault(fstype, {})
+ if attr:
+ cat_stats = categories.setdefault(category, {})
+ val = cat_stats.setdefault(attr, 0)
+ stats[fstype][category][attr] = val + 1
+ else:
+ val = categories.setdefault(category, 0)
+ stats[fstype][category] = val + 1
+
+ # over all packages
+ for pkg in spack.repo.path.all_packages():
+ npkgs += 1
+
+ # look at each version
+ for v, args in pkg.versions.items():
+ # figure out what type of fetcher it is
+ fetcher = fs.for_package_version(pkg, v)
+ nvers += 1
+
+ fstype = fetcher.url_attr
+ inc(fstype, 'total')
+
+ # put some special stats in for particular types of fetchers.
+ if fstype == 'git':
+ if 'commit' in args:
+ inc('git', 'security', 'commit')
+ else:
+ inc('git', 'security', 'no commit')
+ elif fstype == 'url':
+ for h in crypto.hashes:
+ if h in args:
+ inc('url', 'checksums', h)
+ break
+ else:
+ if 'checksum' in args:
+ h = crypto.hash_algo_for_digest(args['checksum'])
+ inc('url', 'checksums', h)
+ else:
+ inc('url', 'checksums', 'no checksum')
+
+ # parse out the URL scheme (https/http/ftp/etc.)
+ urlinfo = urlparse(fetcher.url)
+ inc('url', 'schemes', urlinfo.scheme)
+
+ # print a nice summary table
+ tty.msg("%d total versions for %d packages:" % (nvers, npkgs))
+ line_width = 36
+ print("-" * line_width)
+ for fetcher, fetcher_stats in sorted(stats.items(), reverse=True):
+ fs_total = fetcher_stats['total']
+ fs_pct = float(fs_total) / nvers * 100
+ print("%-22s%5d%8.1f%%" % (fetcher, fs_total, fs_pct))
+
+ for category, cat_stats in sorted(fetcher_stats.items(), reverse=True):
+ if category == 'total':
+ continue
+ print(" %s" % category)
+
+ for name, number in sorted(cat_stats.items(), reverse=True):
+ pct = float(number) / fs_total * 100
+ print(" %-18s%5d%8.1f%%" % (name, number, pct))
+ print("-" * line_width)
+
+
def print_name_and_version(url):
"""Prints a URL. Underlines the detected name with dashes and
the detected version with tildes.
diff --git a/lib/spack/spack/cmd/use.py b/lib/spack/spack/cmd/use.py
index 956f5c6cbc..80ae80329a 100644
--- a/lib/spack/spack/cmd/use.py
+++ b/lib/spack/spack/cmd/use.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
-from spack.cmd.common import print_module_placeholder_help
+from spack.cmd.common import print_module_placeholder_help, arguments
description = "add package to environment using dotkit"
-section = "environment"
+section = "modules"
level = "long"
@@ -36,6 +17,7 @@ def setup_parser(subparser):
subparser.add_argument(
'spec', nargs=argparse.REMAINDER,
help='spec of package to use with dotkit')
+ arguments.add_common_arguments(subparser, ['recurse_dependencies'])
def use(parser, args):
diff --git a/lib/spack/spack/cmd/versions.py b/lib/spack/spack/cmd/versions.py
index 9c6f2d1ead..007e86c164 100644
--- a/lib/spack/spack/cmd/versions.py
+++ b/lib/spack/spack/cmd/versions.py
@@ -1,32 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
from llnl.util.tty.colify import colify
import llnl.util.tty as tty
-import spack
+
+import spack.repo
description = "list available versions of a package"
section = "packaging"
@@ -41,20 +23,27 @@ def setup_parser(subparser):
def versions(parser, args):
pkg = spack.repo.get(args.package)
+ tty.msg('Safe versions (already checksummed):')
+
safe_versions = pkg.versions
+
+ if not safe_versions:
+ print(' Found no versions for {0}'.format(pkg.name))
+ tty.debug('Manually add versions to the package.')
+ else:
+ colify(sorted(safe_versions, reverse=True), indent=2)
+
+ tty.msg('Remote versions (not yet checksummed):')
+
fetched_versions = pkg.fetch_remote_versions()
remote_versions = set(fetched_versions).difference(safe_versions)
- tty.msg("Safe versions (already checksummed):")
- colify(sorted(safe_versions, reverse=True), indent=2)
-
- tty.msg("Remote versions (not yet checksummed):")
if not remote_versions:
if not fetched_versions:
- print(" Found no versions for %s" % pkg.name)
- tty.debug("Check the list_url and list_depth attribute on the "
- "package to help Spack find versions.")
+ print(' Found no versions for {0}'.format(pkg.name))
+ tty.debug('Check the list_url and list_depth attributes of the '
+ 'package to help Spack find versions.')
else:
- print(" Found no unchecksummed versions for %s" % pkg.name)
+ print(' Found no unchecksummed versions for {0}'.format(pkg.name))
else:
colify(sorted(remote_versions, reverse=True), indent=2)
diff --git a/lib/spack/spack/cmd/view.py b/lib/spack/spack/cmd/view.py
index 13005053ff..9768458f02 100644
--- a/lib/spack/spack/cmd/view.py
+++ b/lib/spack/spack/cmd/view.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
'''Produce a "view" of a Spack DAG.
A "view" is file hierarchy representing the union of a number of
@@ -52,16 +33,17 @@ All operations on views are performed via proxy objects such as
YamlFilesystemView.
'''
-
import os
-import spack
+
+import llnl.util.tty as tty
+from llnl.util.link_tree import MergeConflictError
+
import spack.cmd
import spack.store
from spack.filesystem_view import YamlFilesystemView
-import llnl.util.tty as tty
description = "produce a single-rooted directory view of packages"
-section = "environment"
+section = "environments"
level = "short"
actions_link = ["symlink", "add", "soft", "hardlink", "hard"]
@@ -172,6 +154,7 @@ def setup_parser(sp):
def view(parser, args):
'Produce a view of a set of packages.'
+ specs = spack.cmd.parse_specs(args.specs)
path = args.path[0]
view = YamlFilesystemView(
@@ -189,26 +172,32 @@ def view(parser, args):
elif args.action in actions_link:
# only link commands need to disambiguate specs
- specs = [spack.cmd.disambiguate_spec(s) for s in args.specs]
+ specs = [spack.cmd.disambiguate_spec(s) for s in specs]
elif args.action in actions_status:
# no specs implies all
- if len(args.specs) == 0:
+ if len(specs) == 0:
specs = view.get_all_specs()
else:
- specs = relaxed_disambiguate(args.specs, view)
+ specs = relaxed_disambiguate(specs, view)
else:
# status and remove can map the name to packages in view
- specs = relaxed_disambiguate(args.specs, view)
+ specs = relaxed_disambiguate(specs, view)
with_dependencies = args.dependencies.lower() in ['true', 'yes']
# Map action to corresponding functionality
if args.action in actions_link:
- view.add_specs(*specs,
- with_dependencies=with_dependencies,
- exclude=args.exclude)
+ try:
+ view.add_specs(*specs,
+ with_dependencies=with_dependencies,
+ exclude=args.exclude)
+ except MergeConflictError:
+ tty.info("Some file blocked the merge, adding the '-i' flag will "
+ "ignore this conflict. For more information see e.g. "
+ "https://github.com/spack/spack/issues/9029")
+ raise
elif args.action in actions_remove:
view.remove_specs(*specs,
diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py
index e19601116f..3bca4d1eae 100644
--- a/lib/spack/spack/compiler.py
+++ b/lib/spack/spack/compiler.py
@@ -1,38 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import re
import itertools
import llnl.util.tty as tty
-from llnl.util.filesystem import join_path
+import llnl.util.multiproc as mp
import spack.error
import spack.spec
import spack.architecture
-from spack.util.multiproc import parmap
from spack.util.executable import Executable, ProcessError
from spack.util.environment import get_path
@@ -179,40 +159,40 @@ class Compiler(object):
@property
def openmp_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support OpenMP.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self, "OpenMP", "openmp_flag")
+
+ # This property should be overridden in the compiler subclass if
+ # C++98 is not the default standard for that compiler
+ @property
+ def cxx98_flag(self):
+ return ""
# This property should be overridden in the compiler subclass if
# C++11 is supported by that compiler
@property
def cxx11_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support C++11.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag")
# This property should be overridden in the compiler subclass if
# C++14 is supported by that compiler
@property
def cxx14_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support C++14.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag")
# This property should be overridden in the compiler subclass if
# C++17 is supported by that compiler
@property
def cxx17_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support C++17.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag")
#
# Compiler classes have methods for querying the version of
@@ -270,7 +250,7 @@ class Compiler(object):
files = os.listdir(directory)
for exe in files:
- full_path = join_path(directory, exe)
+ full_path = os.path.join(directory, exe)
prod = itertools.product(prefixes, compiler_names, suffixes)
for pre, name, suf in prod:
@@ -278,27 +258,11 @@ class Compiler(object):
match = re.match(regex, exe)
if match:
- key = (full_path,) + match.groups()
+ key = (full_path,) + match.groups() + (detect_version,)
checks.append(key)
- def check(key):
- try:
- full_path, prefix, suffix = key
- version = detect_version(full_path)
- return (version, prefix, suffix, full_path)
- except ProcessError as e:
- tty.debug(
- "Couldn't get version for compiler %s" % full_path, e)
- return None
- except Exception as e:
- # Catching "Exception" here is fine because it just
- # means something went wrong running a candidate executable.
- tty.debug("Error while executing candidate compiler %s"
- % full_path,
- "%s: %s" % (e.__class__.__name__, e))
- return None
-
- successful = [k for k in parmap(check, checks) if k is not None]
+ successful = [k for k in mp.parmap(_get_versioned_tuple, checks)
+ if k is not None]
# The 'successful' list is ordered like the input paths.
# Reverse it here so that the dict creation (last insert wins)
@@ -322,6 +286,28 @@ class Compiler(object):
str(self.operating_system)))))
+def _get_versioned_tuple(compiler_check_tuple):
+ full_path, prefix, suffix, detect_version = compiler_check_tuple
+ try:
+ version = detect_version(full_path)
+ if (not version) or (not str(version).strip()):
+ tty.debug(
+ "Couldn't get version for compiler %s" % full_path)
+ return None
+ return (version, prefix, suffix, full_path)
+ except ProcessError as e:
+ tty.debug(
+ "Couldn't get version for compiler %s" % full_path, e)
+ return None
+ except Exception as e:
+ # Catching "Exception" here is fine because it just
+ # means something went wrong running a candidate executable.
+ tty.debug("Error while executing candidate compiler %s"
+ % full_path,
+ "%s: %s" % (e.__class__.__name__, e))
+ return None
+
+
class CompilerAccessError(spack.error.SpackError):
def __init__(self, path):
@@ -334,3 +320,19 @@ class InvalidCompilerError(spack.error.SpackError):
def __init__(self):
super(InvalidCompilerError, self).__init__(
"Compiler has no executables.")
+
+
+class UnsupportedCompilerFlag(spack.error.SpackError):
+
+ def __init__(self, compiler, feature, flag_name, ver_string=None):
+ super(UnsupportedCompilerFlag, self).__init__(
+ "{0} ({1}) does not support {2} (as compiler.{3})."
+ .format(compiler.name,
+ ver_string if ver_string else compiler.version,
+ feature,
+ flag_name),
+ "If you think it should, please edit the compiler.{0} subclass to"
+ .format(compiler.name) +
+ " implement the {0} property and submit a pull request or issue."
+ .format(flag_name)
+ )
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index f251889f83..188b7fd329 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -1,41 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This module contains functions related to finding compilers on the
system and configuring Spack to use multiple compilers.
"""
-import imp
+import os
from llnl.util.lang import list_modules
-from llnl.util.filesystem import join_path
-import spack
+import spack.paths
import spack.error
import spack.spec
import spack.config
import spack.architecture
-
+import spack.util.imp as simp
from spack.util.naming import mod_to_class
_imported_compilers_module = 'spack.compilers'
@@ -88,9 +68,9 @@ def get_compiler_config(scope=None, init_config=True):
compilers_dict = []
for compiler in compilers:
compilers_dict.append(_to_dict(compiler))
- spack.config.update_config('compilers', compilers_dict, scope=scope)
+ spack.config.set('compilers', compilers_dict, scope=scope)
- config = spack.config.get_config('compilers', scope=scope)
+ config = spack.config.get('compilers', scope=scope)
# Update the configuration if there are currently no compilers
# configured. Avoid updating automatically if there ARE site
# compilers configured but no user ones.
@@ -98,15 +78,15 @@ def get_compiler_config(scope=None, init_config=True):
if scope is None:
# We know no compilers were configured in any scope.
init_compiler_config()
- config = spack.config.get_config('compilers', scope=scope)
+ config = spack.config.get('compilers', scope=scope)
elif scope == 'user':
# Check the site config and update the user config if
# nothing is configured at the site level.
- site_config = spack.config.get_config('compilers', scope='site')
- sys_config = spack.config.get_config('compilers', scope='system')
+ site_config = spack.config.get('compilers', scope='site')
+ sys_config = spack.config.get('compilers', scope='system')
if not site_config and not sys_config:
init_compiler_config()
- config = spack.config.get_config('compilers', scope=scope)
+ config = spack.config.get('compilers', scope=scope)
return config
elif config:
return config
@@ -116,11 +96,12 @@ def get_compiler_config(scope=None, init_config=True):
def compiler_config_files():
config_files = list()
- for scope in spack.config.config_scopes:
- config = spack.config.get_config('compilers', scope=scope)
- if config:
- config_files.append(spack.config.config_scopes[scope]
- .get_section_filename('compilers'))
+ config = spack.config.config
+ for scope in config.file_scopes:
+ name = scope.name
+ compiler_config = config.get('compilers', scope=name)
+ if compiler_config:
+ config_files.append(config.get_config_filename(name, 'compilers'))
return config_files
@@ -136,7 +117,7 @@ def add_compilers_to_config(compilers, scope=None, init_config=True):
compiler_config.append(_to_dict(compiler))
global _cache_config_file
_cache_config_file = compiler_config
- spack.config.update_config('compilers', compiler_config, scope)
+ spack.config.set('compilers', compiler_config, scope=scope)
@_auto_compiler_spec
@@ -161,7 +142,7 @@ def remove_compiler_from_config(compiler_spec, scope=None):
_cache_config_file = filtered_compiler_config
if len(filtered_compiler_config) == config_length: # No items removed
CompilerSpecInsufficientlySpecificError(compiler_spec)
- spack.config.update_config('compilers', filtered_compiler_config, scope)
+ spack.config.set('compilers', filtered_compiler_config, scope=scope)
def all_compilers_config(scope=None, init_config=True):
@@ -204,7 +185,8 @@ def supported_compilers():
See available_compilers() to get a list of all the available
versions of supported compilers.
"""
- return sorted(name for name in list_modules(spack.compilers_path))
+ return sorted(
+ name for name in list_modules(spack.paths.compilers_path))
@_auto_compiler_spec
@@ -337,17 +319,18 @@ def compiler_for_spec(compiler_spec, arch_spec):
@_auto_compiler_spec
def get_compiler_duplicates(compiler_spec, arch_spec):
- config_scopes = spack.config.config_scopes
- scope_to_compilers = dict()
- for scope in config_scopes:
+ config = spack.config.config
+
+ scope_to_compilers = {}
+ for scope in config.scopes:
compilers = compilers_for_spec(compiler_spec, arch_spec=arch_spec,
scope=scope, use_cache=False)
if compilers:
scope_to_compilers[scope] = compilers
- cfg_file_to_duplicates = dict()
+ cfg_file_to_duplicates = {}
for scope, compilers in scope_to_compilers.items():
- config_file = config_scopes[scope].get_section_filename('compilers')
+ config_file = config.get_config_filename(scope, 'compilers')
cfg_file_to_duplicates[config_file] = compilers
return cfg_file_to_duplicates
@@ -357,8 +340,8 @@ def class_for_compiler_name(compiler_name):
"""Given a compiler module name, get the corresponding Compiler class."""
assert(supported(compiler_name))
- file_path = join_path(spack.compilers_path, compiler_name + ".py")
- compiler_mod = imp.load_source(_imported_compilers_module, file_path)
+ file_path = os.path.join(spack.paths.compilers_path, compiler_name + ".py")
+ compiler_mod = simp.load_source(_imported_compilers_module, file_path)
cls = getattr(compiler_mod, mod_to_class(compiler_name))
# make a note of the name in the module so we can get to it easily.
diff --git a/lib/spack/spack/compilers/arm.py b/lib/spack/spack/compilers/arm.py
new file mode 100644
index 0000000000..f80dba7ea1
--- /dev/null
+++ b/lib/spack/spack/compilers/arm.py
@@ -0,0 +1,73 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import re
+
+from spack.compiler import Compiler, _version_cache
+from spack.util.executable import Executable
+
+
+class Arm(Compiler):
+ # Subclasses use possible names of C compiler
+ cc_names = ['armclang']
+
+ # Subclasses use possible names of C++ compiler
+ cxx_names = ['armclang++']
+
+ # Subclasses use possible names of Fortran 77 compiler
+ f77_names = ['armflang']
+
+ # Subclasses use possible names of Fortran 90 compiler
+ fc_names = ['armflang']
+
+ # Named wrapper links within lib/spack/env
+ link_paths = {'cc': 'clang/clang',
+ 'cxx': 'clang/clang++',
+ 'f77': 'clang/flang',
+ 'fc': 'clang/flang'}
+
+ @property
+ def openmp_flag(self):
+ return "-fopenmp"
+
+ @property
+ def cxx11_flag(self):
+ return "-std=c++11"
+
+ @property
+ def cxx14_flag(self):
+ return "-std=c++14"
+
+ @property
+ def cxx17_flag(self):
+ return "-std=c++1z"
+
+ @property
+ def pic_flag(self):
+ return "-fPIC"
+
+ @classmethod
+ def default_version(cls, comp):
+ if comp not in _version_cache:
+ compiler = Executable(comp)
+ output = compiler('--version', output=str, error=str)
+
+ ver = 'unknown'
+ match = re.search(r'Arm C/C++/Fortran Compiler version ([^ )]+)',
+ output)
+ if match:
+ ver = match.group(1)
+
+ _version_cache[comp] = ver
+
+ return _version_cache[comp]
+
+ @classmethod
+ def fc_version(cls, fc):
+ return cls.default_version(fc)
+
+ @classmethod
+ def f77_version(cls, f77):
+ return cls.fc_version(f77)
diff --git a/lib/spack/spack/compilers/cce.py b/lib/spack/spack/compilers/cce.py
index 7bb95492ad..879f6432ef 100644
--- a/lib/spack/spack/compilers/cce.py
+++ b/lib/spack/spack/compilers/cce.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack.compiler import Compiler, get_compiler_version
diff --git a/lib/spack/spack/compilers/clang.py b/lib/spack/spack/compilers/clang.py
index a748bd95bd..6f6f462559 100644
--- a/lib/spack/spack/compilers/clang.py
+++ b/lib/spack/spack/compilers/clang.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
import os
import sys
@@ -29,12 +10,31 @@ from shutil import copytree, ignore_patterns
import llnl.util.tty as tty
-import spack
-from spack.compiler import Compiler, _version_cache
+import spack.paths
+from spack.compiler import Compiler, _version_cache, UnsupportedCompilerFlag
from spack.util.executable import Executable
from spack.version import ver
+#: compiler symlink mappings for mixed f77 compilers
+f77_mapping = [
+ ('gfortran', 'clang/gfortran'),
+ ('xlf_r', 'xl_r/xlf_r'),
+ ('xlf', 'xl/xlf'),
+ ('pgfortran', 'pgi/pgfortran'),
+ ('ifort', 'intel/ifort')
+]
+
+#: compiler symlink mappings for mixed f90/fc compilers
+fc_mapping = [
+ ('gfortran', 'clang/gfortran'),
+ ('xlf90_r', 'xl_r/xlf90_r'),
+ ('xlf90', 'xl/xlf90'),
+ ('pgfortran', 'pgi/pgfortran'),
+ ('ifort', 'intel/ifort')
+]
+
+
class Clang(Compiler):
# Subclasses use possible names of C compiler
cc_names = ['clang']
@@ -43,23 +43,36 @@ class Clang(Compiler):
cxx_names = ['clang++']
# Subclasses use possible names of Fortran 77 compiler
- f77_names = ['flang', 'gfortran']
+ f77_names = ['flang', 'gfortran', 'xlf_r']
# Subclasses use possible names of Fortran 90 compiler
- fc_names = ['flang', 'gfortran']
+ fc_names = ['flang', 'gfortran', 'xlf90_r']
- # Named wrapper links within spack.build_env_path
- link_paths = {'cc': 'clang/clang',
- 'cxx': 'clang/clang++'}
+ # Clang has support for using different fortran compilers with the
+ # clang executable.
+ @property
+ def link_paths(self):
+ # clang links are always the same
+ link_paths = {'cc': 'clang/clang',
+ 'cxx': 'clang/clang++'}
+
+ # fortran links need to look at the actual compiler names from
+ # compilers.yaml to figure out which named symlink to use
+ for compiler_name, link_path in f77_mapping:
+ if self.f77 and compiler_name in self.f77:
+ link_paths['f77'] = link_path
+ break
+ else:
+ link_paths['f77'] = 'clang/flang'
- if sys.platform == 'darwin':
- # Use default wrappers for fortran, in case provided in
- # compilers.yaml
- link_paths['f77'] = 'clang/gfortran'
- link_paths['fc'] = 'clang/gfortran'
- else:
- link_paths['f77'] = 'clang/flang'
- link_paths['fc'] = 'clang/flang'
+ for compiler_name, link_path in fc_mapping:
+ if self.fc and compiler_name in self.fc:
+ link_paths['fc'] = link_path
+ break
+ else:
+ link_paths['fc'] = 'clang/flang'
+
+ return link_paths
@property
def is_apple(self):
@@ -69,7 +82,10 @@ class Clang(Compiler):
@property
def openmp_flag(self):
if self.is_apple:
- tty.die("Clang from Apple does not support Openmp yet.")
+ raise UnsupportedCompilerFlag(self,
+ "OpenMP",
+ "openmp_flag",
+ "Xcode {0}".format(self.version))
else:
return "-fopenmp"
@@ -77,14 +93,20 @@ class Clang(Compiler):
def cxx11_flag(self):
if self.is_apple:
# Adapted from CMake's AppleClang-CXX rules
- # Spack's AppleClang detection only valid form Xcode >= 4.6
+ # Spack's AppleClang detection only valid from Xcode >= 4.6
if self.version < ver('4.0.0'):
- tty.die("Only Apple LLVM 4.0 and above support c++11")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "Xcode < 4.0.0")
else:
return "-std=c++11"
else:
if self.version < ver('3.3'):
- tty.die("Only Clang 3.3 and above support c++11.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 3.3")
else:
return "-std=c++11"
@@ -93,14 +115,20 @@ class Clang(Compiler):
if self.is_apple:
# Adapted from CMake's rules for AppleClang
if self.version < ver('5.1.0'):
- tty.die("Only Apple LLVM 5.1 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "Xcode < 5.1.0")
elif self.version < ver('6.1.0'):
return "-std=c++1y"
else:
return "-std=c++14"
else:
if self.version < ver('3.4'):
- tty.die("Only Clang 3.4 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "< 3.5")
elif self.version < ver('3.5'):
return "-std=c++1y"
else:
@@ -111,14 +139,22 @@ class Clang(Compiler):
if self.is_apple:
# Adapted from CMake's rules for AppleClang
if self.version < ver('6.1.0'):
- tty.die("Only Apple LLVM 6.1 and above support c++17.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag",
+ "Xcode < 6.1.0")
else:
return "-std=c++1z"
else:
if self.version < ver('3.5'):
- tty.die("Only Clang 3.5 and above support c++17.")
- else:
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag",
+ "< 5.0")
+ elif self.version < ver('5.0'):
return "-std=c++1z"
+ else:
+ return "-std=c++17"
@property
def pic_flag(self):
@@ -228,7 +264,7 @@ class Clang(Compiler):
raise OSError(msg)
real_root = os.path.dirname(os.path.dirname(real_root))
- developer_root = os.path.join(spack.stage_path,
+ developer_root = os.path.join(spack.paths.stage_path,
'xcode-select',
self.name,
str(self.version))
@@ -267,8 +303,9 @@ class Clang(Compiler):
for fname in os.listdir(dev_dir):
if fname in bins:
os.unlink(os.path.join(dev_dir, fname))
- os.symlink(os.path.join(spack.build_env_path, 'cc'),
- os.path.join(dev_dir, fname))
+ os.symlink(
+ os.path.join(spack.paths.build_env_path, 'cc'),
+ os.path.join(dev_dir, fname))
os.symlink(developer_root, xcode_link)
diff --git a/lib/spack/spack/compilers/gcc.py b/lib/spack/spack/compilers/gcc.py
index b97d8b2e24..241a8d97e6 100644
--- a/lib/spack/spack/compilers/gcc.py
+++ b/lib/spack/spack/compilers/gcc.py
@@ -1,31 +1,11 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import llnl.util.tty as tty
-
-import spack
-from spack.compiler import Compiler, get_compiler_version
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import spack.compilers.clang
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -47,7 +27,7 @@ class Gcc(Compiler):
# Old compatibility versions may contain XY suffixes.
suffixes = [r'-mp-\d\.\d', r'-\d\.\d', r'-\d', r'\d\d']
- # Named wrapper links within spack.build_env_path
+ # Named wrapper links within build_env_path
link_paths = {'cc': 'gcc/gcc',
'cxx': 'gcc/g++',
'f77': 'gcc/gfortran',
@@ -61,9 +41,19 @@ class Gcc(Compiler):
return "-fopenmp"
@property
+ def cxx98_flag(self):
+ if self.version < ver('6.0'):
+ return ""
+ else:
+ return "-std=c++98"
+
+ @property
def cxx11_flag(self):
if self.version < ver('4.3'):
- tty.die("Only gcc 4.3 and above support c++11.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ " < 4.3")
elif self.version < ver('4.7'):
return "-std=c++0x"
else:
@@ -72,18 +62,28 @@ class Gcc(Compiler):
@property
def cxx14_flag(self):
if self.version < ver('4.8'):
- tty.die("Only gcc 4.8 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "< 4.8")
elif self.version < ver('4.9'):
return "-std=c++1y"
- else:
+ elif self.version < ver('6.0'):
return "-std=c++14"
+ else:
+ return ""
@property
def cxx17_flag(self):
if self.version < ver('5.0'):
- tty.die("Only gcc 5.0 and above support c++17.")
- else:
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag",
+ "< 5.0")
+ elif self.version < ver('6.0'):
return "-std=c++1z"
+ else:
+ return "-std=c++17"
@property
def pic_flag(self):
@@ -113,7 +113,7 @@ class Gcc(Compiler):
return 'unknown'
version = super(Gcc, cls).default_version(cc)
- if version in ['7']:
+ if ver(version) >= ver('7'):
version = get_compiler_version(cc, '-dumpfullversion')
return version
@@ -142,7 +142,7 @@ class Gcc(Compiler):
version = get_compiler_version(
fc, '-dumpversion',
r'(?:GNU Fortran \(GCC\) )?([\d.]+)')
- if version in ['7']:
+ if ver(version) >= ver('7'):
version = get_compiler_version(fc, '-dumpfullversion')
return version
diff --git a/lib/spack/spack/compilers/intel.py b/lib/spack/spack/compilers/intel.py
index b66436ecc0..53d78d09a1 100644
--- a/lib/spack/spack/compilers/intel.py
+++ b/lib/spack/spack/compilers/intel.py
@@ -1,30 +1,10 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import llnl.util.tty as tty
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -41,7 +21,7 @@ class Intel(Compiler):
# Subclasses use possible names of Fortran 90 compiler
fc_names = ['ifort']
- # Named wrapper links within spack.build_env_path
+ # Named wrapper links within build_env_path
link_paths = {'cc': 'intel/icc',
'cxx': 'intel/icpc',
'f77': 'intel/ifort',
@@ -60,7 +40,11 @@ class Intel(Compiler):
@property
def cxx11_flag(self):
if self.version < ver('11.1'):
- tty.die("Only intel 11.1 and above support c++11.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 11.1")
+
elif self.version < ver('13'):
return "-std=c++0x"
else:
@@ -70,7 +54,10 @@ class Intel(Compiler):
def cxx14_flag(self):
# Adapted from CMake's Intel-CXX rules.
if self.version < ver('15'):
- tty.die("Only intel 15.0 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "< 15")
elif self.version < ver('15.0.2'):
return "-std=c++1y"
else:
diff --git a/lib/spack/spack/compilers/nag.py b/lib/spack/spack/compilers/nag.py
index 20688b67ef..18e5634bfd 100644
--- a/lib/spack/spack/compilers/nag.py
+++ b/lib/spack/spack/compilers/nag.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack.compiler import Compiler, get_compiler_version
@@ -38,7 +19,7 @@ class Nag(Compiler):
# Subclasses use possible names of Fortran 90 compiler
fc_names = ['nagfor']
- # Named wrapper links within spack.build_env_path
+ # Named wrapper links within build_env_path
# Use default wrappers for C and C++, in case provided in compilers.yaml
link_paths = {
'cc': 'cc',
@@ -72,7 +53,7 @@ class Nag(Compiler):
return '-Wl,-Wl,,-rpath,,'
@classmethod
- def default_version(self, comp):
+ def default_version(cls, comp):
"""The ``-V`` option works for nag compilers.
Output looks like this::
diff --git a/lib/spack/spack/compilers/pgi.py b/lib/spack/spack/compilers/pgi.py
index 0a90c4202d..a224e3ea6f 100644
--- a/lib/spack/spack/compilers/pgi.py
+++ b/lib/spack/spack/compilers/pgi.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack.compiler import Compiler, get_compiler_version
@@ -38,7 +19,7 @@ class Pgi(Compiler):
# Subclasses use possible names of Fortran 90 compiler
fc_names = ['pgfortran', 'pgf95', 'pgf90']
- # Named wrapper links within spack.build_env_path
+ # Named wrapper links within build_env_path
link_paths = {'cc': 'pgi/pgcc',
'cxx': 'pgi/pgc++',
'f77': 'pgi/pgfortran',
diff --git a/lib/spack/spack/compilers/xl.py b/lib/spack/spack/compilers/xl.py
index 827ffeba1b..2f7085fca5 100644
--- a/lib/spack/spack/compilers/xl.py
+++ b/lib/spack/spack/compilers/xl.py
@@ -1,30 +1,10 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import llnl.util.tty as tty
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -41,7 +21,7 @@ class Xl(Compiler):
# Subclasses use possible names of Fortran 90 compiler
fc_names = ['xlf90', 'xlf95', 'xlf2003', 'xlf2008']
- # Named wrapper links within spack.build_env_path
+ # Named wrapper links within build_env_path
link_paths = {'cc': 'xl/xlc',
'cxx': 'xl/xlc++',
'f77': 'xl/xlf',
@@ -54,7 +34,10 @@ class Xl(Compiler):
@property
def cxx11_flag(self):
if self.version < ver('13.1'):
- tty.die("Only xlC 13.1 and above have some c++11 support.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 13.1")
else:
return "-qlanglvl=extended0x"
@@ -112,6 +95,12 @@ class Xl(Compiler):
older version of AIX and linux on power.
"""
fver = get_compiler_version(fc, '-qversion', r'([0-9]?[0-9]\.[0-9])')
+ if fver >= 16:
+ """Starting with version 16.1, the XL C and Fortran compilers
+ have the same version. So no need to downgrade the Fortran
+ compiler version to match that of the C compiler version.
+ """
+ return str(fver)
cver = float(fver) - 2
if cver < 10:
cver = cver - 0.1
diff --git a/lib/spack/spack/compilers/xl_r.py b/lib/spack/spack/compilers/xl_r.py
index 1afaa45e63..18ffe0631d 100644
--- a/lib/spack/spack/compilers/xl_r.py
+++ b/lib/spack/spack/compilers/xl_r.py
@@ -1,31 +1,10 @@
-##############################################################################
-# Copyright (c) 2016, International Business Machines Corporation
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Serban Maerean, serban@us.ibm.com based on a similar file,
-# spack/lib/spack/spack/compilers/xl.py, produced by Todd Gamblin,
-# tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import llnl.util.tty as tty
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -42,7 +21,7 @@ class XlR(Compiler):
# Subclasses use possible names of Fortran 90 compiler
fc_names = ['xlf90_r', 'xlf95_r', 'xlf2003_r', 'xlf2008_r']
- # Named wrapper links within spack.build_env_path
+ # Named wrapper links within build_env_path
link_paths = {'cc': 'xl_r/xlc_r',
'cxx': 'xl_r/xlc++_r',
'f77': 'xl_r/xlf_r',
@@ -55,7 +34,10 @@ class XlR(Compiler):
@property
def cxx11_flag(self):
if self.version < ver('13.1'):
- tty.die("Only xlC 13.1 and above have some c++11 support.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 13.1")
else:
return "-qlanglvl=extended0x"
@@ -72,7 +54,7 @@ class XlR(Compiler):
return "-qzerosize"
@classmethod
- def default_version(self, comp):
+ def default_version(cls, comp):
"""The '-qversion' is the standard option fo XL compilers.
Output looks like this::
@@ -113,6 +95,12 @@ class XlR(Compiler):
older version of AIX and linux on power.
"""
fver = get_compiler_version(fc, '-qversion', r'([0-9]?[0-9]\.[0-9])')
+ if fver >= 16:
+ """Starting with version 16.1, the XL C and Fortran compilers
+ have the same version. So no need to downgrade the Fortran
+ compiler version to match that of the C compiler version.
+ """
+ return str(fver)
cver = float(fver) - 2
if cver < 10:
cver = cver - 0.1
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index 3b1e83cb5b..4b12588c56 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
Functions here are used to take abstract specs and make them concrete.
For example, if a spec asks for a version between 1.8 and 1.9, these
@@ -36,9 +17,13 @@ TODO: make this customizable and allow users to configure
from __future__ import print_function
from itertools import chain
from functools_backport import reverse_order
+from contextlib import contextmanager
from six import iteritems
-import spack
+import llnl.util.lang
+
+import spack.repo
+import spack.abi
import spack.spec
import spack.compilers
import spack.architecture
@@ -47,11 +32,30 @@ from spack.version import ver, Version, VersionList, VersionRange
from spack.package_prefs import PackagePrefs, spec_externals, is_spec_buildable
-class DefaultConcretizer(object):
- """This class doesn't have any state, it just provides some methods for
- concretization. You can subclass it to override just some of the
- default concretization strategies, or you can override all of them.
+#: Concretizer singleton
+concretizer = llnl.util.lang.Singleton(lambda: Concretizer())
+
+
+#: impements rudimentary logic for ABI compatibility
+_abi = llnl.util.lang.Singleton(lambda: spack.abi.ABI())
+
+
+class Concretizer(object):
+ """You can subclass this class to override some of the default
+ concretization strategies, or you can override all of them.
"""
+ def __init__(self):
+ # controls whether we check that compiler versions actually exist
+ # during concretization. Used for testing and for mirror creation
+ self.check_for_compiler_existence = True
+
+ @contextmanager
+ def disable_compiler_existence_check(self):
+ saved = self.check_for_compiler_existence
+ self.check_for_compiler_existence = False
+ yield
+ self.check_for_compiler_existence = saved
+
def _valid_virtuals_and_externals(self, spec):
"""Returns a list of candidate virtual dep providers and external
packages that coiuld be used to concretize a spec.
@@ -63,7 +67,7 @@ class DefaultConcretizer(object):
pref_key = lambda spec: 0 # no-op pref key
if spec.virtual:
- candidates = spack.repo.providers_for(spec)
+ candidates = spack.repo.path.providers_for(spec)
if not candidates:
raise spack.spec.UnsatisfiableProviderSpecError(
candidates[0], spec)
@@ -124,8 +128,8 @@ class DefaultConcretizer(object):
return sorted(candidates,
reverse=True,
key=lambda spec: (
- spack.abi.compatible(spec, abi_exemplar, loose=True),
- spack.abi.compatible(spec, abi_exemplar)))
+ _abi.compatible(spec, abi_exemplar, loose=True),
+ _abi.compatible(spec, abi_exemplar)))
def concretize_version(self, spec):
"""If the spec is already concrete, return. Otherwise take
@@ -214,27 +218,29 @@ class DefaultConcretizer(object):
DAG has an architecture, then use the root otherwise use the defaults
on the platform.
"""
- root_arch = spec.root.architecture
- sys_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
+ try:
+ # Get the nearest architecture with any fields set
+ nearest = next(p for p in spec.traverse(direction='parents')
+ if (p.architecture and p is not spec))
+ nearest_arch = nearest.architecture
+ except StopIteration:
+ # Default to the system architecture if nothing set
+ nearest_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
+
spec_changed = False
+ # ensure type safety for the architecture
if spec.architecture is None:
- spec.architecture = spack.spec.ArchSpec(sys_arch)
+ spec.architecture = spack.spec.ArchSpec()
spec_changed = True
- default_archs = list(x for x in [root_arch, sys_arch] if x)
- for arch in default_archs:
- if spec.architecture.concrete:
- break
-
- replacement_fields = [k for k, v in iteritems(arch.to_cmp_dict())
- if v and not getattr(spec.architecture, k)]
- for field in replacement_fields:
- setattr(spec.architecture, field, getattr(arch, field))
- spec_changed = True
-
- if not spec.architecture.concrete:
- raise InsufficientArchitectureInfoError(spec, default_archs)
+ # replace each of the fields (platform, os, target) separately
+ nearest_dict = nearest_arch.to_cmp_dict()
+ replacement_fields = [k for k, v in iteritems(nearest_dict)
+ if v and not getattr(spec.architecture, k)]
+ for field in replacement_fields:
+ setattr(spec.architecture, field, getattr(nearest_arch, field))
+ spec_changed = True
return spec_changed
@@ -283,14 +289,9 @@ class DefaultConcretizer(object):
def _proper_compiler_style(cspec, aspec):
return spack.compilers.compilers_for_spec(cspec, arch_spec=aspec)
- all_compiler_specs = spack.compilers.all_compiler_specs()
- if not all_compiler_specs:
- raise spack.compilers.NoCompilersError()
-
- if (spec.compiler and
- spec.compiler.concrete and
- spec.compiler in all_compiler_specs):
- if not _proper_compiler_style(spec.compiler, spec.architecture):
+ if spec.compiler and spec.compiler.concrete:
+ if (self.check_for_compiler_existence and not
+ _proper_compiler_style(spec.compiler, spec.architecture)):
_compiler_concretization_failure(
spec.compiler, spec.architecture)
return False
@@ -302,6 +303,22 @@ class DefaultConcretizer(object):
assert(other_spec)
# Check if the compiler is already fully specified
+ if (other_compiler and other_compiler.concrete and
+ not self.check_for_compiler_existence):
+ spec.compiler = other_compiler.copy()
+ return True
+
+ all_compiler_specs = spack.compilers.all_compiler_specs()
+ if not all_compiler_specs:
+ # If compiler existence checking is disabled, then we would have
+ # exited by now if there were sufficient hints to form a full
+ # compiler spec. Therefore even if compiler existence checking is
+ # disabled, compilers must be available at this point because the
+ # available compilers are used to choose a compiler. If compiler
+ # existence checking is enabled then some compiler must exist in
+ # order to complete the spec.
+ raise spack.compilers.NoCompilersError()
+
if other_compiler in all_compiler_specs:
spec.compiler = other_compiler.copy()
if not _proper_compiler_style(spec.compiler, spec.architecture):
@@ -377,8 +394,13 @@ class DefaultConcretizer(object):
# Include the compiler flag defaults from the config files
# This ensures that spack will detect conflicts that stem from a change
# in default compiler flags.
- compiler = spack.compilers.compiler_for_spec(
- spec.compiler, spec.architecture)
+ try:
+ compiler = spack.compilers.compiler_for_spec(
+ spec.compiler, spec.architecture)
+ except spack.compilers.NoCompilerForSpecError:
+ if self.check_for_compiler_existence:
+ raise
+ return ret
for flag in compiler.flags:
config_flags = set(compiler.flags.get(flag, []))
flags = set(spec.compiler_flags.get(flag, []))
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index 4be407fd68..2ecd669cfe 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This module implements Spack's configuration file handling.
This implements Spack's configuration system, which handles merging
@@ -53,28 +34,34 @@ import copy
import os
import re
import sys
+import multiprocessing
+from contextlib import contextmanager
from six import string_types
from six import iteritems
-
-import yaml
-import jsonschema
-from yaml.error import MarkedYAMLError
-from jsonschema import Draft4Validator, validators
from ordereddict_backport import OrderedDict
+import ruamel.yaml as yaml
+from ruamel.yaml.error import MarkedYAMLError
+
+import llnl.util.lang
import llnl.util.tty as tty
from llnl.util.filesystem import mkdirp
-import spack
+import spack.paths
import spack.architecture
+import spack.schema.compilers
+import spack.schema.mirrors
+import spack.schema.repos
+import spack.schema.packages
+import spack.schema.modules
+import spack.schema.config
from spack.error import SpackError
-import spack.schema
# Hacked yaml for configuration files preserves line numbers.
import spack.util.spack_yaml as syaml
-"""Dict from section names -> schema for that section."""
+#: Dict from section names -> schema for that section
section_schemas = {
'compilers': spack.schema.compilers.schema,
'mirrors': spack.schema.mirrors.schema,
@@ -84,20 +71,51 @@ section_schemas = {
'config': spack.schema.config.schema,
}
-"""OrderedDict of config scopes keyed by name.
- Later scopes will override earlier scopes.
-"""
-config_scopes = OrderedDict()
+#: Builtin paths to configuration files in Spack
+configuration_paths = (
+ # Default configuration scope is the lowest-level scope. These are
+ # versioned with Spack and can be overridden by systems, sites or users
+ ('defaults', os.path.join(spack.paths.etc_path, 'spack', 'defaults')),
+
+ # System configuration is per machine.
+ # No system-level configs should be checked into spack by default
+ ('system', os.path.join(spack.paths.system_etc_path, 'spack')),
+
+ # Site configuration is per spack instance, for sites or projects
+ # No site-level configs should be checked into spack by default.
+ ('site', os.path.join(spack.paths.etc_path, 'spack')),
+
+ # User configuration can override both spack defaults and site config
+ ('user', spack.paths.user_config_path)
+)
+
+#: Hard-coded default values for some key configuration options.
+#: This ensures that Spack will still work even if config.yaml in
+#: the defaults scope is removed.
+config_defaults = {
+ 'config': {
+ 'debug': False,
+ 'verify_ssl': True,
+ 'checksum': True,
+ 'dirty': False,
+ 'build_jobs': multiprocessing.cpu_count(),
+ }
+}
+#: metavar to use for commands that accept scopes
+#: this is shorter and more readable than listing all choices
+scopes_metavar = '{defaults,system,site,user}[/PLATFORM]'
-def validate_section_name(section):
- """Exit if the section is not a valid section."""
- if section not in section_schemas:
- tty.die("Invalid config section: '%s'. Options are: %s"
- % (section, " ".join(section_schemas.keys())))
+
+def first_existing(dictionary, keys):
+ """Get the value of the first key in keys that is in the dictionary."""
+ try:
+ return next(k for k in keys if k in dictionary)
+ except StopIteration:
+ raise KeyError("None of %s is in dict!" % keys)
-def extend_with_default(validator_class):
+def _extend_with_default(validator_class):
"""Add support for the 'default' attr for properties and patternProperties.
jsonschema does not handle this out of the box -- it only
@@ -106,6 +124,7 @@ def extend_with_default(validator_class):
commented out.
"""
+ import jsonschema
validate_properties = validator_class.VALIDATORS["properties"]
validate_pattern_properties = validator_class.VALIDATORS[
"patternProperties"]
@@ -113,7 +132,8 @@ def extend_with_default(validator_class):
def set_defaults(validator, properties, instance, schema):
for property, subschema in iteritems(properties):
if "default" in subschema:
- instance.setdefault(property, subschema["default"])
+ instance.setdefault(
+ property, copy.deepcopy(subschema["default"]))
for err in validate_properties(
validator, properties, instance, schema):
yield err
@@ -124,34 +144,18 @@ def extend_with_default(validator_class):
if isinstance(instance, dict):
for key, val in iteritems(instance):
if re.match(property, key) and val is None:
- instance[key] = subschema["default"]
+ instance[key] = copy.deepcopy(subschema["default"])
for err in validate_pattern_properties(
validator, properties, instance, schema):
yield err
- return validators.extend(validator_class, {
+ return jsonschema.validators.extend(validator_class, {
"properties": set_defaults,
"patternProperties": set_pp_defaults
})
-DefaultSettingValidator = extend_with_default(Draft4Validator)
-
-
-def validate_section(data, schema):
- """Validate data read in from a Spack YAML file.
-
- This leverages the line information (start_mark, end_mark) stored
- on Spack YAML structures.
-
- """
- try:
- DefaultSettingValidator(schema).validate(data)
- except jsonschema.ValidationError as e:
- raise ConfigFormatError(e, data)
-
-
class ConfigScope(object):
"""This class represents a configuration scope.
@@ -164,13 +168,8 @@ class ConfigScope(object):
self.path = path # path to directory containing configs.
self.sections = syaml.syaml_dict() # sections read from config files.
- # Register in a dict of all ConfigScopes
- # TODO: make this cleaner. Mocking up for testing is brittle.
- global config_scopes
- config_scopes[name] = self
-
def get_section_filename(self, section):
- validate_section_name(section)
+ _validate_section_name(section)
return os.path.join(self.path, "%s.yaml" % section)
def get_section(self, section):
@@ -184,13 +183,13 @@ class ConfigScope(object):
def write_section(self, section):
filename = self.get_section_filename(section)
data = self.get_section(section)
+ _validate(data, section_schemas[section])
+
try:
mkdirp(self.path)
with open(filename, 'w') as f:
- validate_section(data, section_schemas[section])
+ _validate(data, section_schemas[section])
syaml.dump(data, stream=f, default_flow_style=False)
- except jsonschema.ValidationError as e:
- raise ConfigSanityError(e, data)
except (yaml.YAMLError, IOError) as e:
raise ConfigFileError(
"Error writing to config file: '%s'" % str(e))
@@ -203,61 +202,514 @@ class ConfigScope(object):
return '<ConfigScope: %s: %s>' % (self.name, self.path)
-#
-# Below are configuration scopes.
-#
-# Each scope can have per-platfom overrides in subdirectories of the
-# configuration directory.
-#
-_platform = spack.architecture.platform().name
+class SingleFileScope(ConfigScope):
+ """This class represents a configuration scope in a single YAML file."""
+ def __init__(self, name, path, schema, yaml_path=None):
+ """Similar to ``ConfigScope`` but can be embedded in another schema.
+
+ Arguments:
+ schema (dict): jsonschema for the file to read
+ yaml_path (list): list of dict keys in the schema where
+ config data can be found;
+
+ Elements of ``yaml_path`` can be tuples or lists to represent an
+ "or" of keys (e.g. "env" or "spack" is ``('env', 'spack')``)
+
+ """
+ super(SingleFileScope, self).__init__(name, path)
+ self._raw_data = None
+ self.schema = schema
+ self.yaml_path = yaml_path or []
+
+ def get_section_filename(self, section):
+ return self.path
+
+ def get_section(self, section):
+ # read raw data from the file, which looks like:
+ # {
+ # 'config': {
+ # ... data ...
+ # },
+ # 'packages': {
+ # ... data ...
+ # },
+ # }
+ if self._raw_data is None:
+ self._raw_data = _read_config_file(self.path, self.schema)
+ if self._raw_data is None:
+ return None
+
+ for key in self.yaml_path:
+ if self._raw_data is None:
+ return None
+
+ # support tuples as "or" in the yaml path
+ if isinstance(key, (list, tuple)):
+ key = first_existing(self._raw_data, key)
+
+ self._raw_data = self._raw_data[key]
+
+ # data in self.sections looks (awkwardly) like this:
+ # {
+ # 'config': {
+ # 'config': {
+ # ... data ...
+ # }
+ # },
+ # 'packages': {
+ # 'packages': {
+ # ... data ...
+ # }
+ # }
+ # }
+ #
+ # UNLESS there is no section, in which case it is stored as:
+ # {
+ # 'config': None,
+ # ...
+ # }
+ value = self._raw_data.get(section)
+ self.sections.setdefault(
+ section, None if value is None else {section: value})
+ return self.sections[section]
+
+ def write_section(self, section):
+ _validate(self.sections, self.schema)
+ try:
+ parent = os.path.dirname(self.path)
+ mkdirp(parent)
-"""Default configuration scope is the lowest-level scope. These are
- versioned with Spack and can be overridden by systems, sites or users."""
-_defaults_path = os.path.join(spack.etc_path, 'spack', 'defaults')
-ConfigScope('defaults', _defaults_path)
-ConfigScope('defaults/%s' % _platform, os.path.join(_defaults_path, _platform))
+ tmp = os.path.join(parent, '.%s.tmp' % self.path)
+ with open(tmp, 'w') as f:
+ syaml.dump(self.sections, stream=f, default_flow_style=False)
+ os.path.move(tmp, self.path)
+ except (yaml.YAMLError, IOError) as e:
+ raise ConfigFileError(
+ "Error writing to config file: '%s'" % str(e))
-"""System configuration is per machine.
- No system-level configs should be checked into spack by default"""
-_system_path = os.path.join(spack.system_etc_path, 'spack')
-ConfigScope('system', _system_path)
-ConfigScope('system/%s' % _platform, os.path.join(_system_path, _platform))
+ def __repr__(self):
+ return '<SingleFileScope: %s: %s>' % (self.name, self.path)
-"""Site configuration is per spack instance, for sites or projects.
- No site-level configs should be checked into spack by default."""
-_site_path = os.path.join(spack.etc_path, 'spack')
-ConfigScope('site', _site_path)
-ConfigScope('site/%s' % _platform, os.path.join(_site_path, _platform))
-"""User configuration can override both spack defaults and site config."""
-_user_path = spack.user_config_path
-ConfigScope('user', _user_path)
-ConfigScope('user/%s' % _platform, os.path.join(_user_path, _platform))
+class ImmutableConfigScope(ConfigScope):
+ """A configuration scope that cannot be written to.
+ This is used for ConfigScopes passed on the command line.
+ """
-def highest_precedence_scope():
- """Get the scope with highest precedence (prefs will override others)."""
- return config_scopes.values()[-1]
+ def write_section(self, section):
+ raise ConfigError("Cannot write to immutable scope %s" % self)
+ def __repr__(self):
+ return '<ImmutableConfigScope: %s: %s>' % (self.name, self.path)
-def validate_scope(scope):
- """Ensure that scope is valid, and return a valid scope if it is None.
- This should be used by routines in ``config.py`` to validate
- scope name arguments, and to determine a default scope where no
- scope is specified.
+class InternalConfigScope(ConfigScope):
+ """An internal configuration scope that is not persisted to a file.
+ This is for spack internal use so that command-line options and
+ config file settings are accessed the same way, and Spack can easily
+ override settings from files.
"""
- if scope is None:
- # default to the scope with highest precedence.
- return highest_precedence_scope()
+ def __init__(self, name, data=None):
+ super(InternalConfigScope, self).__init__(name, None)
+ self.sections = syaml.syaml_dict()
+
+ if data:
+ for section in data:
+ dsec = data[section]
+ _validate({section: dsec}, section_schemas[section])
+ self.sections[section] = _mark_internal(
+ syaml.syaml_dict({section: dsec}), name)
- elif scope in config_scopes:
- return config_scopes[scope]
+ def get_section_filename(self, section):
+ raise NotImplementedError(
+ "Cannot get filename for InternalConfigScope.")
+
+ def get_section(self, section):
+ """Just reads from an internal dictionary."""
+ if section not in self.sections:
+ self.sections[section] = None
+ return self.sections[section]
+
+ def write_section(self, section):
+ """This only validates, as the data is already in memory."""
+ data = self.get_section(section)
+ if data is not None:
+ _validate(data, section_schemas[section])
+ self.sections[section] = _mark_internal(data, self.name)
+
+ def __repr__(self):
+ return '<InternalConfigScope: %s>' % self.name
+
+
+class Configuration(object):
+ """A full Spack configuration, from a hierarchy of config files.
+
+ This class makes it easy to add a new scope on top of an existing one.
+ """
+
+ def __init__(self, *scopes):
+ """Initialize a configuration with an initial list of scopes.
+
+ Args:
+ scopes (list of ConfigScope): list of scopes to add to this
+ Configuration, ordered from lowest to highest precedence
+
+ """
+ self.scopes = OrderedDict()
+ for scope in scopes:
+ self.push_scope(scope)
+
+ def push_scope(self, scope):
+ """Add a higher precedence scope to the Configuration."""
+ cmd_line_scope = None
+ if self.scopes:
+ highest_precedence_scope = list(self.scopes.values())[-1]
+ if highest_precedence_scope.name == 'command_line':
+ # If the command-line scope is present, it should always
+ # be the scope of highest precedence
+ cmd_line_scope = self.pop_scope()
+
+ self.scopes[scope.name] = scope
+ if cmd_line_scope:
+ self.scopes['command_line'] = cmd_line_scope
+
+ def pop_scope(self):
+ """Remove the highest precedence scope and return it."""
+ name, scope = self.scopes.popitem(last=True)
+ return scope
+
+ def remove_scope(self, scope_name):
+ return self.scopes.pop(scope_name)
+
+ @property
+ def file_scopes(self):
+ """List of writable scopes with an associated file."""
+ return [s for s in self.scopes.values() if type(s) == ConfigScope]
+
+ def highest_precedence_scope(self):
+ """Non-internal scope with highest precedence."""
+ return next(reversed(self.file_scopes), None)
+
+ def _validate_scope(self, scope):
+ """Ensure that scope is valid in this configuration.
+
+ This should be used by routines in ``config.py`` to validate
+ scope name arguments, and to determine a default scope where no
+ scope is specified.
+
+ Raises:
+ ValueError: if ``scope`` is not valid
+
+ Returns:
+ ConfigScope: a valid ConfigScope if ``scope`` is ``None`` or valid
+ """
+ if scope is None:
+ # default to the scope with highest precedence.
+ return self.highest_precedence_scope()
+
+ elif scope in self.scopes:
+ return self.scopes[scope]
+
+ else:
+ raise ValueError("Invalid config scope: '%s'. Must be one of %s"
+ % (scope, self.scopes.keys()))
+
+ def get_config_filename(self, scope, section):
+ """For some scope and section, get the name of the configuration file.
+ """
+ scope = self._validate_scope(scope)
+ return scope.get_section_filename(section)
+
+ def clear_caches(self):
+ """Clears the caches for configuration files,
+
+ This will cause files to be re-read upon the next request."""
+ for scope in self.scopes.values():
+ scope.clear()
+
+ def update_config(self, section, update_data, scope=None):
+ """Update the configuration file for a particular scope.
+
+ Overwrites contents of a section in a scope with update_data,
+ then writes out the config file.
+
+ update_data should have the top-level section name stripped off
+ (it will be re-added). Data itself can be a list, dict, or any
+ other yaml-ish structure.
+ """
+ _validate_section_name(section) # validate section name
+ scope = self._validate_scope(scope) # get ConfigScope object
+
+ # read only the requested section's data.
+ scope.sections[section] = {section: update_data}
+ scope.write_section(section)
+
+ def get_config(self, section, scope=None):
+ """Get configuration settings for a section.
+
+ If ``scope`` is ``None`` or not provided, return the merged contents
+ of all of Spack's configuration scopes. If ``scope`` is provided,
+ return only the confiugration as specified in that scope.
+
+ This off the top-level name from the YAML section. That is, for a
+ YAML config file that looks like this::
+
+ config:
+ install_tree: $spack/opt/spack
+ module_roots:
+ lmod: $spack/share/spack/lmod
+
+ ``get_config('config')`` will return::
+
+ { 'install_tree': '$spack/opt/spack',
+ 'module_roots: {
+ 'lmod': '$spack/share/spack/lmod'
+ }
+ }
+
+ """
+ _validate_section_name(section)
+
+ if scope is None:
+ scopes = self.scopes.values()
+ else:
+ scopes = [self._validate_scope(scope)]
+
+ merged_section = syaml.syaml_dict()
+ for scope in scopes:
+ # read potentially cached data from the scope.
+
+ data = scope.get_section(section)
+
+ # Skip empty configs
+ if not data or not isinstance(data, dict):
+ continue
+
+ if section not in data:
+ continue
+
+ merged_section = _merge_yaml(merged_section, data)
+
+ # no config files -- empty config.
+ if section not in merged_section:
+ return {}
+
+ # take the top key off before returning.
+ return merged_section[section]
+
+ def get(self, path, default=None, scope=None):
+ """Get a config section or a single value from one.
+
+ Accepts a path syntax that allows us to grab nested config map
+ entries. Getting the 'config' section would look like::
+
+ spack.config.get('config')
+
+ and the ``dirty`` section in the ``config`` scope would be::
+
+ spack.config.get('config:dirty')
+
+ We use ``:`` as the separator, like YAML objects.
+ """
+ # TODO: Currently only handles maps. Think about lists if neded.
+ section, _, rest = path.partition(':')
+
+ value = self.get_config(section, scope=scope)
+ if not rest:
+ return value
+
+ parts = rest.split(':')
+ while parts:
+ key = parts.pop(0)
+ value = value.get(key, default)
+
+ return value
+
+ def set(self, path, value, scope=None):
+ """Convenience function for setting single values in config files.
+
+ Accepts the path syntax described in ``get()``.
+ """
+ section, _, rest = path.partition(':')
+
+ if not rest:
+ self.update_config(section, value, scope=scope)
+ else:
+ section_data = self.get_config(section, scope=scope)
+
+ parts = rest.split(':')
+ data = section_data
+ while len(parts) > 1:
+ key = parts.pop(0)
+ data = data[key]
+ data[parts[0]] = value
+
+ self.update_config(section, section_data, scope=scope)
+
+ def __iter__(self):
+ """Iterate over scopes in this configuration."""
+ for scope in self.scopes.values():
+ yield scope
+
+ def print_section(self, section, blame=False):
+ """Print a configuration to stdout."""
+ try:
+ data = syaml.syaml_dict()
+ data[section] = self.get_config(section)
+ syaml.dump(
+ data, stream=sys.stdout, default_flow_style=False, blame=blame)
+ except (yaml.YAMLError, IOError):
+ raise ConfigError("Error reading configuration: %s" % section)
+
+@contextmanager
+def override(path_or_scope, value=None):
+ """Simple way to override config settings within a context.
+
+ Arguments:
+ path_or_scope (ConfigScope or str): scope or single option to override
+ value (object, optional): value for the single option
+
+ Temporarily push a scope on the current configuration, then remove it
+ after the context completes. If a single option is provided, create
+ an internal config scope for it and push/pop that scope.
+
+ """
+ if isinstance(path_or_scope, ConfigScope):
+ overrides = path_or_scope
+ config.push_scope(path_or_scope)
else:
- raise ValueError("Invalid config scope: '%s'. Must be one of %s"
- % (scope, config_scopes.keys()))
+ overrides = InternalConfigScope('overrides')
+ config.push_scope(overrides)
+ config.set(path_or_scope, value, scope='overrides')
+
+ yield config
+
+ scope = config.remove_scope(overrides.name)
+ assert scope is overrides
+
+
+#: configuration scopes added on the command line
+#: set by ``spack.main.main()``.
+command_line_scopes = []
+
+
+def _add_platform_scope(cfg, scope_type, name, path):
+ """Add a platform-specific subdirectory for the current platform."""
+ platform = spack.architecture.platform().name
+ plat_name = '%s/%s' % (name, platform)
+ plat_path = os.path.join(path, platform)
+ cfg.push_scope(scope_type(plat_name, plat_path))
+
+
+def _add_command_line_scopes(cfg, command_line_scopes):
+ """Add additional scopes from the --config-scope argument.
+
+ Command line scopes are named after their position in the arg list.
+ """
+ for i, path in enumerate(command_line_scopes):
+ # We ensure that these scopes exist and are readable, as they are
+ # provided on the command line by the user.
+ if not os.path.isdir(path):
+ raise ConfigError("config scope is not a directory: '%s'" % path)
+ elif not os.access(path, os.R_OK):
+ raise ConfigError("config scope is not readable: '%s'" % path)
+
+ # name based on order on the command line
+ name = 'cmd_scope_%d' % i
+ cfg.push_scope(ImmutableConfigScope(name, path))
+ _add_platform_scope(cfg, ImmutableConfigScope, name, path)
+
+
+def _config():
+ """Singleton Configuration instance.
+
+ This constructs one instance associated with this module and returns
+ it. It is bundled inside a function so that configuratoin can be
+ initialized lazily.
+
+ Return:
+ (Configuration): object for accessing spack configuration
+
+ """
+ cfg = Configuration()
+
+ # first do the builtin, hardcoded defaults
+ defaults = InternalConfigScope('_builtin', config_defaults)
+ cfg.push_scope(defaults)
+
+ # add each scope and its platform-specific directory
+ for name, path in configuration_paths:
+ cfg.push_scope(ConfigScope(name, path))
+
+ # Each scope can have per-platfom overrides in subdirectories
+ _add_platform_scope(cfg, ConfigScope, name, path)
+
+ # add command-line scopes
+ _add_command_line_scopes(cfg, command_line_scopes)
+
+ # we make a special scope for spack commands so that they can
+ # override configuration options.
+ cfg.push_scope(InternalConfigScope('command_line'))
+
+ return cfg
+
+
+#: This is the singleton configuration instance for Spack.
+config = llnl.util.lang.Singleton(_config)
+
+
+def get(path, default=None, scope=None):
+ """Module-level wrapper for ``Configuration.get()``."""
+ return config.get(path, default, scope)
+
+
+def set(path, value, scope=None):
+ """Convenience function for getting single values in config files.
+
+ Accepts the path syntax described in ``get()``.
+ """
+ return config.set(path, value, scope)
+
+
+def scopes():
+ """Convenience function to get list of configuration scopes."""
+ return config.scopes
+
+
+def _validate_section_name(section):
+ """Exit if the section is not a valid section."""
+ if section not in section_schemas:
+ raise ConfigSectionError(
+ "Invalid config section: '%s'. Options are: %s"
+ % (section, " ".join(section_schemas.keys())))
+
+
+def _validate(data, schema, set_defaults=True):
+ """Validate data read in from a Spack YAML file.
+
+ Arguments:
+ data (dict or list): data read from a Spack YAML file
+ schema (dict or list): jsonschema to validate data
+ set_defaults (bool): whether to set defaults based on the schema
+
+ This leverages the line information (start_mark, end_mark) stored
+ on Spack YAML structures.
+
+ """
+ import jsonschema
+
+ if not hasattr(_validate, 'validator'):
+ default_setting_validator = _extend_with_default(
+ jsonschema.Draft4Validator)
+ _validate.validator = default_setting_validator
+
+ try:
+ _validate.validator(schema).validate(data)
+ except jsonschema.ValidationError as e:
+ raise ConfigFormatError(e, data)
def _read_config_file(filename, schema):
@@ -279,7 +731,7 @@ def _read_config_file(filename, schema):
data = _mark_overrides(syaml.load(f))
if data:
- validate_section(data, schema)
+ _validate(data, schema)
return data
except MarkedYAMLError as e:
@@ -291,14 +743,7 @@ def _read_config_file(filename, schema):
"Error reading configuration file %s: %s" % (filename, str(e)))
-def clear_config_caches():
- """Clears the caches for configuration files, which will cause them
- to be re-read upon the next request"""
- for scope in config_scopes.values():
- scope.clear()
-
-
-def override(string):
+def _override(string):
"""Test if a spack YAML string is an override.
See ``spack_yaml`` for details. Keys in Spack YAML can end in `::`,
@@ -311,7 +756,7 @@ def override(string):
def _mark_overrides(data):
if isinstance(data, list):
- return [_mark_overrides(elt) for elt in data]
+ return syaml.syaml_list(_mark_overrides(elt) for elt in data)
elif isinstance(data, dict):
marked = syaml.syaml_dict()
@@ -326,6 +771,26 @@ def _mark_overrides(data):
return data
+def _mark_internal(data, name):
+ """Add a simple name mark to raw YAML/JSON data.
+
+ This is used by `spack config blame` to show where config lines came from.
+ """
+ if isinstance(data, dict):
+ d = syaml.syaml_dict((_mark_internal(k, name), _mark_internal(v, name))
+ for k, v in data.items())
+ elif isinstance(data, list):
+ d = syaml.syaml_list(_mark_internal(e, name) for e in data)
+ else:
+ d = syaml.syaml_type(data)
+
+ if syaml.markable(d):
+ d._start_mark = yaml.Mark(name, None, None, None, None, None)
+ d._end_mark = yaml.Mark(name, None, None, None, None, None)
+
+ return d
+
+
def _merge_yaml(dest, source):
"""Merges source into dest; entries in source take precedence over dest.
@@ -357,13 +822,28 @@ def _merge_yaml(dest, source):
# Source dict is merged into dest.
elif they_are(dict):
+ # track keys for marking
+ key_marks = {}
+
for sk, sv in iteritems(source):
- if override(sk) or sk not in dest:
+ if _override(sk) or sk not in dest:
# if sk ended with ::, or if it's new, completely override
dest[sk] = copy.copy(sv)
else:
# otherwise, merge the YAML
dest[sk] = _merge_yaml(dest[sk], source[sk])
+
+ # this seems unintuitive, but see below. We need this because
+ # Python dicts do not overwrite keys on insert, and we want
+ # to copy mark information on source keys to dest.
+ key_marks[sk] = sk
+
+ # ensure that keys are marked in the destination. the key_marks dict
+ # ensures we can get the actual source key objects from dest keys
+ for dk in dest.keys():
+ if dk in key_marks:
+ syaml.mark(dk, key_marks[dk])
+
return dest
# In any other case, overwrite with a copy of the source value.
@@ -371,154 +851,105 @@ def _merge_yaml(dest, source):
return copy.copy(source)
-def get_config(section, scope=None):
- """Get configuration settings for a section.
-
- If ``scope`` is ``None`` or not provided, return the merged contents
- of all of Spack's configuration scopes. If ``scope`` is provided,
- return only the confiugration as specified in that scope.
-
- This off the top-level name from the YAML section. That is, for a
- YAML config file that looks like this::
-
- config:
- install_tree: $spack/opt/spack
- module_roots:
- lmod: $spack/share/spack/lmod
-
- ``get_config('config')`` will return::
-
- { 'install_tree': '$spack/opt/spack',
- 'module_roots: {
- 'lmod': '$spack/share/spack/lmod'
- }
- }
+#
+# Settings for commands that modify configuration
+#
+def default_modify_scope():
+ """Return the config scope that commands should modify by default.
+ Commands that modify configuration by default modify the *highest*
+ priority scope.
"""
- validate_section_name(section)
- merged_section = syaml.syaml_dict()
-
- if scope is None:
- scopes = config_scopes.values()
- else:
- scopes = [validate_scope(scope)]
-
- for scope in scopes:
- # read potentially cached data from the scope.
-
- data = scope.get_section(section)
-
- # Skip empty configs
- if not data or not isinstance(data, dict):
- continue
-
- if section not in data:
- tty.warn("Skipping bad configuration file: '%s'" % scope.path)
- continue
-
- merged_section = _merge_yaml(merged_section, data)
+ return spack.config.config.highest_precedence_scope().name
- # no config files -- empty config.
- if section not in merged_section:
- return {}
- # take the top key off before returning.
- return merged_section[section]
-
-
-def get_config_filename(scope, section):
- """For some scope and section, get the name of the configuration file"""
- scope = validate_scope(scope)
- return scope.get_section_filename(section)
-
-
-def update_config(section, update_data, scope=None):
- """Update the configuration file for a particular scope.
-
- Overwrites contents of a section in a scope with update_data,
- then writes out the config file.
-
- update_data should have the top-level section name stripped off
- (it will be re-added). Data itself can be a list, dict, or any
- other yaml-ish structure.
+def default_list_scope():
+ """Return the config scope that is listed by default.
+ Commands that list configuration list *all* scopes (merged) by default.
"""
- validate_section_name(section) # validate section name
- scope = validate_scope(scope) # get ConfigScope object from string.
+ return None
- # read in the config to ensure we've got current data
- configuration = get_config(section)
- if isinstance(update_data, list):
- configuration = update_data
- else:
- configuration.update(update_data)
+class ConfigError(SpackError):
+ """Superclass for all Spack config related errors."""
- # read only the requested section's data.
- scope.sections[section] = {section: configuration}
- scope.write_section(section)
+class ConfigSectionError(ConfigError):
+ """Error for referring to a bad config section name in a configuration."""
-def print_section(section):
- """Print a configuration to stdout."""
- try:
- data = syaml.syaml_dict()
- data[section] = get_config(section)
- syaml.dump(data, stream=sys.stdout, default_flow_style=False)
- except (yaml.YAMLError, IOError):
- raise ConfigError("Error reading configuration: %s" % section)
+class ConfigFileError(ConfigError):
+ """Issue reading or accessing a configuration file."""
-class ConfigError(SpackError):
- pass
+class ConfigFormatError(ConfigError):
+ """Raised when a configuration format does not match its schema."""
-class ConfigFileError(ConfigError):
- pass
+ def __init__(self, validation_error, data, filename=None, line=None):
+ self.filename = filename # record this for ruamel.yaml
+ location = '<unknown file>'
-def get_path(path, data):
- if path:
- return get_path(path[1:], data[path[0]])
- else:
- return data
+ # spack yaml has its own file/line marks -- try to find them
+ if not filename and not line:
+ mark = self._get_mark(validation_error, data)
+ if mark:
+ filename = mark.name
+ line = mark.line + 1
+ if filename:
+ location = '%s' % filename
+ if line is not None:
+ location += ':%d' % line
-class ConfigFormatError(ConfigError):
- """Raised when a configuration format does not match its schema."""
+ message = '%s: %s' % (location, validation_error.message)
+ super(ConfigError, self).__init__(message)
- def __init__(self, validation_error, data):
- # Try to get line number from erroneous instance and its parent
- instance_mark = getattr(validation_error.instance, '_start_mark', None)
- parent_mark = getattr(validation_error.parent, '_start_mark', None)
- path = [str(s) for s in getattr(validation_error, 'path', None)]
+ def _get_mark(self, validation_error, data):
+ """Get the file/line mark fo a validation error from a Spack YAML file.
+ """
+ def _get_mark_or_first_member_mark(obj):
+ # mark of object itelf
+ mark = getattr(obj, '_start_mark', None)
+ if mark:
+ return mark
+
+ # mark of first member if it is a container
+ if isinstance(obj, (list, dict)):
+ first_member = next(iter(obj), None)
+ if first_member:
+ mark = getattr(first_member, '_start_mark', None)
+ if mark:
+ return mark
+
+ # Try various places, starting with instance and parent
+ for obj in (validation_error.instance, validation_error.parent):
+ mark = _get_mark_or_first_member_mark(obj)
+ if mark:
+ return mark
+
+ def get_path(path, data):
+ if path:
+ return get_path(path[1:], data[path[0]])
+ else:
+ return data
# Try really hard to get the parent (which sometimes is not
# set) This digs it out of the validated structure if it's not
# on the validation_error.
- if path and not parent_mark:
- parent_path = list(path)[:-1]
- parent = get_path(parent_path, data)
+ path = validation_error.path
+ if path:
+ parent = get_path(list(path)[:-1], data)
if path[-1] in parent:
if isinstance(parent, dict):
- keylist = parent.keys()
+ keylist = list(parent.keys())
elif isinstance(parent, list):
keylist = parent
idx = keylist.index(path[-1])
- parent_mark = getattr(keylist[idx], '_start_mark', None)
-
- if instance_mark:
- location = '%s:%d' % (instance_mark.name, instance_mark.line + 1)
- elif parent_mark:
- location = '%s:%d' % (parent_mark.name, parent_mark.line + 1)
- elif path:
- location = 'At ' + ':'.join(path)
- else:
- location = '<unknown line>'
-
- message = '%s: %s' % (location, validation_error.message)
- super(ConfigError, self).__init__(message)
-
+ mark = getattr(keylist[idx], '_start_mark', None)
+ if mark:
+ return mark
-class ConfigSanityError(ConfigFormatError):
- """Same as ConfigFormatError, raised when config is written by Spack."""
+ # give up and return None if nothing worked
+ return None
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index fd4aae00cd..33942c362f 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Spack's installation tracking database.
The database serves two purposes:
@@ -39,6 +20,8 @@ provides a cache and a sanity checking mechanism for what is in the
filesystem.
"""
+import datetime
+import time
import os
import sys
import socket
@@ -46,21 +29,22 @@ import contextlib
from six import string_types
from six import iteritems
-from yaml.error import MarkedYAMLError, YAMLError
+from ruamel.yaml.error import MarkedYAMLError, YAMLError
import llnl.util.tty as tty
-from llnl.util.filesystem import join_path, mkdirp
-from llnl.util.lock import Lock, WriteTransaction, ReadTransaction
+from llnl.util.filesystem import mkdirp
import spack.store
-import spack.repository
+import spack.repo
import spack.spec
import spack.util.spack_yaml as syaml
import spack.util.spack_json as sjson
+from spack.filesystem_view import YamlFilesystemView
from spack.util.crypto import bit_length
from spack.directory_layout import DirectoryLayoutError
from spack.error import SpackError
from spack.version import Version
+from spack.util.lock import Lock, WriteTransaction, ReadTransaction, LockError
# DB goes in this directory underneath the root
@@ -70,12 +54,17 @@ _db_dirname = '.spack-db'
_db_version = Version('0.9.3')
# Timeout for spack database locks in seconds
-_db_lock_timeout = 60
+_db_lock_timeout = 120
# Types of dependencies tracked by the database
_tracked_deps = ('link', 'run')
+def _now():
+ """Returns the time since the epoch"""
+ return time.time()
+
+
def _autospec(function):
"""Decorator that automatically converts the argument of a single-arg
function to a Spec."""
@@ -103,14 +92,31 @@ class InstallRecord(object):
actually remove from the database until a spec has no installed
dependents left.
+ Args:
+ spec (Spec): spec tracked by the install record
+ path (str): path where the spec has been installed
+ installed (bool): whether or not the spec is currently installed
+ ref_count (int): number of specs that depend on this one
+ explicit (bool, optional): whether or not this spec was explicitly
+ installed, or pulled-in as a dependency of something else
+ installation_time (time, optional): time of the installation
"""
- def __init__(self, spec, path, installed, ref_count=0, explicit=False):
+ def __init__(
+ self,
+ spec,
+ path,
+ installed,
+ ref_count=0,
+ explicit=False,
+ installation_time=None
+ ):
self.spec = spec
self.path = str(path)
self.installed = bool(installed)
self.ref_count = ref_count
self.explicit = explicit
+ self.installation_time = installation_time or _now()
def to_dict(self):
return {
@@ -118,14 +124,15 @@ class InstallRecord(object):
'path': self.path,
'installed': self.installed,
'ref_count': self.ref_count,
- 'explicit': self.explicit
+ 'explicit': self.explicit,
+ 'installation_time': self.installation_time
}
@classmethod
def from_dict(cls, spec, dictionary):
- d = dictionary
- return InstallRecord(spec, d['path'], d['installed'], d['ref_count'],
- d.get('explicit', False))
+ d = dict(dictionary.items())
+ d.pop('spec', None)
+ return InstallRecord(spec, **d)
class Database(object):
@@ -159,37 +166,48 @@ class Database(object):
if db_dir is None:
# If the db_dir is not provided, default to within the db root.
- self._db_dir = join_path(self.root, _db_dirname)
+ self._db_dir = os.path.join(self.root, _db_dirname)
else:
# Allow customizing the database directory location for testing.
self._db_dir = db_dir
# Set up layout of database files within the db dir
- self._old_yaml_index_path = join_path(self._db_dir, 'index.yaml')
- self._index_path = join_path(self._db_dir, 'index.json')
- self._lock_path = join_path(self._db_dir, 'lock')
+ self._old_yaml_index_path = os.path.join(self._db_dir, 'index.yaml')
+ self._index_path = os.path.join(self._db_dir, 'index.json')
+ self._lock_path = os.path.join(self._db_dir, 'lock')
# This is for other classes to use to lock prefix directories.
- self.prefix_lock_path = join_path(self._db_dir, 'prefix_lock')
+ self.prefix_lock_path = os.path.join(self._db_dir, 'prefix_lock')
# Create needed directories and files
if not os.path.exists(self._db_dir):
mkdirp(self._db_dir)
# initialize rest of state.
- self.lock = Lock(self._lock_path)
+ self.db_lock_timeout = (
+ spack.config.get('config:db_lock_timeout') or _db_lock_timeout)
+ self.package_lock_timeout = (
+ spack.config.get('config:package_lock_timeout') or None)
+ tty.debug('DATABASE LOCK TIMEOUT: {0}s'.format(
+ str(self.db_lock_timeout)))
+ timeout_format_str = ('{0}s'.format(str(self.package_lock_timeout))
+ if self.package_lock_timeout else 'No timeout')
+ tty.debug('PACKAGE LOCK TIMEOUT: {0}'.format(
+ str(timeout_format_str)))
+ self.lock = Lock(self._lock_path,
+ default_timeout=self.db_lock_timeout)
self._data = {}
# whether there was an error at the start of a read transaction
self._error = None
- def write_transaction(self, timeout=_db_lock_timeout):
+ def write_transaction(self):
"""Get a write lock context manager for use in a `with` block."""
- return WriteTransaction(self.lock, self._read, self._write, timeout)
+ return WriteTransaction(self.lock, self._read, self._write)
- def read_transaction(self, timeout=_db_lock_timeout):
+ def read_transaction(self):
"""Get a read lock context manager for use in a `with` block."""
- return ReadTransaction(self.lock, self._read, timeout=timeout)
+ return ReadTransaction(self.lock, self._read)
def prefix_lock(self, spec):
"""Get a lock on a particular spec's installation directory.
@@ -210,26 +228,44 @@ class Database(object):
if prefix not in self._prefix_locks:
self._prefix_locks[prefix] = Lock(
self.prefix_lock_path,
- spec.dag_hash_bit_prefix(bit_length(sys.maxsize)), 1)
+ start=spec.dag_hash_bit_prefix(bit_length(sys.maxsize)),
+ length=1,
+ default_timeout=self.package_lock_timeout)
return self._prefix_locks[prefix]
@contextlib.contextmanager
def prefix_read_lock(self, spec):
prefix_lock = self.prefix_lock(spec)
+ prefix_lock.acquire_read()
+
try:
- prefix_lock.acquire_read(60)
yield self
- finally:
+ except LockError:
+ # This addresses the case where a nested lock attempt fails inside
+ # of this context manager
+ raise
+ except (Exception, KeyboardInterrupt):
+ prefix_lock.release_read()
+ raise
+ else:
prefix_lock.release_read()
@contextlib.contextmanager
def prefix_write_lock(self, spec):
prefix_lock = self.prefix_lock(spec)
+ prefix_lock.acquire_write()
+
try:
- prefix_lock.acquire_write(60)
yield self
- finally:
+ except LockError:
+ # This addresses the case where a nested lock attempt fails inside
+ # of this context manager
+ raise
+ except (Exception, KeyboardInterrupt):
+ prefix_lock.release_write()
+ raise
+ else:
prefix_lock.release_write()
def _write_to_file(self, stream):
@@ -347,7 +383,7 @@ class Database(object):
def invalid_record(hash_key, error):
msg = ("Invalid record in Spack database: "
"hash: %s, cause: %s: %s")
- msg %= (hash_key, type(e).__name__, str(e))
+ msg %= (hash_key, type(error).__name__, str(error))
raise CorruptDatabaseError(msg, self._index_path)
# Build up the database in three passes:
@@ -409,7 +445,7 @@ class Database(object):
self._data = {}
transaction = WriteTransaction(
- self.lock, _read_suppress_error, self._write, _db_lock_timeout
+ self.lock, _read_suppress_error, self._write
)
with transaction:
@@ -442,12 +478,18 @@ class Database(object):
tty.debug(
'RECONSTRUCTING FROM SPEC.YAML: {0}'.format(spec))
explicit = True
+ inst_time = os.stat(spec.prefix).st_ctime
if old_data is not None:
old_info = old_data.get(spec.dag_hash())
if old_info is not None:
explicit = old_info.explicit
+ inst_time = old_info.installation_time
- self._add(spec, directory_layout, explicit=explicit)
+ extra_args = {
+ 'explicit': explicit,
+ 'installation_time': inst_time
+ }
+ self._add(spec, directory_layout, **extra_args)
processed_specs.add(spec)
@@ -479,7 +521,8 @@ class Database(object):
kwargs = {
'spec': entry.spec,
'directory_layout': layout,
- 'explicit': entry.explicit
+ 'explicit': entry.explicit,
+ 'installation_time': entry.installation_time # noqa: E501
}
self._add(**kwargs)
processed_specs.add(entry.spec)
@@ -566,7 +609,7 @@ class Database(object):
if os.access(self._db_dir, os.R_OK | os.W_OK):
# if we can write, then read AND write a JSON file.
self._read_from_file(self._old_yaml_index_path, format='yaml')
- with WriteTransaction(self.lock, timeout=_db_lock_timeout):
+ with WriteTransaction(self.lock):
self._write(None, None, None)
else:
# Read chck for a YAML file if we can't find JSON.
@@ -575,27 +618,56 @@ class Database(object):
else:
# The file doesn't exist, try to traverse the directory.
# reindex() takes its own write lock, so no lock here.
- with WriteTransaction(self.lock, timeout=_db_lock_timeout):
+ with WriteTransaction(self.lock):
self._write(None, None, None)
self.reindex(spack.store.layout)
- def _add(self, spec, directory_layout=None, explicit=False):
+ def _add(
+ self,
+ spec,
+ directory_layout=None,
+ explicit=False,
+ installation_time=None
+ ):
"""Add an install record for this spec to the database.
Assumes spec is installed in ``layout.path_for_spec(spec)``.
Also ensures dependencies are present and updated in the DB as
- either intsalled or missing.
+ either installed or missing.
+
+ Args:
+ spec: spec to be added
+ directory_layout: layout of the spec installation
+ **kwargs:
+
+ explicit
+ Possible values: True, False, any
+
+ A spec that was installed following a specific user
+ request is marked as explicit. If instead it was
+ pulled-in as a dependency of a user requested spec
+ it's considered implicit.
+
+ installation_time
+ Date and time of installation
"""
if not spec.concrete:
raise NonConcreteSpecAddError(
"Specs added to DB must be concrete.")
+ # Retrieve optional arguments
+ installation_time = installation_time or _now()
+
for dep in spec.dependencies(_tracked_deps):
dkey = dep.dag_hash()
if dkey not in self._data:
- self._add(dep, directory_layout, explicit=False)
+ extra_args = {
+ 'explicit': False,
+ 'installation_time': installation_time
+ }
+ self._add(dep, directory_layout, **extra_args)
key = spec.dag_hash()
if key not in self._data:
@@ -613,8 +685,13 @@ class Database(object):
# Create a new install record with no deps initially.
new_spec = spec.copy(deps=False)
+ extra_args = {
+ 'explicit': explicit,
+ 'installation_time': installation_time
+ }
self._data[key] = InstallRecord(
- new_spec, path, installed, ref_count=0, explicit=explicit)
+ new_spec, path, installed, ref_count=0, **extra_args
+ )
# Connect dependencies from the DB to the new copy.
for name, dep in iteritems(spec.dependencies_dict(_tracked_deps)):
@@ -757,7 +834,8 @@ class Database(object):
the given spec
"""
if extensions_layout is None:
- extensions_layout = spack.store.extensions
+ view = YamlFilesystemView(extendee_spec.prefix, spack.store.layout)
+ extensions_layout = view.extensions_layout
for spec in self.query():
try:
extensions_layout.check_activated(extendee_spec, spec)
@@ -766,48 +844,68 @@ class Database(object):
continue
# TODO: conditional way to do this instead of catching exceptions
- def query(self, query_spec=any, known=any, installed=True, explicit=any):
- """Run a query on the database.
-
- ``query_spec``
- Queries iterate through specs in the database and return
- those that satisfy the supplied ``query_spec``. If
- query_spec is `any`, This will match all specs in the
- database. If it is a spec, we'll evaluate
- ``spec.satisfies(query_spec)``.
-
- The query can be constrained by two additional attributes:
-
- ``known``
- Possible values: True, False, any
-
- Specs that are "known" are those for which Spack can
- locate a ``package.py`` file -- i.e., Spack "knows" how to
- install them. Specs that are unknown may represent
- packages that existed in a previous version of Spack, but
- have since either changed their name or been removed.
-
- ``installed``
- Possible values: True, False, any
-
- Specs for which a prefix exists are "installed". A spec
- that is NOT installed will be in the database if some
- other spec depends on it but its installation has gone
- away since Spack installed it.
-
- TODO: Specs are a lot like queries. Should there be a
- wildcard spec object, and should specs have attributes
- like installed and known that can be queried? Or are
- these really special cases that only belong here?
+ def query(
+ self,
+ query_spec=any,
+ known=any,
+ installed=True,
+ explicit=any,
+ start_date=None,
+ end_date=None,
+ hashes=None
+ ):
+ """Run a query on the database
+
+ Args:
+ query_spec: queries iterate through specs in the database and
+ return those that satisfy the supplied ``query_spec``. If
+ query_spec is `any`, This will match all specs in the
+ database. If it is a spec, we'll evaluate
+ ``spec.satisfies(query_spec)``
+
+ known (bool or any, optional): Specs that are "known" are those
+ for which Spack can locate a ``package.py`` file -- i.e.,
+ Spack "knows" how to install them. Specs that are unknown may
+ represent packages that existed in a previous version of
+ Spack, but have since either changed their name or
+ been removed
+
+ installed (bool or any, optional): Specs for which a prefix exists
+ are "installed". A spec that is NOT installed will be in the
+ database if some other spec depends on it but its installation
+ has gone away since Spack installed it.
+
+ explicit (bool or any, optional): A spec that was installed
+ following a specific user request is marked as explicit. If
+ instead it was pulled-in as a dependency of a user requested
+ spec it's considered implicit.
+
+ start_date (datetime, optional): filters the query discarding
+ specs that have been installed before ``start_date``.
+
+ end_date (datetime, optional): filters the query discarding
+ specs that have been installed after ``end_date``.
+
+ hashes (container): list or set of hashes that we can use to
+ restrict the search
+
+ Returns:
+ list of specs that match the query
"""
+ # TODO: Specs are a lot like queries. Should there be a
+ # TODO: wildcard spec object, and should specs have attributes
+ # TODO: like installed and known that can be queried? Or are
+ # TODO: these really special cases that only belong here?
+
+ # TODO: handling of hashes restriction is not particularly elegant.
with self.read_transaction():
# Just look up concrete specs with hashes; no fancy search.
- if (isinstance(query_spec, spack.spec.Spec) and
- query_spec._concrete):
+ if isinstance(query_spec, spack.spec.Spec) and query_spec.concrete:
hash_key = query_spec.dag_hash()
- if hash_key in self._data:
+ if (hash_key in self._data and
+ (not hashes or hash_key in hashes)):
return [self._data[hash_key].spec]
else:
return []
@@ -815,14 +913,29 @@ class Database(object):
# Abstract specs require more work -- currently we test
# against everything.
results = []
+ start_date = start_date or datetime.datetime.min
+ end_date = end_date or datetime.datetime.max
+
for key, rec in self._data.items():
+ if hashes is not None and rec.spec.dag_hash() not in hashes:
+ continue
+
if installed is not any and rec.installed != installed:
continue
+
if explicit is not any and rec.explicit != explicit:
continue
- if known is not any and spack.repo.exists(
+
+ if known is not any and spack.repo.path.exists(
rec.spec.name) != known:
continue
+
+ inst_date = datetime.datetime.fromtimestamp(
+ rec.installation_time
+ )
+ if not (start_date < inst_date < end_date):
+ continue
+
if query_spec is any or rec.spec.satisfies(query_spec):
results.append(rec.spec)
@@ -835,7 +948,8 @@ class Database(object):
query. Returns None if no installed package matches.
"""
- concrete_specs = self.query(query_spec, known, installed)
+ concrete_specs = self.query(
+ query_spec, known=known, installed=installed)
assert len(concrete_specs) <= 1
return concrete_specs[0] if concrete_specs else None
diff --git a/lib/spack/spack/dependency.py b/lib/spack/spack/dependency.py
index 99a16c9d45..34b9a85537 100644
--- a/lib/spack/spack/dependency.py
+++ b/lib/spack/spack/dependency.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Data structures that represent Spack's dependency relationships.
"""
from six import string_types
-import spack
+import spack.spec
#: The types of dependency relationships that Spack understands.
@@ -72,7 +53,7 @@ class Dependency(object):
This class differs from ``spack.spec.DependencySpec`` because it
represents metadata at the ``Package`` level.
``spack.spec.DependencySpec`` is a descriptor for an actual package
- confiuguration, while ``Dependency`` is a descriptor for a package's
+ configuration, while ``Dependency`` is a descriptor for a package's
dependency *requirements*.
A dependency is a requirement for a configuration of another package
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py
index 7255875541..9125d55e9a 100644
--- a/lib/spack/spack/directives.py
+++ b/lib/spack/spack/directives.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This package contains directives that can be used within a package.
Directives are functions that can be called inside a package
@@ -48,24 +29,20 @@ The available directives are:
import collections
import functools
-import inspect
import os.path
import re
from six import string_types
import llnl.util.lang
-from llnl.util.filesystem import join_path
-import spack
import spack.error
import spack.spec
import spack.url
+import spack.variant
from spack.dependency import Dependency, default_deptype, canonical_deptype
from spack.fetch_strategy import from_kwargs
from spack.patch import Patch
from spack.resource import Resource
-from spack.spec import Spec, parse_anonymous_spec
-from spack.variant import Variant
from spack.version import Version
__all__ = []
@@ -74,7 +51,7 @@ __all__ = []
reserved_names = ['patches']
-class DirectiveMetaMixin(type):
+class DirectiveMeta(type):
"""Flushes the directives that were temporarily stored in the staging
area into the package.
"""
@@ -83,7 +60,7 @@ class DirectiveMetaMixin(type):
_directive_names = set()
_directives_to_be_executed = []
- def __new__(mcs, name, bases, attr_dict):
+ def __new__(cls, name, bases, attr_dict):
# Initialize the attribute containing the list of directives
# to be executed. Here we go reversed because we want to execute
# commands:
@@ -107,27 +84,27 @@ class DirectiveMetaMixin(type):
# Move things to be executed from module scope (where they
# are collected first) to class scope
- if DirectiveMetaMixin._directives_to_be_executed:
+ if DirectiveMeta._directives_to_be_executed:
attr_dict['_directives_to_be_executed'].extend(
- DirectiveMetaMixin._directives_to_be_executed)
- DirectiveMetaMixin._directives_to_be_executed = []
+ DirectiveMeta._directives_to_be_executed)
+ DirectiveMeta._directives_to_be_executed = []
- return super(DirectiveMetaMixin, mcs).__new__(
- mcs, name, bases, attr_dict)
+ return super(DirectiveMeta, cls).__new__(
+ cls, name, bases, attr_dict)
def __init__(cls, name, bases, attr_dict):
# The class is being created: if it is a package we must ensure
# that the directives are called on the class to set it up
- module = inspect.getmodule(cls)
- if 'spack.pkg' in module.__name__:
+
+ if 'spack.pkg' in cls.__module__:
# Package name as taken
# from llnl.util.lang.get_calling_module_name
- pkg_name = module.__name__.split('.')[-1]
+ pkg_name = cls.__module__.split('.')[-1]
setattr(cls, 'name', pkg_name)
# Ensure the presence of the dictionaries associated
# with the directives
- for d in DirectiveMetaMixin._directive_names:
+ for d in DirectiveMeta._directive_names:
setattr(cls, d, {})
# Lazily execute directives
@@ -136,9 +113,9 @@ class DirectiveMetaMixin(type):
# Ignore any directives executed *within* top-level
# directives by clearing out the queue they're appended to
- DirectiveMetaMixin._directives_to_be_executed = []
+ DirectiveMeta._directives_to_be_executed = []
- super(DirectiveMetaMixin, cls).__init__(name, bases, attr_dict)
+ super(DirectiveMeta, cls).__init__(name, bases, attr_dict)
@staticmethod
def directive(dicts=None):
@@ -188,7 +165,7 @@ class DirectiveMetaMixin(type):
message = "dicts arg must be list, tuple, or string. Found {0}"
raise TypeError(message.format(type(dicts)))
# Add the dictionary names if not already there
- DirectiveMetaMixin._directive_names |= set(dicts)
+ DirectiveMeta._directive_names |= set(dicts)
# This decorator just returns the directive functions
def _decorator(decorated_function):
@@ -202,7 +179,7 @@ class DirectiveMetaMixin(type):
# This allows nested directive calls in packages. The
# caller can return the directive if it should be queued.
def remove_directives(arg):
- directives = DirectiveMetaMixin._directives_to_be_executed
+ directives = DirectiveMeta._directives_to_be_executed
if isinstance(arg, (list, tuple)):
# Descend into args that are lists or tuples
for a in arg:
@@ -228,32 +205,32 @@ class DirectiveMetaMixin(type):
if not isinstance(values, collections.Sequence):
values = (values, )
- DirectiveMetaMixin._directives_to_be_executed.extend(values)
+ DirectiveMeta._directives_to_be_executed.extend(values)
# wrapped function returns same result as original so
# that we can nest directives
return result
-
return _wrapper
return _decorator
-directive = DirectiveMetaMixin.directive
+directive = DirectiveMeta.directive
@directive('versions')
def version(ver, checksum=None, **kwargs):
- """Adds a version and metadata describing how to fetch it.
- Metadata is just stored as a dict in the package's versions
- dictionary. Package must turn it into a valid fetch strategy
- later.
+ """Adds a version and metadata describing how to fetch its source code.
+
+ Metadata is stored as a dict of ``kwargs`` in the package class's
+ ``versions`` dictionary.
+
+ The ``dict`` of arguments is turned into a valid fetch strategy
+ later. See ``spack.fetch_strategy.for_package_version()``.
"""
def _execute_version(pkg):
- # TODO: checksum vs md5 distinction is confusing -- fix this.
- # special case checksum for backward compatibility
if checksum:
- kwargs['md5'] = checksum
+ kwargs['checksum'] = checksum
# Store kwargs for the package to later with a fetch_strategy.
pkg.versions[Version(ver)] = kwargs
@@ -267,9 +244,9 @@ def _depends_on(pkg, spec, when=None, type=default_deptype, patches=None):
# If when is None or True make sure the condition is always satisfied
if when is None or when is True:
when = pkg.name
- when_spec = parse_anonymous_spec(when, pkg.name)
+ when_spec = spack.spec.parse_anonymous_spec(when, pkg.name)
- dep_spec = Spec(spec)
+ dep_spec = spack.spec.Spec(spec)
if pkg.name == dep_spec.name:
raise CircularReferenceError(
"Package '%s' cannot depend on itself." % pkg.name)
@@ -330,7 +307,7 @@ def conflicts(conflict_spec, when=None, msg=None):
def _execute_conflicts(pkg):
# If when is not specified the conflict always holds
condition = pkg.name if when is None else when
- when_spec = parse_anonymous_spec(condition, pkg.name)
+ when_spec = spack.spec.parse_anonymous_spec(condition, pkg.name)
# Save in a list the conflicts and the associated custom messages
when_spec_list = pkg.conflicts.setdefault(conflict_spec, [])
@@ -362,13 +339,14 @@ def depends_on(spec, when=None, type=default_deptype, patches=None):
@directive(('extendees', 'dependencies'))
def extends(spec, **kwargs):
- """Same as depends_on, but dependency is symlinked into parent prefix.
+ """Same as depends_on, but allows symlinking into dependency's
+ prefix tree.
This is for Python and other language modules where the module
needs to be installed into the prefix of the Python installation.
Spack handles this by installing modules into their own prefix,
but allowing ONE module version to be symlinked into a parent
- Python install at a time.
+ Python install at a time, using ``spack activate``.
keyword arguments can be passed to extends() so that extension
packages can pass parameters to the extendee's extension
@@ -381,9 +359,9 @@ def extends(spec, **kwargs):
# msg = 'Packages can extend at most one other package.'
# raise DirectiveError(directive, msg)
- when = kwargs.pop('when', pkg.name)
+ when = kwargs.get('when', pkg.name)
_depends_on(pkg, spec, when=when)
- pkg.extendees[spec] = (Spec(spec), kwargs)
+ pkg.extendees[spec] = (spack.spec.Spec(spec), kwargs)
return _execute_extends
@@ -395,7 +373,7 @@ def provides(*specs, **kwargs):
"""
def _execute_provides(pkg):
spec_string = kwargs.get('when', pkg.name)
- provider_spec = parse_anonymous_spec(spec_string, pkg.name)
+ provider_spec = spack.spec.parse_anonymous_spec(spec_string, pkg.name)
for string in specs:
for provided_spec in spack.spec.parse(string):
@@ -432,7 +410,8 @@ def patch(url_or_filename, level=1, when=None, working_dir=".", **kwargs):
"""
def _execute_patch(pkg_or_dep):
constraint = pkg_or_dep.name if when is None else when
- when_spec = parse_anonymous_spec(constraint, pkg_or_dep.name)
+ when_spec = spack.spec.parse_anonymous_spec(
+ constraint, pkg_or_dep.name)
# if this spec is identical to some other, then append this
# patch to the existing list.
@@ -492,7 +471,7 @@ def variant(
msg = "Invalid variant name in {0}: '{1}'"
raise DirectiveError(directive, msg.format(pkg.name, name))
- pkg.variants[name] = Variant(
+ pkg.variants[name] = spack.variant.Variant(
name, default, description, values, multi, validator
)
return _execute_variant
@@ -522,24 +501,24 @@ def resource(**kwargs):
# Check if the path is relative
if os.path.isabs(destination):
- message = 'The destination keyword of a resource directive '
- 'can\'t be an absolute path.\n'
+ message = ('The destination keyword of a resource directive '
+ 'can\'t be an absolute path.\n')
message += "\tdestination : '{dest}\n'".format(dest=destination)
raise RuntimeError(message)
# Check if the path falls within the main package stage area
test_path = 'stage_folder_root'
normalized_destination = os.path.normpath(
- join_path(test_path, destination)
+ os.path.join(test_path, destination)
) # Normalized absolute path
if test_path not in normalized_destination:
- message = "The destination folder of a resource must fall "
- "within the main package stage directory.\n"
+ message = ("The destination folder of a resource must fall "
+ "within the main package stage directory.\n")
message += "\tdestination : '{dest}'\n".format(dest=destination)
raise RuntimeError(message)
- when_spec = parse_anonymous_spec(when, pkg.name)
+ when_spec = spack.spec.parse_anonymous_spec(when, pkg.name)
resources = pkg.resources.setdefault(when_spec, [])
name = kwargs.get('name')
fetcher = from_kwargs(**kwargs)
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index e07db0ede4..9fc0c08d22 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -1,37 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import shutil
import glob
import tempfile
-import yaml
import re
-from llnl.util.filesystem import join_path, mkdirp
+import ruamel.yaml as yaml
-import spack
+from llnl.util.filesystem import mkdirp, chgrp
+
+import spack.config
import spack.spec
from spack.error import SpackError
@@ -128,7 +110,6 @@ class ExtensionsLayout(object):
"""
def __init__(self, root, **kwargs):
self.root = root
- self.link = kwargs.get("link", os.symlink)
def add_extension(self, spec, ext_spec):
"""Add to the list of currently installed extensions."""
@@ -227,7 +208,7 @@ class YamlDirectoryLayout(DirectoryLayout):
with open(path) as f:
spec = spack.spec.Spec.from_yaml(f)
except Exception as e:
- if spack.debug:
+ if spack.config.get('config:debug'):
raise
raise SpecReadError(
'Unable to read file: %s' % path, 'Cause: ' + str(e))
@@ -239,22 +220,22 @@ class YamlDirectoryLayout(DirectoryLayout):
def spec_file_path(self, spec):
"""Gets full path to spec file"""
_check_concrete(spec)
- return join_path(self.metadata_path(spec), self.spec_file_name)
+ return os.path.join(self.metadata_path(spec), self.spec_file_name)
def metadata_path(self, spec):
- return join_path(self.path_for_spec(spec), self.metadata_dir)
+ return os.path.join(self.path_for_spec(spec), self.metadata_dir)
def build_log_path(self, spec):
- return join_path(self.path_for_spec(spec), self.metadata_dir,
- self.build_log_name)
+ return os.path.join(self.path_for_spec(spec), self.metadata_dir,
+ self.build_log_name)
def build_env_path(self, spec):
- return join_path(self.path_for_spec(spec), self.metadata_dir,
- self.build_env_name)
+ return os.path.join(self.path_for_spec(spec), self.metadata_dir,
+ self.build_env_name)
def build_packages_path(self, spec):
- return join_path(self.path_for_spec(spec), self.metadata_dir,
- self.packages_dir)
+ return os.path.join(self.path_for_spec(spec), self.metadata_dir,
+ self.packages_dir)
def create_install_directory(self, spec):
_check_concrete(spec)
@@ -263,7 +244,19 @@ class YamlDirectoryLayout(DirectoryLayout):
if prefix:
raise InstallDirectoryAlreadyExistsError(prefix)
- mkdirp(self.metadata_path(spec))
+ # Create install directory with properly configured permissions
+ # Cannot import at top of file
+ from spack.package_prefs import get_package_dir_permissions
+ from spack.package_prefs import get_package_group
+ group = get_package_group(spec)
+ perms = get_package_dir_permissions(spec)
+ mkdirp(spec.prefix, mode=perms)
+ if group:
+ chgrp(spec.prefix, group)
+ # Need to reset the sticky group bit after chgrp
+ os.chmod(spec.prefix, perms)
+
+ mkdirp(self.metadata_path(spec), mode=perms)
self.write_spec(spec, self.spec_file_path(spec))
def check_installed(self, spec):
@@ -302,7 +295,7 @@ class YamlDirectoryLayout(DirectoryLayout):
path_elems = ["*"] * len(self.path_scheme.split(os.sep))
path_elems += [self.metadata_dir, self.spec_file_name]
- pattern = join_path(self.root, *path_elems)
+ pattern = os.path.join(self.root, *path_elems)
spec_files = glob.glob(pattern)
return [self.read_spec(s) for s in spec_files]
@@ -313,14 +306,14 @@ class YamlDirectoryLayout(DirectoryLayout):
return by_hash
-class YamlExtensionsLayout(ExtensionsLayout):
- """Implements globally activated extensions within a YamlDirectoryLayout.
+class YamlViewExtensionsLayout(ExtensionsLayout):
+ """Maintain extensions within a view.
"""
def __init__(self, root, layout):
"""layout is the corresponding YamlDirectoryLayout object for which
we implement extensions.
"""
- super(YamlExtensionsLayout, self).__init__(root)
+ super(YamlViewExtensionsLayout, self).__init__(root)
self.layout = layout
self.extension_file_name = 'extensions.yaml'
@@ -354,19 +347,29 @@ class YamlExtensionsLayout(ExtensionsLayout):
raise NoSuchExtensionError(spec, ext_spec)
def extension_file_path(self, spec):
- """Gets full path to an installed package's extension file"""
+ """Gets full path to an installed package's extension file, which
+ keeps track of all the extensions for that package which have been
+ added to this view.
+ """
_check_concrete(spec)
- return join_path(self.layout.metadata_path(spec),
- self.extension_file_name)
+ normalize_path = lambda p: (
+ os.path.abspath(p).rstrip(os.path.sep))
+ if normalize_path(spec.prefix) == normalize_path(self.root):
+ # For backwards compatibility, when the root is the extended
+ # package's installation directory, do not include the spec name
+ # as a subdirectory.
+ components = [self.root, self.layout.metadata_dir,
+ self.extension_file_name]
+ else:
+ components = [self.root, self.layout.metadata_dir, spec.name,
+ self.extension_file_name]
+ return os.path.join(*components)
def extension_map(self, spec):
"""Defensive copying version of _extension_map() for external API."""
_check_concrete(spec)
return self._extension_map(spec).copy()
- def extendee_target_directory(self, extendee):
- return extendee.prefix
-
def remove_extension(self, spec, ext_spec):
_check_concrete(spec)
_check_concrete(ext_spec)
@@ -419,6 +422,8 @@ class YamlExtensionsLayout(ExtensionsLayout):
# Create a temp file in the same directory as the actual file.
dirname, basename = os.path.split(path)
+ mkdirp(dirname)
+
tmp = tempfile.NamedTemporaryFile(
prefix=basename, dir=dirname, delete=False)
@@ -436,23 +441,6 @@ class YamlExtensionsLayout(ExtensionsLayout):
os.rename(tmp.name, path)
-class YamlViewExtensionsLayout(YamlExtensionsLayout):
- """Governs the directory layout present when creating filesystem views in a
- certain root folder.
-
- Meant to replace YamlDirectoryLayout when working with filesystem views.
- """
-
- def extension_file_path(self, spec):
- """Gets the full path to an installed package's extension file."""
- _check_concrete(spec)
- return join_path(self.root, self.layout.metadata_dir, spec.name,
- self.extension_file_name)
-
- def extendee_target_directory(self, extendee):
- return self.root
-
-
class DirectoryLayoutError(SpackError):
"""Superclass for directory layout errors."""
@@ -492,7 +480,7 @@ class InstallDirectoryAlreadyExistsError(DirectoryLayoutError):
def __init__(self, path):
super(InstallDirectoryAlreadyExistsError, self).__init__(
- "Install path %s already exists!")
+ "Install path %s already exists!" % path)
class SpecReadError(DirectoryLayoutError):
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
index d85c67d7fc..40d63eaa0e 100644
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -1,559 +1,906 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import collections
-import inspect
-import json
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
+import re
import sys
-import os.path
-import subprocess
+import shutil
+import jsonschema
+import ruamel.yaml
-class NameModifier(object):
+import llnl.util.filesystem as fs
+import llnl.util.tty as tty
- def __init__(self, name, **kwargs):
- self.name = name
- self.args = {'name': name}
- self.args.update(kwargs)
+import spack.error
+import spack.repo
+import spack.schema.env
+import spack.spec
+import spack.util.spack_json as sjson
+import spack.config
+from spack.spec import Spec
- def update_args(self, **kwargs):
- self.__dict__.update(kwargs)
- self.args.update(kwargs)
+#: environment variable used to indicate the active environment
+spack_env_var = 'SPACK_ENV'
-class NameValueModifier(object):
- def __init__(self, name, value, **kwargs):
- self.name = name
- self.value = value
- self.separator = kwargs.get('separator', ':')
- self.args = {'name': name, 'value': value, 'separator': self.separator}
- self.args.update(kwargs)
+#: currently activated environment
+_active_environment = None
- def update_args(self, **kwargs):
- self.__dict__.update(kwargs)
- self.args.update(kwargs)
+#: path where environments are stored in the spack tree
+env_path = os.path.join(spack.paths.var_path, 'environments')
-class SetEnv(NameValueModifier):
- def execute(self):
- os.environ[self.name] = str(self.value)
+#: Name of the input yaml file for an environment
+manifest_name = 'spack.yaml'
-class AppendFlagsEnv(NameValueModifier):
+#: Name of the input yaml file for an environment
+lockfile_name = 'spack.lock'
- def execute(self):
- if self.name in os.environ and os.environ[self.name]:
- os.environ[self.name] += self.separator + str(self.value)
- else:
- os.environ[self.name] = str(self.value)
+#: Name of the directory where environments store repos, logs, views
+env_subdir_name = '.spack-env'
-class UnsetEnv(NameModifier):
- def execute(self):
- # Avoid throwing if the variable was not set
- os.environ.pop(self.name, None)
+#: default spack.yaml file to put in new environments
+default_manifest_yaml = """\
+# This is a Spack Environment file.
+#
+# It describes a set of packages to be installed, along with
+# configuration settings.
+spack:
+ # add package specs to the `specs` list
+ specs:
+ -
+"""
+#: regex for validating enviroment names
+valid_environment_name_re = r'^\w[\w-]*$'
+#: version of the lockfile format. Must increase monotonically.
+lockfile_format_version = 1
-class SetPath(NameValueModifier):
+#: legal first keys in the spack.yaml manifest file
+env_schema_keys = ('spack', 'env')
- def execute(self):
- string_path = concatenate_paths(self.value, separator=self.separator)
- os.environ[self.name] = string_path
+#: jsonschema validator for environments
+_validator = None
-class AppendPath(NameValueModifier):
+def valid_env_name(name):
+ return re.match(valid_environment_name_re, name)
- def execute(self):
- environment_value = os.environ.get(self.name, '')
- directories = environment_value.split(
- self.separator) if environment_value else []
- directories.append(os.path.normpath(self.value))
- os.environ[self.name] = self.separator.join(directories)
+def validate_env_name(name):
+ if not valid_env_name(name):
+ raise ValueError((
+ "'%s': names must start with a letter, and only contain "
+ "letters, numbers, _, and -.") % name)
+ return name
-class PrependPath(NameValueModifier):
- def execute(self):
- environment_value = os.environ.get(self.name, '')
- directories = environment_value.split(
- self.separator) if environment_value else []
- directories = [os.path.normpath(self.value)] + directories
- os.environ[self.name] = self.separator.join(directories)
+def activate(env, use_env_repo=False):
+ """Activate an environment.
+ To activate an environment, we add its configuration scope to the
+ existing Spack configuration, and we set active to the current
+ environment.
-class RemovePath(NameValueModifier):
+ Arguments:
+ env (Environment): the environment to activate
+ use_env_repo (bool): use the packages exactly as they appear in the
+ environment's repository
- def execute(self):
- environment_value = os.environ.get(self.name, '')
- directories = environment_value.split(
- self.separator) if environment_value else []
- directories = [os.path.normpath(x) for x in directories
- if x != os.path.normpath(self.value)]
- os.environ[self.name] = self.separator.join(directories)
+ TODO: Add support for views here. Activation should set up the shell
+ TODO: environment to use the activated spack environment.
+ """
+ global _active_environment
+
+ _active_environment = env
+ prepare_config_scope(_active_environment)
+ if use_env_repo:
+ spack.repo.path.put_first(_active_environment.repo)
+
+ tty.debug("Using environmennt '%s'" % _active_environment.name)
-class EnvironmentModifications(object):
- """Keeps track of requests to modify the current environment.
+def deactivate():
+ """Undo any configuration or repo settings modified by ``activate()``.
- Each call to a method to modify the environment stores the extra
- information on the caller in the request:
+ Returns:
+ (bool): True if an environment was deactivated, False if no
+ environment was active.
- * 'filename' : filename of the module where the caller is defined
- * 'lineno': line number where the request occurred
- * 'context' : line of code that issued the request that failed
"""
+ global _active_environment
- def __init__(self, other=None):
- """Initializes a new instance, copying commands from 'other'
- if it is not None.
+ if not _active_environment:
+ return
- Args:
- other (EnvironmentModifications): list of environment modifications
- to be extended (optional)
- """
- self.env_modifications = []
- if other is not None:
- self.extend(other)
-
- def __iter__(self):
- return iter(self.env_modifications)
-
- def __len__(self):
- return len(self.env_modifications)
-
- def extend(self, other):
- self._check_other(other)
- self.env_modifications.extend(other.env_modifications)
-
- @staticmethod
- def _check_other(other):
- if not isinstance(other, EnvironmentModifications):
- raise TypeError(
- 'other must be an instance of EnvironmentModifications')
-
- def _get_outside_caller_attributes(self):
- stack = inspect.stack()
- try:
- _, filename, lineno, _, context, index = stack[2]
- context = context[index].strip()
- except Exception:
- filename = 'unknown file'
- lineno = 'unknown line'
- context = 'unknown context'
- args = {'filename': filename, 'lineno': lineno, 'context': context}
- return args
-
- def set(self, name, value, **kwargs):
- """Stores a request to set an environment variable.
-
- Args:
- name: name of the environment variable to be set
- value: value of the environment variable
- """
- kwargs.update(self._get_outside_caller_attributes())
- item = SetEnv(name, value, **kwargs)
- self.env_modifications.append(item)
+ deactivate_config_scope(_active_environment)
- def append_flags(self, name, value, sep=' ', **kwargs):
- """
- Stores in the current object a request to append to an env variable
+ # use _repo so we only remove if a repo was actually constructed
+ if _active_environment._repo:
+ spack.repo.path.remove(_active_environment._repo)
- Args:
- name: name of the environment variable to be appended to
- value: value to append to the environment variable
- Appends with spaces separating different additions to the variable
- """
- kwargs.update(self._get_outside_caller_attributes())
- kwargs.update({'separator': sep})
- item = AppendFlagsEnv(name, value, **kwargs)
- self.env_modifications.append(item)
+ tty.debug("Deactivated environmennt '%s'" % _active_environment.name)
+ _active_environment = None
- def unset(self, name, **kwargs):
- """Stores a request to unset an environment variable.
- Args:
- name: name of the environment variable to be set
- """
- kwargs.update(self._get_outside_caller_attributes())
- item = UnsetEnv(name, **kwargs)
- self.env_modifications.append(item)
+def find_environment(args):
+ """Find active environment from args, spack.yaml, or environment variable.
- def set_path(self, name, elements, **kwargs):
- """Stores a request to set a path generated from a list.
+ This is called in ``spack.main`` to figure out which environment to
+ activate.
- Args:
- name: name o the environment variable to be set.
- elements: elements of the path to set.
- """
- kwargs.update(self._get_outside_caller_attributes())
- item = SetPath(name, elements, **kwargs)
- self.env_modifications.append(item)
+ Check for an environment in this order:
+ 1. via ``spack -e ENV`` or ``spack -D DIR`` (arguments)
+ 2. as a spack.yaml file in the current directory, or
+ 3. via a path in the SPACK_ENV environment variable.
- def append_path(self, name, path, **kwargs):
- """Stores a request to append a path to a path list.
+ If an environment is found, read it in. If not, return None.
- Args:
- name: name of the path list in the environment
- path: path to be appended
- """
- kwargs.update(self._get_outside_caller_attributes())
- item = AppendPath(name, path, **kwargs)
- self.env_modifications.append(item)
+ Arguments:
+ args (Namespace): argparse namespace wtih command arguments
- def prepend_path(self, name, path, **kwargs):
- """Same as `append_path`, but the path is pre-pended.
+ Returns:
+ (Environment): a found environment, or ``None``
+ """
+ # try arguments
+ env = getattr(args, 'env', None)
- Args:
- name: name of the path list in the environment
- path: path to be pre-pended
- """
- kwargs.update(self._get_outside_caller_attributes())
- item = PrependPath(name, path, **kwargs)
- self.env_modifications.append(item)
+ # treat env as a name
+ if env:
+ if exists(env):
+ return read(env)
- def remove_path(self, name, path, **kwargs):
- """Stores a request to remove a path from a path list.
+ else:
+ # if env was specified, see if it is a dirctory otherwise, look
+ # at env_dir (env and env_dir are mutually exclusive)
+ env = getattr(args, 'env_dir', None)
- Args:
- name: name of the path list in the environment
- path: path to be removed
- """
- kwargs.update(self._get_outside_caller_attributes())
- item = RemovePath(name, path, **kwargs)
- self.env_modifications.append(item)
+ # if no argument, look for a manifest file
+ if not env:
+ if os.path.exists(manifest_name):
+ env = os.getcwd()
- def group_by_name(self):
- """Returns a dict of the modifications grouped by variable name.
+ # if no env, env_dir, or manifest try the environment
+ if not env:
+ env = os.environ.get(spack_env_var)
- Returns:
- dict mapping the environment variable name to the modifications to
- be done on it
+ # nothing was set; there's no active environment
+ if not env:
+ return None
+
+ # if we get here, env isn't the name of a spack environment; it has
+ # to be a path to an environment, or there is something wrong.
+ if is_env_dir(env):
+ return Environment(env)
+
+ raise SpackEnvironmentError('no environment in %s' % env)
+
+
+def get_env(args, cmd_name, required=True):
+ """Used by commands to get the active environment.
+
+ This first checks for an ``env`` argument, then looks at the
+ ``active`` environment. We check args first because Spack's
+ subcommand arguments are parsed *after* the ``-e`` and ``-D``
+ arguments to ``spack``. So there may be an ``env`` argument that is
+ *not* the active environment, and we give it precedence.
+
+ This is used by a number of commands for determining whether there is
+ an active environment.
+
+ If an environment is not found *and* is required, print an error
+ message that says the calling command *needs* an active environment.
+
+ Arguments:
+ args (Namespace): argparse namespace wtih command arguments
+ cmd_name (str): name of calling command
+ required (bool): if ``False``, return ``None`` if no environment
+ is found instead of raising an exception.
+
+ Returns:
+ (Environment): if there is an arg or active environment
+ """
+ # try argument first
+ env = getattr(args, 'env', None)
+ if env:
+ if exists(env):
+ return read(env)
+ elif is_env_dir(env):
+ return Environment(env)
+ else:
+ raise SpackEnvironmentError('no environment in %s' % env)
+
+ # try the active environment. This is set by find_environment() (above)
+ if _active_environment:
+ return _active_environment
+ elif not required:
+ return None
+ else:
+ tty.die(
+ '`spack %s` requires an environment' % cmd_name,
+ 'activate an environment first:',
+ ' spack env activate ENV',
+ 'or use:',
+ ' spack -e ENV %s ...' % cmd_name)
+
+
+def root(name):
+ """Get the root directory for an environment by name."""
+ validate_env_name(name)
+ return os.path.join(env_path, name)
+
+
+def exists(name):
+ """Whether an environment with this name exists or not."""
+ if not valid_env_name(name):
+ return False
+ return os.path.isdir(root(name))
+
+
+def active(name):
+ """True if the named environment is active."""
+ return _active_environment and name == _active_environment.name
+
+
+def is_env_dir(path):
+ """Whether a directory contains a spack environment."""
+ return os.path.isdir(path) and os.path.exists(
+ os.path.join(path, manifest_name))
+
+
+def read(name):
+ """Get an environment with the supplied name."""
+ validate_env_name(name)
+ if not exists(name):
+ raise SpackEnvironmentError("no such environment '%s'" % name)
+ return Environment(root(name))
+
+
+def create(name, init_file=None):
+ """Create a named environment in Spack."""
+ validate_env_name(name)
+ if exists(name):
+ raise SpackEnvironmentError("'%s': environment already exists" % name)
+ return Environment(root(name), init_file)
+
+
+def config_dict(yaml_data):
+ """Get the configuration scope section out of an spack.yaml"""
+ key = spack.config.first_existing(yaml_data, env_schema_keys)
+ return yaml_data[key]
+
+
+def all_environment_names():
+ """List the names of environments that currently exist."""
+ # just return empty if the env path does not exist. A read-only
+ # operation like list should not try to create a directory.
+ if not os.path.exists(env_path):
+ return []
+
+ candidates = sorted(os.listdir(env_path))
+ names = []
+ for candidate in candidates:
+ yaml_path = os.path.join(root(candidate), manifest_name)
+ if valid_env_name(candidate) and os.path.exists(yaml_path):
+ names.append(candidate)
+ return names
+
+
+def all_environments():
+ """Generator for all named Environments."""
+ for name in all_environment_names():
+ yield read(name)
+
+
+def validate(data, filename=None):
+ global _validator
+ if _validator is None:
+ _validator = jsonschema.Draft4Validator(spack.schema.env.schema)
+ try:
+ _validator.validate(data)
+ except jsonschema.ValidationError as e:
+ raise spack.config.ConfigFormatError(
+ e, data, filename, e.instance.lc.line + 1)
+
+
+def _read_yaml(str_or_file):
+ """Read YAML from a file for round-trip parsing."""
+ data = ruamel.yaml.load(str_or_file, ruamel.yaml.RoundTripLoader)
+ filename = getattr(str_or_file, 'name', None)
+ validate(data, filename)
+ return data
+
+
+def _write_yaml(data, str_or_file):
+ """Write YAML to a file preserving comments and dict order."""
+ filename = getattr(str_or_file, 'name', None)
+ validate(data, filename)
+ ruamel.yaml.dump(data, str_or_file, Dumper=ruamel.yaml.RoundTripDumper,
+ default_flow_style=False)
+
+
+class Environment(object):
+ def __init__(self, path, init_file=None):
+ """Create a new environment.
+
+ The environment can be optionally initialized with either a
+ spack.yaml or spack.lock file.
+
+ Arguments:
+ path (str): path to the root directory of this environment
+ init_file (str or file object): filename or file object to
+ initialize the environment
"""
- modifications = collections.defaultdict(list)
- for item in self:
- modifications[item.name].append(item)
- return modifications
+ self.path = os.path.abspath(path)
+ self.clear()
+
+ if init_file:
+ # initialize the environment from a file if provided
+ with fs.open_if_filename(init_file) as f:
+ if hasattr(f, 'name') and f.name.endswith('.lock'):
+ # Initialize the environment from a lockfile
+ self._read_lockfile(f)
+ self._set_user_specs_from_lockfile()
+ self.yaml = _read_yaml(default_manifest_yaml)
+ else:
+ # Initialize the environment from a spack.yaml file
+ self._read_manifest(f)
+ else:
+ # read lockfile, if it exists
+ if os.path.exists(self.lock_path):
+ with open(self.lock_path) as f:
+ self._read_lockfile(f)
+
+ if os.path.exists(self.manifest_path):
+ # read the spack.yaml file, if exists
+ with open(self.manifest_path) as f:
+ self._read_manifest(f)
+
+ elif self.concretized_user_specs:
+ # if not, take user specs from the lockfile
+ self._set_user_specs_from_lockfile()
+ self.yaml = _read_yaml(default_manifest_yaml)
+ else:
+ # if there's no manifest or lockfile, use the default
+ self._read_manifest(default_manifest_yaml)
+
+ def _read_manifest(self, f):
+ """Read manifest file and set up user specs."""
+ self.yaml = _read_yaml(f)
+ spec_list = config_dict(self.yaml).get('specs')
+ if spec_list:
+ self.user_specs = [Spec(s) for s in spec_list if s]
+
+ def _set_user_specs_from_lockfile(self):
+ """Copy user_specs from a read-in lockfile."""
+ self.user_specs = [Spec(s) for s in self.concretized_user_specs]
def clear(self):
+ self.user_specs = [] # current user specs
+ self.concretized_user_specs = [] # user specs from last concretize
+ self.concretized_order = [] # roots of last concretize, in order
+ self.specs_by_hash = {} # concretized specs by hash
+ self.new_specs = [] # write packages for these on write()
+ self._repo = None # RepoPath for this env (memoized)
+ self._previous_active = None # previously active environment
+
+ @property
+ def internal(self):
+ """Whether this environment is managed by Spack."""
+ return self.path.startswith(env_path)
+
+ @property
+ def name(self):
+ """Human-readable representation of the environment.
+
+ This is the path for directory environments, and just the name
+ for named environments.
"""
- Clears the current list of modifications
+ if self.internal:
+ return os.path.basename(self.path)
+ else:
+ return self.path
+
+ @property
+ def active(self):
+ """True if this environment is currently active."""
+ return _active_environment and self.path == _active_environment.path
+
+ @property
+ def manifest_path(self):
+ """Path to spack.yaml file in this environment."""
+ return os.path.join(self.path, manifest_name)
+
+ @property
+ def lock_path(self):
+ """Path to spack.lock file in this environment."""
+ return os.path.join(self.path, lockfile_name)
+
+ @property
+ def env_subdir_path(self):
+ """Path to directory where the env stores repos, logs, views."""
+ return os.path.join(self.path, env_subdir_name)
+
+ @property
+ def repos_path(self):
+ return os.path.join(self.path, env_subdir_name, 'repos')
+
+ @property
+ def log_path(self):
+ return os.path.join(self.path, env_subdir_name, 'logs')
+
+ @property
+ def repo(self):
+ if self._repo is None:
+ self._repo = make_repo_path(self.repos_path)
+ return self._repo
+
+ def included_config_scopes(self):
+ """List of included configuration scopes from the environment.
+
+ Scopes are listed in the YAML file in order from highest to
+ lowest precedence, so configuration from earlier scope will take
+ precedence over later ones.
+
+ This routine returns them in the order they should be pushed onto
+ the internal scope stack (so, in reverse, from lowest to highest).
"""
- self.env_modifications.clear()
-
- def apply_modifications(self):
- """Applies the modifications and clears the list."""
- modifications = self.group_by_name()
- # Apply modifications one variable at a time
- for name, actions in sorted(modifications.items()):
- for x in actions:
- x.execute()
-
- @staticmethod
- def from_sourcing_file(filename, *args, **kwargs):
- """Returns modifications that would be made by sourcing a file.
-
- Parameters:
- filename (str): The file to source
- *args (list of str): Arguments to pass on the command line
-
- Keyword Arguments:
- shell (str): The shell to use (default: ``bash``)
- shell_options (str): Options passed to the shell (default: ``-c``)
- source_command (str): The command to run (default: ``source``)
- suppress_output (str): Redirect used to suppress output of command
- (default: ``&> /dev/null``)
- concatenate_on_success (str): Operator used to execute a command
- only when the previous command succeeds (default: ``&&``)
+ scopes = []
+
+ # load config scopes added via 'include:', in reverse so that
+ # highest-precedence scopes are last.
+ includes = config_dict(self.yaml).get('include', [])
+ for i, config_path in enumerate(reversed(includes)):
+ # allow paths to contain environment variables
+ config_path = config_path.format(**os.environ)
+
+ # treat relative paths as relative to the environment
+ if not os.path.isabs(config_path):
+ config_path = os.path.join(self.path, config_path)
+ config_path = os.path.normpath(os.path.realpath(config_path))
+
+ if os.path.isdir(config_path):
+ # directories are treated as regular ConfigScopes
+ config_name = 'env:%s:%s' % (
+ self.name, os.path.basename(config_path))
+ scope = spack.config.ConfigScope(config_name, config_path)
+ else:
+ # files are assumed to be SingleFileScopes
+ base, ext = os.path.splitext(os.path.basename(config_path))
+ config_name = 'env:%s:%s' % (self.name, base)
+ scope = spack.config.SingleFileScope(
+ config_name, config_path, spack.schema.merged.schema)
+
+ scopes.append(scope)
+
+ return scopes
+
+ def env_file_config_scope_name(self):
+ """Name of the config scope of this environment's manifest file."""
+ return 'env:%s' % self.name
+
+ def env_file_config_scope(self):
+ """Get the configuration scope for the environment's manifest file."""
+ config_name = self.env_file_config_scope_name()
+ return spack.config.SingleFileScope(config_name,
+ self.manifest_path,
+ spack.schema.env.schema,
+ [env_schema_keys])
+
+ def config_scopes(self):
+ """A list of all configuration scopes for this environment."""
+ return self.included_config_scopes() + [self.env_file_config_scope()]
+
+ def destroy(self):
+ """Remove this environment from Spack entirely."""
+ shutil.rmtree(self.path)
+
+ def add(self, user_spec):
+ """Add a single user_spec (non-concretized) to the Environment
Returns:
- EnvironmentModifications: an object that, if executed, has
- the same effect on the environment as sourcing the file
+ (bool): True if the spec was added, False if it was already
+ present and did not need to be added
+
"""
- # Check if the file actually exists
- if not os.path.isfile(filename):
- msg = 'Trying to source non-existing file: {0}'.format(filename)
- raise RuntimeError(msg)
-
- # Kwargs parsing and default values
- shell = kwargs.get('shell', '/bin/bash')
- shell_options = kwargs.get('shell_options', '-c')
- source_command = kwargs.get('source_command', 'source')
- suppress_output = kwargs.get('suppress_output', '&> /dev/null')
- concatenate_on_success = kwargs.get('concatenate_on_success', '&&')
-
- source_file = [source_command, filename]
- source_file.extend(args)
- source_file = ' '.join(source_file)
-
- dump_cmd = 'import os, json; print(json.dumps(dict(os.environ)))'
- dump_environment = 'python -c "{0}"'.format(dump_cmd)
-
- # Construct the command that will be executed
- command = [
- shell,
- shell_options,
- ' '.join([
- source_file, suppress_output,
- concatenate_on_success, dump_environment,
- ]),
- ]
-
- # Try to source the file
- proc = subprocess.Popen(
- command, stdout=subprocess.PIPE, env=os.environ)
- proc.wait()
-
- if proc.returncode != 0:
- msg = 'Sourcing file {0} returned a non-zero exit code'.format(
- filename)
- raise RuntimeError(msg)
-
- output = ''.join([line.decode('utf-8') for line in proc.stdout])
-
- # Construct dictionaries of the environment before and after
- # sourcing the file, so that we can diff them.
- env_before = dict(os.environ)
- env_after = json.loads(output)
-
- # If we're in python2, convert to str objects instead of unicode
- # like json gives us. We can't put unicode in os.environ anyway.
- if sys.version_info[0] < 3:
- env_after = dict((k.encode('utf-8'), v.encode('utf-8'))
- for k, v in env_after.items())
-
- # Filter variables that are not related to sourcing a file
- to_be_filtered = 'SHLVL', '_', 'PWD', 'OLDPWD', 'PS2'
- for d in env_after, env_before:
- for name in to_be_filtered:
- d.pop(name, None)
-
- # Fill the EnvironmentModifications instance
- env = EnvironmentModifications()
-
- # New variables
- new_variables = set(env_after) - set(env_before)
- # Variables that have been unset
- unset_variables = set(env_before) - set(env_after)
- # Variables that have been modified
- common_variables = set(
- env_before).intersection(set(env_after))
- modified_variables = [x for x in common_variables
- if env_before[x] != env_after[x]]
-
- def return_separator_if_any(*args):
- separators = ':', ';'
- for separator in separators:
- for arg in args:
- if separator in arg:
- return separator
- return None
-
- # Add variables to env.
- # Assume that variables with 'PATH' in the name or that contain
- # separators like ':' or ';' are more likely to be paths
- for x in new_variables:
- sep = return_separator_if_any(env_after[x])
- if sep:
- env.prepend_path(x, env_after[x], separator=sep)
- elif 'PATH' in x:
- env.prepend_path(x, env_after[x])
- else:
- # We just need to set the variable to the new value
- env.set(x, env_after[x])
-
- for x in unset_variables:
- env.unset(x)
-
- for x in modified_variables:
- before = env_before[x]
- after = env_after[x]
- sep = return_separator_if_any(before, after)
- if sep:
- before_list = before.split(sep)
- after_list = after.split(sep)
-
- # Filter out empty strings
- before_list = list(filter(None, before_list))
- after_list = list(filter(None, after_list))
-
- # Paths that have been removed
- remove_list = [
- ii for ii in before_list if ii not in after_list]
- # Check that nothing has been added in the middle of
- # before_list
- remaining_list = [
- ii for ii in before_list if ii in after_list]
- try:
- start = after_list.index(remaining_list[0])
- end = after_list.index(remaining_list[-1])
- search = sep.join(after_list[start:end + 1])
- except IndexError:
- env.prepend_path(x, env_after[x])
-
- if search not in before:
- # We just need to set the variable to the new value
- env.prepend_path(x, env_after[x])
- else:
- try:
- prepend_list = after_list[:start]
- except KeyError:
- prepend_list = []
- try:
- append_list = after_list[end + 1:]
- except KeyError:
- append_list = []
-
- for item in remove_list:
- env.remove_path(x, item)
- for item in append_list:
- env.append_path(x, item)
- for item in prepend_list:
- env.prepend_path(x, item)
- else:
- # We just need to set the variable to the new value
- env.set(x, env_after[x])
+ spec = Spec(user_spec)
+ if not spec.name:
+ raise SpackEnvironmentError(
+ 'cannot add anonymous specs to an environment!')
+ elif not spack.repo.path.exists(spec.name):
+ raise SpackEnvironmentError('no such package: %s' % spec.name)
+
+ existing = set(s for s in self.user_specs if s.name == spec.name)
+ if not existing:
+ self.user_specs.append(spec)
+ return bool(not existing)
+
+ def remove(self, query_spec, force=False):
+ """Remove specs from an environment that match a query_spec"""
+ query_spec = Spec(query_spec)
+
+ # try abstract specs first
+ matches = []
+ if not query_spec.concrete:
+ matches = [s for s in self.user_specs if s.satisfies(query_spec)]
+
+ if not matches:
+ # concrete specs match against concrete specs in the env
+ specs_hashes = zip(
+ self.concretized_user_specs, self.concretized_order)
+ matches = [
+ s for s, h in specs_hashes if query_spec.dag_hash() == h]
+
+ if not matches:
+ raise SpackEnvironmentError("Not found: {0}".format(query_spec))
+
+ for spec in matches:
+ if spec in self.user_specs:
+ self.user_specs.remove(spec)
+
+ if force and spec in self.concretized_user_specs:
+ i = self.concretized_user_specs.index(spec)
+ del self.concretized_user_specs[i]
+
+ dag_hash = self.concretized_order[i]
+ del self.concretized_order[i]
+ del self.specs_by_hash[dag_hash]
+
+ def concretize(self, force=False):
+ """Concretize user_specs in this environment.
+
+ Only concretizes specs that haven't been concretized yet unless
+ force is ``True``.
+
+ This only modifies the environment in memory. ``write()`` will
+ write out a lockfile containing concretized specs.
+
+ Arguments:
+ force (bool): re-concretize ALL specs, even those that were
+ already concretized
+ """
+ if force:
+ # Clear previously concretized specs
+ self.concretized_user_specs = []
+ self.concretized_order = []
+ self.specs_by_hash = {}
+
+ # keep any concretized specs whose user specs are still in the manifest
+ old_concretized_user_specs = self.concretized_user_specs
+ old_concretized_order = self.concretized_order
+ old_specs_by_hash = self.specs_by_hash
+
+ self.concretized_user_specs = []
+ self.concretized_order = []
+ self.specs_by_hash = {}
+
+ for s, h in zip(old_concretized_user_specs, old_concretized_order):
+ if s in self.user_specs:
+ concrete = old_specs_by_hash[h]
+ self._add_concrete_spec(s, concrete, new=False)
+
+ # concretize any new user specs that we haven't concretized yet
+ for uspec in self.user_specs:
+ if uspec not in old_concretized_user_specs:
+ tty.msg('Concretizing %s' % uspec)
+ concrete = uspec.concretized()
+ self._add_concrete_spec(uspec, concrete)
+
+ # Display concretized spec to the user
+ sys.stdout.write(concrete.tree(
+ recurse_dependencies=True, install_status=True,
+ hashlen=7, hashes=True))
+
+ def install(self, user_spec, concrete_spec=None, **install_args):
+ """Install a single spec into an environment.
+
+ This will automatically concretize the single spec, but it won't
+ affect other as-yet unconcretized specs.
+ """
+ spec = Spec(user_spec)
- return env
+ if self.add(spec):
+ concrete = concrete_spec if concrete_spec else spec.concretized()
+ self._add_concrete_spec(spec, concrete)
+ else:
+ # spec might be in the user_specs, but not installed.
+ spec = next(s for s in self.user_specs if s.name == spec.name)
+ concrete = self.specs_by_hash.get(spec.dag_hash())
+ if not concrete:
+ concrete = spec.concretized()
+ self._add_concrete_spec(spec, concrete)
+ concrete.package.do_install(**install_args)
-def concatenate_paths(paths, separator=':'):
- """Concatenates an iterable of paths into a string of paths separated by
- separator, defaulting to colon.
+ def _add_concrete_spec(self, spec, concrete, new=True):
+ """Called when a new concretized spec is added to the environment.
- Args:
- paths: iterable of paths
- separator: the separator to use, default ':'
+ This ensures that all internal data structures are kept in sync.
- Returns:
- string
- """
- return separator.join(str(item) for item in paths)
+ Arguments:
+ spec (Spec): user spec that resulted in the concrete spec
+ concrete (Spec): spec concretized within this environment
+ new (bool): whether to write this spec's package to the env
+ repo on write()
+ """
+ assert concrete.concrete
+
+ # when a spec is newly concretized, we need to make a note so
+ # that we can write its package to the env repo on write()
+ if new:
+ self.new_specs.append(concrete)
+
+ # update internal lists of specs
+ self.concretized_user_specs.append(spec)
+
+ h = concrete.dag_hash()
+ self.concretized_order.append(h)
+ self.specs_by_hash[h] = concrete
+
+ def install_all(self, args=None):
+ """Install all concretized specs in an environment."""
+
+ # Make sure log directory exists
+ log_path = self.log_path
+ fs.mkdirp(log_path)
+
+ for concretized_hash in self.concretized_order:
+ spec = self.specs_by_hash[concretized_hash]
+
+ # Parse cli arguments and construct a dictionary
+ # that will be passed to Package.do_install API
+ kwargs = dict()
+ if args:
+ spack.cmd.install.update_kwargs_from_args(args, kwargs)
+
+ with fs.working_dir(self.path):
+ spec.package.do_install(**kwargs)
+
+ # Link the resulting log file into logs dir
+ build_log_link = os.path.join(
+ log_path, '%s-%s.log' % (spec.name, spec.dag_hash(7)))
+ if os.path.exists(build_log_link):
+ os.remove(build_log_link)
+ os.symlink(spec.package.build_log_path, build_log_link)
+
+ def all_specs_by_hash(self):
+ """Map of hashes to spec for all specs in this environment."""
+ hashes = {}
+ for h in self.concretized_order:
+ specs = self.specs_by_hash[h].traverse(deptype=('link', 'run'))
+ for spec in specs:
+ hashes[spec.dag_hash()] = spec
+ return hashes
+
+ def all_specs(self):
+ """Return all specs, even those a user spec would shadow."""
+ return sorted(self.all_specs_by_hash().values())
+
+ def all_hashes(self):
+ """Return all specs, even those a user spec would shadow."""
+ return list(self.all_specs_by_hash().keys())
+
+ def roots(self):
+ """Specs explicitly requested by the user *in this environment*.
+
+ Yields both added and installed specs that have user specs in
+ `spack.yaml`.
+ """
+ concretized = dict(self.concretized_specs())
+ for spec in self.user_specs:
+ concrete = concretized.get(spec)
+ yield concrete if concrete else spec
+ def added_specs(self):
+ """Specs that are not yet installed.
-def set_or_unset_not_first(variable, changes, errstream):
- """Check if we are going to set or unset something after other
- modifications have already been requested.
- """
- indexes = [ii for ii, item in enumerate(changes)
- if ii != 0 and
- not item.args.get('force', False) and
- type(item) in [SetEnv, UnsetEnv]]
- if indexes:
- good = '\t \t{context} at {filename}:{lineno}'
- nogood = '\t--->\t{context} at {filename}:{lineno}'
- message = "Suspicious requests to set or unset '{var}' found"
- errstream(message.format(var=variable))
- for ii, item in enumerate(changes):
- print_format = nogood if ii in indexes else good
- errstream(print_format.format(**item.args))
-
-
-def validate(env, errstream):
- """Validates the environment modifications to check for the presence of
- suspicious patterns. Prompts a warning for everything that was found.
-
- Current checks:
- - set or unset variables after other changes on the same variable
-
- Args:
- env: list of environment modifications
- """
- modifications = env.group_by_name()
- for variable, list_of_changes in sorted(modifications.items()):
- set_or_unset_not_first(variable, list_of_changes, errstream)
+ Yields the user spec for non-concretized specs, and the concrete
+ spec for already concretized but not yet installed specs.
+ """
+ concretized = dict(self.concretized_specs())
+ for spec in self.user_specs:
+ concrete = concretized.get(spec)
+ if not concrete:
+ yield spec
+ elif not concrete.package.installed:
+ yield concrete
+
+ def concretized_specs(self):
+ """Tuples of (user spec, concrete spec) for all concrete specs."""
+ for s, h in zip(self.concretized_user_specs, self.concretized_order):
+ yield (s, self.specs_by_hash[h])
+
+ def removed_specs(self):
+ """Tuples of (user spec, concrete spec) for all specs that will be
+ removed on nexg concretize."""
+ needed = set()
+ for s, c in self.concretized_specs():
+ if s in self.user_specs:
+ for d in c.traverse():
+ needed.add(d)
+
+ for s, c in self.concretized_specs():
+ for d in c.traverse():
+ if d not in needed:
+ yield d
+
+ def _get_environment_specs(self, recurse_dependencies=True):
+ """Returns the specs of all the packages in an environment.
+
+ If these specs appear under different user_specs, only one copy
+ is added to the list returned.
+ """
+ package_to_spec = {}
+ spec_list = list()
+
+ for spec_hash in self.concretized_order:
+ spec = self.specs_by_hash[spec_hash]
+ specs = (spec.traverse(deptype=('link', 'run'))
+ if recurse_dependencies else (spec,))
-def filter_environment_blacklist(env, variables):
- """Generator that filters out any change to environment variables present in
- the input list.
+ for dep in specs:
+ prior = package_to_spec.get(dep.name)
+ if prior and prior != dep:
+ tty.debug("{0} takes priority over {1}"
+ .format(package_to_spec[dep.name].format(),
+ dep.format()))
+ else:
+ package_to_spec[dep.name] = dep
+ spec_list.append(dep)
+
+ return spec_list
+
+ def _to_lockfile_dict(self):
+ """Create a dictionary to store a lockfile for this environment."""
+ concrete_specs = {}
+ for spec in self.specs_by_hash.values():
+ for s in spec.traverse():
+ dag_hash = s.dag_hash()
+ if dag_hash not in concrete_specs:
+ concrete_specs[dag_hash] = s.to_node_dict(all_deps=True)
+
+ hash_spec_list = zip(
+ self.concretized_order, self.concretized_user_specs)
+
+ # this is the lockfile we'll write out
+ data = {
+ # metadata about the format
+ '_meta': {
+ 'file-type': 'spack-lockfile',
+ 'lockfile-version': lockfile_format_version,
+ },
+
+ # users specs + hashes are the 'roots' of the environment
+ 'roots': [{
+ 'hash': h,
+ 'spec': str(s)
+ } for h, s in hash_spec_list],
+
+ # Concrete specs by hash, including dependencies
+ 'concrete_specs': concrete_specs,
+ }
+
+ return data
+
+ def _read_lockfile(self, file_or_json):
+ """Read a lockfile from a file or from a raw string."""
+ lockfile_dict = sjson.load(file_or_json)
+ self._read_lockfile_dict(lockfile_dict)
+
+ def _read_lockfile_dict(self, d):
+ """Read a lockfile dictionary into this environment."""
+ roots = d['roots']
+ self.concretized_user_specs = [Spec(r['spec']) for r in roots]
+ self.concretized_order = [r['hash'] for r in roots]
+
+ json_specs_by_hash = d['concrete_specs']
+ root_hashes = set(self.concretized_order)
+
+ specs_by_hash = {}
+ for dag_hash, node_dict in json_specs_by_hash.items():
+ specs_by_hash[dag_hash] = Spec.from_node_dict(node_dict)
+
+ for dag_hash, node_dict in json_specs_by_hash.items():
+ for dep_name, dep_hash, deptypes in (
+ Spec.dependencies_from_node_dict(node_dict)):
+ specs_by_hash[dag_hash]._add_dependency(
+ specs_by_hash[dep_hash], deptypes)
+
+ self.specs_by_hash = dict(
+ (x, y) for x, y in specs_by_hash.items() if x in root_hashes)
+
+ def write(self):
+ """Writes an in-memory environment to its location on disk.
+
+ This will also write out package files for each newly concretized spec.
+ """
+ # ensure path in var/spack/environments
+ fs.mkdirp(self.path)
+
+ if self.specs_by_hash:
+ # ensure the prefix/.env directory exists
+ fs.mkdirp(self.env_subdir_path)
+
+ for spec in self.new_specs:
+ for dep in spec.traverse():
+ if not dep.concrete:
+ raise ValueError('specs passed to environment.write() '
+ 'must be concrete!')
+
+ root = os.path.join(self.repos_path, dep.namespace)
+ repo = spack.repo.create_or_construct(root, dep.namespace)
+ pkg_dir = repo.dirname_for_package_name(dep.name)
+
+ fs.mkdirp(pkg_dir)
+ spack.repo.path.dump_provenance(dep, pkg_dir)
+ self.new_specs = []
+
+ # write the lock file last
+ with fs.write_tmp_and_move(self.lock_path) as f:
+ sjson.dump(self._to_lockfile_dict(), stream=f)
+ else:
+ if os.path.exists(self.lock_path):
+ os.unlink(self.lock_path)
- Args:
- env: list of environment modifications
- variables: list of variable names to be filtered
+ # invalidate _repo cache
+ self._repo = None
- Returns:
- items in env if they are not in variables
- """
- for item in env:
- if item.name not in variables:
- yield item
+ # put the new user specs in the YAML
+ yaml_spec_list = config_dict(self.yaml).setdefault('specs', [])
+ yaml_spec_list[:] = [str(s) for s in self.user_specs]
+ # if all that worked, write out the manifest file at the top level
+ with fs.write_tmp_and_move(self.manifest_path) as f:
+ _write_yaml(self.yaml, f)
-def inspect_path(root, inspections, exclude=None):
- """Inspects ``root`` to search for the subdirectories in ``inspections``.
- Adds every path found to a list of prepend-path commands and returns it.
+ def __enter__(self):
+ self._previous_active = _active_environment
+ activate(self)
+ return
- Args:
- root (str): absolute path where to search for subdirectories
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ deactivate()
+ if self._previous_active:
+ activate(self._previous_active)
- inspections (dict): maps relative paths to a list of environment
- variables that will be modified if the path exists. The
- modifications are not performed immediately, but stored in a
- command object that is returned to client
- exclude (callable): optional callable. If present it must accept an
- absolute path and return True if it should be excluded from the
- inspection
+def make_repo_path(root):
+ """Make a RepoPath from the repo subdirectories in an environment."""
+ path = spack.repo.RepoPath()
- Examples:
+ if os.path.isdir(root):
+ for repo_root in os.listdir(root):
+ repo_root = os.path.join(root, repo_root)
- The following lines execute an inspection in ``/usr`` to search for
- ``/usr/include`` and ``/usr/lib64``. If found we want to prepend
- ``/usr/include`` to ``CPATH`` and ``/usr/lib64`` to ``MY_LIB64_PATH``.
+ if not os.path.isdir(repo_root):
+ continue
- .. code-block:: python
+ repo = spack.repo.Repo(repo_root)
+ path.put_last(repo)
- # Set up the dictionary containing the inspection
- inspections = {
- 'include': ['CPATH'],
- 'lib64': ['MY_LIB64_PATH']
- }
+ return path
- # Get back the list of command needed to modify the environment
- env = inspect_path('/usr', inspections)
- # Eventually execute the commands
- env.apply_modifications()
+def prepare_config_scope(env):
+ """Add env's scope to the global configuration search path."""
+ for scope in env.config_scopes():
+ spack.config.config.push_scope(scope)
- Returns:
- instance of EnvironmentModifications containing the requested
- modifications
- """
- if exclude is None:
- exclude = lambda x: False
- env = EnvironmentModifications()
- # Inspect the prefix to check for the existence of common directories
- for relative_path, variables in inspections.items():
- expected = os.path.join(root, relative_path)
+def deactivate_config_scope(env):
+ """Remove any scopes from env from the global config path."""
+ for scope in env.config_scopes():
+ spack.config.config.remove_scope(scope.name)
- if os.path.isdir(expected) and not exclude(expected):
- for variable in variables:
- env.prepend_path(variable, expected)
- return env
+class SpackEnvironmentError(spack.error.SpackError):
+ """Superclass for all errors to do with Spack environments."""
diff --git a/lib/spack/spack/error.py b/lib/spack/spack/error.py
index 4a1278b6fe..e53536d819 100644
--- a/lib/spack/spack/error.py
+++ b/lib/spack/spack/error.py
@@ -1,34 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import sys
+import inspect
import llnl.util.tty as tty
-import spack
-import inspect
+
+
+#: whether we should write stack traces or short error messages
+#: this is module-scoped because it needs to be set very early
+debug = False
class SpackError(Exception):
@@ -59,7 +44,7 @@ class SpackError(Exception):
"""Print extended debug information about this exception.
This is usually printed when the top-level Spack error handler
- calls ``die()``, but it acn be called separately beforehand if a
+ calls ``die()``, but it can be called separately beforehand if a
lower-level error handler needs to print error context and
continue without raising the exception to the top level.
"""
@@ -73,7 +58,7 @@ class SpackError(Exception):
sys.stderr.write('\n')
# stack trace, etc. in debug mode.
- if spack.debug:
+ if debug:
if self.traceback:
# exception came from a build child, already got
# traceback in child, so print it.
diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py
index 30e6823207..8cabfa10ac 100644
--- a/lib/spack/spack/fetch_strategy.py
+++ b/lib/spack/spack/fetch_strategy.py
@@ -1,27 +1,8 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
Fetch strategies are used to download source code into a staging area
in order to build it. They need to define the following methods:
@@ -49,14 +30,14 @@ from functools import wraps
from six import string_types, with_metaclass
import llnl.util.tty as tty
-from llnl.util.filesystem import working_dir, mkdirp, join_path
+from llnl.util.filesystem import working_dir, mkdirp
-import spack
+import spack.config
import spack.error
import spack.util.crypto as crypto
import spack.util.pattern as pattern
from spack.util.executable import which
-from spack.util.string import comma_or
+from spack.util.string import comma_and, quote
from spack.version import Version, ver
from spack.util.compression import decompressor_for, extension
@@ -89,7 +70,15 @@ class FSMeta(type):
class FetchStrategy(with_metaclass(FSMeta, object)):
"""Superclass of all fetch strategies."""
enabled = False # Non-abstract subclasses should be enabled.
- required_attributes = None # Attributes required in version() args.
+
+ #: The URL attribute must be specified either at the package class
+ #: level, or as a keyword argument to ``version()``. It is used to
+ #: distinguish fetchers for different versions in the package DSL.
+ url_attr = None
+
+ #: Optional attributes can be used to distinguish fetchers when :
+ #: classes have multiple ``url_attrs`` at the top-level.
+ optional_attrs = [] # optional attributes in version() args.
def __init__(self):
# The stage is initialized late, so that fetch strategies can be
@@ -141,6 +130,14 @@ class FetchStrategy(with_metaclass(FSMeta, object)):
bool: True if can cache, False otherwise.
"""
+ def source_id(self):
+ """A unique ID for the source.
+
+ The returned value is added to the content which determines the full
+ hash for a package using `str()`.
+ """
+ raise NotImplementedError
+
def __str__(self): # Should be human readable URL.
return "FetchStrategy.__str___"
@@ -148,7 +145,7 @@ class FetchStrategy(with_metaclass(FSMeta, object)):
# arguments in packages.
@classmethod
def matches(cls, args):
- return any(k in args for k in cls.required_attributes)
+ return cls.url_attr in args
@pattern.composite(interface=FetchStrategy)
@@ -160,27 +157,35 @@ class FetchStrategyComposite(object):
matches = FetchStrategy.matches
set_stage = FetchStrategy.set_stage
+ def source_id(self):
+ component_ids = tuple(i.source_id() for i in self)
+ if all(component_ids):
+ return component_ids
+
class URLFetchStrategy(FetchStrategy):
"""FetchStrategy that pulls source code from a URL for an archive,
checks the archive against a checksum,and decompresses the archive.
"""
enabled = True
- required_attributes = ['url']
+ url_attr = 'url'
+
+ # these are checksum types. The generic 'checksum' is deprecated for
+ # specific hash names, but we need it for backward compatibility
+ optional_attrs = list(crypto.hashes.keys()) + ['checksum']
- def __init__(self, url=None, digest=None, **kwargs):
+ def __init__(self, url=None, checksum=None, **kwargs):
super(URLFetchStrategy, self).__init__()
- # If URL or digest are provided in the kwargs, then prefer
- # those values.
- self.url = kwargs.get('url', None)
- if not self.url:
- self.url = url
+ # Prefer values in kwargs to the positionals.
+ self.url = kwargs.get('url', url)
- self.digest = next((kwargs[h] for h in crypto.hashes if h in kwargs),
- None)
- if not self.digest:
- self.digest = digest
+ # digest can be set as the first argument, or from an explicit
+ # kwarg by the hash name.
+ self.digest = kwargs.get('checksum', checksum)
+ for h in self.optional_attrs:
+ if h in kwargs:
+ self.digest = kwargs[h]
self.expand_archive = kwargs.get('expand', True)
self.extra_curl_options = kwargs.get('curl_options', [])
@@ -197,6 +202,9 @@ class URLFetchStrategy(FetchStrategy):
self._curl = which('curl', required=True)
return self._curl
+ def source_id(self):
+ return self.digest
+
@_needs_stage
def fetch(self):
if self.archive_file:
@@ -227,7 +235,7 @@ class URLFetchStrategy(FetchStrategy):
self.url,
]
- if spack.insecure:
+ if not spack.config.get('config:verify_ssl'):
curl_args.append('-k')
if sys.stdout.isatty():
@@ -276,15 +284,16 @@ class URLFetchStrategy(FetchStrategy):
# Check if we somehow got an HTML file rather than the archive we
# asked for. We only look at the last content type, to handle
# redirects properly.
- content_types = re.findall(r'Content-Type:[^\r\n]+', headers)
+ content_types = re.findall(r'Content-Type:[^\r\n]+', headers,
+ flags=re.IGNORECASE)
if content_types and 'text/html' in content_types[-1]:
- tty.warn("The contents of ",
- (self.archive_file if self.archive_file is not None
- else "the archive"),
- " look like HTML.",
- "The checksum will likely be bad. If it is, you can use",
- "'spack clean <package>' to remove the bad archive, then",
- "fix your internet gateway issue and install again.")
+ msg = ("The contents of {0} look like HTML. Either the URL "
+ "you are trying to use does not exist or you have an "
+ "internet gateway issue. You can remove the bad archive "
+ "using 'spack clean <package>', then try again using "
+ "the correct URL.")
+ tty.warn(msg.format(self.archive_file or "the archive"))
+
if save_file:
os.rename(partial_file, save_file)
@@ -403,9 +412,6 @@ class URLFetchStrategy(FetchStrategy):
class CacheURLFetchStrategy(URLFetchStrategy):
"""The resource associated with a cache URL may be out of date."""
- def __init__(self, *args, **kwargs):
- super(CacheURLFetchStrategy, self).__init__(*args, **kwargs)
-
@_needs_stage
def fetch(self):
path = re.sub('^file://', '', self.url)
@@ -436,35 +442,38 @@ class CacheURLFetchStrategy(URLFetchStrategy):
class VCSFetchStrategy(FetchStrategy):
+ """Superclass for version control system fetch strategies.
+
+ Like all fetchers, VCS fetchers are identified by the attributes
+ passed to the ``version`` directive. The optional_attrs for a VCS
+ fetch strategy represent types of revisions, e.g. tags, branches,
+ commits, etc.
+
+ The required attributes (git, svn, etc.) are used to specify the URL
+ and to distinguish a VCS fetch strategy from a URL fetch strategy.
- def __init__(self, name, *rev_types, **kwargs):
+ """
+
+ def __init__(self, **kwargs):
super(VCSFetchStrategy, self).__init__()
- self.name = name
# Set a URL based on the type of fetch strategy.
- self.url = kwargs.get(name, None)
+ self.url = kwargs.get(self.url_attr, None)
if not self.url:
raise ValueError(
- "%s requires %s argument." % (self.__class__, name))
+ "%s requires %s argument." % (self.__class__, self.url_attr))
- # Ensure that there's only one of the rev_types
- if sum(k in kwargs for k in rev_types) > 1:
- raise ValueError(
- "Supply only one of %s to fetch with %s" % (
- comma_or(rev_types), name
- ))
-
- # Set attributes for each rev type.
- for rt in rev_types:
- setattr(self, rt, kwargs.get(rt, None))
+ for attr in self.optional_attrs:
+ setattr(self, attr, kwargs.get(attr, None))
@_needs_stage
def check(self):
- tty.msg("No checksum needed when fetching with %s" % self.name)
+ tty.msg("No checksum needed when fetching with %s" % self.url_attr)
@_needs_stage
def expand(self):
- tty.debug("Source fetched with %s is already expanded." % self.name)
+ tty.debug(
+ "Source fetched with %s is already expanded." % self.url_attr)
@_needs_stage
def archive(self, destination, **kwargs):
@@ -501,15 +510,15 @@ class GoFetchStrategy(VCSFetchStrategy):
Go get does not natively support versions, they can be faked with git
"""
enabled = True
- required_attributes = ('go', )
+ url_attr = 'go'
def __init__(self, **kwargs):
# Discards the keywords in kwargs that may conflict with the next
# call to __init__
forwarded_args = copy.copy(kwargs)
forwarded_args.pop('name', None)
+ super(GoFetchStrategy, self).__init__(**forwarded_args)
- super(GoFetchStrategy, self).__init__('go', **forwarded_args)
self._go = None
@property
@@ -525,7 +534,7 @@ class GoFetchStrategy(VCSFetchStrategy):
@_needs_stage
def fetch(self):
- tty.msg("Trying to get go resource:", self.url)
+ tty.msg("Getting go resource:", self.url)
with working_dir(self.stage.path):
try:
@@ -567,16 +576,16 @@ class GitFetchStrategy(VCSFetchStrategy):
* ``commit``: Particular commit hash in the repo
"""
enabled = True
- required_attributes = ('git', )
+ url_attr = 'git'
+ optional_attrs = ['tag', 'branch', 'commit', 'submodules']
def __init__(self, **kwargs):
# Discards the keywords in kwargs that may conflict with the next call
# to __init__
forwarded_args = copy.copy(kwargs)
forwarded_args.pop('name', None)
+ super(GitFetchStrategy, self).__init__(**forwarded_args)
- super(GitFetchStrategy, self).__init__(
- 'git', 'tag', 'branch', 'commit', **forwarded_args)
self._git = None
self.submodules = kwargs.get('submodules', False)
@@ -592,7 +601,7 @@ class GitFetchStrategy(VCSFetchStrategy):
# If the user asked for insecure fetching, make that work
# with git as well.
- if spack.insecure:
+ if not spack.config.get('config:verify_ssl'):
self._git.add_default_env('GIT_SSL_NO_VERIFY', 'true')
return self._git
@@ -601,6 +610,16 @@ class GitFetchStrategy(VCSFetchStrategy):
def cachable(self):
return bool(self.commit or self.tag)
+ def source_id(self):
+ return self.commit or self.tag
+
+ def get_source_id(self):
+ if not self.branch:
+ return
+ output = self.git('ls-remote', self.url, self.branch, output=str)
+ if output:
+ return output.split()[0]
+
def fetch(self):
if self.stage.source_path:
tty.msg("Already fetched %s" % self.stage.source_path)
@@ -614,20 +633,20 @@ class GitFetchStrategy(VCSFetchStrategy):
elif self.branch:
args = 'on branch %s' % self.branch
- tty.msg("Trying to clone git repository: %s %s" % (self.url, args))
+ tty.msg("Cloning git repository: %s %s" % (self.url, args))
git = self.git
if self.commit:
# Need to do a regular clone and check out everything if
# they asked for a particular commit.
with working_dir(self.stage.path):
- if spack.debug:
+ if spack.config.get('config:debug'):
git('clone', self.url)
else:
git('clone', '--quiet', self.url)
with working_dir(self.stage.source_path):
- if spack.debug:
+ if spack.config.get('config:debug'):
git('checkout', self.commit)
else:
git('checkout', '--quiet', self.commit)
@@ -635,7 +654,7 @@ class GitFetchStrategy(VCSFetchStrategy):
else:
# Can be more efficient if not checking out a specific commit.
args = ['clone']
- if not spack.debug:
+ if not spack.config.get('config:debug'):
args.append('--quiet')
# If we want a particular branch ask for it.
@@ -673,7 +692,7 @@ class GitFetchStrategy(VCSFetchStrategy):
# pull --tags returns a "special" error code of 1 in
# older versions that we have to ignore.
# see: https://github.com/git/git/commit/19d122b
- if spack.debug:
+ if spack.config.get('config:debug'):
git('pull', '--tags', ignore_errors=1)
git('checkout', self.tag)
else:
@@ -683,7 +702,7 @@ class GitFetchStrategy(VCSFetchStrategy):
with working_dir(self.stage.source_path):
# Init submodules if the user asked for them.
if self.submodules:
- if spack.debug:
+ if spack.config.get('config:debug'):
git('submodule', 'update', '--init', '--recursive')
else:
git('submodule', '--quiet', 'update', '--init',
@@ -695,7 +714,7 @@ class GitFetchStrategy(VCSFetchStrategy):
@_needs_stage
def reset(self):
with working_dir(self.stage.source_path):
- if spack.debug:
+ if spack.config.get('config:debug'):
self.git('checkout', '.')
self.git('clean', '-f')
else:
@@ -719,16 +738,16 @@ class SvnFetchStrategy(VCSFetchStrategy):
revision='1641')
"""
enabled = True
- required_attributes = ['svn']
+ url_attr = 'svn'
+ optional_attrs = ['revision']
def __init__(self, **kwargs):
# Discards the keywords in kwargs that may conflict with the next call
# to __init__
forwarded_args = copy.copy(kwargs)
forwarded_args.pop('name', None)
+ super(SvnFetchStrategy, self).__init__(**forwarded_args)
- super(SvnFetchStrategy, self).__init__(
- 'svn', 'revision', **forwarded_args)
self._svn = None
if self.revision is not None:
self.revision = str(self.revision)
@@ -743,13 +762,25 @@ class SvnFetchStrategy(VCSFetchStrategy):
def cachable(self):
return bool(self.revision)
+ def source_id(self):
+ return self.revision
+
+ def get_source_id(self):
+ output = self.svn('info', self.url, output=str)
+ if not output:
+ return None
+ lines = output.split('\n')
+ for line in lines:
+ if line.startswith('Revision:'):
+ return line.split()[-1]
+
@_needs_stage
def fetch(self):
if self.stage.source_path:
tty.msg("Already fetched %s" % self.stage.source_path)
return
- tty.msg("Trying to check out svn repository: %s" % self.url)
+ tty.msg("Checking out subversion repository: %s" % self.url)
args = ['checkout', '--force', '--quiet']
if self.revision:
@@ -807,16 +838,16 @@ class HgFetchStrategy(VCSFetchStrategy):
* ``revision``: Particular revision, branch, or tag.
"""
enabled = True
- required_attributes = ['hg']
+ url_attr = 'hg'
+ optional_attrs = ['revision']
def __init__(self, **kwargs):
# Discards the keywords in kwargs that may conflict with the next call
# to __init__
forwarded_args = copy.copy(kwargs)
forwarded_args.pop('name', None)
+ super(HgFetchStrategy, self).__init__(**forwarded_args)
- super(HgFetchStrategy, self).__init__(
- 'hg', 'revision', **forwarded_args)
self._hg = None
@property
@@ -838,6 +869,14 @@ class HgFetchStrategy(VCSFetchStrategy):
def cachable(self):
return bool(self.revision)
+ def source_id(self):
+ return self.revision
+
+ def get_source_id(self):
+ output = self.hg('id', self.url, output=str)
+ if output:
+ return output.strip()
+
@_needs_stage
def fetch(self):
if self.stage.source_path:
@@ -847,11 +886,11 @@ class HgFetchStrategy(VCSFetchStrategy):
args = []
if self.revision:
args.append('at revision %s' % self.revision)
- tty.msg("Trying to clone Mercurial repository:", self.url, *args)
+ tty.msg("Cloning mercurial repository:", self.url, *args)
args = ['clone']
- if spack.insecure:
+ if not spack.config.get('config:verify_ssl'):
args.append('--insecure')
args.append(self.url)
@@ -911,47 +950,112 @@ def from_kwargs(**kwargs):
for fetcher in all_strategies:
if fetcher.matches(kwargs):
return fetcher(**kwargs)
- # Raise an error in case we can't instantiate any known strategy
- message = "Cannot instantiate any FetchStrategy"
- long_message = message + " from the given arguments : {arguments}".format(
- srguments=kwargs)
- raise FetchError(message, long_message)
+ raise InvalidArgsError(**kwargs)
+
+
+def check_pkg_attributes(pkg):
+ """Find ambiguous top-level fetch attributes in a package.
+
+ Currently this only ensures that two or more VCS fetch strategies are
+ not specified at once.
+ """
+ # a single package cannot have URL attributes for multiple VCS fetch
+ # strategies *unless* they are the same attribute.
+ conflicts = set([s.url_attr for s in all_strategies
+ if hasattr(pkg, s.url_attr)])
+
+ # URL isn't a VCS fetch method. We can use it with a VCS method.
+ conflicts -= set(['url'])
+
+ if len(conflicts) > 1:
+ raise FetcherConflict(
+ 'Package %s cannot specify %s together. Pick at most one.'
+ % (pkg.name, comma_and(quote(conflicts))))
-def args_are_for(args, fetcher):
- fetcher.matches(args)
+
+def _check_version_attributes(fetcher, pkg, version):
+ """Ensure that the fetcher for a version is not ambiguous.
+
+ This assumes that we have already determined the fetcher for the
+ specific version using ``for_package_version()``
+ """
+ all_optionals = set(a for s in all_strategies for a in s.optional_attrs)
+
+ args = pkg.versions[version]
+ extra = set(args) - set(fetcher.optional_attrs) - set([fetcher.url_attr])
+ extra.intersection_update(all_optionals)
+
+ if extra:
+ legal_attrs = [fetcher.url_attr] + list(fetcher.optional_attrs)
+ raise FetcherConflict(
+ "%s version '%s' has extra arguments: %s"
+ % (pkg.name, version, comma_and(quote(extra))),
+ "Valid arguments for a %s fetcher are: \n %s"
+ % (fetcher.url_attr, comma_and(quote(legal_attrs))))
+
+
+def _extrapolate(pkg, version):
+ """Create a fetcher from an extrapolated URL for this version."""
+ try:
+ return URLFetchStrategy(pkg.url_for_version(version))
+ except spack.package.NoURLError:
+ msg = ("Can't extrapolate a URL for version %s "
+ "because package %s defines no URLs")
+ raise ExtrapolationError(msg % (version, pkg.name))
+
+
+def _from_merged_attrs(fetcher, pkg, version):
+ """Create a fetcher from merged package and version attributes."""
+ if fetcher.url_attr == 'url':
+ url = pkg.url_for_version(version)
+ else:
+ url = getattr(pkg, fetcher.url_attr)
+
+ attrs = {fetcher.url_attr: url}
+ attrs.update(pkg.versions[version])
+ return fetcher(**attrs)
def for_package_version(pkg, version):
"""Determine a fetch strategy based on the arguments supplied to
version() in the package description."""
- # If it's not a known version, extrapolate one.
+ check_pkg_attributes(pkg)
+
+ if not isinstance(version, Version):
+ version = Version(version)
+
+ # If it's not a known version, try to extrapolate one by URL
if version not in pkg.versions:
- url = pkg.url_for_version(version)
- if not url:
- raise InvalidArgsError(pkg, version)
- return URLFetchStrategy(url)
+ return _extrapolate(pkg, version)
# Grab a dict of args out of the package version dict
args = pkg.versions[version]
- # Test all strategies against per-version arguments.
+ # If the version specifies a `url_attr` directly, use that.
for fetcher in all_strategies:
- if fetcher.matches(args):
+ if fetcher.url_attr in args:
+ _check_version_attributes(fetcher, pkg, version)
return fetcher(**args)
- # If nothing matched for a *specific* version, test all strategies
- # against
+ # if a version's optional attributes imply a particular fetch
+ # strategy, and we have the `url_attr`, then use that strategy.
for fetcher in all_strategies:
- attrs = dict((attr, getattr(pkg, attr, None))
- for attr in fetcher.required_attributes)
- if 'url' in attrs:
- attrs['url'] = pkg.url_for_version(version)
- attrs.update(args)
- if fetcher.matches(attrs):
- return fetcher(**attrs)
+ if hasattr(pkg, fetcher.url_attr) or fetcher.url_attr == 'url':
+ optionals = fetcher.optional_attrs
+ if optionals and any(a in args for a in optionals):
+ _check_version_attributes(fetcher, pkg, version)
+ return _from_merged_attrs(fetcher, pkg, version)
+
+ # if the optional attributes tell us nothing, then use any `url_attr`
+ # on the package. This prefers URL vs. VCS, b/c URLFetchStrategy is
+ # defined first in this file.
+ for fetcher in all_strategies:
+ if hasattr(pkg, fetcher.url_attr):
+ _check_version_attributes(fetcher, pkg, version)
+ return _from_merged_attrs(fetcher, pkg, version)
- raise InvalidArgsError(pkg, version)
+ raise InvalidArgsError(pkg, version, **args)
def from_list_url(pkg):
@@ -962,15 +1066,25 @@ def from_list_url(pkg):
try:
versions = pkg.fetch_remote_versions()
try:
+ # get a URL, and a checksum if we have it
url_from_list = versions[pkg.version]
- digest = None
- if pkg.version in pkg.versions:
- digest = pkg.versions[pkg.version].get('md5', None)
- return URLFetchStrategy(url=url_from_list, digest=digest)
+ checksum = None
+
+ # try to find a known checksum for version, from the package
+ version = pkg.version
+ if version in pkg.versions:
+ args = pkg.versions[version]
+ checksum = next(
+ (v for k, v in args.items() if k in crypto.hashes),
+ args.get('checksum'))
+
+ # construct a fetcher
+ return URLFetchStrategy(url_from_list, checksum)
except KeyError:
- tty.msg("Can not find version %s in url_list" %
- pkg.version)
+ tty.msg("Cannot find version %s in url_list" % pkg.version)
+
except BaseException:
+ # TODO: Don't catch BaseException here! Be more specific.
tty.msg("Could not determine url from list_url.")
@@ -979,7 +1093,7 @@ class FsCache(object):
def __init__(self, root):
self.root = os.path.abspath(root)
- def store(self, fetcher, relativeDst):
+ def store(self, fetcher, relative_dest):
# skip fetchers that aren't cachable
if not fetcher.cachable:
return
@@ -988,12 +1102,12 @@ class FsCache(object):
if isinstance(fetcher, CacheURLFetchStrategy):
return
- dst = join_path(self.root, relativeDst)
+ dst = os.path.join(self.root, relative_dest)
mkdirp(os.path.dirname(dst))
fetcher.archive(dst)
- def fetcher(self, targetPath, digest, **kwargs):
- path = join_path(self.root, targetPath)
+ def fetcher(self, target_path, digest, **kwargs):
+ path = os.path.join(self.root, target_path)
return CacheURLFetchStrategy(path, digest, **kwargs)
def destroy(self):
@@ -1024,12 +1138,24 @@ class NoDigestError(FetchError):
"""Raised after attempt to checksum when URL has no digest."""
+class ExtrapolationError(FetchError):
+ """Raised when we can't extrapolate a version for a package."""
+
+
+class FetcherConflict(FetchError):
+ """Raised for packages with invalid fetch attributes."""
+
+
class InvalidArgsError(FetchError):
- def __init__(self, pkg, version):
- msg = ("Could not construct a fetch strategy for package %s at "
- "version %s")
- msg %= (pkg.name, version)
- super(InvalidArgsError, self).__init__(msg)
+ """Raised when a version can't be deduced from a set of arguments."""
+ def __init__(self, pkg=None, version=None, **args):
+ msg = "Could not guess a fetch strategy"
+ if pkg:
+ msg += ' for {pkg}'.format(pkg=pkg)
+ if version:
+ msg += '@{version}'.format(version=version)
+ long_msg = 'with arguments: {args}'.format(args=args)
+ super(InvalidArgsError, self).__init__(msg, long_msg)
class ChecksumError(FetchError):
diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py
index 9be55e381b..d3e9878b32 100644
--- a/lib/spack/spack/filesystem_view.py
+++ b/lib/spack/spack/filesystem_view.py
@@ -1,38 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the LICENSE file for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import filecmp
import functools as ft
import os
import re
import shutil
import sys
-from llnl.util.filesystem import join_path
-from llnl.util.link_tree import LinkTree
+from llnl.util.link_tree import LinkTree, MergeConflictError
from llnl.util import tty
+from llnl.util.lang import match_predicate
-import spack
import spack.spec
import spack.store
from spack.directory_layout import ExtensionAlreadyInstalledError
@@ -94,7 +75,7 @@ class FilesystemView(object):
def add_extension(self, spec):
"""
- Add (link) an extension in this view.
+ Add (link) an extension in this view. Does not add dependencies.
"""
raise NotImplementedError
@@ -225,17 +206,9 @@ class YamlFilesystemView(FilesystemView):
% colorize_spec(spec))
return True
- try:
- if not spec.package.is_activated(self.extensions_layout):
- spec.package.do_activate(
- verbose=self.verbose,
- extensions_layout=self.extensions_layout)
-
- except ExtensionAlreadyInstalledError:
- # As we use sets in add_specs(), the order in which packages get
- # activated is essentially random. So this spec might have already
- # been activated as dependency of another package -> fail silently
- pass
+ if not spec.package.is_activated(self):
+ spec.package.do_activate(
+ self, verbose=self.verbose, with_dependencies=False)
# make sure the meta folder is linked as well (this is not done by the
# extension-activation mechnism)
@@ -273,29 +246,66 @@ class YamlFilesystemView(FilesystemView):
long=False)
return False
- tree = LinkTree(spec.prefix)
+ self.merge(spec)
- if not self.ignore_conflicts:
- conflict = tree.find_conflict(self.root)
- if conflict is not None:
- tty.error(self._croot +
- "Cannot link package %s, file already exists: %s"
- % (spec.name, conflict))
- return False
-
- conflicts = tree.merge(self.root, link=self.link,
- ignore=ignore_metadata_dir,
- ignore_conflicts=self.ignore_conflicts)
self.link_meta_folder(spec)
- if self.ignore_conflicts:
- for c in conflicts:
- tty.warn(self._croot + "Could not link: %s" % c)
-
if self.verbose:
tty.info(self._croot + 'Linked package: %s' % colorize_spec(spec))
return True
+ def merge(self, spec, ignore=None):
+ pkg = spec.package
+ view_source = pkg.view_source()
+ view_dst = pkg.view_destination(self)
+
+ tree = LinkTree(view_source)
+
+ ignore = ignore or (lambda f: False)
+ ignore_file = match_predicate(
+ self.layout.hidden_file_paths, ignore)
+
+ # check for dir conflicts
+ conflicts = tree.find_dir_conflicts(view_dst, ignore_file)
+
+ merge_map = tree.get_file_map(view_dst, ignore_file)
+ if not self.ignore_conflicts:
+ conflicts.extend(pkg.view_file_conflicts(self, merge_map))
+
+ if conflicts:
+ raise MergeConflictError(conflicts[0])
+
+ # merge directories with the tree
+ tree.merge_directories(view_dst, ignore_file)
+
+ pkg.add_files_to_view(self, merge_map)
+
+ def unmerge(self, spec, ignore=None):
+ pkg = spec.package
+ view_source = pkg.view_source()
+ view_dst = pkg.view_destination(self)
+
+ tree = LinkTree(view_source)
+
+ ignore = ignore or (lambda f: False)
+ ignore_file = match_predicate(
+ self.layout.hidden_file_paths, ignore)
+
+ merge_map = tree.get_file_map(view_dst, ignore_file)
+ pkg.remove_files_from_view(self, merge_map)
+
+ # now unmerge the directory tree
+ tree.unmerge_directories(view_dst, ignore_file)
+
+ def remove_file(self, src, dest):
+ if not os.path.islink(dest):
+ raise ValueError("%s is not a link tree!" % dest)
+ # remove if dest is a hardlink/symlink to src; this will only
+ # be false if two packages are merged into a prefix and have a
+ # conflicting file
+ if filecmp.cmp(src, dest, shallow=True):
+ os.remove(dest)
+
def check_added(self, spec):
assert spec.concrete
return spec == self.get_spec(spec)
@@ -363,11 +373,11 @@ class YamlFilesystemView(FilesystemView):
# The spec might have been deactivated as depdency of another package
# already
- if spec.package.is_activated(self.extensions_layout):
+ if spec.package.is_activated(self):
spec.package.do_deactivate(
+ self,
verbose=self.verbose,
- remove_dependents=with_dependents,
- extensions_layout=self.extensions_layout)
+ remove_dependents=with_dependents)
self.unlink_meta_folder(spec)
def remove_standalone(self, spec):
@@ -379,15 +389,15 @@ class YamlFilesystemView(FilesystemView):
'Skipping package not linked in view: %s' % spec.name)
return
- tree = LinkTree(spec.prefix)
- tree.unmerge(self.root, ignore=ignore_metadata_dir)
+ self.unmerge(spec)
self.unlink_meta_folder(spec)
if self.verbose:
tty.info(self._croot + 'Removed package: %s' % colorize_spec(spec))
def get_all_specs(self):
- dotspack = join_path(self.root, spack.store.layout.metadata_dir)
+ dotspack = os.path.join(self.root,
+ spack.store.layout.metadata_dir)
if os.path.exists(dotspack):
return list(filter(None, map(self.get_spec, os.listdir(dotspack))))
else:
@@ -404,12 +414,14 @@ class YamlFilesystemView(FilesystemView):
def get_path_meta_folder(self, spec):
"Get path to meta folder for either spec or spec name."
- return join_path(self.root, spack.store.layout.metadata_dir,
- getattr(spec, "name", spec))
+ return os.path.join(self.root,
+ spack.store.layout.metadata_dir,
+ getattr(spec, "name", spec))
def get_spec(self, spec):
dotspack = self.get_path_meta_folder(spec)
- filename = join_path(dotspack, spack.store.layout.spec_file_name)
+ filename = os.path.join(dotspack,
+ spack.store.layout.spec_file_name)
try:
with open(filename, "r") as f:
@@ -541,7 +553,3 @@ def get_dependencies(specs):
retval = set()
set(map(retval.update, (set(s.traverse()) for s in specs)))
return retval
-
-
-def ignore_metadata_dir(f):
- return f in spack.store.layout.hidden_file_paths
diff --git a/lib/spack/spack/graph.py b/lib/spack/spack/graph.py
index 896bf15e36..6b65932e7d 100644
--- a/lib/spack/spack/graph.py
+++ b/lib/spack/spack/graph.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Functions for graphing DAGs of dependencies.
This file contains code for graphing DAGs of software packages
@@ -543,7 +524,9 @@ def graph_dot(specs, deptype='all', static=False, out=None):
# Static graph includes anything a package COULD depend on.
if static:
- names = set.union(*[s.package.possible_dependencies() for s in specs])
+ names = set.union(*[
+ s.package.possible_dependencies(expand_virtuals=False)
+ for s in specs])
specs = [Spec(name) for name in names]
labeled = set()
diff --git a/lib/spack/spack/hooks/__init__.py b/lib/spack/spack/hooks/__init__.py
index 5bf4110608..b25dfeade2 100644
--- a/lib/spack/spack/hooks/__init__.py
+++ b/lib/spack/spack/hooks/__init__.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This package contains modules with hooks for various stages in the
Spack install process. You can add modules here and they'll be
executed by package at various times during the package lifecycle.
@@ -41,20 +22,20 @@
systems (e.g. modules, dotkit, etc.) or to add other custom
features.
"""
-import imp
+import os.path
-import spack
-from llnl.util.filesystem import join_path
+import spack.paths
+import spack.util.imp as simp
from llnl.util.lang import memoized, list_modules
@memoized
def all_hook_modules():
modules = []
- for name in list_modules(spack.hooks_path):
+ for name in list_modules(spack.paths.hooks_path):
mod_name = __name__ + '.' + name
- path = join_path(spack.hooks_path, name) + ".py"
- mod = imp.load_source(mod_name, path)
+ path = os.path.join(spack.paths.hooks_path, name) + ".py"
+ mod = simp.load_source(mod_name, path)
modules.append(mod)
return modules
diff --git a/lib/spack/spack/hooks/case_consistency.py b/lib/spack/spack/hooks/case_consistency.py
deleted file mode 100644
index 54139cb039..0000000000
--- a/lib/spack/spack/hooks/case_consistency.py
+++ /dev/null
@@ -1,110 +0,0 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-from __future__ import absolute_import
-
-import os
-import re
-import platform
-
-from llnl.util.filesystem import working_dir
-
-import spack
-from spack.cmd import spack_is_git_repo
-from spack.util.executable import which, ProcessError
-
-
-def pre_run():
- if platform.system() != "Darwin":
- return
-
- try:
- repo = spack.repo.get_repo('builtin')
- git_case_consistency_check(repo.packages_path)
- except spack.repository.UnknownNamespaceError:
- pass
-
-
-def git_case_consistency_check(path):
- """Re-sync case of files in a directory with git.
-
- On case-insensitive but case-preserving filesystems like Mac OS X,
- Git doesn't properly rename files that only had their case changed.
-
- This checks files in a directory against git and does a
- case-restoring rename (actually two renames, e.g.::
-
- name -> tmp -> NAME
-
- We use this in Spack to ensure package directories are named
- correctly.
-
- TODO: this check can probably be removed once package names have been
- TODO: lowercase for a long while.
-
- """
- # Don't bother fixing case if Spack isn't in a git repository
- if not spack_is_git_repo():
- return
-
- git = which('git', required=False)
- if not git:
- return
-
- with working_dir(path):
- try:
- git_filenames = git('ls-tree', '--name-only', 'HEAD', output=str)
- git_filenames = set(re.split(r'\s+', git_filenames.strip()))
- except ProcessError:
- return # Ignore errors calling git
-
- lower_to_mixed = {}
- for fn in git_filenames:
- lower = fn.lower()
- mixed = lower_to_mixed.setdefault(lower, [])
- mixed.append(fn)
-
- # Iterate through all actual files and make sure their names are
- # the same as corresponding names in git
- actual_filenames = os.listdir('.')
- for actual in actual_filenames:
- lower = actual.lower()
-
- # not tracked by git
- if lower not in lower_to_mixed:
- continue
-
- # Don't know what to do with multiple matches
- if len(lower_to_mixed[lower]) != 1:
- continue
-
- # Skip if case is already correct
- git_name = lower_to_mixed[lower][0]
- if git_name == actual:
- continue
-
- # restore case with two renames
- tmp_name = actual + '.spack.tmp'
- os.rename(actual, tmp_name)
- os.rename(tmp_name, git_name)
diff --git a/lib/spack/spack/hooks/extensions.py b/lib/spack/spack/hooks/extensions.py
index 7865c34dc0..271e01ab2e 100644
--- a/lib/spack/spack/hooks/extensions.py
+++ b/lib/spack/spack/hooks/extensions.py
@@ -1,27 +1,10 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import spack
+from spack.filesystem_view import YamlFilesystemView
def pre_uninstall(spec):
@@ -29,6 +12,9 @@ def pre_uninstall(spec):
assert spec.concrete
if pkg.is_extension:
- if pkg.is_activated():
+ target = pkg.extendee_spec.prefix
+ view = YamlFilesystemView(target, spack.store.layout)
+
+ if pkg.is_activated(view):
# deactivate globally
pkg.do_deactivate(force=True)
diff --git a/lib/spack/spack/hooks/licensing.py b/lib/spack/spack/hooks/licensing.py
index 9b5a2728ed..bc4d0c2ee2 100644
--- a/lib/spack/spack/hooks/licensing.py
+++ b/lib/spack/spack/hooks/licensing.py
@@ -1,32 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
-import spack
import llnl.util.tty as tty
-from llnl.util.filesystem import join_path, mkdirp
+from llnl.util.filesystem import mkdirp
+
+from spack.util.editor import editor
def pre_install(spec):
@@ -55,7 +37,7 @@ def set_up_license(pkg):
# Create a new license file
write_license_file(pkg, license_path)
# Open up file in user's favorite $EDITOR for editing
- spack.editor(license_path)
+ editor(license_path)
tty.msg("Added global license file %s" % license_path)
else:
# Use already existing license file
@@ -84,63 +66,74 @@ def write_license_file(pkg, license_path):
Comments give suggestions on alternative methods of
installing a license."""
- comment = pkg.license_comment
+ # License files
+ linktargets = ""
+ for f in pkg.license_files:
+ linktargets += "\t%s\n" % f
- # Global license directory may not already exist
- if not os.path.exists(os.path.dirname(license_path)):
- os.makedirs(os.path.dirname(license_path))
- license = open(license_path, 'w')
+ # Environment variables
+ envvars = ""
+ if pkg.license_vars:
+ for varname in pkg.license_vars:
+ envvars += "\t%s\n" % varname
- # License files
- license.write("""\
-{0} A license is required to use {1}.
-{0}
-{0} The recommended solution is to store your license key in this global
-{0} license file. After installation, the following symlink(s) will be
-{0} added to point to this file (relative to the installation prefix):
-{0}
-""".format(comment, pkg.name))
+ # Documentation
+ url = ""
+ if pkg.license_url:
+ url += "\t%s\n" % pkg.license_url
- for filename in pkg.license_files:
- license.write("{0}\t{1}\n".format(comment, filename))
+ # Assemble. NB: pkg.license_comment will be prepended upon output.
+ txt = """
+ A license is required to use package '{0}'.
- license.write("{0}\n".format(comment))
+ * If your system is already properly configured for such a license, save this
+ file UNCHANGED. The system may be configured if:
- # Environment variables
- if pkg.license_vars:
- license.write("""\
-{0} Alternatively, use one of the following environment variable(s):
-{0}
-""".format(comment))
+ - A license file is installed in a default location.
+""".format(pkg.name)
- for var in pkg.license_vars:
- license.write("{0}\t{1}\n".format(comment, var))
+ if envvars:
+ txt += """\
+ - One of the following environment variable(s) is set for you, possibly via
+ a module file:
- license.write("""\
{0}
-{0} If you choose to store your license in a non-standard location, you may
-{0} set one of these variable(s) to the full pathname to the license file, or
-{0} port@host if you store your license keys on a dedicated license server.
-{0} You will likely want to set this variable in a module file so that it
-{0} gets loaded every time someone tries to use {1}.
-{0}
-""".format(comment, pkg.name))
+""".format(envvars)
+
+ txt += """\
+ * Otherwise, depending on the license you have, enter AT THE BEGINNING of
+ this file:
+
+ - the contents of your license file, or
+ - the address(es) of your license server.
+
+ After installation, the following symlink(s) will be added to point to
+ this Spack-global file (relative to the installation prefix).
- # Documentation
- if pkg.license_url:
- license.write("""\
-{0} For further information on how to acquire a license, please refer to:
-{0}
-{0}\t{1}
{0}
-""".format(comment, pkg.license_url))
+""".format(linktargets)
+
+ if url:
+ txt += """\
+ * For further information on licensing, see:
- license.write("""\
-{0} You may enter your license below.
+{0}
+""".format(url)
-""".format(comment))
+ txt += """\
+ Recap:
+ - You may not need to modify this file at all.
+ - Otherwise, enter your license or server address AT THE BEGINNING.
+"""
+ # Global license directory may not already exist
+ if not os.path.exists(os.path.dirname(license_path)):
+ os.makedirs(os.path.dirname(license_path))
- license.close()
+ # Output
+ with open(license_path, 'w') as f:
+ for line in txt.splitlines():
+ f.write("{0}{1}\n".format(pkg.license_comment, line))
+ f.close()
def post_install(spec):
@@ -156,7 +149,8 @@ def symlink_license(pkg):
"""Create local symlinks that point to the global license file."""
target = pkg.global_license_file
for filename in pkg.license_files:
- link_name = join_path(pkg.prefix, filename)
+ link_name = os.path.join(pkg.prefix, filename)
+ link_name = os.path.abspath(link_name)
license_dir = os.path.dirname(link_name)
if not os.path.exists(license_dir):
mkdirp(license_dir)
diff --git a/lib/spack/spack/hooks/module_file_generation.py b/lib/spack/spack/hooks/module_file_generation.py
index 6858b0874e..5581b20b64 100644
--- a/lib/spack/spack/hooks/module_file_generation.py
+++ b/lib/spack/spack/hooks/module_file_generation.py
@@ -1,33 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import spack.modules
import spack.modules.common
import llnl.util.tty as tty
try:
- enabled = spack.modules.common.configuration['enable']
+ enabled = spack.config.get('modules:enable')
except KeyError:
tty.debug('NO MODULE WRITTEN: list of enabled module files is empty')
enabled = []
diff --git a/lib/spack/spack/hooks/permissions_setters.py b/lib/spack/spack/hooks/permissions_setters.py
new file mode 100644
index 0000000000..ceb6105c16
--- /dev/null
+++ b/lib/spack/spack/hooks/permissions_setters.py
@@ -0,0 +1,45 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+
+from llnl.util.filesystem import chmod_x, chgrp
+
+from spack.package_prefs import get_package_permissions, get_package_group
+from spack.package_prefs import get_package_dir_permissions
+
+
+def forall_files(path, fn, args, dir_args=None):
+ """Apply function to all files in directory, with file as first arg.
+
+ Does not apply to the root dir. Does not apply to links"""
+ for root, dirs, files in os.walk(path):
+ for d in dirs:
+ if not os.path.islink(os.path.join(root, d)):
+ if dir_args:
+ fn(os.path.join(root, d), *dir_args)
+ else:
+ fn(os.path.join(root, d), *args)
+ for f in files:
+ if not os.path.islink(os.path.join(root, d)):
+ fn(os.path.join(root, f), *args)
+
+
+def chmod_real_entries(path, perms):
+ # Don't follow links so we don't change things outside the prefix
+ if not os.path.islink(path):
+ chmod_x(path, perms)
+
+
+def post_install(spec):
+ if not spec.external:
+ perms = get_package_permissions(spec)
+ dir_perms = get_package_dir_permissions(spec)
+ group = get_package_group(spec)
+
+ forall_files(spec.prefix, chmod_real_entries, [perms], [dir_perms])
+
+ if group:
+ forall_files(spec.prefix, chgrp, [group])
diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py
index 887dfdc5b9..e03c397d6f 100644
--- a/lib/spack/spack/hooks/sbang.py
+++ b/lib/spack/spack/hooks/sbang.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import stat
import re
import llnl.util.tty as tty
-import spack
+import spack.paths
import spack.modules
# Character limit for shebang line. Using Linux's 127 characters
@@ -56,7 +37,7 @@ def filter_shebang(path):
original = original_file.read()
# This line will be prepended to file
- new_sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.spack_root
+ new_sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.paths.prefix
# Skip files that are already using sbang.
if original.startswith(new_sbang_line):
diff --git a/lib/spack/spack/hooks/yaml_version_check.py b/lib/spack/spack/hooks/yaml_version_check.py
index 338d2e51e7..a6978673ac 100644
--- a/lib/spack/spack/hooks/yaml_version_check.py
+++ b/lib/spack/spack/hooks/yaml_version_check.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Yaml Version Check is a module for ensuring that config file
formats are compatible with the current version of Spack."""
import os.path
@@ -36,8 +17,9 @@ def pre_run():
def check_compiler_yaml_version():
- config_scopes = spack.config.config_scopes
- for scope in config_scopes.values():
+ config = spack.config.config
+
+ for scope in config.file_scopes:
file_name = os.path.join(scope.path, 'compilers.yaml')
data = None
if os.path.isfile(file_name):
@@ -45,8 +27,8 @@ def check_compiler_yaml_version():
data = syaml.load(f)
if data:
- compilers = data['compilers']
- if len(compilers) > 0:
+ compilers = data.get('compilers')
+ if compilers and len(compilers) > 0:
if (not isinstance(compilers, list) or
'operating_system' not in compilers[0]['compiler']):
new_file = os.path.join(scope.path, '_old_compilers.yaml')
diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py
index c3e1ea4506..4f77cd986d 100644
--- a/lib/spack/spack/main.py
+++ b/lib/spack/spack/main.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This is the implementation of the Spack command line executable.
In a normal Spack installation, this is invoked from the bin/spack script
@@ -30,6 +11,7 @@ after the system path is set up.
from __future__ import print_function
import sys
+import re
import os
import inspect
import pstats
@@ -37,32 +19,47 @@ import argparse
from six import StringIO
import llnl.util.tty as tty
+import llnl.util.tty.color as color
from llnl.util.tty.log import log_output
import spack
+import spack.architecture
+import spack.config
import spack.cmd
+import spack.environment as ev
+import spack.hooks
+import spack.paths
+import spack.repo
+import spack.store
+import spack.util.debug
+import spack.util.path
from spack.error import SpackError
-# names of profile statistics
+#: names of profile statistics
stat_names = pstats.Stats.sort_arg_dict_default
-# help levels in order of detail (i.e., number of commands shown)
+#: top-level aliases for Spack commands
+aliases = {
+ 'rm': 'remove'
+}
+
+#: help levels in order of detail (i.e., number of commands shown)
levels = ['short', 'long']
-# intro text for help at different levels
+#: intro text for help at different levels
intro_by_level = {
'short': 'These are common spack commands:',
'long': 'Complete list of spack commands:',
}
-# control top-level spack options shown in basic vs. advanced help
+#: control top-level spack options shown in basic vs. advanced help
options_by_level = {
'short': ['h', 'k', 'V', 'color'],
'long': 'all'
}
-# Longer text for each section, to show in help
+#: Longer text for each section, to show in help
section_descriptions = {
'admin': 'administration',
'basic': 'query packages',
@@ -76,37 +73,42 @@ section_descriptions = {
'system': 'system',
}
-# preferential command order for some sections (e.g., build pipeline is
-# in execution order, not alphabetical)
+#: preferential command order for some sections (e.g., build pipeline is
+#: in execution order, not alphabetical)
section_order = {
'basic': ['list', 'info', 'find'],
'build': ['fetch', 'stage', 'patch', 'configure', 'build', 'restage',
- 'install', 'uninstall', 'clean']
+ 'install', 'uninstall', 'clean'],
+ 'packaging': ['create', 'edit']
}
-# Properties that commands are required to set.
+#: Properties that commands are required to set.
required_command_properties = ['level', 'section', 'description']
+#: Recorded directory where spack command was originally invoked
+spack_working_dir = None
+
def set_working_dir():
"""Change the working directory to getcwd, or spack prefix if no cwd."""
+ global spack_working_dir
try:
- spack.spack_working_dir = os.getcwd()
+ spack_working_dir = os.getcwd()
except OSError:
- os.chdir(spack.spack_prefix)
- spack.spack_working_dir = spack.spack_prefix
+ os.chdir(spack.paths.prefix)
+ spack_working_dir = spack.paths.prefix
def add_all_commands(parser):
"""Add all spack subcommands to the parser."""
- for cmd in spack.cmd.commands:
+ for cmd in spack.cmd.all_commands():
parser.add_command(cmd)
def index_commands():
"""create an index of commands by section for this help level"""
index = {}
- for command in spack.cmd.commands:
+ for command in spack.cmd.all_commands():
cmd_module = spack.cmd.get_module(command)
# make sure command modules have required properties
@@ -127,6 +129,22 @@ def index_commands():
return index
+class SpackHelpFormatter(argparse.RawTextHelpFormatter):
+ def _format_actions_usage(self, actions, groups):
+ """Formatter with more concise usage strings."""
+ usage = super(
+ SpackHelpFormatter, self)._format_actions_usage(actions, groups)
+
+ # compress single-character flags that are not mutually exclusive
+ # at the beginning of the usage string
+ chars = ''.join(re.findall(r'\[-(.)\]', usage))
+ usage = re.sub(r'\[-.\] ?', '', usage)
+ if chars:
+ return '[-%s] %s' % (chars, usage)
+ else:
+ return usage
+
+
class SpackArgumentParser(argparse.ArgumentParser):
def format_help_sections(self, level):
"""Format help on sections for a particular verbosity level.
@@ -149,7 +167,7 @@ class SpackArgumentParser(argparse.ArgumentParser):
self.actions = self._subparsers._actions[-1]._get_subactions()
# make a set of commands not yet added.
- remaining = set(spack.cmd.commands)
+ remaining = set(spack.cmd.all_commands())
def add_group(group):
formatter.start_section(group.title)
@@ -159,11 +177,11 @@ class SpackArgumentParser(argparse.ArgumentParser):
def add_subcommand_group(title, commands):
"""Add informational help group for a specific subcommand set."""
- cmd_set = set(commands)
+ cmd_set = set(c for c in commands)
# make a dict of commands of interest
- cmds = dict((action.metavar, action) for action in self.actions
- if action.metavar in cmd_set)
+ cmds = dict((a.dest, a) for a in self.actions
+ if a.dest in cmd_set)
# add commands to a group in order, and add the group
group = argparse._ArgumentGroup(self, title=title)
@@ -182,14 +200,11 @@ class SpackArgumentParser(argparse.ArgumentParser):
new_actions = [opts[letter] for letter in show_options]
self._optionals._group_actions = new_actions
- options = ''.join(opt.option_strings[0].strip('-')
- for opt in self._optionals._group_actions)
-
- index = index_commands()
-
- # usage
- formatter.add_text(
- "usage: %s [-%s] <command> [...]" % (self.prog, options))
+ # custom, more concise usage for top level
+ help_options = self._optionals._group_actions
+ help_options = help_options + [self._positionals._group_actions[-1]]
+ formatter.add_usage(
+ self.usage, help_options, self._mutually_exclusive_groups)
# description
formatter.add_text(self.description)
@@ -198,7 +213,9 @@ class SpackArgumentParser(argparse.ArgumentParser):
formatter.add_text(intro_by_level[level])
# add argument groups based on metadata in commands
+ index = index_commands()
sections = index[level]
+
for section in sorted(sections):
if section == 'help':
continue # Cover help in the epilog.
@@ -226,7 +243,7 @@ class SpackArgumentParser(argparse.ArgumentParser):
# epilog
formatter.add_text("""\
{help}:
- spack help -a list all available commands
+ spack help --all list all commands and options
spack help <command> help on a specific command
spack help --spec help on the spec syntax
spack docs open http://spack.rtfd.io/ in a browser"""
@@ -235,11 +252,20 @@ class SpackArgumentParser(argparse.ArgumentParser):
# determine help from format above
return formatter.format_help()
- def add_command(self, name):
- """Add one subcommand to this parser."""
- # convert CLI command name to python module name
- name = spack.cmd.get_python_name(name)
+ def add_subparsers(self, **kwargs):
+ """Ensure that sensible defaults are propagated to subparsers"""
+ kwargs.setdefault('metavar', 'SUBCOMMAND')
+ sp = super(SpackArgumentParser, self).add_subparsers(**kwargs)
+ old_add_parser = sp.add_parser
+
+ def add_parser(name, **kwargs):
+ kwargs.setdefault('formatter_class', SpackHelpFormatter)
+ return old_add_parser(name, **kwargs)
+ sp.add_parser = add_parser
+ return sp
+ def add_command(self, cmd_name):
+ """Add one subcommand to this parser."""
# lazily initialize any subparsers
if not hasattr(self, 'subparsers'):
# remove the dummy "command" argument.
@@ -250,12 +276,18 @@ class SpackArgumentParser(argparse.ArgumentParser):
# each command module implements a parser() function, to which we
# pass its subparser for setup.
- module = spack.cmd.get_module(name)
- cmd_name = name.replace('_', '-')
+ module = spack.cmd.get_module(cmd_name)
+
+ # build a list of aliases
+ alias_list = [k for k, v in aliases.items() if v == cmd_name]
+
subparser = self.subparsers.add_parser(
- cmd_name, help=module.description, description=module.description)
+ cmd_name, aliases=alias_list,
+ help=module.description, description=module.description)
module.setup_parser(subparser)
- return module
+
+ # return the callable function for the command
+ return spack.cmd.get_command(cmd_name)
def format_help(self, level='short'):
if self.prog == 'spack':
@@ -267,43 +299,89 @@ class SpackArgumentParser(argparse.ArgumentParser):
return super(SpackArgumentParser, self).format_help()
-def make_argument_parser():
+def make_argument_parser(**kwargs):
"""Create an basic argument parser without any subcommands added."""
parser = SpackArgumentParser(
- formatter_class=argparse.RawTextHelpFormatter, add_help=False,
+ formatter_class=SpackHelpFormatter, add_help=False,
description=(
"A flexible package manager that supports multiple versions,\n"
- "configurations, platforms, and compilers."))
+ "configurations, platforms, and compilers."),
+ **kwargs)
# stat names in groups of 7, for nice wrapping.
stat_lines = list(zip(*(iter(stat_names),) * 7))
- parser.add_argument('-h', '--help', action='store_true',
- help="show this help message and exit")
- parser.add_argument('--color', action='store', default='auto',
- choices=('always', 'never', 'auto'),
- help="when to colorize output; default is auto")
- parser.add_argument('-d', '--debug', action='store_true',
- help="write out debug logs during compile")
- parser.add_argument('-D', '--pdb', action='store_true',
- help="run spack under the pdb debugger")
- parser.add_argument('-k', '--insecure', action='store_true',
- help="do not check ssl certificates when downloading")
- parser.add_argument('-m', '--mock', action='store_true',
- help="use mock packages instead of real ones")
- parser.add_argument('-p', '--profile', action='store_true',
- help="profile execution using cProfile")
- parser.add_argument('-P', '--sorted-profile', default=None, metavar="STAT",
- help="profile and sort by one or more of:\n[%s]" %
- ',\n '.join([', '.join(line) for line in stat_lines]))
- parser.add_argument('--lines', default=20, action='store',
- help="lines of profile output; default 20; or 'all'")
- parser.add_argument('-v', '--verbose', action='store_true',
- help="print additional output during builds")
- parser.add_argument('-s', '--stacktrace', action='store_true',
- help="add stacktraces to all printed statements")
- parser.add_argument('-V', '--version', action='store_true',
- help='show version number and exit')
+ parser.add_argument(
+ '-h', '--help',
+ dest='help', action='store_const', const='short', default=None,
+ help="show this help message and exit")
+ parser.add_argument(
+ '-H', '--all-help',
+ dest='help', action='store_const', const='long', default=None,
+ help="show help for all commands (same as spack help --all)")
+ parser.add_argument(
+ '--color', action='store', default='auto',
+ choices=('always', 'never', 'auto'),
+ help="when to colorize output (default: auto)")
+ parser.add_argument(
+ '-C', '--config-scope', dest='config_scopes', action='append',
+ metavar='DIR', help="add a custom configuration scope")
+ parser.add_argument(
+ '-d', '--debug', action='store_true',
+ help="write out debug logs during compile")
+ parser.add_argument(
+ '--pdb', action='store_true',
+ help="run spack under the pdb debugger")
+
+ env_group = parser.add_mutually_exclusive_group()
+ env_group.add_argument(
+ '-e', '--env', dest='env', metavar='ENV', action='store',
+ help="run with a specific environment (see spack env)")
+ env_group.add_argument(
+ '-D', '--env-dir', dest='env_dir', metavar='DIR', action='store',
+ help="run with an environment directory (ignore named environments)")
+ env_group.add_argument(
+ '-E', '--no-env', dest='no_env', action='store_true',
+ help="run without any environments activated (see spack env)")
+ parser.add_argument(
+ '--use-env-repo', action='store_true',
+ help="when running in an environment, use its package repository")
+
+ parser.add_argument(
+ '-k', '--insecure', action='store_true',
+ help="do not check ssl certificates when downloading")
+ parser.add_argument(
+ '-l', '--enable-locks', action='store_true', dest='locks',
+ default=None, help="use filesystem locking (default)")
+ parser.add_argument(
+ '-L', '--disable-locks', action='store_false', dest='locks',
+ help="do not use filesystem locking (unsafe)")
+ parser.add_argument(
+ '-m', '--mock', action='store_true',
+ help="use mock packages instead of real ones")
+ parser.add_argument(
+ '-p', '--profile', action='store_true', dest='spack_profile',
+ help="profile execution using cProfile")
+ parser.add_argument(
+ '--sorted-profile', default=None, metavar="STAT",
+ help="profile and sort by one or more of:\n[%s]" %
+ ',\n '.join([', '.join(line) for line in stat_lines]))
+ parser.add_argument(
+ '--lines', default=20, action='store',
+ help="lines of profile output or 'all' (default: 20)")
+ parser.add_argument(
+ '-v', '--verbose', action='store_true',
+ help="print additional output during builds")
+ parser.add_argument(
+ '--stacktrace', action='store_true',
+ help="add stacktraces to all printed statements")
+ parser.add_argument(
+ '-V', '--version', action='store_true',
+ help='show version number and exit')
+ parser.add_argument(
+ '--print-shell-vars', action='store',
+ help="print info needed by setup-env.[c]sh")
+
return parser
@@ -313,23 +391,30 @@ def setup_main_options(args):
tty.set_verbose(args.verbose)
tty.set_debug(args.debug)
tty.set_stacktrace(args.stacktrace)
- spack.debug = args.debug
- if spack.debug:
- import spack.util.debug as debug
- debug.register_interrupt_handler()
+ # debug must be set first so that it can even affect behvaior of
+ # errors raised by spack.config.
+ if args.debug:
+ spack.error.debug = True
+ spack.util.debug.register_interrupt_handler()
+ spack.config.set('config:debug', True, scope='command_line')
+
+ # override lock configuration if passed on command line
+ if args.locks is not None:
+ spack.util.lock.check_lock_safety(spack.paths.prefix)
+ spack.config.set('config:locks', False, scope='command_line')
if args.mock:
- from spack.repository import RepoPath
- spack.repo.swap(RepoPath(spack.mock_packages_path))
+ rp = spack.repo.RepoPath(spack.paths.mock_packages_path)
+ spack.repo.set_path(rp)
# If the user asked for it, don't check ssl certs.
if args.insecure:
tty.warn("You asked for --insecure. Will NOT check SSL certificates.")
- spack.insecure = True
+ spack.config.set('config:verify_ssl', False, scope='command_line')
# when to use color (takes always, auto, or never)
- tty.color.set_color_when(args.color)
+ color.set_color_when(args.color)
def allows_unknown_args(command):
@@ -345,7 +430,7 @@ def allows_unknown_args(command):
return (argcount == 3 and varnames[2] == 'unknown_args')
-def _invoke_spack_command(command, parser, args, unknown_args):
+def _invoke_command(command, parser, args, unknown_args):
"""Run a spack command *without* setting spack global options."""
if allows_unknown_args(command):
return_val = command(parser, args, unknown_args)
@@ -369,12 +454,15 @@ class SpackCommand(object):
Use this to invoke Spack commands directly from Python and check
their output.
"""
- def __init__(self, command):
- """Create a new SpackCommand that invokes ``command`` when called."""
+ def __init__(self, command_name):
+ """Create a new SpackCommand that invokes ``command_name`` when called.
+
+ Args:
+ command_name (str): name of the command to invoke
+ """
self.parser = make_argument_parser()
- self.parser.add_command(command)
- self.command_name = command
- self.command = spack.cmd.get_command(command)
+ self.command = self.parser.add_command(command_name)
+ self.command_name = command_name
def __call__(self, *argv, **kwargs):
"""Invoke this SpackCommand.
@@ -388,7 +476,7 @@ class SpackCommand(object):
Returns:
(str): combined output and error as a string
- On return, if ``fail_on_error`` is False, return value of comman
+ On return, if ``fail_on_error`` is False, return value of command
is set in ``returncode`` property, and the error is set in the
``error`` property. Otherwise, raise an error.
"""
@@ -404,7 +492,7 @@ class SpackCommand(object):
out = StringIO()
try:
with log_output(out):
- self.returncode = _invoke_spack_command(
+ self.returncode = _invoke_command(
self.command, self.parser, args, unknown)
except SystemExit as e:
@@ -424,30 +512,6 @@ class SpackCommand(object):
return out.getvalue()
-def _main(command, parser, args, unknown_args):
- """Run a spack command *and* set spack globaloptions."""
- # many operations will fail without a working directory.
- set_working_dir()
-
- # only setup main options in here, after the real parse (we'll get it
- # wrong if we do it after the initial, partial parse)
- setup_main_options(args)
- spack.hooks.pre_run()
-
- # Now actually execute the command
- try:
- return _invoke_spack_command(command, parser, args, unknown_args)
- except SpackError as e:
- e.die() # gracefully die on any SpackErrors
- except Exception as e:
- if spack.debug:
- raise
- tty.die(str(e))
- except KeyboardInterrupt:
- sys.stderr.write('\n')
- tty.die("Keyboard interrupt.")
-
-
def _profile_wrapper(command, parser, args, unknown_args):
import cProfile
@@ -470,7 +534,7 @@ def _profile_wrapper(command, parser, args, unknown_args):
# make a profiler and run the code.
pr = cProfile.Profile()
pr.enable()
- return _main(command, parser, args, unknown_args)
+ return _invoke_command(command, parser, args, unknown_args)
finally:
pr.disable()
@@ -481,6 +545,46 @@ def _profile_wrapper(command, parser, args, unknown_args):
stats.print_stats(nlines)
+def print_setup_info(*info):
+ """Print basic information needed by setup-env.[c]sh.
+
+ Args:
+ info (list of str): list of things to print: comma-separated list
+ of 'csh', 'sh', or 'modules'
+
+ This is in ``main.py`` to make it fast; the setup scripts need to
+ invoke spack in login scripts, and it needs to be quick.
+
+ """
+ shell = 'csh' if 'csh' in info else 'sh'
+
+ def shell_set(var, value):
+ if shell == 'sh':
+ print("%s='%s'" % (var, value))
+ elif shell == 'csh':
+ print("set %s = '%s'" % (var, value))
+ else:
+ tty.die('shell must be sh or csh')
+
+ # print sys type
+ shell_set('_sp_sys_type', spack.architecture.sys_type())
+
+ # print roots for all module systems
+ module_roots = spack.config.get('config:module_roots')
+ for name, path in module_roots.items():
+ path = spack.util.path.canonicalize_path(path)
+ shell_set('_sp_%s_root' % name, path)
+
+ # print environment module system if available. This can be expensive
+ # on clusters, so skip it if not needed.
+ if 'modules' in info:
+ specs = spack.store.db.query('environment-modules')
+ if specs:
+ shell_set('_sp_module_prefix', specs[-1].prefix)
+ else:
+ shell_set('_sp_module_prefix', 'not_installed')
+
+
def main(argv=None):
"""This is the entry point for the Spack command.
@@ -496,55 +600,85 @@ def main(argv=None):
parser.add_argument('command', nargs=argparse.REMAINDER)
args, unknown = parser.parse_known_args(argv)
+ # activate an environment if one was specified on the command line
+ if not args.no_env:
+ env = ev.find_environment(args)
+ if env:
+ ev.activate(env, args.use_env_repo)
+
+ # make spack.config aware of any command line configuration scopes
+ if args.config_scopes:
+ spack.config.command_line_scopes = args.config_scopes
+
+ if args.print_shell_vars:
+ print_setup_info(*args.print_shell_vars.split(','))
+ return 0
+
# Just print help and exit if run with no arguments at all
no_args = (len(sys.argv) == 1) if argv is None else (len(argv) == 0)
if no_args:
parser.print_help()
return 1
- # -h and -V are special as they do not require a command, but all the
- # other options do nothing without a command.
- if not args.command:
- if args.version:
- print(spack.spack_version)
- return 0
- else:
- parser.print_help()
- return 0 if args.help else 1
-
- # Try to load the particular command the caller asked for. If there
- # is no module for it, just die.
- command_name = spack.cmd.get_python_name(args.command[0])
- try:
- parser.add_command(command_name)
- except ImportError:
- if spack.debug:
- raise
- tty.die("Unknown command: %s" % args.command[0])
-
- # Re-parse with the proper sub-parser added.
- args, unknown = parser.parse_known_args()
-
- # we now know whether options go with spack or the command
+ # -h, -H, and -V are special as they do not require a command, but
+ # all the other options do nothing without a command.
if args.version:
print(spack.spack_version)
return 0
elif args.help:
- parser.print_help()
+ sys.stdout.write(parser.format_help(level=args.help))
return 0
+ elif not args.command:
+ parser.print_help()
+ return 1
- # now we can actually execute the command.
- command = spack.cmd.get_command(command_name)
try:
- if args.profile or args.sorted_profile:
+ # ensure options on spack command come before everything
+ setup_main_options(args)
+
+ # Try to load the particular command the caller asked for. If there
+ # is no module for it, just die.
+ cmd_name = args.command[0]
+ cmd_name = aliases.get(cmd_name, cmd_name)
+
+ try:
+ command = parser.add_command(cmd_name)
+ except ImportError:
+ if spack.config.get('config:debug'):
+ raise
+ tty.die("Unknown command: %s" % args.command[0])
+
+ # Re-parse with the proper sub-parser added.
+ args, unknown = parser.parse_known_args()
+
+ # many operations will fail without a working directory.
+ set_working_dir()
+
+ # pre-run hooks happen after we know we have a valid working dir
+ spack.hooks.pre_run()
+
+ # now we can actually execute the command.
+ if args.spack_profile or args.sorted_profile:
_profile_wrapper(command, parser, args, unknown)
elif args.pdb:
import pdb
- pdb.runctx('_main(command, parser, args, unknown)',
+ pdb.runctx('_invoke_command(command, parser, args, unknown)',
globals(), locals())
return 0
else:
- return _main(command, parser, args, unknown)
+ return _invoke_command(command, parser, args, unknown)
+
+ except SpackError as e:
+ e.die() # gracefully die on any SpackErrors
+
+ except Exception as e:
+ if spack.config.get('config:debug'):
+ raise
+ tty.die(str(e))
+
+ except KeyboardInterrupt:
+ sys.stderr.write('\n')
+ tty.die("Keyboard interrupt.")
except SystemExit as e:
return e.code
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index f8cedc38b4..3310bc53fb 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This file contains code for creating spack mirror directories. A
mirror is an organized hierarchy containing specially named archive
@@ -33,9 +14,9 @@ to download packages directly from a mirror (e.g., on an intranet).
import sys
import os
import llnl.util.tty as tty
-from llnl.util.filesystem import mkdirp, join_path
+from llnl.util.filesystem import mkdirp
-import spack
+import spack.config
import spack.error
import spack.url as url
import spack.fetch_strategy as fs
@@ -44,7 +25,7 @@ from spack.version import VersionList
from spack.util.compression import allowed_archive
-def mirror_archive_filename(spec, fetcher, resourceId=None):
+def mirror_archive_filename(spec, fetcher, resource_id=None):
"""Get the name of the spec's archive in the mirror."""
if not spec.version.concrete:
raise ValueError("mirror.path requires spec with concrete version.")
@@ -87,18 +68,18 @@ Spack not to expand it with the following syntax:
# Otherwise we'll make a .tar.gz ourselves
ext = 'tar.gz'
- if resourceId:
- filename = "%s-%s" % (resourceId, spec.version) + ".%s" % ext
+ if resource_id:
+ filename = "%s-%s" % (resource_id, spec.version) + ".%s" % ext
else:
filename = "%s-%s" % (spec.package.name, spec.version) + ".%s" % ext
return filename
-def mirror_archive_path(spec, fetcher, resourceId=None):
+def mirror_archive_path(spec, fetcher, resource_id=None):
"""Get the relative path to the spec's archive within a mirror."""
- return join_path(
- spec.name, mirror_archive_filename(spec, fetcher, resourceId))
+ return os.path.join(
+ spec.name, mirror_archive_filename(spec, fetcher, resource_id))
def get_matching_versions(specs, **kwargs):
@@ -222,12 +203,12 @@ def add_single_spec(spec, mirror_root, categories, **kwargs):
fetcher = stage.fetcher
if ii == 0:
# create a subdirectory for the current package@version
- archive_path = os.path.abspath(join_path(
+ archive_path = os.path.abspath(os.path.join(
mirror_root, mirror_archive_path(spec, fetcher)))
name = spec.cformat("$_$@")
else:
resource = stage.resource
- archive_path = os.path.abspath(join_path(
+ archive_path = os.path.abspath(os.path.join(
mirror_root,
mirror_archive_path(spec, fetcher, resource.name)))
name = "{resource} ({pkg}).".format(
@@ -255,7 +236,7 @@ def add_single_spec(spec, mirror_root, categories, **kwargs):
categories['mirrored'].append(spec)
except Exception as e:
- if spack.debug:
+ if spack.config.get('config:debug'):
sys.excepthook(*sys.exc_info())
else:
tty.warn(
diff --git a/lib/spack/spack/mixins.py b/lib/spack/spack/mixins.py
new file mode 100644
index 0000000000..bae8ec7494
--- /dev/null
+++ b/lib/spack/spack/mixins.py
@@ -0,0 +1,194 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""This module contains additional behavior that can be attached to any given
+package.
+"""
+import collections
+import os
+
+import llnl.util.filesystem
+
+__all__ = [
+ 'filter_compiler_wrappers'
+]
+
+
+class PackageMixinsMeta(type):
+ """This metaclass serves the purpose of implementing a declarative syntax
+ for package mixins.
+
+ Mixins are implemented below in the form of a function. Each one of them
+ needs to register a callable that takes a single argument to be run
+ before or after a certain phase. This callable is basically a method that
+ gets implicitly attached to the package class by calling the mixin.
+ """
+
+ _methods_to_be_added = {}
+ _add_method_before = collections.defaultdict(list)
+ _add_method_after = collections.defaultdict(list)
+
+ @staticmethod
+ def register_method_before(fn, phase):
+ """Registers a method to be run before a certain phase.
+
+ Args:
+ fn: function taking a single argument (self)
+ phase (str): phase before which fn must run
+ """
+ PackageMixinsMeta._methods_to_be_added[fn.__name__] = fn
+ PackageMixinsMeta._add_method_before[phase].append(fn)
+
+ @staticmethod
+ def register_method_after(fn, phase):
+ """Registers a method to be run after a certain phase.
+
+ Args:
+ fn: function taking a single argument (self)
+ phase (str): phase after which fn must run
+ """
+ PackageMixinsMeta._methods_to_be_added[fn.__name__] = fn
+ PackageMixinsMeta._add_method_after[phase].append(fn)
+
+ def __init__(cls, name, bases, attr_dict):
+
+ # Add the methods to the class being created
+ if PackageMixinsMeta._methods_to_be_added:
+ attr_dict.update(PackageMixinsMeta._methods_to_be_added)
+ PackageMixinsMeta._methods_to_be_added.clear()
+
+ attr_fmt = '_InstallPhase_{0}'
+
+ # Copy the phases that needs it to the most derived classes
+ # in order not to interfere with other packages in the hierarchy
+ phases_to_be_copied = list(
+ PackageMixinsMeta._add_method_before.keys()
+ )
+ phases_to_be_copied += list(
+ PackageMixinsMeta._add_method_after.keys()
+ )
+
+ for phase in phases_to_be_copied:
+
+ attr_name = attr_fmt.format(phase)
+
+ # Here we want to get the attribute directly from the class (not
+ # from the instance), so that we can modify it and add the mixin
+ # method to the pipeline.
+ phase = getattr(cls, attr_name)
+
+ # Due to MRO, we may have taken a method from a parent class
+ # and modifying it may influence other packages in unwanted
+ # manners. Solve the problem by copying the phase into the most
+ # derived class.
+ setattr(cls, attr_name, phase.copy())
+
+ # Insert the methods in the appropriate position
+ # in the installation pipeline.
+
+ for phase in PackageMixinsMeta._add_method_before:
+
+ attr_name = attr_fmt.format(phase)
+ phase_obj = getattr(cls, attr_name)
+ fn_list = PackageMixinsMeta._add_method_after[phase]
+
+ for f in fn_list:
+ phase_obj.run_before.append(f)
+
+ # Flush the dictionary for the next class
+ PackageMixinsMeta._add_method_before.clear()
+
+ for phase in PackageMixinsMeta._add_method_after:
+
+ attr_name = attr_fmt.format(phase)
+ phase_obj = getattr(cls, attr_name)
+ fn_list = PackageMixinsMeta._add_method_after[phase]
+
+ for f in fn_list:
+ phase_obj.run_after.append(f)
+
+ # Flush the dictionary for the next class
+ PackageMixinsMeta._add_method_after.clear()
+
+ super(PackageMixinsMeta, cls).__init__(name, bases, attr_dict)
+
+
+def filter_compiler_wrappers(*files, **kwargs):
+ """Substitutes any path referring to a Spack compiler wrapper with the
+ path of the underlying compiler that has been used.
+
+ If this isn't done, the files will have CC, CXX, F77, and FC set to
+ Spack's generic cc, c++, f77, and f90. We want them to be bound to
+ whatever compiler they were built with.
+
+ Args:
+ *files: files to be filtered relative to the search root (which is,
+ by default, the installation prefix)
+
+ **kwargs: allowed keyword arguments
+
+ after
+ specifies after which phase the files should be
+ filtered (defaults to 'install')
+
+ relative_root
+ path relative to prefix where to start searching for
+ the files to be filtered. If not set the install prefix
+ wil be used as the search root. **It is highly recommended
+ to set this, as searching from the installation prefix may
+ affect performance severely in some cases**.
+
+ ignore_absent, backup
+ these two keyword arguments, if present, will be forwarded
+ to ``filter_file`` (see its documentation for more information
+ on their behavior)
+
+ recursive
+ this keyword argument, if present, will be forwarded to
+ ``find`` (see its documentation for more information on the
+ behavior)
+ """
+ after = kwargs.get('after', 'install')
+ relative_root = kwargs.get('relative_root', None)
+
+ filter_kwargs = {
+ 'ignore_absent': kwargs.get('ignore_absent', True),
+ 'backup': kwargs.get('backup', False),
+ 'string': True
+ }
+
+ find_kwargs = {
+ 'recursive': kwargs.get('recursive', False)
+ }
+
+ def _filter_compiler_wrappers_impl(self):
+ # Compute the absolute path of the search root
+ root = os.path.join(
+ self.prefix, relative_root
+ ) if relative_root else self.prefix
+
+ # Compute the absolute path of the files to be filtered and
+ # remove links from the list.
+ abs_files = llnl.util.filesystem.find(root, files, **find_kwargs)
+ abs_files = [x for x in abs_files if not os.path.islink(x)]
+
+ x = llnl.util.filesystem.FileFilter(*abs_files)
+
+ replacements = [
+ ('CC', self.compiler.cc),
+ ('CXX', self.compiler.cxx),
+ ('F77', self.compiler.f77),
+ ('FC', self.compiler.fc)
+ ]
+ for env_var, compiler_path in replacements:
+ if env_var in os.environ:
+ x.filter(os.environ[env_var], compiler_path, **filter_kwargs)
+
+ # Remove this linking flag if present (it turns RPATH into RUNPATH)
+ x.filter('-Wl,--enable-new-dtags', '', **filter_kwargs)
+
+ PackageMixinsMeta.register_method_after(
+ _filter_compiler_wrappers_impl, after
+ )
diff --git a/lib/spack/spack/modules/__init__.py b/lib/spack/spack/modules/__init__.py
index 47802092a5..edafb2e57b 100644
--- a/lib/spack/spack/modules/__init__.py
+++ b/lib/spack/spack/modules/__init__.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This package contains code for creating environment modules, which can
include dotkits, TCL non-hierarchical modules, LUA hierarchical modules, and
others.
diff --git a/lib/spack/spack/modules/common.py b/lib/spack/spack/modules/common.py
index 86abaae7c3..482c3e1321 100644
--- a/lib/spack/spack/modules/common.py
+++ b/lib/spack/spack/modules/common.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Here we consolidate the logic for creating an abstract description
of the information that module systems need.
@@ -56,22 +37,23 @@ import re
import six
import llnl.util.filesystem
import llnl.util.tty as tty
-import spack
+
+import spack.paths
import spack.build_environment as build_environment
-import spack.environment
+import spack.util.environment
import spack.tengine as tengine
import spack.util.path
import spack.util.environment
import spack.error
-#: Root folders where the various module files should be written
-roots = spack.config.get_config('config').get('module_roots', {})
+#: config section for this file
+configuration = spack.config.get('modules')
-#: Merged modules.yaml as a dictionary
-configuration = spack.config.get_config('modules')
+#: Root folders where the various module files should be written
+roots = spack.config.get('config:module_roots', {})
#: Inspections that needs to be done on spec prefixes
-prefix_inspections = configuration.get('prefix_inspections', {})
+prefix_inspections = spack.config.get('modules:prefix_inspections', {})
#: Valid tokens for naming scheme and env variable names
_valid_tokens = (
@@ -191,7 +173,7 @@ def merge_config_rules(configuration, spec):
if constraint.endswith(':'):
constraint = constraint.strip(':')
override = True
- if spec.satisfies(constraint):
+ if spec.satisfies(constraint, strict=True):
if override:
spec_configuration = {}
update_dictionary_extending_lists(spec_configuration, action)
@@ -229,7 +211,7 @@ def root_path(name):
Returns:
root folder for module file installation
"""
- path = roots.get(name, os.path.join(spack.share_path, name))
+ path = roots.get(name, os.path.join(spack.paths.share_path, name))
return spack.util.path.canonicalize_path(path)
@@ -274,7 +256,7 @@ class BaseConfiguration(object):
"""List of environment modifications that should be done in the
module.
"""
- env_mods = spack.environment.EnvironmentModifications()
+ env_mods = spack.util.environment.EnvironmentModifications()
actions = self.conf.get('environment', {})
def process_arglist(arglist):
@@ -518,14 +500,14 @@ class BaseContext(tengine.Context):
def environment_modifications(self):
"""List of environment modifications to be processed."""
# Modifications guessed inspecting the spec prefix
- env = spack.environment.inspect_path(
+ env = spack.util.environment.inspect_path(
self.spec.prefix,
prefix_inspections,
exclude=spack.util.environment.is_system_path
)
# Modifications that are coded at package level
- _ = spack.environment.EnvironmentModifications()
+ _ = spack.util.environment.EnvironmentModifications()
# TODO : the code down below is quite similar to
# TODO : build_environment.setup_package and needs to be factored out
# TODO : to a single place
@@ -564,7 +546,7 @@ class BaseContext(tengine.Context):
# tokens uppercase.
transform = {}
for token in _valid_tokens:
- transform[token] = str.upper
+ transform[token] = lambda spec, string: str.upper(string)
for x in env:
# Ensure all the tokens are valid in this context
diff --git a/lib/spack/spack/modules/dotkit.py b/lib/spack/spack/modules/dotkit.py
index e1374292d6..156a267b4f 100644
--- a/lib/spack/spack/modules/dotkit.py
+++ b/lib/spack/spack/modules/dotkit.py
@@ -1,35 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This module implements the classes necessary to generate dotkit modules."""
import os.path
+import spack.config
from .common import BaseConfiguration, BaseFileLayout
-from .common import BaseContext, BaseModuleFileWriter, configuration
+from .common import BaseContext, BaseModuleFileWriter
#: Dotkit specific part of the configuration
-configuration = configuration.get('dotkit', {})
+configuration = spack.config.get('modules:dotkit', {})
#: Caches the configuration {spec_hash: configuration}
configuration_registry = {}
diff --git a/lib/spack/spack/modules/lmod.py b/lib/spack/spack/modules/lmod.py
index db221b8da3..ffea55184f 100644
--- a/lib/spack/spack/modules/lmod.py
+++ b/lib/spack/spack/modules/lmod.py
@@ -1,42 +1,25 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os.path
+
import llnl.util.lang as lang
+import itertools
+import collections
+
+import spack.config
import spack.compilers
import spack.spec
import spack.error
-import itertools
-import collections
import spack.tengine as tengine
from .common import BaseConfiguration, BaseFileLayout
-from .common import BaseContext, BaseModuleFileWriter, configuration
+from .common import BaseContext, BaseModuleFileWriter
-#: LMOD specific part of the configuration
-configuration = configuration.get('lmod', {})
+#: TCL specific part of the configuration
+configuration = spack.config.get('modules:lmod', {})
#: Caches the configuration {spec_hash: configuration}
configuration_registry = {}
@@ -63,6 +46,46 @@ def make_context(spec):
return LmodContext(conf)
+def guess_core_compilers(store=False):
+ """Guesses the list of core compilers installed in the system.
+
+ Args:
+ store (bool): if True writes the core compilers to the
+ modules.yaml configuration file
+
+ Returns:
+ List of core compilers, if found, or None
+ """
+ core_compilers = []
+ for compiler_config in spack.compilers.all_compilers_config():
+ try:
+ compiler = compiler_config['compiler']
+ # A compiler is considered to be a core compiler if any of the
+ # C, C++ or Fortran compilers reside in a system directory
+ is_system_compiler = any(
+ os.path.dirname(x) in spack.util.environment.system_dirs
+ for x in compiler['paths'].values() if x is not None
+ )
+ if is_system_compiler:
+ core_compilers.append(str(compiler['spec']))
+ except (KeyError, TypeError, AttributeError):
+ continue
+
+ if store and core_compilers:
+ # If we asked to store core compilers, update the entry
+ # in the default modify scope (i.e. within the directory hierarchy
+ # of Spack itself)
+ modules_cfg = spack.config.get(
+ 'modules', scope=spack.config.default_modify_scope()
+ )
+ modules_cfg.setdefault('lmod', {})['core_compilers'] = core_compilers
+ spack.config.set(
+ 'modules', modules_cfg, scope=spack.config.default_modify_scope()
+ )
+
+ return core_compilers or None
+
+
class LmodConfiguration(BaseConfiguration):
"""Configuration class for lmod module files."""
@@ -75,12 +98,12 @@ class LmodConfiguration(BaseConfiguration):
specified in the configuration file or the sequence
is empty
"""
- value = configuration.get('core_compilers')
- if value is None:
- msg = "'core_compilers' key not found in configuration file"
- raise CoreCompilersNotFoundError(msg)
+ value = configuration.get(
+ 'core_compilers'
+ ) or guess_core_compilers(store=True)
+
if not value:
- msg = "'core_compilers' list cannot be empty"
+ msg = 'the key "core_compilers" must be set in modules.yaml'
raise CoreCompilersNotFoundError(msg)
return value
diff --git a/lib/spack/spack/modules/tcl.py b/lib/spack/spack/modules/tcl.py
index e3085f5d79..bec4e27d4a 100644
--- a/lib/spack/spack/modules/tcl.py
+++ b/lib/spack/spack/modules/tcl.py
@@ -1,41 +1,23 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This module implements the classes necessary to generate TCL
non-hierarchical modules.
"""
import os.path
import string
-import spack.tengine as tengine
import llnl.util.tty as tty
+import spack.config
+import spack.tengine as tengine
from .common import BaseConfiguration, BaseFileLayout
-from .common import BaseContext, BaseModuleFileWriter, configuration
+from .common import BaseContext, BaseModuleFileWriter
#: TCL specific part of the configuration
-configuration = configuration.get('tcl', {})
+configuration = spack.config.get('modules:tcl', {})
#: Caches the configuration {spec_hash: configuration}
configuration_registry = {}
diff --git a/lib/spack/spack/multimethod.py b/lib/spack/spack/multimethod.py
index 78d547a69a..a66abe7bf7 100644
--- a/lib/spack/spack/multimethod.py
+++ b/lib/spack/spack/multimethod.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""This module contains utilities for using multi-methods in
spack. You can think of multi-methods like overloaded methods --
they're methods with the same name, and we need to select a version
diff --git a/lib/spack/spack/operating_systems/__init__.py b/lib/spack/spack/operating_systems/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/spack/operating_systems/__init__.py
+++ b/lib/spack/spack/operating_systems/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/spack/operating_systems/cnk.py b/lib/spack/spack/operating_systems/cnk.py
index 008e5fc33b..aca4e869f4 100644
--- a/lib/spack/spack/operating_systems/cnk.py
+++ b/lib/spack/spack/operating_systems/cnk.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack.architecture import OperatingSystem
diff --git a/lib/spack/spack/operating_systems/cnl.py b/lib/spack/spack/operating_systems/cnl.py
index d64e4d06dc..d0d4e037be 100644
--- a/lib/spack/spack/operating_systems/cnl.py
+++ b/lib/spack/spack/operating_systems/cnl.py
@@ -1,35 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
import llnl.util.tty as tty
+import llnl.util.multiproc as mp
-import spack.spec
-import spack.compilers
from spack.architecture import OperatingSystem
-from spack.util.multiproc import parmap
from spack.util.module_cmd import get_module_cmd
@@ -42,16 +21,27 @@ class Cnl(OperatingSystem):
"""
def __init__(self):
- name = 'CNL'
- version = '10'
+ name = 'cnl'
+ version = self._detect_crayos_version()
super(Cnl, self).__init__(name, version)
def __str__(self):
- return self.name
+ return self.name + str(self.version)
+
+ def _detect_crayos_version(self):
+ modulecmd = get_module_cmd()
+ output = modulecmd("avail", "PrgEnv-", output=str, error=str)
+ matches = re.findall(r'PrgEnv-\w+/(\d+).\d+.\d+', output)
+ major_versions = set(matches)
+ latest_version = max(major_versions)
+ return latest_version
def find_compilers(self, *paths):
+ # function-local so that cnl doesn't depend on spack.config
+ import spack.compilers
+
types = spack.compilers.all_compiler_types()
- compiler_lists = parmap(
+ compiler_lists = mp.parmap(
lambda cmp_cls: self.find_compiler(cmp_cls, *paths), types)
# ensure all the version calls we made are cached in the parent
@@ -60,6 +50,9 @@ class Cnl(OperatingSystem):
return clist
def find_compiler(self, cmp_cls, *paths):
+ # function-local so that cnl doesn't depend on spack.config
+ import spack.spec
+
compilers = []
if cmp_cls.PrgEnv:
if not cmp_cls.PrgEnv_compiler:
diff --git a/lib/spack/spack/operating_systems/cray_frontend.py b/lib/spack/spack/operating_systems/cray_frontend.py
index d761a758ef..116a4ec802 100644
--- a/lib/spack/spack/operating_systems/cray_frontend.py
+++ b/lib/spack/spack/operating_systems/cray_frontend.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
from spack.operating_systems.linux_distro import LinuxDistro
@@ -61,7 +42,7 @@ class CrayFrontend(LinuxDistro):
# 'intel', 'cce', 'gcc', etc.) will also be unloaded since they are
# specified as prerequisites in the PrgEnv-* modulefiles.
modulecmd = get_module_cmd()
- exec (compile(
+ exec(compile(
modulecmd('unload', prg_env, output=str, error=os.devnull),
'<string>', 'exec'))
diff --git a/lib/spack/spack/operating_systems/linux_distro.py b/lib/spack/spack/operating_systems/linux_distro.py
index 723b4d5447..a12e08671e 100644
--- a/lib/spack/spack/operating_systems/linux_distro.py
+++ b/lib/spack/spack/operating_systems/linux_distro.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
from spack.architecture import OperatingSystem
diff --git a/lib/spack/spack/operating_systems/mac_os.py b/lib/spack/spack/operating_systems/mac_os.py
index a5577fa39d..d50cbf32be 100644
--- a/lib/spack/spack/operating_systems/mac_os.py
+++ b/lib/spack/spack/operating_systems/mac_os.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import platform as py_platform
from spack.architecture import OperatingSystem
@@ -29,7 +10,7 @@ from spack.version import Version
# FIXME: store versions inside OperatingSystem as a Version instead of string
-def macOS_version():
+def macos_version():
"""temporary workaround to return a macOS version as a Version object
"""
return Version('.'.join(py_platform.mac_ver()[0].split('.')[:2]))
@@ -54,7 +35,8 @@ class MacOs(OperatingSystem):
"10.10": "yosemite",
"10.11": "elcapitan",
"10.12": "sierra",
- "10.13": "highsierra"}
+ "10.13": "highsierra",
+ "10.14": "mojave"}
mac_ver = '.'.join(py_platform.mac_ver()[0].split('.')[:2])
name = mac_releases.get(mac_ver, "macos")
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 18091f2e69..279ed89d04 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1,41 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-"""
-This is where most of the action happens in Spack.
-See the Package docs for detailed instructions on how the class works
-and on how to write your own packages.
-
-The spack package structure is based strongly on Homebrew
-(http://wiki.github.com/mxcl/homebrew/), mainly because
-Homebrew makes it very easy to create packages. For a complete
-rundown on spack and how it differs from homebrew, look at the
-README.
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""This is where most of the action happens in Spack.
+
+The spack package class structure is based strongly on Homebrew
+(http://brew.sh/), mainly because Homebrew makes it very easy to create
+packages.
+
"""
+import base64
import contextlib
import copy
import functools
+import glob
+import hashlib
import inspect
import os
import re
@@ -46,33 +26,40 @@ import time
from six import StringIO
from six import string_types
from six import with_metaclass
+from ordereddict_backport import OrderedDict
import llnl.util.tty as tty
-import spack
+
+import spack.config
+import spack.paths
import spack.store
import spack.compilers
import spack.directives
+import spack.directory_layout
import spack.error
import spack.fetch_strategy as fs
import spack.hooks
import spack.mirror
-import spack.repository
+import spack.mixins
+import spack.repo
import spack.url
import spack.util.web
import spack.multimethod
import spack.binary_distribution as binary_distribution
-from llnl.util.filesystem import mkdirp, join_path, touch, ancestor
+from llnl.util.filesystem import mkdirp, touch, chgrp
from llnl.util.filesystem import working_dir, install_tree, install
from llnl.util.lang import memoized
from llnl.util.link_tree import LinkTree
from llnl.util.tty.log import log_output
from llnl.util.tty.color import colorize
-from spack import directory_layout
+from spack.filesystem_view import YamlFilesystemView
from spack.util.executable import which
from spack.stage import Stage, ResourceStage, StageComposite
from spack.util.environment import dump_environment
+from spack.util.package_hash import package_hash
from spack.version import Version
+from spack.package_prefs import get_package_dir_permissions, get_package_group
"""Allowed URL schemes for spack packages."""
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
@@ -141,7 +128,10 @@ class InstallPhase(object):
return other
-class PackageMeta(spack.directives.DirectiveMetaMixin):
+class PackageMeta(
+ spack.directives.DirectiveMeta,
+ spack.mixins.PackageMixinsMeta
+):
"""Conveniently transforms attributes to permit extensible phases
Iterates over the attribute 'phases' and creates / updates private
@@ -152,7 +142,7 @@ class PackageMeta(spack.directives.DirectiveMetaMixin):
_InstallPhase_run_before = {}
_InstallPhase_run_after = {}
- def __new__(mcs, name, bases, attr_dict):
+ def __new__(cls, name, bases, attr_dict):
if 'phases' in attr_dict:
# Turn the strings in 'phases' into InstallPhase instances
@@ -165,7 +155,7 @@ class PackageMeta(spack.directives.DirectiveMetaMixin):
def _flush_callbacks(check_name):
# Name of the attribute I am going to check it exists
attr_name = PackageMeta.phase_fmt.format(check_name)
- checks = getattr(mcs, attr_name)
+ checks = getattr(cls, attr_name)
if checks:
for phase_name, funcs in checks.items():
try:
@@ -182,18 +172,21 @@ class PackageMeta(spack.directives.DirectiveMetaMixin):
PackageMeta.phase_fmt.format(phase_name),
None
)
+ if phase is not None:
+ break
+
attr_dict[PackageMeta.phase_fmt.format(
phase_name)] = phase.copy()
phase = attr_dict[
PackageMeta.phase_fmt.format(phase_name)]
getattr(phase, check_name).extend(funcs)
# Clear the attribute for the next class
- setattr(mcs, attr_name, {})
+ setattr(cls, attr_name, {})
_flush_callbacks('run_before')
_flush_callbacks('run_after')
- return super(PackageMeta, mcs).__new__(mcs, name, bases, attr_dict)
+ return super(PackageMeta, cls).__new__(cls, name, bases, attr_dict)
@staticmethod
def register_callback(check_type, *phases):
@@ -247,215 +240,91 @@ def on_package_attributes(**attr_dict):
return _execute_under_condition
-class PackageBase(with_metaclass(PackageMeta, object)):
- """This is the superclass for all spack packages.
-
- ***The Package class***
-
- Package is where the bulk of the work of installing packages is done.
-
- A package defines how to fetch, verfiy (via, e.g., md5), build, and
- install a piece of software. A Package also defines what other
- packages it depends on, so that dependencies can be installed along
- with the package itself. Packages are written in pure python.
-
- Packages are all submodules of spack.packages. If spack is installed
- in ``$prefix``, all of its python files are in ``$prefix/lib/spack``.
- Most of them are in the spack module, so all the packages live in
- ``$prefix/lib/spack/spack/packages``.
-
- All you have to do to create a package is make a new subclass of Package
- in this directory. Spack automatically scans the python files there
- and figures out which one to import when you invoke it.
-
- **An example package**
-
- Let's look at the cmake package to start with. This package lives in
- ``$prefix/var/spack/repos/builtin/packages/cmake/package.py``:
-
- .. code-block:: python
-
- from spack import *
- class Cmake(Package):
- homepage = 'https://www.cmake.org'
- url = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
- md5 = '097278785da7182ec0aea8769d06860c'
-
- def install(self, spec, prefix):
- configure('--prefix=%s' % prefix,
- '--parallel=%s' % make_jobs)
- make()
- make('install')
-
- **Naming conventions**
-
- There are two names you should care about:
-
- 1. The module name, ``cmake``.
-
- * User will refers to this name, e.g. 'spack install cmake'.
- * It can include ``_``, ``-``, and numbers (it can even start with a
- number).
-
- 2. The class name, "Cmake". This is formed by converting `-` or
- ``_`` in the module name to camel case. If the name starts with
- a number, we prefix the class name with ``_``. Examples:
-
- =========== ==========
- Module Name Class Name
- =========== ==========
- foo_bar FooBar
- docbook-xml DocbookXml
- FooBar Foobar
- 3proxy _3proxy
- =========== ==========
-
- The class name is what spack looks for when it loads a package module.
-
- **Required Attributes**
-
- Aside from proper naming, here is the bare minimum set of things you
- need when you make a package:
-
- homepage:
- informational URL, so that users know what they're
- installing.
-
- url or url_for_version(self, version):
- If url, then the URL of the source archive that spack will fetch.
- If url_for_version(), then a method returning the URL required
- to fetch a particular version.
-
- install():
- This function tells spack how to build and install the
- software it downloaded.
-
- **Optional Attributes**
-
- You can also optionally add these attributes, if needed:
-
- list_url:
- Webpage to scrape for available version strings. Default is the
- directory containing the tarball; use this if the default isn't
- correct so that invoking 'spack versions' will work for this
- package.
-
- url_version(self, version):
- When spack downloads packages at particular versions, it just
- converts version to string with str(version). Override this if
- your package needs special version formatting in its URL. boost
- is an example of a package that needs this.
-
- ***Creating Packages***
-
- As a package creator, you can probably ignore most of the preceding
- information, because you can use the 'spack create' command to do it
- all automatically.
-
- You as the package creator generally only have to worry about writing
- your install function and specifying dependencies.
-
- **spack create**
-
- Most software comes in nicely packaged tarballs, like this one
-
- http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
-
- Taking a page from homebrew, spack deduces pretty much everything it
- needs to know from the URL above. If you simply type this::
-
- spack create http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
-
- Spack will download the tarball, generate an md5 hash, figure out the
- version and the name of the package from the URL, and create a new
- package file for you with all the names and attributes set correctly.
+class PackageViewMixin(object):
+ """This collects all functionality related to adding installed Spack
+ package to views. Packages can customize how they are added to views by
+ overriding these functions.
+ """
+ def view_source(self):
+ """The source root directory that will be added to the view: files are
+ added such that their path relative to the view destination matches
+ their path relative to the view source.
+ """
+ return self.spec.prefix
- Once this skeleton code is generated, spack pops up the new package in
- your $EDITOR so that you can modify the parts that need changes.
+ def view_destination(self, view):
+ """The target root directory: each file is added relative to this
+ directory.
+ """
+ return view.root
- **Dependencies**
+ def view_file_conflicts(self, view, merge_map):
+ """Report any files which prevent adding this package to the view. The
+ default implementation looks for any files which already exist.
+ Alternative implementations may allow some of the files to exist in
+ the view (in this case they would be omitted from the results).
+ """
+ return set(dst for dst in merge_map.values() if os.path.exists(dst))
- If your package requires another in order to build, you can specify that
- like this:
+ def add_files_to_view(self, view, merge_map):
+ """Given a map of package files to destination paths in the view, add
+ the files to the view. By default this adds all files. Alternative
+ implementations may skip some files, for example if other packages
+ linked into the view already include the file.
+ """
+ for src, dst in merge_map.items():
+ if not os.path.exists(dst):
+ view.link(src, dst)
+
+ def remove_files_from_view(self, view, merge_map):
+ """Given a map of package files to files currently linked in the view,
+ remove the files from the view. The default implementation removes all
+ files. Alternative implementations may not remove all files. For
+ example if two packages include the same file, it should only be
+ removed when both packages are removed.
+ """
+ for src, dst in merge_map.items():
+ view.remove_file(src, dst)
- .. code-block:: python
- class Stackwalker(Package):
- ...
- depends_on("libdwarf")
- ...
-
- This tells spack that before it builds stackwalker, it needs to build
- the libdwarf package as well. Note that this is the module name, not
- the class name (The class name is really only used by spack to find
- your package).
-
- Spack will download an install each dependency before it installs your
- package. In addtion, it will add -L, -I, and rpath arguments to your
- compiler and linker for each dependency. In most cases, this allows you
- to avoid specifying any dependencies in your configure or cmake line;
- you can just run configure or cmake without any additional arguments and
- it will find the dependencies automatically.
-
- **The Install Function**
-
- The install function is designed so that someone not too terribly familiar
- with Python could write a package installer. For example, we put a number
- of commands in install scope that you can use almost like shell commands.
- These include make, configure, cmake, rm, rmtree, mkdir, mkdirp, and
- others.
-
- You can see above in the cmake script that these commands are used to run
- configure and make almost like they're used on the command line. The
- only difference is that they are python function calls and not shell
- commands.
-
- It may be puzzling to you where the commands and functions in install live.
- They are NOT instance variables on the class; this would require us to
- type 'self.' all the time and it makes the install code unnecessarily long.
- Rather, spack puts these commands and variables in *module* scope for your
- Package subclass. Since each package has its own module, this doesn't
- pollute other namespaces, and it allows you to more easily implement an
- install function.
-
- For a full list of commands and variables available in module scope, see
- the add_commands_to_module() function in this class. This is where most
- of them are created and set on the module.
-
- **Parallel Builds**
-
- By default, Spack will run make in parallel when you run make() in your
- install function. Spack figures out how many cores are available on
- your system and runs make with -j<cores>. If you do not want this
- behavior, you can explicitly mark a package not to use parallel make:
+class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
+ """This is the superclass for all spack packages.
- .. code-block:: python
+ ***The Package class***
- class SomePackage(Package):
- ...
- parallel = False
- ...
+ A package defines how to fetch, verify (via, e.g., sha256), build,
+ and install a piece of software. A Package also defines what other
+ packages it depends on, so that dependencies can be installed along
+ with the package itself. Packages are written in pure python by
+ users of Spack.
- This changes the default behavior so that make is sequential. If you still
- want to build some parts in parallel, you can do this in your install
- function:
+ There are two main parts of a Spack package:
- .. code-block:: python
+ 1. **The package class**. Classes contain ``directives``, which are
+ special functions, that add metadata (versions, patches,
+ dependencies, and other information) to packages (see
+ ``directives.py``). Directives provide the constraints that are
+ used as input to the concretizer.
- make(parallel=True)
+ 2. **Package instances**. Once instantiated, a package is
+ essentially an installer for a particular piece of
+ software. Spack calls methods like ``do_install()`` on the
+ ``Package`` object, and it uses those to drive user-implemented
+ methods like ``patch()``, ``install()``, and other build steps.
+ To install software, An instantiated package needs a *concrete*
+ spec, which guides the behavior of the various install methods.
- Likewise, if you do not supply parallel = True in your Package, you can
- keep the default parallel behavior and run make like this when you want a
- sequential build:
+ Packages are imported from repos (see ``repo.py``).
- .. code-block:: python
+ **Package DSL**
- make(parallel=False)
+ Look in ``lib/spack/docs`` or check https://spack.readthedocs.io for
+ the full documentation of the package domain-specific language. That
+ used to be partially documented here, but as it grew, the docs here
+ became increasingly out of date.
**Package Lifecycle**
- This section is really only for developers of new spack commands.
-
A package's lifecycle over a run of Spack looks something like this:
.. code-block:: python
@@ -481,8 +350,15 @@ class PackageBase(with_metaclass(PackageMeta, object)):
package writers to override, and doing so may break the functionality
of the Package class.
- Package creators override functions like install() (all of them do this),
- clean() (some of them do this), and others to provide custom behavior.
+ Package creators have a lot of freedom, and they could technically
+ override anything in this class. That is not usually required.
+
+ For most use cases. Package creators typically just add attributes
+ like ``url`` and ``homepage``, or functions like ``install()``.
+ There are many custom ``Package`` subclasses in the
+ ``spack.build_systems`` package that make things even easier for
+ specific build systems.
+
"""
#
# These are default values for instance variables.
@@ -492,7 +368,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
parallel = True
#: # jobs to use for parallel make. If set, overrides default of ncpus.
- make_jobs = spack.build_jobs
+ make_jobs = None
#: By default do not run tests within package's install()
run_tests = False
@@ -518,6 +394,12 @@ class PackageBase(with_metaclass(PackageMeta, object)):
#: directories, sanity checks will fail.
sanity_check_is_dir = []
+ #: List of glob expressions. Each expression must either be
+ #: absolute or relative to the package source path.
+ #: Matching artifacts found at the end of the build process will
+ #: be copied in the same directory tree as build.env and build.out.
+ archive_files = []
+
#
# Set default licensing information
#
@@ -556,6 +438,10 @@ class PackageBase(with_metaclass(PackageMeta, object)):
#: Do not include @ here in order not to unnecessarily ping the users.
maintainers = []
+ #: List of attributes which affect do not affect a package's content.
+ metadata_attrs = ['homepage', 'url', 'list_url', 'extendable', 'parallel',
+ 'make_jobs']
+
def __init__(self, spec):
# this determines how the package should be built.
self.spec = spec
@@ -584,24 +470,6 @@ class PackageBase(with_metaclass(PackageMeta, object)):
except ValueError as e:
raise ValueError("In package %s: %s" % (self.name, e.message))
- # stage used to build this package.
- self._stage = None
-
- # Init fetch strategy and url to None
- self._fetcher = None
- self.url = getattr(self.__class__, 'url', None)
-
- # Fix up self.url if this package fetches with a URLFetchStrategy.
- # This makes self.url behave sanely.
- if self.spec.versions.concrete:
- # TODO: this is a really roundabout way of determining the type
- # TODO: of fetch to do. figure out a more sane fetch
- # TODO: strategy/package init order (right now it's conflated with
- # TODO: stage, package, and the tests make assumptions)
- f = fs.for_package_version(self, self.version)
- if isinstance(f, fs.URLFetchStrategy):
- self.url = self.url_for_version(self.spec.version)
-
# Set a default list URL (place to find available versions)
if not hasattr(self, 'list_url'):
self.list_url = None
@@ -609,40 +477,53 @@ class PackageBase(with_metaclass(PackageMeta, object)):
if not hasattr(self, 'list_depth'):
self.list_depth = 0
- # Set up some internal variables for timing.
+ # init internal variables
+ self._stage = None
+ self._fetcher = None
+
+ # Set up timing variables
self._fetch_time = 0.0
self._total_time = 0.0
if self.is_extension:
spack.repo.get(self.extendee_spec)._check_extendable()
- self.extra_args = {}
+ super(PackageBase, self).__init__()
- def possible_dependencies(self, transitive=True, visited=None):
- """Return set of possible transitive dependencies of this package.
+ def possible_dependencies(
+ self, transitive=True, expand_virtuals=True, visited=None):
+ """Return set of possible dependencies of this package.
+
+ Note: the set returned *includes* the package itself.
Args:
- transitive (bool): include all transitive dependencies if True,
+ transitive (bool): return all transitive dependencies if True,
only direct dependencies if False.
+ expand_virtuals (bool): expand virtual dependencies into all
+ possible implementations.
+ visited (set): set of names of dependencies visited so far.
"""
if visited is None:
- visited = set()
-
- visited.add(self.name)
- for name in self.dependencies:
- spec = spack.spec.Spec(name)
+ visited = set([self.name])
- if not spec.virtual:
- visited.add(name)
- if transitive:
- pkg = spack.repo.get(name)
- pkg.possible_dependencies(transitive, visited)
+ for i, name in enumerate(self.dependencies):
+ if spack.repo.path.is_virtual(name):
+ if expand_virtuals:
+ providers = spack.repo.path.providers_for(name)
+ dep_names = [spec.name for spec in providers]
+ else:
+ visited.add(name)
+ continue
else:
- for provider in spack.repo.providers_for(spec):
- visited.add(provider.name)
+ dep_names = [name]
+
+ for dep_name in dep_names:
+ if dep_name not in visited:
+ visited.add(dep_name)
if transitive:
- pkg = spack.repo.get(provider.name)
- pkg.possible_dependencies(transitive, visited)
+ pkg = spack.repo.get(dep_name)
+ pkg.possible_dependencies(
+ transitive, expand_virtuals, visited)
return visited
@@ -655,8 +536,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
def global_license_dir(self):
"""Returns the directory where global license files for all
packages are stored."""
- spack_root = ancestor(__file__, 4)
- return join_path(spack_root, 'etc', 'spack', 'licenses')
+ return os.path.join(spack.paths.prefix, 'etc', 'spack', 'licenses')
@property
def global_license_file(self):
@@ -664,8 +544,8 @@ class PackageBase(with_metaclass(PackageMeta, object)):
particular package should be stored."""
if not self.license_files:
return
- return join_path(self.global_license_dir, self.name,
- os.path.basename(self.license_files[0]))
+ return os.path.join(self.global_license_dir, self.name,
+ os.path.basename(self.license_files[0]))
@property
def version(self):
@@ -675,33 +555,46 @@ class PackageBase(with_metaclass(PackageMeta, object)):
@memoized
def version_urls(self):
- """Return a list of URLs for different versions of this
- package, sorted by version. A version's URL only appears
- in this list if it has an explicitly defined URL."""
- version_urls = {}
- for v in sorted(self.versions):
- args = self.versions[v]
+ """OrderedDict of explicitly defined URLs for versions of this package.
+
+ Return:
+ An OrderedDict (version -> URL) different versions of this
+ package, sorted by version.
+
+ A version's URL only appears in the result if it has an an
+ explicitly defined ``url`` argument. So, this list may be empty
+ if a package only defines ``url`` at the top level.
+ """
+ version_urls = OrderedDict()
+ for v, args in sorted(self.versions.items()):
if 'url' in args:
version_urls[v] = args['url']
return version_urls
def nearest_url(self, version):
- """Finds the URL for the next lowest version with a URL.
- If there is no lower version with a URL, uses the
- package url property. If that isn't there, uses a
- *higher* URL, and if that isn't there raises an error.
+ """Finds the URL with the "closest" version to ``version``.
+
+ This uses the following precedence order:
+
+ 1. Find the next lowest or equal version with a URL.
+ 2. If no lower URL, return the next *higher* URL.
+ 3. If no higher URL, return None.
+
"""
version_urls = self.version_urls()
- url = getattr(self.__class__, 'url', None)
- for v in version_urls:
- if v > version and url:
- break
- if version_urls[v]:
- url = version_urls[v]
- return url
+ if version in version_urls:
+ return version_urls[version]
+
+ last_url = None
+ for v, u in self.version_urls().items():
+ if v > version:
+ if last_url:
+ return last_url
+ last_url = u
+
+ return last_url
- # TODO: move this out of here and into some URL extrapolation module?
def url_for_version(self, version):
"""Returns a URL from which the specified version of this package
may be downloaded.
@@ -714,18 +607,24 @@ class PackageBase(with_metaclass(PackageMeta, object)):
if not isinstance(version, Version):
version = Version(version)
- cls = self.__class__
- if not (hasattr(cls, 'url') or self.version_urls()):
- raise NoURLError(cls)
-
# If we have a specific URL for this version, don't extrapolate.
version_urls = self.version_urls()
if version in version_urls:
return version_urls[version]
- # If we have no idea, try to substitute the version.
+ # If no specific URL, use the default, class-level URL
+ default_url = getattr(self, 'url', None)
+
+ # if no exact match AND no class-level default, use the nearest URL
+ if not default_url:
+ default_url = self.nearest_url(version)
+
+ # if there are NO URLs to go by, then we can't do anything
+ if not default_url:
+ raise NoURLError(self.__class__)
+
return spack.url.substitute_version(
- self.nearest_url(version), self.url_version(version))
+ default_url, self.url_version(version))
def _make_resource_stage(self, root_stage, fetcher, resource):
resource_stage_folder = self._resource_stage(resource)
@@ -794,11 +693,17 @@ class PackageBase(with_metaclass(PackageMeta, object)):
@property
def env_path(self):
- return os.path.join(self.stage.source_path, 'spack-build.env')
+ if self.stage.source_path is None:
+ return None
+ else:
+ return os.path.join(self.stage.source_path, 'spack-build.env')
@property
def log_path(self):
- return os.path.join(self.stage.source_path, 'spack-build.out')
+ if self.stage.source_path is None:
+ return None
+ else:
+ return os.path.join(self.stage.source_path, 'spack-build.out')
def _make_fetcher(self):
# Construct a composite fetcher that always contains at least
@@ -903,13 +808,12 @@ class PackageBase(with_metaclass(PackageMeta, object)):
s = self.extendee_spec
return s and spec.satisfies(s)
- def is_activated(self, extensions_layout=None):
+ def is_activated(self, view):
"""Return True if package is activated."""
if not self.is_extension:
raise ValueError(
- "is_extension called on package that is not an extension.")
- if extensions_layout is None:
- extensions_layout = spack.store.extensions
+ "is_activated called on package that is not an extension.")
+ extensions_layout = view.extensions_layout
exts = extensions_layout.extension_map(self.extendee_spec)
return (self.name in exts) and (exts[self.name] == self.spec)
@@ -917,11 +821,30 @@ class PackageBase(with_metaclass(PackageMeta, object)):
"""
True if this package provides a virtual package with the specified name
"""
- return any(s.name == vpkg_name for s in self.provided)
+ return any(
+ any(self.spec.satisfies(c) for c in constraints)
+ for s, constraints in self.provided.items() if s.name == vpkg_name
+ )
@property
def installed(self):
- return os.path.isdir(self.prefix)
+ """Installation status of a package.
+
+ Returns:
+ True if the package has been installed, False otherwise.
+ """
+ has_prefix = os.path.isdir(self.prefix)
+ try:
+ # If the spec is in the DB, check the installed
+ # attribute of the record
+ rec = spack.store.db.get_record(self.spec)
+ db_says_installed = rec.installed
+ except KeyError:
+ # If the spec is not in the DB, the method
+ # above raises a Key error
+ db_says_installed = False
+
+ return has_prefix and db_says_installed
@property
def prefix(self):
@@ -971,7 +894,8 @@ class PackageBase(with_metaclass(PackageMeta, object)):
raise ValueError("Can only fetch concrete packages.")
start_time = time.time()
- if spack.do_checksum and self.version not in self.versions:
+ checksum = spack.config.get('config:checksum')
+ if checksum and self.version not in self.versions:
tty.warn("There is no checksum on file to fetch %s safely." %
self.spec.cformat('$_$@'))
@@ -993,7 +917,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
self.stage.fetch(mirror_only)
self._fetch_time = time.time() - start_time
- if spack.do_checksum and self.version in self.versions:
+ if checksum and self.version in self.versions:
self.stage.check()
self.stage.cache_local()
@@ -1065,9 +989,9 @@ class PackageBase(with_metaclass(PackageMeta, object)):
# Construct paths to special files in the archive dir used to
# keep track of whether patches were successfully applied.
archive_dir = self.stage.source_path
- good_file = join_path(archive_dir, '.spack_patched')
- no_patches_file = join_path(archive_dir, '.spack_no_patches')
- bad_file = join_path(archive_dir, '.spack_patch_failed')
+ good_file = os.path.join(archive_dir, '.spack_patched')
+ no_patches_file = os.path.join(archive_dir, '.spack_no_patches')
+ bad_file = os.path.join(archive_dir, '.spack_patch_failed')
# If we encounter an archive that failed to patch, restage it
# so that we can apply all the patches again.
@@ -1129,6 +1053,34 @@ class PackageBase(with_metaclass(PackageMeta, object)):
else:
touch(no_patches_file)
+ def content_hash(self, content=None):
+ """Create a hash based on the sources and logic used to build the
+ package. This includes the contents of all applied patches and the
+ contents of applicable functions in the package subclass."""
+ if not self.spec.concrete:
+ err_msg = ("Cannot invoke content_hash on a package"
+ " if the associated spec is not concrete")
+ raise spack.error.SpackError(err_msg)
+
+ hash_content = list()
+ source_id = fs.for_package_version(self, self.version).source_id()
+ if not source_id:
+ # TODO? in cases where a digest or source_id isn't available,
+ # should this attempt to download the source and set one? This
+ # probably only happens for source repositories which are
+ # referenced by branch name rather than tag or commit ID.
+ message = 'Missing a source id for {s.name}@{s.version}'
+ tty.warn(message.format(s=self))
+ hash_content.append(''.encode('utf-8'))
+ else:
+ hash_content.append(source_id.encode('utf-8'))
+ hash_content.extend(':'.join((p.sha256, str(p.level))).encode('utf-8')
+ for p in self.spec.patches)
+ hash_content.append(package_hash(self.spec, content))
+ return base64.b32encode(
+ hashlib.sha256(bytes().join(
+ sorted(hash_content))).digest()).lower()
+
@property
def namespace(self):
namespace, dot, module = self.__module__.rpartition('.')
@@ -1138,65 +1090,139 @@ class PackageBase(with_metaclass(PackageMeta, object)):
"""Make a fake install directory containing fake executables,
headers, and libraries."""
- name = self.name
- library_name = 'lib' + self.name
+ command = self.name
+ header = self.name
+ library = self.name
+
+ # Avoid double 'lib' for packages whose names already start with lib
+ if not self.name.startswith('lib'):
+ library = 'lib' + library
+
dso_suffix = '.dylib' if sys.platform == 'darwin' else '.so'
chmod = which('chmod')
+ # Install fake command
mkdirp(self.prefix.bin)
- touch(join_path(self.prefix.bin, name))
- chmod('+x', join_path(self.prefix.bin, name))
+ touch(os.path.join(self.prefix.bin, command))
+ chmod('+x', os.path.join(self.prefix.bin, command))
+ # Install fake header file
mkdirp(self.prefix.include)
- touch(join_path(self.prefix.include, name + '.h'))
+ touch(os.path.join(self.prefix.include, header + '.h'))
+ # Install fake shared and static libraries
mkdirp(self.prefix.lib)
- touch(join_path(self.prefix.lib, library_name + dso_suffix))
- touch(join_path(self.prefix.lib, library_name + '.a'))
+ for suffix in [dso_suffix, '.a']:
+ touch(os.path.join(self.prefix.lib, library + suffix))
+ # Install fake man page
mkdirp(self.prefix.man.man1)
packages_dir = spack.store.layout.build_packages_path(self.spec)
dump_packages(self.spec, packages_dir)
- def _if_make_target_execute(self, target):
- try:
- # Check if we have a makefile
- file = [x for x in ('Makefile', 'makefile') if os.path.exists(x)]
- file = file.pop()
- except IndexError:
+ def _has_make_target(self, target):
+ """Checks to see if 'target' is a valid target in a Makefile.
+
+ Parameters:
+ target (str): the target to check for
+
+ Returns:
+ bool: True if 'target' is found, else False
+ """
+ make = inspect.getmodule(self).make
+
+ # Check if we have a Makefile
+ for makefile in ['GNUmakefile', 'Makefile', 'makefile']:
+ if os.path.exists(makefile):
+ break
+ else:
tty.msg('No Makefile found in the build directory')
- return
+ return False
- # Check if 'target' is in the makefile
- regex = re.compile('^' + target + ':')
- with open(file, 'r') as f:
- matches = [line for line in f.readlines() if regex.match(line)]
+ # Check if 'target' is a valid target.
+ #
+ # `make -n target` performs a "dry run". It prints the commands that
+ # would be run but doesn't actually run them. If the target does not
+ # exist, you will see one of the following error messages:
+ #
+ # GNU Make:
+ # make: *** No rule to make target `test'. Stop.
+ # *** No rule to make target 'test'. Stop.
+ #
+ # BSD Make:
+ # make: don't know how to make test. Stop
+ missing_target_msgs = [
+ "No rule to make target `{0}'. Stop.",
+ "No rule to make target '{0}'. Stop.",
+ "don't know how to make {0}. Stop",
+ ]
+
+ kwargs = {
+ 'fail_on_error': False,
+ 'output': os.devnull,
+ 'error': str,
+ }
+
+ stderr = make('-n', target, **kwargs)
+
+ for missing_target_msg in missing_target_msgs:
+ if missing_target_msg.format(target) in stderr:
+ tty.msg("Target '" + target + "' not found in " + makefile)
+ return False
- if not matches:
- tty.msg("Target '" + target + ":' not found in Makefile")
- return
+ return True
- # Execute target
- inspect.getmodule(self).make(target)
+ def _if_make_target_execute(self, target, *args, **kwargs):
+ """Runs ``make target`` if 'target' is a valid target in the Makefile.
+
+ Parameters:
+ target (str): the target to potentially execute
+ """
+ if self._has_make_target(target):
+ # Execute target
+ inspect.getmodule(self).make(target, *args, **kwargs)
- def _if_ninja_target_execute(self, target):
- # Check if we have a ninja build script
+ def _has_ninja_target(self, target):
+ """Checks to see if 'target' is a valid target in a Ninja build script.
+
+ Parameters:
+ target (str): the target to check for
+
+ Returns:
+ bool: True if 'target' is found, else False
+ """
+ ninja = inspect.getmodule(self).ninja
+
+ # Check if we have a Ninja build script
if not os.path.exists('build.ninja'):
- tty.msg('No ninja build script found in the build directory')
- return
+ tty.msg('No Ninja build script found in the build directory')
+ return False
- # Check if 'target' is in the ninja build script
- regex = re.compile('^build ' + target + ':')
- with open('build.ninja', 'r') as f:
- matches = [line for line in f.readlines() if regex.match(line)]
+ # Get a list of all targets in the Ninja build script
+ # https://ninja-build.org/manual.html#_extra_tools
+ all_targets = ninja('-t', 'targets', 'all', output=str).split('\n')
+
+ # Check if 'target' is a valid target
+ matches = [line for line in all_targets
+ if line.startswith(target + ':')]
if not matches:
- tty.msg("Target 'build " + target + ":' not found in build.ninja")
- return
+ tty.msg("Target '" + target + "' not found in build.ninja")
+ return False
+
+ return True
+
+ def _if_ninja_target_execute(self, target, *args, **kwargs):
+ """Runs ``ninja target`` if 'target' is a valid target in the Ninja
+ build script.
- # Execute target
- inspect.getmodule(self).ninja(target)
+ Parameters:
+ target (str): the target to potentially execute
+ """
+ if self._has_ninja_target(target):
+ # Execute target
+ inspect.getmodule(self).ninja(target, *args, **kwargs)
def _get_needed_resources(self):
resources = []
@@ -1279,8 +1305,10 @@ class PackageBase(with_metaclass(PackageMeta, object)):
tty.msg('Installing %s from binary cache' % self.name)
tarball = binary_distribution.download_tarball(binary_spec)
binary_distribution.extract_tarball(
- binary_spec, tarball, yes_to_all=False, force=False)
- spack.store.db.add(self.spec, spack.store.layout, explicit=explicit)
+ binary_spec, tarball, allow_root=False,
+ unsigned=False, force=False)
+ spack.store.db.add(
+ self.spec, spack.store.layout, explicit=explicit)
return True
def do_install(self,
@@ -1293,6 +1321,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
make_jobs=None,
fake=False,
explicit=False,
+ tests=False,
dirty=None,
**kwargs):
"""Called by commands to install a package and its dependencies.
@@ -1318,6 +1347,8 @@ class PackageBase(with_metaclass(PackageMeta, object)):
fake (bool): Don't really build; install fake stub files instead.
explicit (bool): True if package was explicitly installed, False
if package was implicitly installed (as a dependency).
+ tests (bool or list or set): False to run no tests, True to test
+ all packages, or a list of package names to run tests for some
dirty (bool): Don't clean the build environment before installing.
force (bool): Install again, even if already installed.
"""
@@ -1343,6 +1374,11 @@ class PackageBase(with_metaclass(PackageMeta, object)):
msg = '{0.name} is already installed in {0.prefix}'
tty.msg(msg.format(self))
rec = spack.store.db.get_record(self.spec)
+ # In case the stage directory has already been created,
+ # this ensures it's removed after we checked that the spec
+ # is installed
+ if keep_stage is False:
+ self.stage.destroy()
return self._update_explicit_entry_in_db(rec, explicit)
self._do_install_pop_kwargs(kwargs)
@@ -1361,12 +1397,13 @@ class PackageBase(with_metaclass(PackageMeta, object)):
skip_patch=skip_patch,
verbose=verbose,
make_jobs=make_jobs,
+ tests=tests,
dirty=dirty,
**kwargs)
tty.msg(colorize('@*{Installing} @*g{%s}' % self.name))
- if kwargs.get('use_cache', False):
+ if kwargs.get('use_cache', True):
if self.try_install_from_binary_cache(explicit):
tty.msg('Successfully installed %s from binary cache'
% self.name)
@@ -1377,8 +1414,9 @@ class PackageBase(with_metaclass(PackageMeta, object)):
tty.msg('No binary for %s found: installing from source'
% self.name)
- # Set run_tests flag before starting build.
- self.run_tests = spack.package_testing.check(self.name)
+ # Set run_tests flag before starting build
+ self.run_tests = (tests is True or
+ tests and self.name in tests)
# Set parallelism before starting build.
self.make_jobs = make_jobs
@@ -1419,7 +1457,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
else:
source_path = self.stage.source_path
if install_source and os.path.isdir(source_path):
- src_target = join_path(
+ src_target = os.path.join(
self.spec.prefix, 'share', self.name, 'src')
tty.msg('Copying source to {0}'.format(src_target))
install_tree(self.stage.source_path, src_target)
@@ -1462,10 +1500,27 @@ class PackageBase(with_metaclass(PackageMeta, object)):
# preserve verbosity across runs
return echo
+ # hook that allow tests to inspect this Package before installation
+ # see unit_test_check() docs.
+ if not self.unit_test_check():
+ return
+
try:
# Create the install prefix and fork the build process.
if not os.path.exists(self.prefix):
spack.store.layout.create_install_directory(self.spec)
+ else:
+ # Set the proper group for the prefix
+ group = get_package_group(self.spec)
+ if group:
+ chgrp(self.prefix, group)
+ # Set the proper permissions.
+ # This has to be done after group because changing groups blows
+ # away the sticky group bit on the directory
+ mode = os.stat(self.prefix).st_mode
+ perms = get_package_dir_permissions(self.spec)
+ if mode != perms:
+ os.chmod(self.prefix, perms)
# Fork a child to do the actual installation
# we preserve verbosity settings across installs.
@@ -1479,7 +1534,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
spack.store.db.add(
self.spec, spack.store.layout, explicit=explicit
)
- except directory_layout.InstallDirectoryAlreadyExistsError:
+ except spack.directory_layout.InstallDirectoryAlreadyExistsError:
# Abort install if install directory exists.
# But do NOT remove it (you'd be overwriting someone else's stuff)
tty.warn("Keeping existing install prefix in place.")
@@ -1501,14 +1556,38 @@ class PackageBase(with_metaclass(PackageMeta, object)):
# check the filesystem for it.
self.stage.created = False
+ def unit_test_check(self):
+ """Hook for unit tests to assert things about package internals.
+
+ Unit tests can override this function to perform checks after
+ ``Package.install`` and all post-install hooks run, but before
+ the database is updated.
+
+ The overridden function may indicate that the install procedure
+ should terminate early (before updating the database) by
+ returning ``False`` (or any value such that ``bool(result)`` is
+ ``False``).
+
+ Return:
+ (bool): ``True`` to continue, ``False`` to skip ``install()``
+ """
+ return True
+
def check_for_unfinished_installation(
self, keep_prefix=False, restage=False):
"""Check for leftover files from partially-completed prior install to
- prepare for a new install attempt. Options control whether these
- files are reused (vs. destroyed). This function considers a package
- fully-installed if there is a DB entry for it (in that way, it is
- more strict than Package.installed). The return value is used to
- indicate when the prefix exists but the install is not complete.
+ prepare for a new install attempt.
+
+ Options control whether these files are reused (vs. destroyed).
+
+ Args:
+ keep_prefix (bool): True if the installation prefix needs to be
+ kept, False otherwise
+ restage (bool): False if the stage has to be kept, True otherwise
+
+ Returns:
+ True if the prefix exists but the install is not complete, False
+ otherwise.
"""
if self.spec.external:
raise ExternalPackageError("Attempted to repair external spec %s" %
@@ -1529,7 +1608,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
partial = True
stage_is_managed_in_spack = self.stage.path.startswith(
- spack.stage_path)
+ spack.paths.stage_path)
if restage and stage_is_managed_in_spack:
self.stage.destroy()
self.stage.create()
@@ -1564,8 +1643,54 @@ class PackageBase(with_metaclass(PackageMeta, object)):
# FIXME : this potentially catches too many things...
pass
+ # Archive the whole stdout + stderr for the package
install(self.log_path, log_install_path)
+ # Archive the environment used for the build
install(self.env_path, env_install_path)
+ # Finally, archive files that are specific to each package
+ with working_dir(self.stage.source_path):
+ errors = StringIO()
+ target_dir = os.path.join(
+ spack.store.layout.metadata_path(self.spec),
+ 'archived-files')
+
+ for glob_expr in self.archive_files:
+ # Check that we are trying to copy things that are
+ # in the source_path tree (not arbitrary files)
+ abs_expr = os.path.realpath(glob_expr)
+ if os.path.realpath(self.stage.source_path) not in abs_expr:
+ errors.write(
+ '[OUTSIDE SOURCE PATH]: {0}\n'.format(glob_expr)
+ )
+ continue
+ # Now that we are sure that the path is within the correct
+ # folder, make it relative and check for matches
+ if os.path.isabs(glob_expr):
+ glob_expr = os.path.relpath(
+ glob_expr, self.stage.source_path
+ )
+ files = glob.glob(glob_expr)
+ for f in files:
+ try:
+ target = os.path.join(target_dir, f)
+ # We must ensure that the directory exists before
+ # copying a file in
+ mkdirp(os.path.dirname(target))
+ install(f, target)
+ except Exception:
+ # Here try to be conservative, and avoid discarding
+ # the whole install procedure because of copying a
+ # single file failed
+ errors.write('[FAILED TO ARCHIVE]: {0}'.format(f))
+
+ if errors.getvalue():
+ error_file = os.path.join(target_dir, 'errors.txt')
+ mkdirp(target_dir)
+ with open(error_file, 'w') as err:
+ err.write(errors.getvalue())
+ tty.warn('Errors occurred when archiving files.\n\t'
+ 'See: {0}'.format(error_file))
+
dump_packages(self.spec, packages_dir)
def sanity_check_prefix(self):
@@ -1597,7 +1722,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
if self.installed:
return spack.store.layout.build_log_path(self.spec)
else:
- return join_path(self.stage.source_path, 'spack-build.out')
+ return os.path.join(self.stage.source_path, 'spack-build.out')
@property
def module(self):
@@ -1607,6 +1732,31 @@ class PackageBase(with_metaclass(PackageMeta, object)):
return __import__(self.__class__.__module__,
fromlist=[self.__class__.__name__])
+ @classmethod
+ def inject_flags(cls, name, flags):
+ """
+ flag_handler that injects all flags through the compiler wrapper.
+ """
+ return (flags, None, None)
+
+ @classmethod
+ def env_flags(cls, name, flags):
+ """
+ flag_handler that adds all flags to canonical environment variables.
+ """
+ return (None, flags, None)
+
+ @classmethod
+ def build_system_flags(cls, name, flags):
+ """
+ flag_handler that passes flags to the build system arguments. Any
+ package using `build_system_flags` must also implement
+ `flags_to_build_system_args`, or derive from a class that
+ implements it. Currently, AutotoolsPackage and CMakePackage
+ implement it.
+ """
+ return (None, None, flags)
+
def setup_environment(self, spack_env, run_env):
"""Set up the compile and runtime environments for a package.
@@ -1707,28 +1857,6 @@ class PackageBase(with_metaclass(PackageMeta, object)):
"""
pass
- def inject_flags(self, name, flags):
- """
- flag_handler that injects all flags through the compiler wrapper.
- """
- return (flags, None, None)
-
- def env_flags(self, name, flags):
- """
- flag_handler that adds all flags to canonical environment variables.
- """
- return (None, flags, None)
-
- def build_system_flags(self, name, flags):
- """
- flag_handler that passes flags to the build system arguments. Any
- package using `build_system_flags` must also implement
- `flags_to_build_system_args`, or derive from a class that
- implements it. Currently, AutotoolsPackage and CMakePackage
- implement it.
- """
- return (None, None, flags)
-
flag_handler = inject_flags
# The flag handler method is called for each of the allowed compiler flags.
# It returns a triple of inject_flags, env_flags, build_system_flags.
@@ -1770,7 +1898,7 @@ class PackageBase(with_metaclass(PackageMeta, object)):
# Try to get the pcakage for the spec
try:
pkg = spec.package
- except spack.repository.UnknownEntityError:
+ except spack.repo.UnknownEntityError:
pkg = None
# Pre-uninstall hook runs first.
@@ -1819,82 +1947,80 @@ class PackageBase(with_metaclass(PackageMeta, object)):
raise ActivationError("%s does not extend %s!" %
(self.name, self.extendee.name))
- def do_activate(self, force=False, verbose=True, extensions_layout=None):
+ def do_activate(self, view=None, with_dependencies=True, verbose=True):
"""Called on an extension to invoke the extendee's activate method.
Commands should call this routine, and should not call
activate() directly.
"""
+ if verbose:
+ tty.msg('Activating extension {0} for {1}'.format(
+ self.spec.cshort_spec, self.extendee_spec.cshort_spec))
+
self._sanity_check_extension()
+ if not view:
+ view = YamlFilesystemView(
+ self.extendee_spec.prefix, spack.store.layout)
- if extensions_layout is None:
- extensions_layout = spack.store.extensions
+ extensions_layout = view.extensions_layout
extensions_layout.check_extension_conflict(
self.extendee_spec, self.spec)
# Activate any package dependencies that are also extensions.
- if not force:
+ if with_dependencies:
for spec in self.dependency_activations():
- if not spec.package.is_activated(
- extensions_layout=extensions_layout):
+ if not spec.package.is_activated(view):
spec.package.do_activate(
- force=force, verbose=verbose,
- extensions_layout=extensions_layout)
+ view, with_dependencies=with_dependencies,
+ verbose=verbose)
self.extendee_spec.package.activate(
- self, extensions_layout=extensions_layout, **self.extendee_args)
+ self, view, **self.extendee_args)
extensions_layout.add_extension(self.extendee_spec, self.spec)
if verbose:
- tty.msg(
- "Activated extension %s for %s" %
- (self.spec.short_spec,
- self.extendee_spec.cformat("$_$@$+$%@")))
+ tty.debug('Activated extension {0} for {1}'.format(
+ self.spec.cshort_spec, self.extendee_spec.cshort_spec))
def dependency_activations(self):
return (spec for spec in self.spec.traverse(root=False, deptype='run')
if spec.package.extends(self.extendee_spec))
- def activate(self, extension, **kwargs):
- """Make extension package usable by linking all its files to a target
- provided by the directory layout (depending if the user wants to
- activate globally or in a specified file system view).
-
- Package authors can override this method to support other
- extension mechanisms. Spack internals (commands, hooks, etc.)
- should call do_activate() method so that proper checks are
- always executed.
-
+ def activate(self, extension, view, **kwargs):
"""
- extensions_layout = kwargs.get("extensions_layout",
- spack.store.extensions)
- target = extensions_layout.extendee_target_directory(self)
+ Add the extension to the specified view.
- def ignore(filename):
- return (filename in spack.store.layout.hidden_file_paths or
- kwargs.get('ignore', lambda f: False)(filename))
+ Package authors can override this function to maintain some
+ centralized state related to the set of activated extensions
+ for a package.
- tree = LinkTree(extension.prefix)
- conflict = tree.find_conflict(target, ignore=ignore)
- if conflict:
- raise ExtensionConflictError(conflict)
-
- tree.merge(target, ignore=ignore, link=extensions_layout.link)
+ Spack internals (commands, hooks, etc.) should call
+ do_activate() method so that proper checks are always executed.
+ """
+ view.merge(extension.spec, ignore=kwargs.get('ignore', None))
- def do_deactivate(self, **kwargs):
- """Called on the extension to invoke extendee's deactivate() method.
+ def do_deactivate(self, view=None, **kwargs):
+ """Remove this extension package from the specified view. Called
+ on the extension to invoke extendee's deactivate() method.
`remove_dependents=True` deactivates extensions depending on this
package instead of raising an error.
"""
self._sanity_check_extension()
force = kwargs.get('force', False)
- verbose = kwargs.get("verbose", True)
- remove_dependents = kwargs.get("remove_dependents", False)
- extensions_layout = kwargs.get("extensions_layout",
- spack.store.extensions)
+ verbose = kwargs.get('verbose', True)
+ remove_dependents = kwargs.get('remove_dependents', False)
+
+ if verbose:
+ tty.msg('Deactivating extension {0} for {1}'.format(
+ self.spec.cshort_spec, self.extendee_spec.cshort_spec))
+
+ if not view:
+ view = YamlFilesystemView(
+ self.extendee_spec.prefix, spack.store.layout)
+ extensions_layout = view.extensions_layout
# Allow a force deactivate to happen. This can unlink
# spurious files if something was corrupted.
@@ -1912,49 +2038,41 @@ class PackageBase(with_metaclass(PackageMeta, object)):
if remove_dependents:
aspec.package.do_deactivate(**kwargs)
else:
- msg = ("Cannot deactivate %s because %s is "
- "activated and depends on it.")
- raise ActivationError(
- msg % (self.spec.cshort_spec,
- aspec.cshort_spec))
+ msg = ('Cannot deactivate {0} because {1} is '
+ 'activated and depends on it')
+ raise ActivationError(msg.format(
+ self.spec.cshort_spec, aspec.cshort_spec))
self.extendee_spec.package.deactivate(
- self,
- extensions_layout=extensions_layout,
- **self.extendee_args)
+ self, view, **self.extendee_args)
# redundant activation check -- makes SURE the spec is not
# still activated even if something was wrong above.
- if self.is_activated(extensions_layout):
+ if self.is_activated(view):
extensions_layout.remove_extension(
self.extendee_spec, self.spec)
if verbose:
- tty.msg(
- "Deactivated extension %s for %s" %
- (self.spec.short_spec,
- self.extendee_spec.cformat("$_$@$+$%@")))
+ tty.debug('Deactivated extension {0} for {1}'.format(
+ self.spec.cshort_spec, self.extendee_spec.cshort_spec))
- def deactivate(self, extension, **kwargs):
- """Unlinks all files from extension out of this package's install dir
- or the corresponding filesystem view.
+ def deactivate(self, extension, view, **kwargs):
+ """
+ Remove all extension files from the specified view.
Package authors can override this method to support other
extension mechanisms. Spack internals (commands, hooks, etc.)
should call do_deactivate() method so that proper checks are
always executed.
-
"""
- extensions_layout = kwargs.get("extensions_layout",
- spack.store.extensions)
- target = extensions_layout.extendee_target_directory(self)
+ view.unmerge(extension.spec, ignore=kwargs.get('ignore', None))
- def ignore(filename):
- return (filename in spack.store.layout.hidden_file_paths or
- kwargs.get('ignore', lambda f: False)(filename))
-
- tree = LinkTree(extension.prefix)
- tree.unmerge(target, ignore=ignore)
+ def view(self):
+ """Create a view with the prefix of this package as the root.
+ Extensions added to this view will modify the installation prefix of
+ this package.
+ """
+ return YamlFilesystemView(self.prefix, spack.store.layout)
def do_restage(self):
"""Reverts expanded/checked out source to a pristine state."""
@@ -1980,8 +2098,15 @@ class PackageBase(with_metaclass(PackageMeta, object)):
@property
def all_urls(self):
+ """A list of all URLs in a package.
+
+ Check both class-level and version-specific URLs.
+
+ Returns:
+ list: a list of URLs
+ """
urls = []
- if self.url:
+ if hasattr(self, 'url') and self.url:
urls.append(self.url)
for args in self.versions.values():
@@ -1990,10 +2115,15 @@ class PackageBase(with_metaclass(PackageMeta, object)):
return urls
def fetch_remote_versions(self):
- """Try to find remote versions of this package using the
- list_url and any other URLs described in the package file."""
+ """Find remote versions of this package.
+
+ Uses ``list_url`` and any other URLs listed in the package file.
+
+ Returns:
+ dict: a dictionary mapping versions to URLs
+ """
if not self.all_urls:
- raise spack.util.web.VersionFetchError(self.__class__)
+ return {}
try:
return spack.util.web.find_versions_of_archive(
@@ -2063,6 +2193,11 @@ class PackageBase(with_metaclass(PackageMeta, object)):
tty.warn(msg.format(name))
+inject_flags = PackageBase.inject_flags
+env_flags = PackageBase.env_flags
+build_system_flags = PackageBase.build_system_flags
+
+
class Package(PackageBase):
"""General purpose class with a single ``install``
phase that needs to be coded by packagers.
@@ -2125,7 +2260,7 @@ def dump_packages(spec, path):
# Locate the dependency package in the install tree and find
# its provenance information.
source = spack.store.layout.build_packages_path(node)
- source_repo_root = join_path(source, node.namespace)
+ source_repo_root = os.path.join(source, node.namespace)
# There's no provenance installed for the source package. Skip it.
# User can always get something current from the builtin repo.
@@ -2134,25 +2269,25 @@ def dump_packages(spec, path):
# Create a source repo and get the pkg directory out of it.
try:
- source_repo = spack.repository.Repo(source_repo_root)
+ source_repo = spack.repo.Repo(source_repo_root)
source_pkg_dir = source_repo.dirname_for_package_name(
node.name)
- except spack.repository.RepoError:
+ except spack.repo.RepoError:
tty.warn("Warning: Couldn't copy in provenance for %s" %
node.name)
# Create a destination repository
- dest_repo_root = join_path(path, node.namespace)
+ dest_repo_root = os.path.join(path, node.namespace)
if not os.path.exists(dest_repo_root):
- spack.repository.create_repo(dest_repo_root)
- repo = spack.repository.Repo(dest_repo_root)
+ spack.repo.create_repo(dest_repo_root)
+ repo = spack.repo.Repo(dest_repo_root)
# Get the location of the package in the dest repo.
dest_pkg_dir = repo.dirname_for_package_name(node.name)
if node is not spec:
install_tree(source_pkg_dir, dest_pkg_dir)
else:
- spack.repo.dump_provenance(node, dest_pkg_dir)
+ spack.repo.path.dump_provenance(node, dest_pkg_dir)
def print_pkg(message):
@@ -2197,7 +2332,6 @@ class ExternalPackageError(InstallError):
class PackageStillNeededError(InstallError):
"""Raised when package is still needed by another on uninstall."""
-
def __init__(self, spec, dependents):
super(PackageStillNeededError, self).__init__("Cannot uninstall %s" %
spec)
@@ -2207,14 +2341,12 @@ class PackageStillNeededError(InstallError):
class PackageError(spack.error.SpackError):
"""Raised when something is wrong with a package definition."""
-
def __init__(self, message, long_msg=None):
super(PackageError, self).__init__(message, long_msg)
class PackageVersionError(PackageError):
"""Raised when a version URL cannot automatically be determined."""
-
def __init__(self, version):
super(PackageVersionError, self).__init__(
"Cannot determine a URL automatically for version %s" % version,
@@ -2230,26 +2362,17 @@ class NoURLError(PackageError):
class ExtensionError(PackageError):
-
- pass
-
-
-class ExtensionConflictError(ExtensionError):
-
- def __init__(self, path):
- super(ExtensionConflictError, self).__init__(
- "Extension blocked by file: %s" % path)
+ """Superclass for all errors having to do with extension packages."""
class ActivationError(ExtensionError):
-
+ """Raised when there are problems activating an extension."""
def __init__(self, msg, long_msg=None):
super(ActivationError, self).__init__(msg, long_msg)
class DependencyConflictError(spack.error.SpackError):
"""Raised when the dependencies cannot be flattened as asked for."""
-
def __init__(self, conflict):
super(DependencyConflictError, self).__init__(
"%s conflicts with another file in the flattened directory." % (
diff --git a/lib/spack/spack/package_prefs.py b/lib/spack/spack/package_prefs.py
index 489e87b9b0..bd400b1eb8 100644
--- a/lib/spack/spack/package_prefs.py
+++ b/lib/spack/spack/package_prefs.py
@@ -1,37 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import stat
+
from six import string_types
from six import iteritems
from llnl.util.lang import classproperty
-import spack
+import spack.repo
import spack.error
from spack.util.path import canonicalize_path
from spack.version import VersionList
-
+from spack.config import ConfigError
_lesser_spec_types = {'compiler': spack.spec.CompilerSpec,
'version': VersionList}
@@ -44,14 +27,14 @@ def _spec_type(component):
def get_packages_config():
"""Wrapper around get_packages_config() to validate semantics."""
- config = spack.config.get_config('packages')
+ config = spack.config.get('packages')
# Get a list of virtuals from packages.yaml. Note that because we
# check spack.repo, this collects virtuals that are actually provided
# by sometihng, not just packages/names that don't exist.
# So, this won't include, e.g., 'all'.
virtuals = [(pkg_name, pkg_name._start_mark) for pkg_name in config
- if spack.repo.is_virtual(pkg_name)]
+ if spack.repo.path.is_virtual(pkg_name)]
# die if there are virtuals in `packages.py`
if virtuals:
@@ -204,25 +187,6 @@ class PackagePrefs(object):
if name in pkg.variants)
-class PackageTesting(object):
- def __init__(self):
- self.packages_to_test = set()
- self._test_all = False
-
- def test(self, package_name):
- self.packages_to_test.add(package_name)
-
- def test_all(self):
- self._test_all = True
-
- def clear(self):
- self._test_all = False
- self.packages_to_test.clear()
-
- def check(self, package_name):
- return self._test_all or (package_name in self.packages_to_test)
-
-
def spec_externals(spec):
"""Return a list of external specs (w/external directory path filled in),
one for each known external installation."""
@@ -271,5 +235,79 @@ def is_spec_buildable(spec):
return allpkgs[spec.name]['buildable']
+def get_package_dir_permissions(spec):
+ """Return the permissions configured for the spec.
+
+ Include the GID bit if group permissions are on. This makes the group
+ attribute sticky for the directory. Package-specific settings take
+ precedent over settings for ``all``"""
+ perms = get_package_permissions(spec)
+ if perms & stat.S_IRWXG:
+ perms |= stat.S_ISGID
+ return perms
+
+
+def get_package_permissions(spec):
+ """Return the permissions configured for the spec.
+
+ Package-specific settings take precedence over settings for ``all``"""
+
+ # Get read permissions level
+ for name in (spec.name, 'all'):
+ try:
+ readable = spack.config.get('packages:%s:permissions:read' % name,
+ '')
+ if readable:
+ break
+ except AttributeError:
+ readable = 'world'
+
+ # Get write permissions level
+ for name in (spec.name, 'all'):
+ try:
+ writable = spack.config.get('packages:%s:permissions:write' % name,
+ '')
+ if writable:
+ break
+ except AttributeError:
+ writable = 'user'
+
+ perms = stat.S_IRWXU
+ if readable in ('world', 'group'): # world includes group
+ perms |= stat.S_IRGRP | stat.S_IXGRP
+ if readable == 'world':
+ perms |= stat.S_IROTH | stat.S_IXOTH
+
+ if writable in ('world', 'group'):
+ if readable == 'user':
+ raise ConfigError('Writable permissions may not be more' +
+ ' permissive than readable permissions.\n' +
+ ' Violating package is %s' % spec.name)
+ perms |= stat.S_IWGRP
+ if writable == 'world':
+ if readable != 'world':
+ raise ConfigError('Writable permissions may not be more' +
+ ' permissive than readable permissions.\n' +
+ ' Violating package is %s' % spec.name)
+ perms |= stat.S_IWOTH
+
+ return perms
+
+
+def get_package_group(spec):
+ """Return the unix group associated with the spec.
+
+ Package-specific settings take precedence over settings for ``all``"""
+ for name in (spec.name, 'all'):
+ try:
+ group = spack.config.get('packages:%s:permissions:group' % name,
+ '')
+ if group:
+ break
+ except AttributeError:
+ group = ''
+ return group
+
+
class VirtualInPackagesYAMLError(spack.error.SpackError):
"""Raised when a disallowed virtual is found in packages.yaml"""
diff --git a/lib/spack/spack/package_test.py b/lib/spack/spack/package_test.py
index e3f2e82d03..29edfc6d38 100644
--- a/lib/spack/spack/package_test.py
+++ b/lib/spack/spack/package_test.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
from spack.util.executable import which, Executable
diff --git a/lib/spack/spack/parse.py b/lib/spack/spack/parse.py
index 1bdefde7a4..0b3d81d5a1 100644
--- a/lib/spack/spack/parse.py
+++ b/lib/spack/spack/parse.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
import shlex
import sys
diff --git a/lib/spack/spack/patch.py b/lib/spack/spack/patch.py
index 2fea1d9aff..a865d429a4 100644
--- a/lib/spack/spack/patch.py
+++ b/lib/spack/spack/patch.py
@@ -1,33 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import os.path
import inspect
import hashlib
-import spack
import spack.error
import spack.fetch_strategy as fs
import spack.stage
@@ -154,7 +134,7 @@ class UrlPatch(Patch):
if self.archive_sha256:
fetch_digest = self.archive_sha256
- fetcher = fs.URLFetchStrategy(self.url, digest=fetch_digest)
+ fetcher = fs.URLFetchStrategy(self.url, fetch_digest)
mirror = os.path.join(
os.path.dirname(stage.mirror_path),
os.path.basename(self.url))
diff --git a/lib/spack/spack/paths.py b/lib/spack/spack/paths.py
new file mode 100644
index 0000000000..d1d1d27136
--- /dev/null
+++ b/lib/spack/spack/paths.py
@@ -0,0 +1,61 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Defines paths that are part of Spack's directory structure.
+
+Do not import other ``spack`` modules here. This module is used
+throughout Spack and should bring in a minimal number of external
+dependencies.
+"""
+import os
+from llnl.util.filesystem import ancestor
+
+
+#: This file lives in $prefix/lib/spack/spack/__file__
+prefix = ancestor(__file__, 4)
+
+#: synonym for prefix
+spack_root = prefix
+
+#: bin directory in the spack prefix
+bin_path = os.path.join(prefix, "bin")
+
+#: The spack script itself
+spack_script = os.path.join(bin_path, "spack")
+
+# spack directory hierarchy
+lib_path = os.path.join(prefix, "lib", "spack")
+external_path = os.path.join(lib_path, "external")
+build_env_path = os.path.join(lib_path, "env")
+module_path = os.path.join(lib_path, "spack")
+command_path = os.path.join(module_path, "cmd")
+platform_path = os.path.join(module_path, 'platforms')
+compilers_path = os.path.join(module_path, "compilers")
+build_systems_path = os.path.join(module_path, 'build_systems')
+operating_system_path = os.path.join(module_path, 'operating_systems')
+test_path = os.path.join(module_path, "test")
+hooks_path = os.path.join(module_path, "hooks")
+var_path = os.path.join(prefix, "var", "spack")
+stage_path = os.path.join(var_path, "stage")
+repos_path = os.path.join(var_path, "repos")
+share_path = os.path.join(prefix, "share", "spack")
+
+# Paths to built-in Spack repositories.
+packages_path = os.path.join(repos_path, "builtin")
+mock_packages_path = os.path.join(repos_path, "builtin.mock")
+
+#: User configuration location
+user_config_path = os.path.expanduser('~/.spack')
+
+
+opt_path = os.path.join(prefix, "opt")
+etc_path = os.path.join(prefix, "etc")
+system_etc_path = '/etc'
+
+# GPG paths.
+gpg_keys_path = os.path.join(var_path, "gpg")
+mock_gpg_data_path = os.path.join(var_path, "gpg.mock", "data")
+mock_gpg_keys_path = os.path.join(var_path, "gpg.mock", "keys")
+gpg_path = os.path.join(opt_path, "spack", "gpg")
diff --git a/lib/spack/spack/pkgkit.py b/lib/spack/spack/pkgkit.py
new file mode 100644
index 0000000000..39d1855a01
--- /dev/null
+++ b/lib/spack/spack/pkgkit.py
@@ -0,0 +1,49 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+# flake8: noqa: F401
+"""pkgkit is a set of useful build tools and directives for packages.
+
+Everything in this module is automatically imported into Spack package files.
+"""
+import llnl.util.filesystem
+from llnl.util.filesystem import *
+
+from spack.package import Package, run_before, run_after, on_package_attributes
+from spack.package import inject_flags, env_flags, build_system_flags
+from spack.build_systems.makefile import MakefilePackage
+from spack.build_systems.aspell_dict import AspellDictPackage
+from spack.build_systems.autotools import AutotoolsPackage
+from spack.build_systems.cmake import CMakePackage
+from spack.build_systems.cuda import CudaPackage
+from spack.build_systems.qmake import QMakePackage
+from spack.build_systems.scons import SConsPackage
+from spack.build_systems.waf import WafPackage
+from spack.build_systems.octave import OctavePackage
+from spack.build_systems.python import PythonPackage
+from spack.build_systems.r import RPackage
+from spack.build_systems.perl import PerlPackage
+from spack.build_systems.intel import IntelPackage
+from spack.build_systems.meson import MesonPackage
+
+from spack.mixins import filter_compiler_wrappers
+
+from spack.version import Version, ver
+
+from spack.spec import Spec
+
+from spack.dependency import all_deptypes
+
+from spack.multimethod import when
+
+import spack.directives
+from spack.directives import *
+
+import spack.util.executable
+from spack.util.executable import *
+
+from spack.package import \
+ install_dependency_symlinks, flatten_dependencies, \
+ DependencyConflictError, InstallError, ExternalPackageError
diff --git a/lib/spack/spack/platforms/__init__.py b/lib/spack/spack/platforms/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/spack/platforms/__init__.py
+++ b/lib/spack/spack/platforms/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/spack/platforms/bgq.py b/lib/spack/spack/platforms/bgq.py
index f0dfe1dd14..9763dfadb3 100644
--- a/lib/spack/spack/platforms/bgq.py
+++ b/lib/spack/spack/platforms/bgq.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
from spack.architecture import Platform, Target
from spack.operating_systems.linux_distro import LinuxDistro
@@ -53,5 +34,5 @@ class Bgq(Platform):
self.add_operating_system(str(back_distro), back_distro)
@classmethod
- def detect(self):
+ def detect(cls):
return os.path.exists('/bgsys')
diff --git a/lib/spack/spack/platforms/cray.py b/lib/spack/spack/platforms/cray.py
index 095a426b22..2190552e2b 100644
--- a/lib/spack/spack/platforms/cray.py
+++ b/lib/spack/spack/platforms/cray.py
@@ -1,37 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import re
import llnl.util.tty as tty
-from spack import build_env_path
+from spack.paths import build_env_path
from spack.util.executable import which
from spack.architecture import Platform, Target, NoPlatformError
from spack.operating_systems.cray_frontend import CrayFrontend
from spack.operating_systems.cnl import Cnl
-from llnl.util.filesystem import join_path
-from spack.util.module_cmd import get_module_cmd
+from spack.util.module_cmd import get_module_cmd, unload_module
def _get_modules_in_modulecmd_output(output):
@@ -103,12 +83,23 @@ class Cray(Platform):
""" Change the linker to default dynamic to be more
similar to linux/standard linker behavior
"""
+ # Unload these modules to prevent any silent linking or unnecessary
+ # I/O profiling in the case of darshan.
+ modules_to_unload = ["cray-mpich", "darshan", "cray-libsci"]
+ for module in modules_to_unload:
+ unload_module(module)
+
env.set('CRAYPE_LINK_TYPE', 'dynamic')
- cray_wrapper_names = join_path(build_env_path, 'cray')
+ cray_wrapper_names = os.path.join(build_env_path, 'cray')
+
if os.path.isdir(cray_wrapper_names):
env.prepend_path('PATH', cray_wrapper_names)
env.prepend_path('SPACK_ENV_PATH', cray_wrapper_names)
+ # Makes spack installed pkg-config work on Crays
+ env.append_path("PKG_CONFIG_PATH", "/usr/lib64/pkgconfig")
+ env.append_path("PKG_CONFIG_PATH", "/usr/local/lib64/pkgconfig")
+
@classmethod
def detect(cls):
return os.environ.get('CRAYPE_VERSION') is not None
diff --git a/lib/spack/spack/platforms/darwin.py b/lib/spack/spack/platforms/darwin.py
index be2a1e7e41..1a793e4ed2 100644
--- a/lib/spack/spack/platforms/darwin.py
+++ b/lib/spack/spack/platforms/darwin.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import platform
from spack.architecture import Platform, Target
from spack.operating_systems.mac_os import MacOs
@@ -45,5 +26,5 @@ class Darwin(Platform):
self.add_operating_system(str(mac_os), mac_os)
@classmethod
- def detect(self):
+ def detect(cls):
return 'darwin' in platform.system().lower()
diff --git a/lib/spack/spack/platforms/linux.py b/lib/spack/spack/platforms/linux.py
index 4913be4ed2..2c36c24ebc 100644
--- a/lib/spack/spack/platforms/linux.py
+++ b/lib/spack/spack/platforms/linux.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import platform
from spack.architecture import Platform, Target
from spack.operating_systems.linux_distro import LinuxDistro
@@ -49,5 +30,5 @@ class Linux(Platform):
self.add_operating_system(str(linux_dist), linux_dist)
@classmethod
- def detect(self):
+ def detect(cls):
return 'linux' in platform.system().lower()
diff --git a/lib/spack/spack/platforms/test.py b/lib/spack/spack/platforms/test.py
index 3a4d2c00ad..18d283347f 100644
--- a/lib/spack/spack/platforms/test.py
+++ b/lib/spack/spack/platforms/test.py
@@ -1,29 +1,10 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack.architecture import Platform, Target
-from spack.architecture import OperatingSystem as OS
+from spack.architecture import OperatingSystem
class Test(Platform):
@@ -41,9 +22,11 @@ class Test(Platform):
self.add_target(self.default, Target(self.default))
self.add_target(self.front_end, Target(self.front_end))
- self.add_operating_system(self.default_os, OS('debian', 6))
- self.add_operating_system(self.front_os, OS('redhat', 6))
+ self.add_operating_system(
+ self.default_os, OperatingSystem('debian', 6))
+ self.add_operating_system(
+ self.front_os, OperatingSystem('redhat', 6))
@classmethod
- def detect(self):
+ def detect(cls):
return True
diff --git a/lib/spack/spack/provider_index.py b/lib/spack/spack/provider_index.py
index 21bde7ce5c..222f98c0d9 100644
--- a/lib/spack/spack/provider_index.py
+++ b/lib/spack/spack/provider_index.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
The ``virtual`` module contains utility classes for virtual dependencies.
"""
@@ -29,11 +10,9 @@ from itertools import product as iproduct
from six import iteritems
from pprint import pformat
-import spack.util.spack_yaml as syaml
-from yaml.error import MarkedYAMLError
-
-import spack
import spack.error
+import spack.util.spack_yaml as syaml
+from ruamel.yaml.error import MarkedYAMLError
class ProviderIndex(object):
diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py
index 1f62c70231..664551740a 100644
--- a/lib/spack/spack/relocate.py
+++ b/lib/spack/spack/relocate.py
@@ -1,38 +1,31 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import platform
import re
-import spack
+import spack.repo
import spack.cmd
-from spack.util.executable import Executable
+from spack.util.executable import Executable, ProcessError
from llnl.util.filesystem import filter_file
import llnl.util.tty as tty
+class InstallRootStringException(spack.error.SpackError):
+ """
+ Raised when the relocated binary still has the install root string.
+ """
+ def __init__(self, file_path, root_path):
+ super(InstallRootStringException, self).__init__(
+ "\n %s \ncontains string\n %s \n"
+ "after replacing it in rpaths.\n"
+ "Package should not be relocated.\n Use -a to override." %
+ (file_path, root_path))
+
+
def get_patchelf():
"""
Builds and installs spack patchelf package on linux platforms
@@ -56,10 +49,15 @@ def get_existing_elf_rpaths(path_name):
as a list of strings.
"""
if platform.system() == 'Linux':
- command = Executable(get_patchelf())
- output = command('--print-rpath', '%s' %
- path_name, output=str, err=str)
- return output.rstrip('\n').split(':')
+ patchelf = Executable(get_patchelf())
+ try:
+ output = patchelf('--print-rpath', '%s' %
+ path_name, output=str, error=str)
+ return output.rstrip('\n').split(':')
+ except ProcessError as e:
+ tty.debug('patchelf --print-rpath produced an error on %s' %
+ path_name, e)
+ return []
else:
tty.die('relocation not supported for this platform')
return
@@ -81,6 +79,29 @@ def get_relative_rpaths(path_name, orig_dir, orig_rpaths):
return rel_rpaths
+def set_placeholder(dirname):
+ """
+ return string of @'s with same length
+ """
+ return '@' * len(dirname)
+
+
+def get_placeholder_rpaths(path_name, orig_rpaths):
+ """
+ Replaces original layout root dir with a placeholder string in all rpaths.
+ """
+ rel_rpaths = []
+ orig_dir = spack.store.layout.root
+ for rpath in orig_rpaths:
+ if re.match(orig_dir, rpath):
+ placeholder = set_placeholder(orig_dir)
+ rel = re.sub(orig_dir, placeholder, rpath)
+ rel_rpaths.append('%s' % rel)
+ else:
+ rel_rpaths.append(rpath)
+ return rel_rpaths
+
+
def macho_get_paths(path_name):
"""
Examines the output of otool -l path_name for these three fields:
@@ -116,7 +137,7 @@ def macho_get_paths(path_name):
def macho_make_paths_relative(path_name, old_dir, rpaths, deps, idpath):
"""
Replace old_dir with relative path from dirname(path_name)
- in rpaths and deps; idpaths are replaced with @rpath/basebane(path_name);
+ in rpaths and deps; idpaths are replaced with @rpath/libname as needed;
replacement are returned.
"""
new_idpath = None
@@ -139,6 +160,34 @@ def macho_make_paths_relative(path_name, old_dir, rpaths, deps, idpath):
return (new_rpaths, new_deps, new_idpath)
+def macho_make_paths_placeholder(rpaths, deps, idpath):
+ """
+ Replace old_dir with a placeholder of the same length
+ in rpaths and deps and idpaths is needed.
+ replacement are returned.
+ """
+ new_idpath = None
+ old_dir = spack.store.layout.root
+ placeholder = set_placeholder(old_dir)
+ if idpath:
+ new_idpath = re.sub(old_dir, placeholder, idpath)
+ new_rpaths = list()
+ new_deps = list()
+ for rpath in rpaths:
+ if re.match(old_dir, rpath):
+ ph = re.sub(old_dir, placeholder, rpath)
+ new_rpaths.append('%s' % ph)
+ else:
+ new_rpaths.append(rpath)
+ for dep in deps:
+ if re.match(old_dir, dep):
+ ph = re.sub(old_dir, placeholder, dep)
+ new_deps.append('%s' % ph)
+ else:
+ new_deps.append(dep)
+ return (new_rpaths, new_deps, new_idpath)
+
+
def macho_replace_paths(old_dir, new_dir, rpaths, deps, idpath):
"""
Replace old_dir with new_dir in rpaths, deps and idpath
@@ -174,38 +223,44 @@ def modify_macho_object(cur_path, rpaths, deps, idpath,
if 'libgcc_' in cur_path:
return
install_name_tool = Executable('install_name_tool')
+ args = []
if new_idpath:
- install_name_tool('-id', new_idpath, str(cur_path),
- output=str, err=str)
+ args.extend(['-id', new_idpath])
for orig, new in zip(deps, new_deps):
- install_name_tool('-change', orig, new, str(cur_path))
+ args.extend(['-change', orig, new])
for orig, new in zip(rpaths, new_rpaths):
- install_name_tool('-rpath', orig, new, str(cur_path))
+ args.extend(['-rpath', orig, new])
+ args.append(str(cur_path))
+ install_name_tool(*args)
return
-def get_filetype(path_name):
+def strings_contains_installroot(path_name, root_dir):
"""
- Return the output of file path_name as a string to identify file type.
+ Check if the file contain the install root string.
"""
- file = Executable('file')
- file.add_default_env('LC_ALL', 'C')
- output = file('-b', '-h', '%s' % path_name,
- output=str, err=str)
- return output.strip()
+ strings = Executable('strings')
+ output = strings('%s' % path_name,
+ output=str, err=str)
+ return (root_dir in output)
-def modify_elf_object(path_name, orig_rpath, new_rpath):
+def modify_elf_object(path_name, new_rpaths):
"""
Replace orig_rpath with new_rpath in RPATH of elf object path_name
"""
if platform.system() == 'Linux':
- new_joined = ':'.join(new_rpath)
+ new_joined = ':'.join(new_rpaths)
patchelf = Executable(get_patchelf())
- patchelf('--force-rpath', '--set-rpath', '%s' % new_joined,
- '%s' % path_name, output=str, cmd=str)
+ try:
+ patchelf('--force-rpath', '--set-rpath', '%s' % new_joined,
+ '%s' % path_name, output=str, error=str)
+ except ProcessError as e:
+ tty.die('patchelf --set-rpath %s failed' %
+ path_name, e)
+ pass
else:
tty.die('relocation not supported for this platform')
@@ -237,33 +292,68 @@ def needs_text_relocation(filetype):
return ("text" in filetype)
-def relocate_binary(path_names, old_dir, new_dir):
+def relocate_binary(path_names, old_dir, new_dir, allow_root):
"""
Change old_dir to new_dir in RPATHs of elf or mach-o files
+ Account for the case where old_dir is now a placeholder
"""
+ placeholder = set_placeholder(old_dir)
if platform.system() == 'Darwin':
for path_name in path_names:
- rpaths, deps, idpath = macho_get_paths(path_name)
- new_rpaths, new_deps, new_idpath = macho_replace_paths(old_dir,
- new_dir,
- rpaths,
- deps,
- idpath)
+ (rpaths, deps, idpath) = macho_get_paths(path_name)
+ # new style buildaches with placeholder in binaries
+ if (deps[0].startswith(placeholder) or
+ rpaths[0].startswith(placeholder) or
+ (idpath and idpath.startswith(placeholder))):
+ (new_rpaths,
+ new_deps,
+ new_idpath) = macho_replace_paths(placeholder,
+ new_dir,
+ rpaths,
+ deps,
+ idpath)
+ # old style buildcaches with original install root in binaries
+ else:
+ (new_rpaths,
+ new_deps,
+ new_idpath) = macho_replace_paths(old_dir,
+ new_dir,
+ rpaths,
+ deps,
+ idpath)
modify_macho_object(path_name,
rpaths, deps, idpath,
new_rpaths, new_deps, new_idpath)
+ if (not allow_root and
+ old_dir != new_dir and
+ strings_contains_installroot(path_name, old_dir)):
+ raise InstallRootStringException(path_name, old_dir)
+
elif platform.system() == 'Linux':
for path_name in path_names:
orig_rpaths = get_existing_elf_rpaths(path_name)
- new_rpaths = substitute_rpath(orig_rpaths, old_dir, new_dir)
- modify_elf_object(path_name, orig_rpaths, new_rpaths)
+ if orig_rpaths:
+ if orig_rpaths[0].startswith(placeholder):
+ # new style buildaches with placeholder in binaries
+ new_rpaths = substitute_rpath(orig_rpaths,
+ placeholder, new_dir)
+ else:
+ # old style buildcaches with original install
+ # root in binaries
+ new_rpaths = substitute_rpath(orig_rpaths,
+ old_dir, new_dir)
+ modify_elf_object(path_name, new_rpaths)
+ if (not allow_root and
+ old_dir != new_dir and
+ strings_contains_installroot(path_name, old_dir)):
+ raise InstallRootStringException(path_name, old_dir)
else:
tty.die("Relocation not implemented for %s" % platform.system())
-def make_binary_relative(cur_path_names, orig_path_names, old_dir):
+def make_binary_relative(cur_path_names, orig_path_names, old_dir, allow_root):
"""
- Make RPATHs relative to old_dir in given elf or mach-o files
+ Replace old RPATHs with paths relative to old_dir in binary files
"""
if platform.system() == 'Darwin':
for cur_path, orig_path in zip(cur_path_names, orig_path_names):
@@ -275,16 +365,56 @@ def make_binary_relative(cur_path_names, orig_path_names, old_dir):
modify_macho_object(cur_path,
rpaths, deps, idpath,
new_rpaths, new_deps, new_idpath)
+ if (not allow_root and
+ strings_contains_installroot(cur_path)):
+ raise InstallRootStringException(cur_path)
elif platform.system() == 'Linux':
for cur_path, orig_path in zip(cur_path_names, orig_path_names):
orig_rpaths = get_existing_elf_rpaths(cur_path)
- new_rpaths = get_relative_rpaths(orig_path, old_dir,
- orig_rpaths)
- modify_elf_object(cur_path, orig_rpaths, new_rpaths)
+ if orig_rpaths:
+ new_rpaths = get_relative_rpaths(orig_path, old_dir,
+ orig_rpaths)
+ modify_elf_object(cur_path, new_rpaths)
+ if (not allow_root and
+ strings_contains_installroot(cur_path, old_dir)):
+ raise InstallRootStringException(cur_path, old_dir)
else:
tty.die("Prelocation not implemented for %s" % platform.system())
+def make_binary_placeholder(cur_path_names, allow_root):
+ """
+ Replace old install root in RPATHs with placeholder in binary files
+ """
+ if platform.system() == 'Darwin':
+ for cur_path in cur_path_names:
+ rpaths, deps, idpath = macho_get_paths(cur_path)
+ (new_rpaths,
+ new_deps,
+ new_idpath) = macho_make_paths_placeholder(rpaths, deps, idpath)
+ modify_macho_object(cur_path,
+ rpaths, deps, idpath,
+ new_rpaths, new_deps, new_idpath)
+ if (not allow_root and
+ strings_contains_installroot(cur_path,
+ spack.store.layout.root)):
+ raise InstallRootStringException(
+ cur_path, spack.store.layout.root)
+ elif platform.system() == 'Linux':
+ for cur_path in cur_path_names:
+ orig_rpaths = get_existing_elf_rpaths(cur_path)
+ if orig_rpaths:
+ new_rpaths = get_placeholder_rpaths(cur_path, orig_rpaths)
+ modify_elf_object(cur_path, new_rpaths)
+ if (not allow_root and
+ strings_contains_installroot(
+ cur_path, spack.store.layout.root)):
+ raise InstallRootStringException(
+ cur_path, spack.store.layout.root)
+ else:
+ tty.die("Placeholder not implemented for %s" % platform.system())
+
+
def relocate_text(path_names, old_dir, new_dir):
"""
Replace old path with new path in text file path_name
diff --git a/lib/spack/spack/repository.py b/lib/spack/spack/repo.py
index e38af165f9..7e5a297664 100644
--- a/lib/spack/spack/repository.py
+++ b/lib/spack/spack/repo.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import collections
import os
import stat
@@ -29,10 +10,11 @@ import shutil
import errno
import sys
import inspect
-import imp
import re
import traceback
import json
+from contextlib import contextmanager
+from six import string_types
try:
from collections.abc import Mapping
@@ -41,24 +23,25 @@ except ImportError:
from types import ModuleType
-import yaml
+import ruamel.yaml as yaml
import llnl.util.lang
import llnl.util.tty as tty
-from llnl.util.filesystem import mkdirp, join_path, install
+from llnl.util.filesystem import mkdirp, install
-import spack
+import spack.config
+import spack.caches
import spack.error
import spack.spec
+import spack.util.imp as simp
from spack.provider_index import ProviderIndex
from spack.util.path import canonicalize_path
from spack.util.naming import NamespaceTrie, valid_module_name
from spack.util.naming import mod_to_class, possible_spack_module_names
-#
-# Super-namespace for all packages.
-# Package modules are imported as spack.pkg.<namespace>.<pkg-name>.
-#
+
+#: Super-namespace for all packages.
+#: Package modules are imported as spack.pkg.<namespace>.<pkg-name>.
repo_namespace = 'spack.pkg'
#
@@ -69,9 +52,25 @@ repo_index_name = 'index.yaml' # Top-level filename for repository index.
packages_dir_name = 'packages' # Top-level repo directory containing pkgs.
package_file_name = 'package.py' # Filename for packages in a repository.
-# Guaranteed unused default value for some functions.
+#: Guaranteed unused default value for some functions.
NOT_PROVIDED = object()
+#: Code in ``_package_prepend`` is prepended to imported packages.
+#:
+#: Spack packages were originally expected to call `from spack import *`
+#: themselves, but it became difficult to manage and imports in the Spack
+#: core the top-level namespace polluted by package symbols this way. To
+#: solve this, the top-level ``spack`` package contains very few symbols
+#: of its own, and importing ``*`` is essentially a no-op. The common
+#: routines and directives that packages need are now in ``spack.pkgkit``,
+#: and the import system forces packages to automatically include
+#: this. This way, old packages that call ``from spack import *`` will
+#: continue to work without modification, but it's no longer required.
+#:
+#: TODO: At some point in the future, consider removing ``from spack import *``
+#: TODO: from packages and shifting to from ``spack.pkgkit import *``
+_package_prepend = 'from spack.pkgkit import *'
+
def _autospec(function):
"""Decorator that automatically converts the argument of a single-arg
@@ -114,8 +113,7 @@ class FastPackageChecker(Mapping):
_paths_cache = {}
def __init__(self, packages_path):
-
- #: The path of the repository managed by this instance
+ # The path of the repository managed by this instance
self.packages_path = packages_path
# If the cache we need is not there yet, then build it appropriately
@@ -138,7 +136,7 @@ class FastPackageChecker(Mapping):
cache = {}
for pkg_name in os.listdir(self.packages_path):
# Skip non-directories in the package root.
- pkg_dir = join_path(self.packages_path, pkg_name)
+ pkg_dir = os.path.join(self.packages_path, pkg_name)
# Warn about invalid names that look like packages.
if not valid_module_name(pkg_name):
@@ -220,8 +218,7 @@ class TagIndex(Mapping):
pkg_name (str): name of the package to be removed from the index
"""
-
- package = spack.repo.get(pkg_name)
+ package = path.get(pkg_name)
# Remove the package from the list of packages, if present
for pkg_list in self._tag_dict.values():
@@ -252,7 +249,8 @@ def make_provider_index_cache(packages_path, namespace):
cache_filename = 'providers/{0}-index.yaml'.format(namespace)
# Compute which packages needs to be updated in the cache
- index_mtime = spack.misc_cache.mtime(cache_filename)
+ misc_cache = spack.caches.misc_cache
+ index_mtime = misc_cache.mtime(cache_filename)
needs_update = [
x for x, sinfo in fast_package_checker.items()
@@ -260,19 +258,19 @@ def make_provider_index_cache(packages_path, namespace):
]
# Read the old ProviderIndex, or make a new one.
- index_existed = spack.misc_cache.init_entry(cache_filename)
+ index_existed = misc_cache.init_entry(cache_filename)
if index_existed and not needs_update:
# If the provider index exists and doesn't need an update
# just read from it
- with spack.misc_cache.read_transaction(cache_filename) as f:
+ with misc_cache.read_transaction(cache_filename) as f:
index = ProviderIndex.from_yaml(f)
else:
# Otherwise we need a write transaction to update it
- with spack.misc_cache.write_transaction(cache_filename) as (old, new):
+ with misc_cache.write_transaction(cache_filename) as (old, new):
index = ProviderIndex.from_yaml(old) if old else ProviderIndex()
@@ -305,7 +303,8 @@ def make_tag_index_cache(packages_path, namespace):
cache_filename = 'tags/{0}-index.json'.format(namespace)
# Compute which packages needs to be updated in the cache
- index_mtime = spack.misc_cache.mtime(cache_filename)
+ misc_cache = spack.caches.misc_cache
+ index_mtime = misc_cache.mtime(cache_filename)
needs_update = [
x for x, sinfo in fast_package_checker.items()
@@ -313,19 +312,19 @@ def make_tag_index_cache(packages_path, namespace):
]
# Read the old ProviderIndex, or make a new one.
- index_existed = spack.misc_cache.init_entry(cache_filename)
+ index_existed = misc_cache.init_entry(cache_filename)
if index_existed and not needs_update:
# If the provider index exists and doesn't need an update
# just read from it
- with spack.misc_cache.read_transaction(cache_filename) as f:
+ with misc_cache.read_transaction(cache_filename) as f:
index = TagIndex.from_json(f)
else:
# Otherwise we need a write transaction to update it
- with spack.misc_cache.write_transaction(cache_filename) as (old, new):
+ with misc_cache.write_transaction(cache_filename) as (old, new):
index = TagIndex.from_json(old) if old else TagIndex()
@@ -341,88 +340,62 @@ def make_tag_index_cache(packages_path, namespace):
class RepoPath(object):
"""A RepoPath is a list of repos that function as one.
- It functions exactly like a Repo, but it operates on the
- combined results of the Repos in its list instead of on a
- single package repository.
+ It functions exactly like a Repo, but it operates on the combined
+ results of the Repos in its list instead of on a single package
+ repository.
+
+ Args:
+ repos (list): list Repo objects or paths to put in this RepoPath
+
+ Optional Args:
+ repo_namespace (str): super-namespace for all packages in this
+ RepoPath (used when importing repos as modules)
"""
- def __init__(self, *repo_dirs, **kwargs):
- # super-namespace for all packages in the RepoPath
+ def __init__(self, *repos, **kwargs):
self.super_namespace = kwargs.get('namespace', repo_namespace)
self.repos = []
self.by_namespace = NamespaceTrie()
- self.by_path = {}
self._all_package_names = None
self._provider_index = None
- # If repo_dirs is empty, just use the configuration
- if not repo_dirs:
- import spack.config
- repo_dirs = spack.config.get_config('repos')
- if not repo_dirs:
- raise NoRepoConfiguredError(
- "Spack configuration contains no package repositories.")
-
# Add each repo to this path.
- for root in repo_dirs:
+ for repo in repos:
try:
- repo = Repo(root, self.super_namespace)
+ if isinstance(repo, string_types):
+ repo = Repo(repo, self.super_namespace)
self.put_last(repo)
except RepoError as e:
- tty.warn("Failed to initialize repository at '%s'." % root,
+ tty.warn("Failed to initialize repository: '%s'." % repo,
e.message,
"To remove the bad repository, run this command:",
- " spack repo rm %s" % root)
-
- def swap(self, other):
- """Convenience function to make swapping repositories easier.
-
- This is currently used by mock tests.
- TODO: Maybe there is a cleaner way.
-
- """
- attrs = ['repos',
- 'by_namespace',
- 'by_path',
- '_all_package_names',
- '_provider_index']
- for attr in attrs:
- tmp = getattr(self, attr)
- setattr(self, attr, getattr(other, attr))
- setattr(other, attr, tmp)
-
- def _add(self, repo):
- """Add a repository to the namespace and path indexes.
-
- Checks for duplicates -- two repos can't have the same root
- directory, and they provide have the same namespace.
-
- """
- if repo.root in self.by_path:
- raise DuplicateRepoError("Duplicate repository: '%s'" % repo.root)
-
- if repo.namespace in self.by_namespace:
- raise DuplicateRepoError(
- "Package repos '%s' and '%s' both provide namespace %s"
- % (repo.root, self.by_namespace[repo.namespace].root,
- repo.namespace))
-
- # Add repo to the pkg indexes
- self.by_namespace[repo.full_namespace] = repo
- self.by_path[repo.root] = repo
+ " spack repo rm %s" % repo)
def put_first(self, repo):
"""Add repo first in the search path."""
- self._add(repo)
+ if isinstance(repo, RepoPath):
+ for r in reversed(repo.repos):
+ self.put_first(r)
+ return
+
self.repos.insert(0, repo)
+ self.by_namespace[repo.full_namespace] = repo
def put_last(self, repo):
"""Add repo last in the search path."""
- self._add(repo)
+ if isinstance(repo, RepoPath):
+ for r in repo.repos:
+ self.put_last(r)
+ return
+
self.repos.append(repo)
+ # don't mask any higher-precedence repos with same namespace
+ if repo.full_namespace not in self.by_namespace:
+ self.by_namespace[repo.full_namespace] = repo
+
def remove(self, repo):
"""Remove a repo from the search path."""
if repo in self.repos:
@@ -648,18 +621,18 @@ class Repo(object):
raise BadRepoError(msg)
# Validate repository layout.
- self.config_file = join_path(self.root, repo_config_name)
+ self.config_file = os.path.join(self.root, repo_config_name)
check(os.path.isfile(self.config_file),
"No %s found in '%s'" % (repo_config_name, root))
- self.packages_path = join_path(self.root, packages_dir_name)
+ self.packages_path = os.path.join(self.root, packages_dir_name)
check(os.path.isdir(self.packages_path),
"No directory '%s' found in '%s'" % (repo_config_name, root))
# Read configuration and validate namespace
config = self._read_config()
check('namespace' in config, '%s must define a namespace.'
- % join_path(root, repo_config_name))
+ % os.path.join(root, repo_config_name))
self.namespace = config['namespace']
check(re.match(r'[a-zA-Z][a-zA-Z0-9_.]+', self.namespace),
@@ -683,7 +656,7 @@ class Repo(object):
self._instances = {}
# Maps that goes from package name to corresponding file stat
- self._fast_package_checker = FastPackageChecker(self.packages_path)
+ self._fast_package_checker = None
# Index of virtual dependencies, computed lazily
self._provider_index = None
@@ -819,7 +792,7 @@ class Repo(object):
% (self.config_file, self.root))
@_autospec
- def get(self, spec, new=False):
+ def get(self, spec):
if not self.exists(spec.name):
raise UnknownPackageError(spec.name)
@@ -828,18 +801,18 @@ class Repo(object):
"Repository %s does not contain package %s"
% (self.namespace, spec.fullname))
- key = hash(spec)
- if new or key not in self._instances:
- package_class = self.get_pkg_class(spec.name)
- try:
- copy = spec.copy() # defensive copy. Package owns its spec.
- self._instances[key] = package_class(copy)
- except Exception:
- if spack.debug:
- sys.excepthook(*sys.exc_info())
- raise FailedConstructorError(spec.fullname, *sys.exc_info())
-
- return self._instances[key]
+ package_class = self.get_pkg_class(spec.name)
+ try:
+ return package_class(spec)
+ except spack.error.SpackError:
+ # pass these through as their error messages will be fine.
+ raise
+ except Exception:
+ # make sure other errors in constructors hit the error
+ # handler by wrapping them
+ if spack.config.get('config:debug'):
+ sys.excepthook(*sys.exc_info())
+ raise FailedConstructorError(spec.fullname, *sys.exc_info())
@_autospec
def dump_provenance(self, spec, path):
@@ -917,7 +890,7 @@ class Repo(object):
"""Get the directory name for a particular package. This is the
directory that contains its package.py file."""
self._check_namespace(spec)
- return join_path(self.packages_path, spec.name)
+ return os.path.join(self.packages_path, spec.name)
@_autospec
def filename_for_package_name(self, spec):
@@ -931,11 +904,17 @@ class Repo(object):
"""
self._check_namespace(spec)
pkg_dir = self.dirname_for_package_name(spec.name)
- return join_path(pkg_dir, package_file_name)
+ return os.path.join(pkg_dir, package_file_name)
+
+ @property
+ def _pkg_checker(self):
+ if self._fast_package_checker is None:
+ self._fast_package_checker = FastPackageChecker(self.packages_path)
+ return self._fast_package_checker
def all_package_names(self):
"""Returns a sorted list of all package names in the Repo."""
- return sorted(self._fast_package_checker.keys())
+ return sorted(self._pkg_checker.keys())
def packages_with_tags(self, *tags):
v = set(self.all_package_names())
@@ -957,7 +936,7 @@ class Repo(object):
def exists(self, pkg_name):
"""Whether a package with the supplied name exists."""
- return pkg_name in self._fast_package_checker
+ return pkg_name in self._pkg_checker
def is_virtual(self, pkg_name):
"""True if the package with this name is virtual, False otherwise."""
@@ -987,7 +966,15 @@ class Repo(object):
# e.g., spack.pkg.builtin.mpich
fullname = "%s.%s" % (self.full_namespace, pkg_name)
- module = imp.load_source(fullname, file_path)
+ try:
+ module = simp.load_source(fullname, file_path,
+ prepend=_package_prepend)
+ except SyntaxError as e:
+ # SyntaxError strips the path from the filename so we need to
+ # manually construct the error message in order to give the
+ # user the correct package.py where the syntax error is located
+ raise SyntaxError('invalid syntax in {0:}, line {1:}'
+ ''.format(file_path, e.lineno))
module.__package__ = self.full_namespace
module.__loader__ = self
self._modules[pkg_name] = module
@@ -1084,6 +1071,78 @@ def create_repo(root, namespace=None):
return full_path, namespace
+def create_or_construct(path, namespace=None):
+ """Create a repository, or just return a Repo if it already exists."""
+ if not os.path.exists(path):
+ mkdirp(path)
+ create_repo(path, namespace)
+ return Repo(path, namespace)
+
+
+def _path():
+ """Get the singleton RepoPath instance for Spack.
+
+ Create a RepoPath, add it to sys.meta_path, and return it.
+
+ TODO: consider not making this a singleton.
+ """
+ repo_dirs = spack.config.get('repos')
+ if not repo_dirs:
+ raise NoRepoConfiguredError(
+ "Spack configuration contains no package repositories.")
+
+ path = RepoPath(*repo_dirs)
+ sys.meta_path.append(path)
+ return path
+
+
+#: Singleton repo path instance
+path = llnl.util.lang.Singleton(_path)
+
+
+def get(spec):
+ """Convenience wrapper around ``spack.repo.get()``."""
+ return path.get(spec)
+
+
+def all_package_names():
+ """Convenience wrapper around ``spack.repo.all_package_names()``."""
+ return path.all_package_names()
+
+
+def set_path(repo):
+ """Set the path singleton to a specific value.
+
+ Overwrite ``path`` and register it as an importer in
+ ``sys.meta_path`` if it is a ``Repo`` or ``RepoPath``.
+ """
+ global path
+ path = repo
+
+ # make the new repo_path an importer if needed
+ append = isinstance(repo, (Repo, RepoPath))
+ if append:
+ sys.meta_path.append(repo)
+ return append
+
+
+@contextmanager
+def swap(repo_path):
+ """Temporarily use another RepoPath."""
+ global path
+
+ # swap out _path for repo_path
+ saved = path
+ remove_from_meta = set_path(repo_path)
+
+ yield
+
+ # restore _path and sys.meta_path
+ if remove_from_meta:
+ sys.meta_path.remove(repo_path)
+ path = saved
+
+
class RepoError(spack.error.SpackError):
"""Superclass for repository-related errors."""
@@ -1100,10 +1159,6 @@ class BadRepoError(RepoError):
"""Raised when repo layout is invalid."""
-class DuplicateRepoError(RepoError):
- """Raised when duplicate repos are added to a RepoPath."""
-
-
class UnknownEntityError(RepoError):
"""Raised when we encounter a package spack doesn't have."""
diff --git a/lib/spack/spack/report.py b/lib/spack/spack/report.py
new file mode 100644
index 0000000000..74e5caf194
--- /dev/null
+++ b/lib/spack/spack/report.py
@@ -0,0 +1,267 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Tools to produce reports of spec installations"""
+import codecs
+import collections
+import functools
+import time
+import traceback
+
+import llnl.util.lang
+import spack.build_environment
+import spack.fetch_strategy
+import spack.package
+from spack.reporter import Reporter
+from spack.reporters.cdash import CDash
+from spack.reporters.junit import JUnit
+
+report_writers = {
+ None: Reporter,
+ 'junit': JUnit,
+ 'cdash': CDash
+}
+
+#: Allowed report formats
+valid_formats = list(report_writers.keys())
+
+__all__ = [
+ 'valid_formats',
+ 'collect_info'
+]
+
+
+def fetch_package_log(pkg):
+ try:
+ with codecs.open(pkg.build_log_path, 'r', 'utf-8') as f:
+ return ''.join(f.readlines())
+ except Exception:
+ return 'Cannot open build log for {0}'.format(
+ pkg.spec.cshort_spec
+ )
+
+
+class InfoCollector(object):
+ """Decorates PackageBase.do_install to collect information
+ on the installation of certain specs.
+
+ When exiting the context this change will be rolled-back.
+
+ The data collected is available through the ``specs``
+ attribute once exited, and it's organized as a list where
+ each item represents the installation of one of the spec.
+
+ Args:
+ specs (list of Spec): specs whose install information will
+ be recorded
+ """
+ #: Backup of PackageBase.do_install
+ _backup_do_install = spack.package.PackageBase.do_install
+
+ def __init__(self, specs):
+ #: Specs that will be installed
+ self.input_specs = specs
+ #: This is where we record the data that will be included
+ #: in our report.
+ self.specs = []
+
+ def __enter__(self):
+ # Initialize the spec report with the data that is available upfront.
+ for input_spec in self.input_specs:
+ name_fmt = '{0}_{1}'
+ name = name_fmt.format(input_spec.name,
+ input_spec.dag_hash(length=7))
+
+ spec = {
+ 'name': name,
+ 'nerrors': None,
+ 'nfailures': None,
+ 'npackages': None,
+ 'time': None,
+ 'timestamp': time.strftime(
+ "%a, %d %b %Y %H:%M:%S", time.gmtime()
+ ),
+ 'properties': [],
+ 'packages': []
+ }
+
+ self.specs.append(spec)
+
+ Property = collections.namedtuple('Property', ['name', 'value'])
+ spec['properties'].append(
+ Property('architecture', input_spec.architecture)
+ )
+ spec['properties'].append(
+ Property('compiler', input_spec.compiler))
+
+ # Check which specs are already installed and mark them as skipped
+ for dep in filter(lambda x: x.package.installed,
+ input_spec.traverse()):
+ package = {
+ 'name': dep.name,
+ 'id': dep.dag_hash(),
+ 'elapsed_time': '0.0',
+ 'result': 'skipped',
+ 'message': 'Spec already installed'
+ }
+ spec['packages'].append(package)
+
+ def gather_info(do_install):
+ """Decorates do_install to gather useful information for
+ a CI report.
+
+ It's defined here to capture the environment and build
+ this context as the installations proceed.
+ """
+ @functools.wraps(do_install)
+ def wrapper(pkg, *args, **kwargs):
+
+ # We accounted before for what is already installed
+ installed_on_entry = pkg.installed
+
+ package = {
+ 'name': pkg.name,
+ 'id': pkg.spec.dag_hash(),
+ 'elapsed_time': None,
+ 'result': None,
+ 'message': None
+ }
+
+ start_time = time.time()
+ value = None
+ try:
+
+ value = do_install(pkg, *args, **kwargs)
+ package['result'] = 'success'
+ package['stdout'] = fetch_package_log(pkg)
+ if installed_on_entry:
+ return
+
+ except spack.build_environment.InstallError as e:
+ # An InstallError is considered a failure (the recipe
+ # didn't work correctly)
+ package['result'] = 'failure'
+ package['stdout'] = fetch_package_log(pkg)
+ package['message'] = e.message or 'Installation failure'
+ package['exception'] = e.traceback
+
+ except (Exception, BaseException) as e:
+ # Everything else is an error (the installation
+ # failed outside of the child process)
+ package['result'] = 'error'
+ package['stdout'] = fetch_package_log(pkg)
+ package['message'] = str(e) or 'Unknown error'
+ package['exception'] = traceback.format_exc()
+
+ finally:
+ package['elapsed_time'] = time.time() - start_time
+
+ # Append the package to the correct spec report. In some
+ # cases it may happen that a spec that is asked to be
+ # installed explicitly will also be installed as a
+ # dependency of another spec. In this case append to both
+ # spec reports.
+ for s in llnl.util.lang.dedupe([pkg.spec.root, pkg.spec]):
+ name = name_fmt.format(s.name, s.dag_hash(length=7))
+ try:
+ item = next((
+ x for x in self.specs
+ if x['name'] == name
+ ))
+ item['packages'].append(package)
+ except StopIteration:
+ pass
+
+ return value
+
+ return wrapper
+
+ spack.package.PackageBase.do_install = gather_info(
+ spack.package.PackageBase.do_install
+ )
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+
+ # Restore the original method in PackageBase
+ spack.package.PackageBase.do_install = InfoCollector._backup_do_install
+
+ for spec in self.specs:
+ spec['npackages'] = len(spec['packages'])
+ spec['nfailures'] = len(
+ [x for x in spec['packages'] if x['result'] == 'failure']
+ )
+ spec['nerrors'] = len(
+ [x for x in spec['packages'] if x['result'] == 'error']
+ )
+ spec['time'] = sum([
+ float(x['elapsed_time']) for x in spec['packages']
+ ])
+
+
+class collect_info(object):
+ """Collects information to build a report while installing
+ and dumps it on exit.
+
+ If the format name is not ``None``, this context manager
+ decorates PackageBase.do_install when entering the context
+ and unrolls the change when exiting.
+
+ Within the context, only the specs that are passed to it
+ on initialization will be recorded for the report. Data from
+ other specs will be discarded.
+
+ Examples:
+
+ .. code-block:: python
+
+ # The file 'junit.xml' is written when exiting
+ # the context
+ specs = [Spec('hdf5').concretized()]
+ with collect_info(specs, 'junit', 'junit.xml'):
+ # A report will be generated for these specs...
+ for spec in specs:
+ spec.do_install()
+ # ...but not for this one
+ Spec('zlib').concretized().do_install()
+
+ Args:
+ format_name (str or None): one of the supported formats
+ install_command (str): the command line passed to spack
+ cdash_upload_url (str or None): where to upload the report
+
+ Raises:
+ ValueError: when ``format_name`` is not in ``valid_formats``
+ """
+ def __init__(self, format_name, install_command, cdash_upload_url):
+ self.filename = None
+ if cdash_upload_url:
+ self.format_name = 'cdash'
+ self.filename = 'cdash_report'
+ else:
+ self.format_name = format_name
+ # Check that the format is valid.
+ if self.format_name not in valid_formats:
+ raise ValueError('invalid report type: {0}'
+ .format(self.format_name))
+ self.report_writer = report_writers[self.format_name](
+ install_command, cdash_upload_url)
+
+ def concretization_report(self, msg):
+ self.report_writer.concretization_report(self.filename, msg)
+
+ def __enter__(self):
+ if self.format_name:
+ # Start the collector and patch PackageBase.do_install
+ self.collector = InfoCollector(self.specs)
+ self.collector.__enter__()
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if self.format_name:
+ # Close the collector and restore the
+ # original PackageBase.do_install
+ self.collector.__exit__(exc_type, exc_val, exc_tb)
+
+ report_data = {'specs': self.collector.specs}
+ self.report_writer.build_report(self.filename, report_data)
diff --git a/lib/spack/spack/reporter.py b/lib/spack/spack/reporter.py
new file mode 100644
index 0000000000..17efe23637
--- /dev/null
+++ b/lib/spack/spack/reporter.py
@@ -0,0 +1,21 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
+__all__ = ['Reporter']
+
+
+class Reporter(object):
+ """Base class for report writers."""
+
+ def __init__(self, install_command, cdash_upload_url):
+ self.install_command = install_command
+ self.cdash_upload_url = cdash_upload_url
+
+ def build_report(self, filename, report_data):
+ pass
+
+ def concretization_report(self, filename, msg):
+ pass
diff --git a/lib/spack/spack/reporters/__init__.py b/lib/spack/spack/reporters/__init__.py
new file mode 100644
index 0000000000..4f442db458
--- /dev/null
+++ b/lib/spack/spack/reporters/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/spack/reporters/cdash.py b/lib/spack/spack/reporters/cdash.py
new file mode 100644
index 0000000000..e27d7e9728
--- /dev/null
+++ b/lib/spack/spack/reporters/cdash.py
@@ -0,0 +1,199 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
+import codecs
+import hashlib
+import os.path
+import platform
+import re
+import socket
+import time
+import xml.sax.saxutils
+from six import text_type
+from six.moves.urllib.request import build_opener, HTTPHandler, Request
+
+import spack.build_environment
+import spack.fetch_strategy
+import spack.package
+from spack.reporter import Reporter
+from spack.util.crypto import checksum
+from spack.util.log_parse import parse_log_events
+
+__all__ = ['CDash']
+
+# Mapping Spack phases to the corresponding CTest/CDash phase.
+map_phases_to_cdash = {
+ 'autoreconf': 'configure',
+ 'cmake': 'configure',
+ 'configure': 'configure',
+ 'edit': 'configure',
+ 'build': 'build',
+ 'install': 'build'
+}
+
+# Initialize data structures common to each phase's report.
+cdash_phases = set(map_phases_to_cdash.values())
+
+
+class CDash(Reporter):
+ """Generate reports of spec installations for CDash.
+
+ To use this reporter, pass the ``--cdash-upload-url`` argument to
+ ``spack install``::
+
+ spack install --cdash-upload-url=\\
+ https://mydomain.com/cdash/submit.php?project=Spack <spec>
+
+ In this example, results will be uploaded to the *Spack* project on the
+ CDash instance hosted at https://mydomain.com/cdash.
+ """
+
+ def __init__(self, install_command, cdash_upload_url):
+ Reporter.__init__(self, install_command, cdash_upload_url)
+ self.template_dir = os.path.join('reports', 'cdash')
+ self.hostname = socket.gethostname()
+ self.osname = platform.system()
+ self.starttime = int(time.time())
+ # TODO: remove hardcoded use of Experimental here.
+ # Make the submission model configurable.
+ self.buildstamp = time.strftime("%Y%m%d-%H%M-Experimental",
+ time.localtime(self.starttime))
+
+ def build_report(self, filename, report_data):
+ self.initialize_report(filename, report_data)
+
+ for phase in cdash_phases:
+ report_data[phase] = {}
+ report_data[phase]['log'] = ""
+ report_data[phase]['status'] = 0
+ report_data[phase]['starttime'] = self.starttime
+ report_data[phase]['endtime'] = self.starttime
+
+ # Track the phases we perform so we know what reports to create.
+ phases_encountered = []
+
+ # Parse output phase-by-phase.
+ phase_regexp = re.compile(r"Executing phase: '(.*)'")
+ for spec in report_data['specs']:
+ for package in spec['packages']:
+ if 'stdout' in package:
+ current_phase = ''
+ cdash_phase = ''
+ for line in package['stdout'].splitlines():
+ match = phase_regexp.search(line)
+ if match:
+ current_phase = match.group(1)
+ if current_phase not in map_phases_to_cdash:
+ current_phase = ''
+ continue
+ cdash_phase = \
+ map_phases_to_cdash[current_phase]
+ if cdash_phase not in phases_encountered:
+ phases_encountered.append(cdash_phase)
+ report_data[cdash_phase]['log'] += \
+ text_type("{0} output for {1}:\n".format(
+ cdash_phase, package['name']))
+ elif cdash_phase:
+ report_data[cdash_phase]['log'] += \
+ xml.sax.saxutils.escape(line) + "\n"
+
+ # Move the build phase to the front of the list if it occurred.
+ # This supports older versions of CDash that expect this phase
+ # to be reported before all others.
+ if "build" in phases_encountered:
+ build_pos = phases_encountered.index("build")
+ phases_encountered.insert(0, phases_encountered.pop(build_pos))
+
+ for phase in phases_encountered:
+ errors, warnings = parse_log_events(
+ report_data[phase]['log'].splitlines())
+ nerrors = len(errors)
+
+ if phase == 'configure' and nerrors > 0:
+ report_data[phase]['status'] = 1
+
+ if phase == 'build':
+ # Convert log output from ASCII to Unicode and escape for XML.
+ def clean_log_event(event):
+ event = vars(event)
+ event['text'] = xml.sax.saxutils.escape(event['text'])
+ event['pre_context'] = xml.sax.saxutils.escape(
+ '\n'.join(event['pre_context']))
+ event['post_context'] = xml.sax.saxutils.escape(
+ '\n'.join(event['post_context']))
+ # source_file and source_line_no are either strings or
+ # the tuple (None,). Distinguish between these two cases.
+ if event['source_file'][0] is None:
+ event['source_file'] = ''
+ event['source_line_no'] = ''
+ else:
+ event['source_file'] = xml.sax.saxutils.escape(
+ event['source_file'])
+ return event
+
+ report_data[phase]['errors'] = []
+ report_data[phase]['warnings'] = []
+ for error in errors:
+ report_data[phase]['errors'].append(clean_log_event(error))
+ for warning in warnings:
+ report_data[phase]['warnings'].append(
+ clean_log_event(warning))
+
+ # Write the report.
+ report_name = phase.capitalize() + ".xml"
+ phase_report = os.path.join(filename, report_name)
+
+ with codecs.open(phase_report, 'w', 'utf-8') as f:
+ env = spack.tengine.make_environment()
+ site_template = os.path.join(self.template_dir, 'Site.xml')
+ t = env.get_template(site_template)
+ f.write(t.render(report_data))
+
+ phase_template = os.path.join(self.template_dir, report_name)
+ t = env.get_template(phase_template)
+ f.write(t.render(report_data))
+ self.upload(phase_report)
+
+ def concretization_report(self, filename, msg):
+ report_data = {}
+ self.initialize_report(filename, report_data)
+ report_data['starttime'] = self.starttime
+ report_data['endtime'] = self.starttime
+ report_data['msg'] = msg
+
+ env = spack.tengine.make_environment()
+ update_template = os.path.join(self.template_dir, 'Update.xml')
+ t = env.get_template(update_template)
+ output_filename = os.path.join(filename, 'Update.xml')
+ with open(output_filename, 'w') as f:
+ f.write(t.render(report_data))
+ self.upload(output_filename)
+
+ def initialize_report(self, filename, report_data):
+ if not os.path.exists(filename):
+ os.mkdir(filename)
+ report_data['install_command'] = self.install_command
+ report_data['buildstamp'] = self.buildstamp
+ report_data['hostname'] = self.hostname
+ report_data['osname'] = self.osname
+
+ def upload(self, filename):
+ if not self.cdash_upload_url:
+ return
+
+ # Compute md5 checksum for the contents of this file.
+ md5sum = checksum(hashlib.md5, filename, block_size=8192)
+
+ opener = build_opener(HTTPHandler)
+ with open(filename, 'rb') as f:
+ url = "{0}&MD5={1}".format(self.cdash_upload_url, md5sum)
+ request = Request(url, data=f)
+ request.add_header('Content-Type', 'text/xml')
+ request.add_header('Content-Length', os.path.getsize(filename))
+ # By default, urllib2 only support GET and POST.
+ # CDash needs expects this file to be uploaded via PUT.
+ request.get_method = lambda: 'PUT'
+ url = opener.open(request)
diff --git a/lib/spack/spack/reporters/junit.py b/lib/spack/spack/reporters/junit.py
new file mode 100644
index 0000000000..264da413f0
--- /dev/null
+++ b/lib/spack/spack/reporters/junit.py
@@ -0,0 +1,29 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+import os.path
+
+import spack.build_environment
+import spack.fetch_strategy
+import spack.package
+from spack.reporter import Reporter
+
+__all__ = ['JUnit']
+
+
+class JUnit(Reporter):
+ """Generate reports of spec installations for JUnit."""
+
+ def __init__(self, install_command, cdash_upload_url):
+ Reporter.__init__(self, install_command, cdash_upload_url)
+ self.template_file = os.path.join('reports', 'junit.xml')
+
+ def build_report(self, filename, report_data):
+ # Write the report
+ with open(filename, 'w') as f:
+ env = spack.tengine.make_environment()
+ t = env.get_template(self.template_file)
+ f.write(t.render(report_data))
diff --git a/lib/spack/spack/resource.py b/lib/spack/spack/resource.py
index 35ae0170e6..da697d4b2f 100644
--- a/lib/spack/spack/resource.py
+++ b/lib/spack/spack/resource.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Describes an optional resource needed for a build.
Typically a bunch of sources that can be built in-tree within another
diff --git a/lib/spack/spack/schema/__init__.py b/lib/spack/spack/schema/__init__.py
index 764dbd23bc..b7a90827f2 100644
--- a/lib/spack/spack/schema/__init__.py
+++ b/lib/spack/spack/schema/__init__.py
@@ -1,33 +1,6 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-"""This module contains jsonschema files for all of Spack's YAML formats.
-"""
-from llnl.util.lang import list_modules
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-# Automatically bring in all sub-modules
-__all__ = []
-for mod in list_modules(__path__[0]):
- __import__('%s.%s' % (__name__, mod))
- __all__.append(mod)
+"""This module contains jsonschema files for all of Spack's YAML formats."""
diff --git a/lib/spack/spack/schema/compilers.py b/lib/spack/spack/schema/compilers.py
index caa0d27662..139462d2d4 100644
--- a/lib/spack/spack/schema/compilers.py
+++ b/lib/spack/spack/schema/compilers.py
@@ -1,43 +1,23 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Schema for compilers.yaml configuration file.
.. literalinclude:: ../spack/schema/compilers.py
- :lines: 32-
+ :lines: 13-
"""
-schema = {
- '$schema': 'http://json-schema.org/schema#',
- 'title': 'Spack compiler configuration file schema',
- 'type': 'object',
- 'additionalProperties': False,
- 'patternProperties': {
- 'compilers': {
- 'type': 'array',
- 'items': {
+#: Properties for inclusion in other schemas
+properties = {
+ 'compilers': {
+ 'type': 'array',
+ 'items': [{
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': {
'compiler': {
'type': 'object',
'additionalProperties': False,
@@ -75,6 +55,7 @@ schema = {
{'type': 'null'}]}}},
'spec': {'type': 'string'},
'operating_system': {'type': 'string'},
+ 'target': {'type': 'string'},
'alias': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'modules': {'anyOf': [{'type': 'string'},
@@ -88,8 +69,37 @@ schema = {
'set': {
'type': 'object',
'patternProperties': {
- r'\w[\w-]*': { # variable name
- 'type': 'string'
+ # Variable name
+ r'\w[\w-]*': {
+ 'anyOf': [{'type': 'string'},
+ {'type': 'number'}]
+ }
+ }
+ },
+ 'unset': {
+ 'type': 'object',
+ 'patternProperties': {
+ # Variable name
+ r'\w[\w-]*': {'type': 'null'}
+ }
+ },
+ 'prepend-path': {
+ 'type': 'object',
+ 'patternProperties': {
+ # Variable name
+ r'\w[\w-]*': {
+ 'anyOf': [{'type': 'string'},
+ {'type': 'number'}]
+ }
+ }
+ },
+ 'append-path': {
+ 'type': 'object',
+ 'patternProperties': {
+ # Variable name
+ r'\w[\w-]*': {
+ 'anyOf': [{'type': 'string'},
+ {'type': 'number'}]
}
}
}
@@ -100,9 +110,19 @@ schema = {
'default': [],
'items': {'type': 'string'}
}
- },
- },
- },
- },
- },
+ }
+ }
+ }
+ }]
+ }
+}
+
+
+#: Full schema with metadata
+schema = {
+ '$schema': 'http://json-schema.org/schema#',
+ 'title': 'Spack compiler configuration file schema',
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': properties,
}
diff --git a/lib/spack/spack/schema/config.py b/lib/spack/spack/schema/config.py
index 57a1c075b1..0558a7a9ae 100644
--- a/lib/spack/spack/schema/config.py
+++ b/lib/spack/spack/schema/config.py
@@ -1,73 +1,70 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Schema for config.yaml configuration file.
.. literalinclude:: ../spack/schema/config.py
- :lines: 32-
+ :lines: 13-
"""
+#: Properties for inclusion in other schemas
+properties = {
+ 'config': {
+ 'type': 'object',
+ 'default': {},
+ 'properties': {
+ 'install_tree': {'type': 'string'},
+ 'install_hash_length': {'type': 'integer', 'minimum': 1},
+ 'install_path_scheme': {'type': 'string'},
+ 'build_stage': {
+ 'oneOf': [
+ {'type': 'string'},
+ {'type': 'array',
+ 'items': {'type': 'string'}}],
+ },
+ 'template_dirs': {
+ 'type': 'array',
+ 'items': {'type': 'string'}
+ },
+ 'module_roots': {
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': {
+ 'tcl': {'type': 'string'},
+ 'lmod': {'type': 'string'},
+ 'dotkit': {'type': 'string'},
+ },
+ },
+ 'source_cache': {'type': 'string'},
+ 'misc_cache': {'type': 'string'},
+ 'verify_ssl': {'type': 'boolean'},
+ 'debug': {'type': 'boolean'},
+ 'checksum': {'type': 'boolean'},
+ 'locks': {'type': 'boolean'},
+ 'dirty': {'type': 'boolean'},
+ 'build_language': {'type': 'string'},
+ 'build_jobs': {'type': 'integer', 'minimum': 1},
+ 'ccache': {'type': 'boolean'},
+ 'db_lock_timeout': {'type': 'integer', 'minimum': 1},
+ 'package_lock_timeout': {
+ 'anyOf': [
+ {'type': 'integer', 'minimum': 1},
+ {'type': 'null'}
+ ],
+ },
+ },
+ },
+}
+
+
+#: Full schema with metadata
schema = {
'$schema': 'http://json-schema.org/schema#',
- 'title': 'Spack module file configuration file schema',
+ 'title': 'Spack core configuration file schema',
'type': 'object',
'additionalProperties': False,
- 'patternProperties': {
- 'config': {
- 'type': 'object',
- 'default': {},
- 'properties': {
- 'install_tree': {'type': 'string'},
- 'install_hash_length': {'type': 'integer', 'minimum': 1},
- 'install_path_scheme': {'type': 'string'},
- 'build_stage': {
- 'oneOf': [
- {'type': 'string'},
- {'type': 'array',
- 'items': {'type': 'string'}}],
- },
- 'template_dirs': {
- 'type': 'array',
- 'items': {'type': 'string'}
- },
- 'module_roots': {
- 'type': 'object',
- 'additionalProperties': False,
- 'properties': {
- 'tcl': {'type': 'string'},
- 'lmod': {'type': 'string'},
- 'dotkit': {'type': 'string'},
- },
- },
- 'source_cache': {'type': 'string'},
- 'misc_cache': {'type': 'string'},
- 'verify_ssl': {'type': 'boolean'},
- 'checksum': {'type': 'boolean'},
- 'dirty': {'type': 'boolean'},
- 'build_jobs': {'type': 'integer', 'minimum': 1},
- }
- },
- },
+ 'properties': properties,
}
diff --git a/lib/spack/spack/schema/env.py b/lib/spack/spack/schema/env.py
new file mode 100644
index 0000000000..7b6ad602f7
--- /dev/null
+++ b/lib/spack/spack/schema/env.py
@@ -0,0 +1,57 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Schema for env.yaml configuration file.
+
+.. literalinclude:: ../spack/schema/env.py
+ :lines: 36-
+"""
+from llnl.util.lang import union_dicts
+
+import spack.schema.merged
+import spack.schema.modules
+
+
+schema = {
+ '$schema': 'http://json-schema.org/schema#',
+ 'title': 'Spack environment file schema',
+ 'definitions': spack.schema.modules.definitions,
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'patternProperties': {
+ '^env|spack$': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': union_dicts(
+ # merged configuration scope schemas
+ spack.schema.merged.properties,
+ # extra environment schema properties
+ {
+ 'include': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'string'
+ },
+ },
+ 'specs': {
+ # Specs is a list of specs, which can have
+ # optional additional properties in a sub-dict
+ 'type': 'array',
+ 'default': [],
+ 'additionalProperties': False,
+ 'items': {
+ 'anyOf': [
+ {'type': 'string'},
+ {'type': 'null'},
+ {'type': 'object'},
+ ]
+ }
+ }
+ }
+ )
+ }
+ }
+}
diff --git a/lib/spack/spack/schema/merged.py b/lib/spack/spack/schema/merged.py
new file mode 100644
index 0000000000..4505728076
--- /dev/null
+++ b/lib/spack/spack/schema/merged.py
@@ -0,0 +1,40 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Schema for configuration merged into one file.
+
+.. literalinclude:: ../spack/schema/merged.py
+ :lines: 40-
+"""
+from llnl.util.lang import union_dicts
+
+import spack.schema.compilers
+import spack.schema.config
+import spack.schema.mirrors
+import spack.schema.modules
+import spack.schema.packages
+import spack.schema.repos
+
+
+#: Properties for inclusion in other schemas
+properties = union_dicts(
+ spack.schema.compilers.properties,
+ spack.schema.config.properties,
+ spack.schema.mirrors.properties,
+ spack.schema.modules.properties,
+ spack.schema.packages.properties,
+ spack.schema.repos.properties
+)
+
+
+#: Full schema with metadata
+schema = {
+ '$schema': 'http://json-schema.org/schema#',
+ 'title': 'Spack merged configuration file schema',
+ 'definitions': spack.schema.modules.definitions,
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': properties,
+}
diff --git a/lib/spack/spack/schema/mirrors.py b/lib/spack/spack/schema/mirrors.py
index b826bc251c..345f43db66 100644
--- a/lib/spack/spack/schema/mirrors.py
+++ b/lib/spack/spack/schema/mirrors.py
@@ -1,48 +1,33 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Schema for mirrors.yaml configuration file.
.. literalinclude:: ../spack/schema/mirrors.py
- :lines: 32-
+ :lines: 13-
"""
+#: Properties for inclusion in other schemas
+properties = {
+ 'mirrors': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'patternProperties': {
+ r'\w[\w-]*': {'type': 'string'},
+ },
+ },
+}
+
+
+#: Full schema with metadata
schema = {
'$schema': 'http://json-schema.org/schema#',
'title': 'Spack mirror configuration file schema',
'type': 'object',
'additionalProperties': False,
- 'patternProperties': {
- r'mirrors': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'patternProperties': {
- r'\w[\w-]*': {
- 'type': 'string'},
- },
- },
- },
+ 'properties': properties,
}
diff --git a/lib/spack/spack/schema/modules.py b/lib/spack/spack/schema/modules.py
index 08380f0789..0a54856105 100644
--- a/lib/spack/spack/schema/modules.py
+++ b/lib/spack/spack/schema/modules.py
@@ -1,182 +1,179 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Schema for modules.yaml configuration file.
.. literalinclude:: ../spack/schema/modules.py
- :lines: 32-
+ :lines: 13-
"""
-schema = {
- '$schema': 'http://json-schema.org/schema#',
- 'title': 'Spack module file configuration file schema',
- 'type': 'object',
- 'additionalProperties': False,
- 'definitions': {
- 'array_of_strings': {
- 'type': 'array',
- 'default': [],
- 'items': {
+#: Definitions for parts of module schema
+definitions = {
+ 'array_of_strings': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {
+ 'type': 'string'
+ }
+ },
+ 'dictionary_of_strings': {
+ 'type': 'object',
+ 'patternProperties': {
+ r'\w[\w-]*': { # key
'type': 'string'
}
- },
- 'dictionary_of_strings': {
- 'type': 'object',
- 'patternProperties': {
- r'\w[\w-]*': { # key
- 'type': 'string'
- }
- }
- },
- 'dependency_selection': {
- 'type': 'string',
- 'enum': ['none', 'direct', 'all']
- },
- 'module_file_configuration': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'properties': {
- 'filter': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'properties': {
- 'environment_blacklist': {
- 'type': 'array',
- 'default': [],
- 'items': {
- 'type': 'string'
- }
+ }
+ },
+ 'dependency_selection': {
+ 'type': 'string',
+ 'enum': ['none', 'direct', 'all']
+ },
+ 'module_file_configuration': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': {
+ 'filter': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': {
+ 'environment_blacklist': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {
+ 'type': 'string'
}
}
+ }
+ },
+ 'template': {
+ 'type': 'string'
+ },
+ 'autoload': {
+ '$ref': '#/definitions/dependency_selection'},
+ 'prerequisites': {
+ '$ref': '#/definitions/dependency_selection'},
+ 'conflict': {
+ '$ref': '#/definitions/array_of_strings'},
+ 'load': {
+ '$ref': '#/definitions/array_of_strings'},
+ 'suffixes': {
+ '$ref': '#/definitions/dictionary_of_strings'},
+ 'environment': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': {
+ 'set': {
+ '$ref': '#/definitions/dictionary_of_strings'},
+ 'unset': {
+ '$ref': '#/definitions/array_of_strings'},
+ 'prepend_path': {
+ '$ref': '#/definitions/dictionary_of_strings'},
+ 'append_path': {
+ '$ref': '#/definitions/dictionary_of_strings'}
+ }
+ }
+ }
+ },
+ 'module_type_configuration': {
+ 'type': 'object',
+ 'default': {},
+ 'anyOf': [
+ {'properties': {
+ 'verbose': {
+ 'type': 'boolean',
+ 'default': False
},
- 'template': {
- 'type': 'string'
+ 'hash_length': {
+ 'type': 'integer',
+ 'minimum': 0,
+ 'default': 7
},
- 'autoload': {
- '$ref': '#/definitions/dependency_selection'},
- 'prerequisites': {
- '$ref': '#/definitions/dependency_selection'},
- 'conflict': {
+ 'whitelist': {
'$ref': '#/definitions/array_of_strings'},
- 'load': {
+ 'blacklist': {
'$ref': '#/definitions/array_of_strings'},
- 'suffixes': {
- '$ref': '#/definitions/dictionary_of_strings'},
- 'environment': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'properties': {
- 'set': {
- '$ref': '#/definitions/dictionary_of_strings'},
- 'unset': {
- '$ref': '#/definitions/array_of_strings'},
- 'prepend_path': {
- '$ref': '#/definitions/dictionary_of_strings'},
- 'append_path': {
- '$ref': '#/definitions/dictionary_of_strings'}
- }
+ 'blacklist_implicits': {
+ 'type': 'boolean',
+ 'default': False
+ },
+ 'naming_scheme': {
+ 'type': 'string' # Can we be more specific here?
}
- }
- },
- 'module_type_configuration': {
- 'type': 'object',
- 'default': {},
- 'anyOf': [
- {'properties': {
- 'verbose': {
- 'type': 'boolean',
- 'default': False
- },
- 'hash_length': {
- 'type': 'integer',
- 'minimum': 0,
- 'default': 7
- },
- 'whitelist': {
- '$ref': '#/definitions/array_of_strings'},
- 'blacklist': {
- '$ref': '#/definitions/array_of_strings'},
- 'naming_scheme': {
- 'type': 'string' # Can we be more specific here?
- }
- }},
- {'patternProperties': {
+ }},
+ {'patternProperties': {
+ r'\w[\w-]*': {
+ '$ref': '#/definitions/module_file_configuration'
+ }
+ }}
+ ]
+ }
+}
+
+
+# Properties for inclusion into other schemas (requires definitions)
+properties = {
+ 'modules': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': {
+ 'prefix_inspections': {
+ 'type': 'object',
+ 'patternProperties': {
+ # prefix-relative path to be inspected for existence
r'\w[\w-]*': {
- '$ref': '#/definitions/module_file_configuration'
- }
- }}
- ]
- }
- },
- 'patternProperties': {
- r'modules': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'properties': {
- 'prefix_inspections': {
- 'type': 'object',
- 'patternProperties': {
- # prefix-relative path to be inspected for existence
- r'\w[\w-]*': {
- '$ref': '#/definitions/array_of_strings'}}},
- 'enable': {
- 'type': 'array',
- 'default': [],
- 'items': {
- 'type': 'string',
- 'enum': ['tcl', 'dotkit', 'lmod']}},
- 'lmod': {
- 'allOf': [
- # Base configuration
- {'$ref': '#/definitions/module_type_configuration'},
- {
- 'core_compilers': {
- '$ref': '#/definitions/array_of_strings'
- },
- 'hierarchical_scheme': {
- '$ref': '#/definitions/array_of_strings'
- }
- } # Specific lmod extensions
- ]},
- 'tcl': {
- 'allOf': [
- # Base configuration
- {'$ref': '#/definitions/module_type_configuration'},
- {} # Specific tcl extensions
- ]},
- 'dotkit': {
- 'allOf': [
- # Base configuration
- {'$ref': '#/definitions/module_type_configuration'},
- {} # Specific dotkit extensions
- ]},
- }
+ '$ref': '#/definitions/array_of_strings'}}},
+ 'enable': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {
+ 'type': 'string',
+ 'enum': ['tcl', 'dotkit', 'lmod']}},
+ 'lmod': {
+ 'allOf': [
+ # Base configuration
+ {'$ref': '#/definitions/module_type_configuration'},
+ {
+ 'core_compilers': {
+ '$ref': '#/definitions/array_of_strings'
+ },
+ 'hierarchical_scheme': {
+ '$ref': '#/definitions/array_of_strings'
+ }
+ } # Specific lmod extensions
+ ]
+ },
+ 'tcl': {
+ 'allOf': [
+ # Base configuration
+ {'$ref': '#/definitions/module_type_configuration'},
+ {} # Specific tcl extensions
+ ]
+ },
+ 'dotkit': {
+ 'allOf': [
+ # Base configuration
+ {'$ref': '#/definitions/module_type_configuration'},
+ {} # Specific dotkit extensions
+ ]
+ },
},
},
}
+
+
+#: Full schema with metadata
+schema = {
+ '$schema': 'http://json-schema.org/schema#',
+ 'title': 'Spack module file configuration file schema',
+ 'definitions': definitions,
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': properties,
+}
diff --git a/lib/spack/spack/schema/packages.py b/lib/spack/spack/schema/packages.py
index 70773c8aef..c762a75ba4 100644
--- a/lib/spack/spack/schema/packages.py
+++ b/lib/spack/spack/schema/packages.py
@@ -1,90 +1,93 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Schema for packages.yaml configuration files.
.. literalinclude:: ../spack/schema/packages.py
- :lines: 32-
+ :lines: 13-
"""
-schema = {
- '$schema': 'http://json-schema.org/schema#',
- 'title': 'Spack package configuration file schema',
- 'type': 'object',
- 'additionalProperties': False,
- 'patternProperties': {
- r'packages': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'patternProperties': {
- r'\w[\w-]*': { # package name
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'properties': {
- 'version': {
- 'type': 'array',
- 'default': [],
- # version strings
- 'items': {'anyOf': [{'type': 'string'},
- {'type': 'number'}]}},
- 'compiler': {
- 'type': 'array',
- 'default': [],
- 'items': {'type': 'string'}}, # compiler specs
- 'buildable': {
- 'type': 'boolean',
- 'default': True,
- },
- 'modules': {
- 'type': 'object',
- 'default': {},
- },
- 'providers': {
- 'type': 'object',
- 'default': {},
- 'additionalProperties': False,
- 'patternProperties': {
- r'\w[\w-]*': {
- 'type': 'array',
- 'default': [],
- 'items': {'type': 'string'}, }, }, },
- 'paths': {
- 'type': 'object',
- 'default': {},
- },
- 'variants': {
- 'oneOf': [
- {'type': 'string'},
- {'type': 'array',
- 'items': {'type': 'string'}}],
+#: Properties for inclusion in other schemas
+properties = {
+ 'packages': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'patternProperties': {
+ r'\w[\w-]*': { # package name
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': {
+ 'version': {
+ 'type': 'array',
+ 'default': [],
+ # version strings
+ 'items': {'anyOf': [{'type': 'string'},
+ {'type': 'number'}]}},
+ 'compiler': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {'type': 'string'}}, # compiler specs
+ 'buildable': {
+ 'type': 'boolean',
+ 'default': True,
+ },
+ 'permissions': {
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': {
+ 'read': {
+ 'type': 'string',
+ 'enum': ['user', 'group', 'world'],
+ },
+ 'write': {
+ 'type': 'string',
+ 'enum': ['user', 'group', 'world'],
+ },
+ 'group': {
+ 'type': 'string',
+ },
},
},
+ 'modules': {
+ 'type': 'object',
+ 'default': {},
+ },
+ 'providers': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'patternProperties': {
+ r'\w[\w-]*': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {'type': 'string'}, }, }, },
+ 'paths': {
+ 'type': 'object',
+ 'default': {},
+ },
+ 'variants': {
+ 'oneOf': [
+ {'type': 'string'},
+ {'type': 'array',
+ 'items': {'type': 'string'}}],
+ },
},
},
},
},
}
+
+
+#: Full schema with metadata
+schema = {
+ '$schema': 'http://json-schema.org/schema#',
+ 'title': 'Spack package configuration file schema',
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'properties': properties,
+}
diff --git a/lib/spack/spack/schema/repos.py b/lib/spack/spack/schema/repos.py
index bdd1dfc5cf..1ee0457d99 100644
--- a/lib/spack/spack/schema/repos.py
+++ b/lib/spack/spack/schema/repos.py
@@ -1,45 +1,30 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Schema for repos.yaml configuration file.
.. literalinclude:: ../spack/schema/repos.py
- :lines: 32-
+ :lines: 13-
"""
+#: Properties for inclusion in other schemas
+properties = {
+ 'repos': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {'type': 'string'},
+ },
+}
+
+
+#: Full schema with metadata
schema = {
'$schema': 'http://json-schema.org/schema#',
'title': 'Spack repository configuration file schema',
'type': 'object',
'additionalProperties': False,
- 'patternProperties': {
- r'repos': {
- 'type': 'array',
- 'default': [],
- 'items': {
- 'type': 'string'},
- },
- },
+ 'properties': properties,
}
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index e29c1bed3c..f8991413cd 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
Spack allows very fine-grained control over how packages are installed and
over how they are built and configured. To make this easy, it has its own
@@ -114,11 +95,12 @@ from llnl.util.lang import key_ordering, HashableMap, ObjectWrapper, dedupe
from llnl.util.lang import check_kwargs
from llnl.util.tty.color import cwrite, colorize, cescape, get_color_when
-import spack
import spack.architecture
+import spack.compiler
import spack.compilers as compilers
import spack.error
import spack.parse
+import spack.repo
import spack.store
import spack.util.spack_json as sjson
import spack.util.spack_yaml as syaml
@@ -138,7 +120,7 @@ from spack.variant import VariantMap, UnknownVariantError
from spack.variant import DuplicateVariantError
from spack.variant import UnsatisfiableVariantSpecError
from spack.version import VersionList, VersionRange, Version, ver
-from yaml.error import MarkedYAMLError
+from ruamel.yaml.error import MarkedYAMLError
__all__ = [
'Spec',
@@ -183,7 +165,7 @@ hash_color = '@K' #: color for highlighting package hashes
#: This map determines the coloring of specs when using color output.
#: We make the fields different colors to enhance readability.
-#: See spack.color for descriptions of the color codes.
+#: See llnl.util.tty.color for descriptions of the color codes.
color_formats = {'%': compiler_color,
'@': version_color,
'=': architecture_color,
@@ -689,7 +671,7 @@ def _headers_default_handler(descriptor, spec, cls):
Raises:
RuntimeError: If no headers are found
"""
- headers = find_headers('*', root=spec.prefix.include, recurse=True)
+ headers = find_headers('*', root=spec.prefix.include, recursive=True)
if headers:
return headers
@@ -702,7 +684,8 @@ def _libs_default_handler(descriptor, spec, cls):
"""Default handler when looking for the 'libs' attribute.
Tries to search for ``lib{spec.name}`` recursively starting from
- ``spec.prefix``.
+ ``spec.prefix``. If ``spec.name`` starts with ``lib``, searches for
+ ``{spec.name}`` instead.
Parameters:
descriptor (ForwardQueryToPackage): descriptor that triggered the call
@@ -727,33 +710,34 @@ def _libs_default_handler(descriptor, spec, cls):
# depending on which one exists (there is a possibility, of course, to
# get something like 'libabcXabc.so, but for now we consider this
# unlikely).
- name = 'lib' + spec.name.replace('-', '?')
-
- if '+shared' in spec:
- libs = find_libraries(
- name, root=spec.prefix, shared=True, recurse=True
- )
- elif '~shared' in spec:
- libs = find_libraries(
- name, root=spec.prefix, shared=False, recurse=True
- )
- else:
- # Prefer shared
- libs = find_libraries(
- name, root=spec.prefix, shared=True, recurse=True
- )
- if libs:
- return libs
-
- libs = find_libraries(
- name, root=spec.prefix, shared=False, recurse=True
- )
+ name = spec.name.replace('-', '?')
+
+ # Avoid double 'lib' for packages whose names already start with lib
+ if not name.startswith('lib'):
+ name = 'lib' + name
+
+ # To speedup the search for external packages configured e.g. in /usr,
+ # perform first non-recursive search in prefix.lib then in prefix.lib64 and
+ # finally search all of prefix recursively. The search stops when the first
+ # match is found.
+ prefix = spec.prefix
+ search_paths = [(prefix.lib, False), (prefix.lib64, False), (prefix, True)]
+
+ # If '+shared' search only for shared library; if '~shared' search only for
+ # static library; otherwise, first search for shared and then for static.
+ search_shared = [True] if ('+shared' in spec) else \
+ ([False] if ('~shared' in spec) else [True, False])
+
+ for shared in search_shared:
+ for path, recursive in search_paths:
+ libs = find_libraries(
+ name, root=path, shared=shared, recursive=recursive
+ )
+ if libs:
+ return libs
- if libs:
- return libs
- else:
- msg = 'Unable to recursively locate {0} libraries in {1}'
- raise RuntimeError(msg.format(spec.name, spec.prefix))
+ msg = 'Unable to recursively locate {0} libraries in {1}'
+ raise RuntimeError(msg.format(spec.name, prefix))
class ForwardQueryToPackage(object):
@@ -770,10 +754,6 @@ class ForwardQueryToPackage(object):
instance
"""
self.attribute_name = attribute_name
- # Turn the default handler into a function with the right
- # signature that always returns None
- if default_handler is None:
- default_handler = lambda descriptor, spec, cls: None
self.default = default_handler
def __get__(self, instance, cls):
@@ -792,8 +772,11 @@ class ForwardQueryToPackage(object):
The first call that produces a value will stop the chain.
- If no call can handle the request or a None value is produced,
- then AttributeError is raised.
+ If no call can handle the request then AttributeError is raised with a
+ message indicating that no relevant attribute exists.
+ If a call returns None, an AttributeError is raised with a message
+ indicating a query failure, e.g. that library files were not found in a
+ 'libs' query.
"""
pkg = instance.package
try:
@@ -814,34 +797,53 @@ class ForwardQueryToPackage(object):
# Try to get the generic method from Package
callbacks_chain.append(lambda: getattr(pkg, self.attribute_name))
# Final resort : default callback
- callbacks_chain.append(lambda: self.default(self, instance, cls))
+ if self.default is not None:
+ callbacks_chain.append(lambda: self.default(self, instance, cls))
# Trigger the callbacks in order, the first one producing a
# value wins
value = None
+ message = None
for f in callbacks_chain:
try:
value = f()
+ # A callback can return None to trigger an error indicating
+ # that the query failed.
+ if value is None:
+ msg = "Query of package '{name}' for '{attrib}' failed\n"
+ msg += "\tprefix : {spec.prefix}\n"
+ msg += "\tspec : {spec}\n"
+ msg += "\tqueried as : {query.name}\n"
+ msg += "\textra parameters : {query.extra_parameters}"
+ message = msg.format(
+ name=pkg.name, attrib=self.attribute_name,
+ spec=instance, query=instance.last_query)
+ else:
+ return value
break
except AttributeError:
pass
- # 'None' value raises AttributeError : this permits to 'disable'
- # the call in a particular package by returning None from the
- # queried attribute, or will trigger an exception if things
- # searched for were not found
- if value is None:
- fmt = '\'{name}\' package has no relevant attribute \'{query}\'\n' # NOQA: ignore=E501
- fmt += '\tspec : \'{spec}\'\n'
- fmt += '\tqueried as : \'{spec.last_query.name}\'\n'
- fmt += '\textra parameters : \'{spec.last_query.extra_parameters}\'\n' # NOQA: ignore=E501
- message = fmt.format(
- name=pkg.name,
- query=self.attribute_name,
- spec=instance
- )
+ # value is 'None'
+ if message is not None:
+ # Here we can use another type of exception. If we do that, the
+ # unit test 'test_getitem_exceptional_paths' in the file
+ # lib/spack/spack/test/spec_dag.py will need to be updated to match
+ # the type.
raise AttributeError(message)
-
- return value
+ # 'None' value at this point means that there are no appropriate
+ # properties defined and no default handler, or that all callbacks
+ # raised AttributeError. In this case, we raise AttributeError with an
+ # appropriate message.
+ fmt = '\'{name}\' package has no relevant attribute \'{query}\'\n' # NOQA: ignore=E501
+ fmt += '\tspec : \'{spec}\'\n'
+ fmt += '\tqueried as : \'{spec.last_query.name}\'\n'
+ fmt += '\textra parameters : \'{spec.last_query.extra_parameters}\'\n' # NOQA: ignore=E501
+ message = fmt.format(
+ name=pkg.name,
+ query=self.attribute_name,
+ spec=instance
+ )
+ raise AttributeError(message)
def __set__(self, instance, value):
cls_name = type(instance).__name__
@@ -884,6 +886,9 @@ class SpecBuildInterface(ObjectWrapper):
@key_ordering
class Spec(object):
+ #: Cache for spec's prefix, computed lazily in the corresponding property
+ _prefix = None
+
@staticmethod
def from_literal(spec_dict, normal=True):
"""Builds a Spec from a dictionary containing the spec literal.
@@ -1064,6 +1069,8 @@ class Spec(object):
self.external_path = kwargs.get('external_path', None)
self.external_module = kwargs.get('external_module', None)
+ self._full_hash = kwargs.get('full_hash', None)
+
@property
def external(self):
return bool(self.external_path) or bool(self.external_module)
@@ -1194,14 +1201,16 @@ class Spec(object):
@property
def package(self):
- return spack.repo.get(self)
+ if not self._package:
+ self._package = spack.repo.get(self)
+ return self._package
@property
def package_class(self):
"""Internal package call gets only the class object for a package.
Use this to just get package metadata.
"""
- return spack.repo.get_pkg_class(self.fullname)
+ return spack.repo.path.get_pkg_class(self.fullname)
@property
def virtual(self):
@@ -1217,7 +1226,7 @@ class Spec(object):
@staticmethod
def is_virtual(name):
"""Test if a name is virtual without requiring a Spec."""
- return (name is not None) and (not spack.repo.exists(name))
+ return (name is not None) and (not spack.repo.path.exists(name))
@property
def concrete(self):
@@ -1374,12 +1383,13 @@ class Spec(object):
@property
def prefix(self):
- if hasattr(self, 'test_prefix'):
- return Prefix(self.test_prefix)
- return Prefix(spack.store.layout.path_for_spec(self))
+ if self._prefix is None:
+ self.prefix = spack.store.layout.path_for_spec(self)
+ return self._prefix
- def _set_test_prefix(self, val):
- self.test_prefix = val
+ @prefix.setter
+ def prefix(self, value):
+ self._prefix = Prefix(value)
def dag_hash(self, length=None):
"""Return a hash of the entire spec DAG, including connectivity."""
@@ -1402,7 +1412,26 @@ class Spec(object):
"""Get the first <bits> bits of the DAG hash as an integer type."""
return base32_prefix_bits(self.dag_hash(), bits)
- def to_node_dict(self):
+ def full_hash(self, length=None):
+ if not self.concrete:
+ raise SpecError("Spec is not concrete: " + str(self))
+
+ if not self._full_hash:
+ yaml_text = syaml.dump(
+ self.to_node_dict(hash_function=lambda s: s.full_hash()),
+ default_flow_style=True, width=maxint)
+ package_hash = self.package.content_hash()
+ sha = hashlib.sha1(yaml_text.encode('utf-8') + package_hash)
+
+ b32_hash = base64.b32encode(sha.digest()).lower()
+ if sys.version_info[0] >= 3:
+ b32_hash = b32_hash.decode('utf-8')
+
+ self._full_hash = b32_hash
+
+ return self._full_hash[:length]
+
+ def to_node_dict(self, hash_function=None, all_deps=False):
d = syaml_dict()
if self.versions:
@@ -1422,6 +1451,7 @@ class Spec(object):
v.yaml_entry() for _, v in self.variants.items()
)
)
+
params.update(sorted(self.compiler_flags.items()))
if params:
d['parameters'] = params
@@ -1429,27 +1459,45 @@ class Spec(object):
if self.external:
d['external'] = {
'path': self.external_path,
- 'module': bool(self.external_module)
+ 'module': self.external_module
}
+ if not self._concrete:
+ d['concrete'] = False
+
+ if 'patches' in self.variants:
+ variant = self.variants['patches']
+ if hasattr(variant, '_patches_in_order_of_appearance'):
+ d['patches'] = variant._patches_in_order_of_appearance
+
# TODO: restore build dependencies here once we have less picky
# TODO: concretization.
- deps = self.dependencies_dict(deptype=('link', 'run'))
+ if all_deps:
+ deptypes = ('link', 'run', 'build')
+ else:
+ deptypes = ('link', 'run')
+ deps = self.dependencies_dict(deptype=deptypes)
if deps:
+ if hash_function is None:
+ hash_function = lambda s: s.dag_hash()
d['dependencies'] = syaml_dict([
(name,
syaml_dict([
- ('hash', dspec.spec.dag_hash()),
+ ('hash', hash_function(dspec.spec)),
('type', sorted(str(s) for s in dspec.deptypes))])
) for name, dspec in sorted(deps.items())
])
return syaml_dict([(self.name, d)])
- def to_dict(self):
+ def to_dict(self, all_deps=False):
+ if all_deps:
+ deptypes = ('link', 'run', 'build')
+ else:
+ deptypes = ('link', 'run')
node_list = []
- for s in self.traverse(order='pre', deptype=('link', 'run')):
- node = s.to_node_dict()
+ for s in self.traverse(order='pre', deptype=deptypes):
+ node = s.to_node_dict(all_deps=all_deps)
node[s.name]['hash'] = s.dag_hash()
node_list.append(node)
@@ -1467,7 +1515,7 @@ class Spec(object):
name = next(iter(node))
node = node[name]
- spec = Spec(name)
+ spec = Spec(name, full_hash=node.get('full_hash', None))
spec.namespace = node.get('namespace', None)
spec._hash = node.get('hash', None)
@@ -1513,12 +1561,34 @@ class Spec(object):
spec.external_path = None
spec.external_module = None
+ # specs read in are concrete unless marked abstract
+ spec._concrete = node.get('concrete', True)
+
+ if 'patches' in node:
+ patches = node['patches']
+ if len(patches) > 0:
+ mvar = spec.variants.setdefault(
+ 'patches', MultiValuedVariant('patches', ())
+ )
+ mvar.value = patches
+ # FIXME: Monkey patches mvar to store patches order
+ mvar._patches_in_order_of_appearance = patches
+
# Don't read dependencies here; from_node_dict() is used by
# from_yaml() to read the root *and* each dependency spec.
return spec
@staticmethod
+ def dependencies_from_node_dict(node):
+ name = next(iter(node))
+ node = node[name]
+ if 'dependencies' not in node:
+ return
+ for t in Spec.read_yaml_dep_specs(node['dependencies']):
+ yield t
+
+ @staticmethod
def read_yaml_dep_specs(dependency_dict):
"""Read the DependencySpec portion of a YAML-formatted Spec.
@@ -1630,13 +1700,15 @@ class Spec(object):
# to presets below, their constraints will all be merged, but we'll
# still need to select a concrete package later.
if not self.virtual:
+ import spack.concretize
+ concretizer = spack.concretize.concretizer
changed |= any(
- (spack.concretizer.concretize_architecture(self),
- spack.concretizer.concretize_compiler(self),
- spack.concretizer.concretize_compiler_flags(
- self), # has to be concretized after compiler
- spack.concretizer.concretize_version(self),
- spack.concretizer.concretize_variants(self)))
+ (concretizer.concretize_architecture(self),
+ concretizer.concretize_compiler(self),
+ # flags must be concretized after compiler
+ concretizer.concretize_compiler_flags(self),
+ concretizer.concretize_version(self),
+ concretizer.concretize_variants(self)))
presets[self.name] = self
visited.add(self.name)
@@ -1697,8 +1769,9 @@ class Spec(object):
if not replacement:
# Get a list of possible replacements in order of
# preference.
- candidates = spack.concretizer.choose_virtual_or_external(
- spec)
+ import spack.concretize
+ concretizer = spack.concretize.concretizer
+ candidates = concretizer.choose_virtual_or_external(spec)
# Try the replacements in order, skipping any that cause
# satisfiability problems.
@@ -1760,26 +1833,21 @@ class Spec(object):
return changed
- def concretize(self):
+ def concretize(self, tests=False):
"""A spec is concrete if it describes one build of a package uniquely.
This will ensure that this spec is concrete.
+ Args:
+ tests (list or bool): list of packages that will need test
+ dependencies, or True/False for test all/none
+
If this spec could describe more than one version, variant, or build
of a package, this will add constraints to make it concrete.
Some rigorous validation and checks are also performed on the spec.
Concretizing ensures that it is self-consistent and that it's
- consistent with requirements of its pacakges. See flatten() and
+ consistent with requirements of its packages. See flatten() and
normalize() for more details on this.
-
- It also ensures that:
-
- .. code-block:: python
-
- for x in self.traverse():
- assert x.package.spec == x
-
- which may not be true *during* the concretization step.
"""
if not self.name:
raise SpecError("Attempting to concretize anonymous spec")
@@ -1790,13 +1858,26 @@ class Spec(object):
changed = True
force = False
+ user_spec_deps = self.flat_dependencies(copy=False)
+
while changed:
- changes = (self.normalize(force),
+ changes = (self.normalize(force, tests=tests,
+ user_spec_deps=user_spec_deps),
self._expand_virtual_packages(),
self._concretize_helper())
changed = any(changes)
force = True
+ visited_user_specs = set()
+ for dep in self.traverse():
+ visited_user_specs.add(dep.name)
+ visited_user_specs.update(x.name for x in dep.package.provided)
+
+ extra = set(user_spec_deps.keys()).difference(visited_user_specs)
+ if extra:
+ raise InvalidDependencyError(
+ self.name + " does not depend on " + comma_or(extra))
+
for s in self.traverse():
# After concretizing, assign namespaces to anything left.
# Note that this doesn't count as a "change". The repository
@@ -1807,7 +1888,7 @@ class Spec(object):
# we can do it as late as possible to allow as much
# compatibility across repositories as possible.
if s.namespace is None:
- s.namespace = spack.repo.repo_for_pkg(s.name).namespace
+ s.namespace = spack.repo.path.repo_for_pkg(s.name).namespace
if s.concrete:
continue
@@ -1850,10 +1931,11 @@ class Spec(object):
mvar.value = mvar.value + tuple(patches)
# FIXME: Monkey patches mvar to store patches order
p = getattr(mvar, '_patches_in_order_of_appearance', [])
- mvar._patches_in_order_of_appearance = dedupe(p + patches)
+ mvar._patches_in_order_of_appearance = list(
+ dedupe(p + patches))
for s in self.traverse():
- if s.external_module:
+ if s.external_module and not s.external_path:
compiler = spack.compilers.compiler_for_spec(
s.compiler, s.architecture)
for mod in compiler.modules:
@@ -1868,19 +1950,14 @@ class Spec(object):
# there are declared conflicts
matches = []
for x in self.traverse():
- for conflict_spec, when_list in x.package.conflicts.items():
- if x.satisfies(conflict_spec):
+ for conflict_spec, when_list in x.package_class.conflicts.items():
+ if x.satisfies(conflict_spec, strict=True):
for when_spec, msg in when_list:
- if x.satisfies(when_spec):
+ if x.satisfies(when_spec, strict=True):
matches.append((x, conflict_spec, when_spec, msg))
if matches:
raise ConflictsInSpecError(self, matches)
- # At this point the spec-package mutual references should
- # be self-consistent
- for x in self.traverse():
- x.package.spec = x
-
def _mark_concrete(self, value=True):
"""Mark this spec and its dependencies as concrete.
@@ -1897,7 +1974,7 @@ class Spec(object):
"""This is a non-destructive version of concretize(). First clones,
then returns a concrete version of this package without modifying
this package. """
- clone = self.copy()
+ clone = self.copy(caches=False)
clone.concretize()
return clone
@@ -1964,8 +2041,7 @@ class Spec(object):
If no conditions are True (and we don't depend on it), return
``(None, None)``.
"""
- pkg = spack.repo.get(self.fullname)
- conditions = pkg.dependencies[name]
+ conditions = self.package_class.dependencies[name]
substitute_abstract_variants(self)
# evaluate when specs to figure out constraints on the dependency.
@@ -2017,7 +2093,7 @@ class Spec(object):
raise UnsatisfiableProviderSpecError(required[0], vdep)
def _merge_dependency(
- self, dependency, visited, spec_deps, provider_index):
+ self, dependency, visited, spec_deps, provider_index, tests):
"""Merge dependency information from a Package into this Spec.
Args:
@@ -2113,10 +2189,10 @@ class Spec(object):
self._add_dependency(spec_dependency, dependency.type)
changed |= spec_dependency._normalize_helper(
- visited, spec_deps, provider_index)
+ visited, spec_deps, provider_index, tests)
return changed
- def _normalize_helper(self, visited, spec_deps, provider_index):
+ def _normalize_helper(self, visited, spec_deps, provider_index, tests):
"""Recursive helper function for _normalize."""
if self.name in visited:
return False
@@ -2132,22 +2208,28 @@ class Spec(object):
any_change = False
changed = True
- pkg = spack.repo.get(self.fullname)
while changed:
changed = False
- for dep_name in pkg.dependencies:
+ for dep_name in self.package_class.dependencies:
# Do we depend on dep_name? If so pkg_dep is not None.
dep = self._evaluate_dependency_conditions(dep_name)
+
# If dep is a needed dependency, merge it.
- if dep and (spack.package_testing.check(self.name) or
- set(dep.type) - set(['test'])):
- changed |= self._merge_dependency(
- dep, visited, spec_deps, provider_index)
+ if dep:
+ merge = (
+ # caller requested test dependencies
+ tests is True or (tests and self.name in tests) or
+ # this is not a test-only dependency
+ dep.type - set(['test']))
+
+ if merge:
+ changed |= self._merge_dependency(
+ dep, visited, spec_deps, provider_index, tests)
any_change |= changed
return any_change
- def normalize(self, force=False):
+ def normalize(self, force=False, tests=False, user_spec_deps=None):
"""When specs are parsed, any dependencies specified are hanging off
the root, and ONLY the ones that were explicitly provided are there.
Normalization turns a partial flat spec into a DAG, where:
@@ -2176,26 +2258,34 @@ class Spec(object):
# Ensure first that all packages & compilers in the DAG exist.
self.validate_or_raise()
- # Get all the dependencies into one DependencyMap
- spec_deps = self.flat_dependencies(copy=False)
+ # Clear the DAG and collect all dependencies in the DAG, which will be
+ # reapplied as constraints. All dependencies collected this way will
+ # have been created by a previous execution of 'normalize'.
+ # A dependency extracted here will only be reintegrated if it is
+ # discovered to apply according to _normalize_helper, so
+ # user-specified dependencies are recorded separately in case they
+ # refer to specs which take several normalization passes to
+ # materialize.
+ all_spec_deps = self.flat_dependencies(copy=False)
+
+ if user_spec_deps:
+ for name, spec in user_spec_deps.items():
+ if name not in all_spec_deps:
+ all_spec_deps[name] = spec
+ else:
+ all_spec_deps[name].constrain(spec)
# Initialize index of virtual dependency providers if
# concretize didn't pass us one already
provider_index = ProviderIndex(
- [s for s in spec_deps.values()], restrict=True)
+ [s for s in all_spec_deps.values()], restrict=True)
# traverse the package DAG and fill out dependencies according
# to package files & their 'when' specs
visited = set()
- any_change = self._normalize_helper(visited, spec_deps, provider_index)
-
- # If there are deps specified but not visited, they're not
- # actually deps of this package. Raise an error.
- extra = set(spec_deps.keys()).difference(visited)
- if extra:
- raise InvalidDependencyError(
- self.name + " does not depend on " + comma_or(extra))
+ any_change = self._normalize_helper(
+ visited, all_spec_deps, provider_index, tests)
# Mark the spec as normal once done.
self._normal = True
@@ -2412,7 +2502,7 @@ class Spec(object):
if not self.virtual and other.virtual:
try:
pkg = spack.repo.get(self.fullname)
- except spack.repository.UnknownEntityError:
+ except spack.repo.UnknownEntityError:
# If we can't get package info on this spec, don't treat
# it as a provider of this vdep.
return False
@@ -2552,7 +2642,7 @@ class Spec(object):
# FIXME: concretization to store the order of patches somewhere.
# FIXME: Needs to be refactored in a cleaner way.
for sha256 in self.variants['patches']._patches_in_order_of_appearance:
- patch = self.package.lookup_patch(sha256)
+ patch = self.package_class.lookup_patch(sha256)
if patch:
patches.append(patch)
continue
@@ -2560,7 +2650,7 @@ class Spec(object):
# if not found in this package, check immediate dependents
# for dependency patches
for dep_spec in self._dependents.values():
- patch = dep_spec.parent.package.lookup_patch(sha256)
+ patch = dep_spec.parent.package_class.lookup_patch(sha256)
if patch:
patches.append(patch)
@@ -2606,6 +2696,8 @@ class Spec(object):
self.external_module != other.external_module and
self.compiler_flags != other.compiler_flags)
+ self._package = None
+
# Local node attributes get copied first.
self.name = other.name
self.versions = other.versions.copy()
@@ -2618,6 +2710,15 @@ class Spec(object):
self.compiler_flags = other.compiler_flags.copy()
self.compiler_flags.spec = self
self.variants = other.variants.copy()
+
+ # FIXME: we manage _patches_in_order_of_appearance specially here
+ # to keep it from leaking out of spec.py, but we should figure
+ # out how to handle it more elegantly in the Variant classes.
+ for k, v in other.variants.items():
+ patches = getattr(v, '_patches_in_order_of_appearance', None)
+ if patches:
+ self.variants[k]._patches_in_order_of_appearance = patches
+
self.variants.spec = self
self.external_path = other.external_path
self.external_module = other.external_module
@@ -2638,16 +2739,18 @@ class Spec(object):
deptypes = deps
self._dup_deps(other, deptypes, caches)
+ self._concrete = other._concrete
+
if caches:
self._hash = other._hash
self._cmp_key_cache = other._cmp_key_cache
self._normal = other._normal
- self._concrete = other._concrete
+ self._full_hash = other._full_hash
else:
self._hash = None
self._cmp_key_cache = None
self._normal = False
- self._concrete = False
+ self._full_hash = None
return changed
@@ -2813,7 +2916,7 @@ class Spec(object):
"""Comparison key for just *this node* and not its deps."""
return (self.name,
self.namespace,
- self.versions,
+ tuple(self.versions),
self.variants,
self.architecture,
self.compiler,
@@ -2871,6 +2974,7 @@ class Spec(object):
You can also use full-string versions, which elide the prefixes::
${PACKAGE} Package name
+ ${FULLPACKAGE} Full package name (with namespace)
${VERSION} Version
${COMPILER} Full compiler string
${COMPILERNAME} Compiler name
@@ -2878,6 +2982,9 @@ class Spec(object):
${COMPILERFLAGS} Compiler flags
${OPTIONS} Options
${ARCHITECTURE} Architecture
+ ${PLATFORM} Platform
+ ${OS} Operating System
+ ${TARGET} Target
${SHA1} Dependencies 8-char sha1 prefix
${HASH:len} DAG hash with optional length specifier
@@ -2885,6 +2992,7 @@ class Spec(object):
${SPACK_INSTALL} The default spack install directory,
${SPACK_PREFIX}/opt
${PREFIX} The package prefix
+ ${NAMESPACE} The package namespace
Note these are case-insensitive: for example you can specify either
``${PACKAGE}`` or ``${package}``.
@@ -2898,11 +3006,9 @@ class Spec(object):
Args:
format_string (str): string containing the format to be expanded
- **kwargs (dict): the following list of keywords is supported
-
- - color (bool): True if returned string is colored
-
- - transform (dict): maps full-string formats to a callable \
+ Keyword Args:
+ color (bool): True if returned string is colored
+ transform (dict): maps full-string formats to a callable \
that accepts a string and returns another one
Examples:
@@ -2922,16 +3028,18 @@ class Spec(object):
color = kwargs.get('color', False)
# Dictionary of transformations for named tokens
- token_transforms = {}
- token_transforms.update(kwargs.get('transform', {}))
+ token_transforms = dict(
+ (k.upper(), v) for k, v in kwargs.get('transform', {}).items())
length = len(format_string)
out = StringIO()
named = escape = compiler = False
named_str = fmt = ''
- def write(s, c):
- f = color_formats[c] + cescape(s) + '@.'
+ def write(s, c=None):
+ f = cescape(s)
+ if c is not None:
+ f = color_formats[c] + f + '@.'
cwrite(f, stream=out, color=color)
iterator = enumerate(format_string)
@@ -2951,7 +3059,8 @@ class Spec(object):
name = self.name if self.name else ''
out.write(fmt % name)
elif c == '.':
- out.write(fmt % self.fullname)
+ name = self.fullname if self.fullname else ''
+ out.write(fmt % name)
elif c == '@':
if self.versions and self.versions != _any_version:
write(fmt % (c + str(self.versions)), c)
@@ -3006,50 +3115,63 @@ class Spec(object):
#
# The default behavior is to leave the string unchanged
# (`lambda x: x` is the identity function)
- token_transform = token_transforms.get(named_str, lambda x: x)
+ transform = token_transforms.get(named_str, lambda s, x: x)
if named_str == 'PACKAGE':
name = self.name if self.name else ''
- write(fmt % token_transform(name), '@')
- if named_str == 'VERSION':
+ write(fmt % transform(self, name))
+ elif named_str == 'FULLPACKAGE':
+ name = self.fullname if self.fullname else ''
+ write(fmt % transform(self, name))
+ elif named_str == 'VERSION':
if self.versions and self.versions != _any_version:
- write(fmt % token_transform(str(self.versions)), '@')
+ write(fmt % transform(self, str(self.versions)), '@')
elif named_str == 'COMPILER':
if self.compiler:
- write(fmt % token_transform(self.compiler), '%')
+ write(fmt % transform(self, self.compiler), '%')
elif named_str == 'COMPILERNAME':
if self.compiler:
- write(fmt % token_transform(self.compiler.name), '%')
+ write(fmt % transform(self, self.compiler.name), '%')
elif named_str in ['COMPILERVER', 'COMPILERVERSION']:
if self.compiler:
write(
- fmt % token_transform(self.compiler.versions),
+ fmt % transform(self, self.compiler.versions),
'%'
)
elif named_str == 'COMPILERFLAGS':
if self.compiler:
write(
- fmt % token_transform(str(self.compiler_flags)),
+ fmt % transform(self, str(self.compiler_flags)),
'%'
)
elif named_str == 'OPTIONS':
if self.variants:
- write(fmt % token_transform(str(self.variants)), '+')
- elif named_str == 'ARCHITECTURE':
+ write(fmt % transform(self, str(self.variants)), '+')
+ elif named_str in ["ARCHITECTURE", "PLATFORM", "TARGET", "OS"]:
if self.architecture and str(self.architecture):
- write(
- fmt % token_transform(str(self.architecture)),
- '='
- )
+ if named_str == "ARCHITECTURE":
+ write(
+ fmt % transform(self, str(self.architecture)),
+ '='
+ )
+ elif named_str == "PLATFORM":
+ platform = str(self.architecture.platform)
+ write(fmt % transform(self, platform), '=')
+ elif named_str == "OS":
+ operating_sys = str(self.architecture.platform_os)
+ write(fmt % transform(self, operating_sys), '=')
+ elif named_str == "TARGET":
+ target = str(self.architecture.target)
+ write(fmt % transform(self, target), '=')
elif named_str == 'SHA1':
if self.dependencies:
- out.write(fmt % token_transform(str(self.dag_hash(7))))
+ out.write(fmt % transform(self, str(self.dag_hash(7))))
elif named_str == 'SPACK_ROOT':
- out.write(fmt % token_transform(spack.prefix))
+ out.write(fmt % transform(self, spack.paths.prefix))
elif named_str == 'SPACK_INSTALL':
- out.write(fmt % token_transform(spack.store.root))
+ out.write(fmt % transform(self, spack.store.root))
elif named_str == 'PREFIX':
- out.write(fmt % token_transform(self.prefix))
+ out.write(fmt % transform(self, self.prefix))
elif named_str.startswith('HASH'):
if named_str.startswith('HASH:'):
_, hashlen = named_str.split(':')
@@ -3057,6 +3179,8 @@ class Spec(object):
else:
hashlen = None
out.write(fmt % (self.dag_hash(hashlen)))
+ elif named_str == 'NAMESPACE':
+ out.write(fmt % transform(self.namespace))
named = False
@@ -3078,7 +3202,7 @@ class Spec(object):
return self.format(*args, **kwargs)
def dep_string(self):
- return ''.join("^" + dep.format() for dep in self.sorted_deps())
+ return ''.join(" ^" + dep.format() for dep in self.sorted_deps())
def __str__(self):
ret = self.format() + self.dep_string()
@@ -3117,7 +3241,8 @@ class Spec(object):
fmt = kwargs.pop('format', '$_$@$%@+$+$=')
prefix = kwargs.pop('prefix', None)
show_types = kwargs.pop('show_types', False)
- deptypes = kwargs.pop('deptypes', ('build', 'link'))
+ deptypes = kwargs.pop('deptypes', 'all')
+ recurse_dependencies = kwargs.pop('recurse_dependencies', True)
check_kwargs(kwargs, self.tree)
out = ""
@@ -3135,7 +3260,7 @@ class Spec(object):
if install_status:
status = node._install_status()
if status is None:
- out += " " # Package isn't installed
+ out += colorize("@K{ - } ", color=color) # not installed
elif status:
out += colorize("@g{[+]} ", color=color) # installed
else:
@@ -3145,18 +3270,32 @@ class Spec(object):
out += colorize('@K{%s} ', color=color) % node.dag_hash(hlen)
if show_types:
+ types = set()
+ if cover == 'nodes':
+ # when only covering nodes, we merge dependency types
+ # from all dependents before showing them.
+ for name, ds in node.dependents_dict().items():
+ if ds.deptypes:
+ types.update(set(ds.deptypes))
+ elif dep_spec.deptypes:
+ # when covering edges or paths, we show dependency
+ # types only for the edge through which we visited
+ types = set(dep_spec.deptypes)
+
out += '['
- if dep_spec.deptypes:
- for t in all_deptypes:
- out += ''.join(t[0] if t in dep_spec.deptypes else ' ')
- else:
- out += ' ' * len(all_deptypes)
+ for t in all_deptypes:
+ out += ''.join(t[0] if t in types else ' ')
out += '] '
out += (" " * d)
if d > 0:
out += "^"
out += node.format(fmt, color=color) + "\n"
+
+ # Check if we wanted just the first line
+ if not recurse_dependencies:
+ break
+
return out
def __repr__(self):
@@ -3370,8 +3509,10 @@ class SpecParser(spack.parse.Parser):
spec._hash = None
spec._cmp_key_cache = None
+ spec._package = None
spec._normal = False
spec._concrete = False
+ spec._full_hash = None
# record this so that we know whether version is
# unspecified or not.
diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py
index 19eca53d1d..32cdaa0090 100644
--- a/lib/spack/spack/stage.py
+++ b/lib/spack/spack/stage.py
@@ -1,28 +1,10 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
+import stat
import sys
import errno
import hashlib
@@ -34,13 +16,14 @@ from six import iteritems
from six.moves.urllib.parse import urljoin
import llnl.util.tty as tty
-import llnl.util.lock
-from llnl.util.filesystem import mkdirp, join_path, can_access
+from llnl.util.filesystem import mkdirp, can_access
from llnl.util.filesystem import remove_if_dead_link, remove_linked_tree
-import spack
+import spack.paths
+import spack.caches
import spack.config
import spack.error
+import spack.util.lock
import spack.fetch_strategy as fs
import spack.util.pattern as pattern
from spack.util.path import canonicalize_path
@@ -83,8 +66,7 @@ def get_tmp_root():
return None
if _tmp_root is None:
- config = spack.config.get_config('config')
- candidates = config['build_stage']
+ candidates = spack.config.get('config:build_stage')
if isinstance(candidates, string_types):
candidates = [candidates]
@@ -93,7 +75,7 @@ def get_tmp_root():
raise StageError("No accessible stage paths in %s", candidates)
# Return None to indicate we're using a local staging area.
- if path == canonicalize_path(spack.stage_path):
+ if path == canonicalize_path(spack.paths.stage_path):
_use_tmp_stage = False
return None
@@ -145,10 +127,6 @@ class Stage(object):
finally:
stage.destroy() # Explicitly destroy the stage directory.
- If spack.use_tmp_stage is True, spack will attempt to create
- stages in a tmp directory. Otherwise, stages are created directly
- in spack.stage_path.
-
There are two kinds of stages: named and unnamed. Named stages
can persist between runs of spack, e.g. if you fetched a tarball
but didn't finish building it, you won't have to fetch it again.
@@ -216,7 +194,7 @@ class Stage(object):
if path is not None:
self.path = path
else:
- self.path = join_path(spack.stage_path, self.name)
+ self.path = os.path.join(spack.paths.stage_path, self.name)
# Flag to decide whether to delete the stage folder on exit or not
self.keep = keep
@@ -229,9 +207,9 @@ class Stage(object):
if self.name not in Stage.stage_locks:
sha1 = hashlib.sha1(self.name.encode('utf-8')).digest()
lock_id = prefix_bits(sha1, bit_length(sys.maxsize))
- stage_lock_path = join_path(spack.stage_path, '.lock')
+ stage_lock_path = os.path.join(spack.paths.stage_path, '.lock')
- Stage.stage_locks[self.name] = llnl.util.lock.Lock(
+ Stage.stage_locks[self.name] = spack.util.lock.Lock(
stage_lock_path, lock_id, 1)
self._lock = Stage.stage_locks[self.name]
@@ -377,7 +355,7 @@ class Stage(object):
# TODO: CompositeFetchStrategy here.
self.skip_checksum_for_mirror = True
if self.mirror_path:
- mirrors = spack.config.get_config('mirrors')
+ mirrors = spack.config.get('mirrors')
# Join URLs of mirror roots with mirror paths. Because
# urljoin() will strip everything past the final '/' in
@@ -408,7 +386,7 @@ class Stage(object):
url, digest, expand=expand, extension=extension))
if self.default_fetcher.cachable:
fetchers.insert(
- 0, spack.fetch_cache.fetcher(
+ 0, spack.caches.fetch_cache.fetcher(
self.mirror_path, digest, expand=expand,
extension=extension))
@@ -436,9 +414,9 @@ class Stage(object):
tty.debug(e)
continue
else:
- errMessage = "All fetchers failed for %s" % self.name
+ err_msg = "All fetchers failed for %s" % self.name
self.fetcher = self.default_fetcher
- raise fs.FetchError(errMessage, None)
+ raise fs.FetchError(err_msg, None)
def check(self):
"""Check the downloaded archive against a checksum digest.
@@ -455,7 +433,7 @@ class Stage(object):
self.fetcher.check()
def cache_local(self):
- spack.fetch_cache.store(self.fetcher, self.mirror_path)
+ spack.caches.fetch_cache.store(self.fetcher, self.mirror_path)
def expand_archive(self):
"""Changes to the stage directory and attempt to expand the downloaded
@@ -478,17 +456,13 @@ class Stage(object):
"""Creates the stage directory.
If get_tmp_root() is None, the stage directory is created
- directly under spack.stage_path, otherwise this will attempt to
+ directly under spack.paths.stage_path, otherwise this will attempt to
create a stage in a temporary directory and link it into
- spack.stage_path.
-
- Spack will use the first writable location in spack.tmp_dirs
- to create a stage. If there is no valid location in tmp_dirs,
- fall back to making the stage inside spack.stage_path.
+ spack.paths.stage_path.
"""
# Create the top-level stage directory
- mkdirp(spack.stage_path)
+ mkdirp(spack.paths.stage_path)
remove_if_dead_link(self.path)
# If a tmp_root exists then create a directory there and then link it
@@ -496,11 +470,13 @@ class Stage(object):
if self._need_to_create_path():
tmp_root = get_tmp_root()
if tmp_root is not None:
+ # tempfile.mkdtemp already sets mode 0700
tmp_dir = tempfile.mkdtemp('', _stage_prefix, tmp_root)
tty.debug('link %s -> %s' % (self.path, tmp_dir))
os.symlink(tmp_dir, self.path)
else:
- mkdirp(self.path)
+ # emulate file permissions for tempfile.mkdtemp
+ mkdirp(self.path, mode=stat.S_IRWXU)
# Make sure we can actually do something with the stage we made.
ensure_access(self.path)
self.created = True
@@ -546,7 +522,7 @@ class ResourceStage(Stage):
if not isinstance(placement, dict):
placement = {'': placement}
- target_path = join_path(
+ target_path = os.path.join(
root_stage.source_path, resource.destination)
try:
@@ -558,15 +534,15 @@ class ResourceStage(Stage):
raise
for key, value in iteritems(placement):
- destination_path = join_path(target_path, value)
- source_path = join_path(self.source_path, key)
+ destination_path = os.path.join(target_path, value)
+ source_path = os.path.join(self.source_path, key)
if not os.path.exists(destination_path):
tty.info('Moving resource stage\n\tsource : '
'{stage}\n\tdestination : {destination}'.format(
stage=source_path, destination=destination_path
))
- shutil.move(source_path, destination_path)
+ shutil.move(os.path.realpath(source_path), destination_path)
@pattern.composite(method_list=[
@@ -651,11 +627,11 @@ class DIYStage(object):
def _get_mirrors():
"""Get mirrors from spack configuration."""
- config = spack.config.get_config('mirrors')
+ config = spack.config.get('mirrors')
return [val for name, val in iteritems(config)]
-def ensure_access(file=spack.stage_path):
+def ensure_access(file=spack.paths.stage_path):
"""Ensure we can access a directory and die with an error if we can't."""
if not can_access(file):
tty.die("Insufficient permissions for %s" % file)
@@ -663,9 +639,9 @@ def ensure_access(file=spack.stage_path):
def purge():
"""Remove all build directories in the top-level stage path."""
- if os.path.isdir(spack.stage_path):
- for stage_dir in os.listdir(spack.stage_path):
- stage_path = join_path(spack.stage_path, stage_dir)
+ if os.path.isdir(spack.paths.stage_path):
+ for stage_dir in os.listdir(spack.paths.stage_path):
+ stage_path = os.path.join(spack.paths.stage_path, stage_dir)
remove_linked_tree(stage_path)
diff --git a/lib/spack/spack/store.py b/lib/spack/spack/store.py
index a9a607150f..9deb208956 100644
--- a/lib/spack/spack/store.py
+++ b/lib/spack/spack/store.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Components that manage Spack's installation tree.
An install tree, or "build store" consists of two parts:
@@ -43,38 +24,63 @@ configuration.
"""
import os
-import spack
+
+import llnl.util.lang
+
+import spack.paths
import spack.config
-from spack.util.path import canonicalize_path
-from spack.database import Database
-from spack.directory_layout import YamlDirectoryLayout
-from spack.directory_layout import YamlExtensionsLayout
+import spack.util.path
+import spack.database
+import spack.directory_layout
-__author__ = "Benedikt Hegner (CERN)"
-__all__ = ['db', 'extensions', 'layout', 'root']
+#: default installation root, relative to the Spack install path
+default_root = os.path.join(spack.paths.opt_path, 'spack')
-#
-# Read in the config
-#
-config = spack.config.get_config("config")
-#
-# Set up the install path
-#
-root = canonicalize_path(
- config.get('install_tree', os.path.join(spack.opt_path, 'spack')))
+class Store(object):
+ """A store is a path full of installed Spack packages.
-#
-# Set up the installed packages database
-#
-db = Database(root)
+ Stores consist of packages installed according to a
+ ``DirectoryLayout``, along with an index, or _database_ of their
+ contents. The directory layout controls what paths look like and how
+ Spack ensures that each uniqe spec gets its own unique directory (or
+ not, though we don't recommend that). The database is a signle file
+ that caches metadata for the entire Spack installation. It prevents
+ us from having to spider the install tree to figure out what's there.
-#
-# This controls how spack lays out install prefixes and
-# stage directories.
-#
-layout = YamlDirectoryLayout(root,
- hash_len=config.get('install_hash_length'),
- path_scheme=config.get('install_path_scheme'))
+ Args:
+ root (str): path to the root of the install tree
+ path_scheme (str): expression according to guidelines in
+ ``spack.util.path`` that describes how to construct a path to
+ a package prefix in this store
+ hash_length (int): length of the hashes used in the directory
+ layout; spec hash suffixes will be truncated to this length
+ """
+ def __init__(self, root, path_scheme=None, hash_length=None):
+ self.root = root
+ self.db = spack.database.Database(root)
+ self.layout = spack.directory_layout.YamlDirectoryLayout(
+ root, hash_len=hash_length, path_scheme=path_scheme)
+
+ def reindex(self):
+ """Convenience function to reindex the store DB with its own layout."""
+ return self.db.reindex(self.layout)
+
+
+def _store():
+ """Get the singleton store instance."""
+ root = spack.config.get('config:install_tree', default_root)
+ root = spack.util.path.canonicalize_path(root)
+
+ return Store(root,
+ spack.config.get('config:install_path_scheme'),
+ spack.config.get('config:install_hash_length'))
+
+
+#: Singleton store instance
+store = llnl.util.lang.Singleton(_store)
-extensions = YamlExtensionsLayout(root, layout)
+# convenience accessors for parts of the singleton store
+root = llnl.util.lang.LazyReference(lambda: store.root)
+db = llnl.util.lang.LazyReference(lambda: store.db)
+layout = llnl.util.lang.LazyReference(lambda: store.layout)
diff --git a/lib/spack/spack/tengine.py b/lib/spack/spack/tengine.py
index 44c62521b1..fa8e8f283f 100644
--- a/lib/spack/spack/tengine.py
+++ b/lib/spack/spack/tengine.py
@@ -1,34 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import textwrap
import jinja2
import llnl.util.lang
import six
-import spack
+
+import spack.config
+from spack.util.path import canonicalize_path
TemplateNotFound = jinja2.TemplateNotFound
@@ -42,10 +24,10 @@ class ContextMeta(type):
#: by the class that is being defined
_new_context_properties = []
- def __new__(mcs, name, bases, attr_dict):
+ def __new__(cls, name, bases, attr_dict):
# Merge all the context properties that are coming from base classes
# into a list without duplicates.
- context_properties = list(mcs._new_context_properties)
+ context_properties = list(cls._new_context_properties)
for x in bases:
try:
context_properties.extend(x.context_properties)
@@ -54,20 +36,20 @@ class ContextMeta(type):
context_properties = list(llnl.util.lang.dedupe(context_properties))
# Flush the list
- mcs._new_context_properties = []
+ cls._new_context_properties = []
# Attach the list to the class being created
attr_dict['context_properties'] = context_properties
- return super(ContextMeta, mcs).__new__(mcs, name, bases, attr_dict)
+ return super(ContextMeta, cls).__new__(cls, name, bases, attr_dict)
@classmethod
- def context_property(mcs, func):
+ def context_property(cls, func):
"""Decorator that adds a function name to the list of new context
properties, and then returns a property.
"""
name = func.__name__
- mcs._new_context_properties.append(name)
+ cls._new_context_properties.append(name)
return property(func)
@@ -90,7 +72,8 @@ def make_environment(dirs=None):
"""Returns an configured environment for template rendering."""
if dirs is None:
# Default directories where to search for templates
- dirs = spack.template_dirs
+ dirs = [canonicalize_path(d)
+ for d in spack.config.get('config:template_dirs')]
# Loader for the templates
loader = jinja2.FileSystemLoader(dirs)
# Environment of the template engine
diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/spack/test/__init__.py
+++ b/lib/spack/spack/test/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py
index 18bf7d66c5..33a002faad 100644
--- a/lib/spack/spack/test/architecture.py
+++ b/lib/spack/spack/test/architecture.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
""" Test checks if the architecture class is created correctly and also that
the functions are looking for the correct architecture name
"""
import itertools
import os
import platform as py_platform
-import spack
+
import spack.architecture
from spack.spec import Spec
from spack.platforms.cray import Cray
diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py
index 37664aa35e..e055bbf99c 100644
--- a/lib/spack/spack/test/build_environment.py
+++ b/lib/spack/spack/test/build_environment.py
@@ -1,41 +1,24 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack
-from llnl.util.filesystem import join_path
+import spack.build_environment
+import spack.spec
+from spack.paths import build_env_path
from spack.build_environment import dso_suffix, _static_to_shared_library
from spack.util.executable import Executable
+from spack.util.spack_yaml import syaml_dict, syaml_str
@pytest.fixture
def build_environment():
- cc = Executable(join_path(spack.build_env_path, "cc"))
- cxx = Executable(join_path(spack.build_env_path, "c++"))
- fc = Executable(join_path(spack.build_env_path, "fc"))
+ cc = Executable(os.path.join(build_env_path, "cc"))
+ cxx = Executable(os.path.join(build_env_path, "c++"))
+ fc = Executable(os.path.join(build_env_path, "fc"))
realcc = "/bin/mycc"
prefix = "/spack-test-prefix"
@@ -57,6 +40,8 @@ def build_environment():
os.environ['SPACK_F77_RPATH_ARG'] = "-Wl,-rpath,"
os.environ['SPACK_FC_RPATH_ARG'] = "-Wl,-rpath,"
+ os.environ['SPACK_SYSTEM_DIRS'] = '/usr/include /usr/lib'
+
if 'SPACK_DEPENDENCIES' in os.environ:
del os.environ['SPACK_DEPENDENCIES']
@@ -66,7 +51,8 @@ def build_environment():
'SPACK_ENV_PATH', 'SPACK_DEBUG_LOG_DIR',
'SPACK_COMPILER_SPEC', 'SPACK_SHORT_SPEC',
'SPACK_CC_RPATH_ARG', 'SPACK_CXX_RPATH_ARG',
- 'SPACK_F77_RPATH_ARG', 'SPACK_FC_RPATH_ARG'):
+ 'SPACK_F77_RPATH_ARG', 'SPACK_FC_RPATH_ARG',
+ 'SPACK_SYSTEM_DIRS'):
del os.environ[name]
@@ -95,5 +81,137 @@ def test_static_to_shared_library(build_environment):
shared_lib = '{0}.{1}'.format(
os.path.splitext(static_lib)[0], dso_suffix)
- assert output == expected[arch].format(
- static_lib, shared_lib, os.path.basename(shared_lib))
+ assert set(output.split()) == set(expected[arch].format(
+ static_lib, shared_lib, os.path.basename(shared_lib)).split())
+
+
+@pytest.mark.regression('8345')
+@pytest.mark.usefixtures('config', 'mock_packages')
+def test_cc_not_changed_by_modules(monkeypatch):
+
+ s = spack.spec.Spec('cmake')
+ s.concretize()
+ pkg = s.package
+
+ def _set_wrong_cc(x):
+ os.environ['CC'] = 'NOT_THIS_PLEASE'
+ os.environ['ANOTHER_VAR'] = 'THIS_IS_SET'
+
+ monkeypatch.setattr(
+ spack.build_environment, 'load_module', _set_wrong_cc
+ )
+ monkeypatch.setattr(
+ pkg.compiler, 'modules', ['some_module']
+ )
+
+ spack.build_environment.setup_package(pkg, False)
+
+ assert os.environ['CC'] != 'NOT_THIS_PLEASE'
+ assert os.environ['ANOTHER_VAR'] == 'THIS_IS_SET'
+
+
+@pytest.mark.usefixtures('config', 'mock_packages')
+def test_compiler_config_modifications(monkeypatch):
+ s = spack.spec.Spec('cmake')
+ s.concretize()
+ pkg = s.package
+
+ os.environ['SOME_VAR_STR'] = ''
+ os.environ['SOME_VAR_NUM'] = '0'
+ os.environ['PATH_LIST'] = '/path/third:/path/forth'
+ os.environ['EMPTY_PATH_LIST'] = ''
+ os.environ.pop('NEW_PATH_LIST', None)
+
+ env_mod = syaml_dict()
+ set_cmd = syaml_dict()
+ env_mod[syaml_str('set')] = set_cmd
+
+ set_cmd[syaml_str('SOME_VAR_STR')] = syaml_str('SOME_STR')
+ set_cmd[syaml_str('SOME_VAR_NUM')] = 1
+
+ monkeypatch.setattr(pkg.compiler, 'environment', env_mod)
+ spack.build_environment.setup_package(pkg, False)
+ assert os.environ['SOME_VAR_STR'] == 'SOME_STR'
+ assert os.environ['SOME_VAR_NUM'] == str(1)
+
+ env_mod = syaml_dict()
+ unset_cmd = syaml_dict()
+ env_mod[syaml_str('unset')] = unset_cmd
+
+ unset_cmd[syaml_str('SOME_VAR_STR')] = None
+
+ monkeypatch.setattr(pkg.compiler, 'environment', env_mod)
+ assert 'SOME_VAR_STR' in os.environ
+ spack.build_environment.setup_package(pkg, False)
+ assert 'SOME_VAR_STR' not in os.environ
+
+ env_mod = syaml_dict()
+ set_cmd = syaml_dict()
+ env_mod[syaml_str('set')] = set_cmd
+ append_cmd = syaml_dict()
+ env_mod[syaml_str('append-path')] = append_cmd
+ unset_cmd = syaml_dict()
+ env_mod[syaml_str('unset')] = unset_cmd
+ prepend_cmd = syaml_dict()
+ env_mod[syaml_str('prepend-path')] = prepend_cmd
+
+ set_cmd[syaml_str('EMPTY_PATH_LIST')] = syaml_str('/path/middle')
+
+ append_cmd[syaml_str('PATH_LIST')] = syaml_str('/path/last')
+ append_cmd[syaml_str('EMPTY_PATH_LIST')] = syaml_str('/path/last')
+ append_cmd[syaml_str('NEW_PATH_LIST')] = syaml_str('/path/last')
+
+ unset_cmd[syaml_str('SOME_VAR_NUM')] = None
+
+ prepend_cmd[syaml_str('PATH_LIST')] = syaml_str('/path/first:/path/second')
+ prepend_cmd[syaml_str('EMPTY_PATH_LIST')] = syaml_str('/path/first')
+ prepend_cmd[syaml_str('NEW_PATH_LIST')] = syaml_str('/path/first')
+ prepend_cmd[syaml_str('SOME_VAR_NUM')] = syaml_str('/8')
+
+ assert 'SOME_VAR_NUM' in os.environ
+ monkeypatch.setattr(pkg.compiler, 'environment', env_mod)
+ spack.build_environment.setup_package(pkg, False)
+ # Check that the order of modifications is respected and the
+ # variable was unset before it was prepended.
+ assert os.environ['SOME_VAR_NUM'] == '/8'
+
+ expected = '/path/first:/path/second:/path/third:/path/forth:/path/last'
+ assert os.environ['PATH_LIST'] == expected
+
+ expected = '/path/first:/path/middle:/path/last'
+ assert os.environ['EMPTY_PATH_LIST'] == expected
+
+ expected = '/path/first:/path/last'
+ assert os.environ['NEW_PATH_LIST'] == expected
+
+ os.environ.pop('SOME_VAR_STR', None)
+ os.environ.pop('SOME_VAR_NUM', None)
+ os.environ.pop('PATH_LIST', None)
+ os.environ.pop('EMPTY_PATH_LIST', None)
+ os.environ.pop('NEW_PATH_LIST', None)
+
+
+@pytest.mark.regression('9107')
+def test_spack_paths_before_module_paths(config, mock_packages, monkeypatch):
+ s = spack.spec.Spec('cmake')
+ s.concretize()
+ pkg = s.package
+
+ module_path = '/path/to/module'
+
+ def _set_wrong_cc(x):
+ os.environ['PATH'] = module_path + ':' + os.environ['PATH']
+
+ monkeypatch.setattr(
+ spack.build_environment, 'load_module', _set_wrong_cc
+ )
+ monkeypatch.setattr(
+ pkg.compiler, 'modules', ['some_module']
+ )
+
+ spack.build_environment.setup_package(pkg, False)
+
+ spack_path = os.path.join(spack.paths.prefix, 'lib/spack/env')
+ paths = os.environ['PATH'].split(':')
+
+ assert paths.index(spack_path) < paths.index(module_path)
diff --git a/lib/spack/spack/test/build_system_guess.py b/lib/spack/spack/test/build_system_guess.py
index b23b66a846..1e11543823 100644
--- a/lib/spack/spack/test/build_system_guess.py
+++ b/lib/spack/spack/test/build_system_guess.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.cmd.create
@@ -45,6 +26,7 @@ import spack.stage
('GNUmakefile', 'makefile'),
('makefile', 'makefile'),
('Makefile', 'makefile'),
+ ('meson.build', 'meson'),
('foobar', 'generic')
]
)
diff --git a/lib/spack/spack/test/build_systems.py b/lib/spack/spack/test/build_systems.py
index 72b88f3f26..3bf2390139 100644
--- a/lib/spack/spack/test/build_systems.py
+++ b/lib/spack/spack/test/build_systems.py
@@ -1,36 +1,107 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import spack
+import glob
+import os
import pytest
-from spack.build_environment import get_std_cmake_args
+import spack.repo
+from llnl.util.filesystem import working_dir
+from spack.build_environment import get_std_cmake_args, setup_package
from spack.spec import Spec
+from spack.util.executable import which
+
+
+DATA_PATH = os.path.join(spack.paths.test_path, 'data')
+
+
+@pytest.mark.parametrize(
+ 'directory',
+ glob.iglob(os.path.join(DATA_PATH, 'make', 'affirmative', '*'))
+)
+def test_affirmative_make_check(directory, config, mock_packages):
+ """Tests that Spack correctly detects targets in a Makefile."""
+
+ # Get a fake package
+ s = Spec('mpich')
+ s.concretize()
+ pkg = spack.repo.get(s)
+ setup_package(pkg, False)
+
+ with working_dir(directory):
+ assert pkg._has_make_target('check')
+
+ pkg._if_make_target_execute('check')
+
+
+@pytest.mark.parametrize(
+ 'directory',
+ glob.iglob(os.path.join(DATA_PATH, 'make', 'negative', '*'))
+)
+@pytest.mark.regression('9067')
+def test_negative_make_check(directory, config, mock_packages):
+ """Tests that Spack correctly ignores false positives in a Makefile."""
+
+ # Get a fake package
+ s = Spec('mpich')
+ s.concretize()
+ pkg = spack.repo.get(s)
+ setup_package(pkg, False)
+
+ with working_dir(directory):
+ assert not pkg._has_make_target('check')
+
+ pkg._if_make_target_execute('check')
+
+
+@pytest.mark.skipif(not which('ninja'), reason='ninja is not installed')
+@pytest.mark.parametrize(
+ 'directory',
+ glob.iglob(os.path.join(DATA_PATH, 'ninja', 'affirmative', '*'))
+)
+def test_affirmative_ninja_check(directory, config, mock_packages):
+ """Tests that Spack correctly detects targets in a Ninja build script."""
+
+ # Get a fake package
+ s = Spec('mpich')
+ s.concretize()
+ pkg = spack.repo.get(s)
+ setup_package(pkg, False)
+
+ with working_dir(directory):
+ assert pkg._has_ninja_target('check')
+
+ pkg._if_ninja_target_execute('check')
+
+ # Clean up Ninja files
+ for filename in glob.iglob('.ninja_*'):
+ os.remove(filename)
+
+
+@pytest.mark.skipif(not which('ninja'), reason='ninja is not installed')
+@pytest.mark.parametrize(
+ 'directory',
+ glob.iglob(os.path.join(DATA_PATH, 'ninja', 'negative', '*'))
+)
+def test_negative_ninja_check(directory, config, mock_packages):
+ """Tests that Spack correctly ignores false positives in a Ninja
+ build script."""
+
+ # Get a fake package
+ s = Spec('mpich')
+ s.concretize()
+ pkg = spack.repo.get(s)
+ setup_package(pkg, False)
+
+ with working_dir(directory):
+ assert not pkg._has_ninja_target('check')
+
+ pkg._if_ninja_target_execute('check')
-def test_cmake_std_args(config, builtin_mock):
+def test_cmake_std_args(config, mock_packages):
# Call the function on a CMakePackage instance
s = Spec('cmake-client')
s.concretize()
@@ -44,7 +115,7 @@ def test_cmake_std_args(config, builtin_mock):
assert get_std_cmake_args(pkg)
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestAutotoolsPackage(object):
def test_with_or_without(self):
diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py
index 671379c717..eb51021eac 100644
--- a/lib/spack/spack/test/cc.py
+++ b/lib/spack/spack/test/cc.py
@@ -1,42 +1,23 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This test checks that the Spack cc compiler wrapper is parsing
arguments correctly.
"""
import os
-import unittest
-import tempfile
-import shutil
+import pytest
-import spack
-from llnl.util.filesystem import mkdirp, join_path
+from spack.paths import build_env_path
+from spack.util.environment import system_dirs, set_env
from spack.util.executable import Executable
+#
# Complicated compiler test command
-test_command = [
+#
+test_args = [
'-I/test/include', '-L/test/lib', '-L/other/lib', '-I/other/include',
'arg1',
'-Wl,--start-group',
@@ -45,344 +26,525 @@ test_command = [
'-llib1', '-llib2',
'arg4',
'-Wl,--end-group',
- '-Xlinker', '-rpath', '-Xlinker', '/third/rpath', '-Xlinker',
- '-rpath', '-Xlinker', '/fourth/rpath',
+ '-Xlinker', '-rpath', '-Xlinker', '/third/rpath',
+ '-Xlinker', '-rpath', '-Xlinker', '/fourth/rpath',
'-llib3', '-llib4',
'arg5', 'arg6']
+#
+# Pieces of the test command above, as they should be parsed out.
+#
+# `_wl_rpaths` are for the compiler (with -Wl,), and `_rpaths` are raw
+# -rpath arguments for the linker.
+#
+test_include_paths = [
+ '-I/test/include', '-I/other/include']
+
+test_library_paths = [
+ '-L/test/lib', '-L/other/lib']
-class CompilerWrapperTest(unittest.TestCase):
-
- def setUp(self):
- self.cc = Executable(join_path(spack.build_env_path, "cc"))
- self.ld = Executable(join_path(spack.build_env_path, "ld"))
- self.cpp = Executable(join_path(spack.build_env_path, "cpp"))
- self.cxx = Executable(join_path(spack.build_env_path, "c++"))
- self.fc = Executable(join_path(spack.build_env_path, "fc"))
-
- self.realcc = "/bin/mycc"
- self.prefix = "/spack-test-prefix"
-
- os.environ['SPACK_CC'] = self.realcc
- os.environ['SPACK_CXX'] = self.realcc
- os.environ['SPACK_FC'] = self.realcc
-
- os.environ['SPACK_PREFIX'] = self.prefix
- os.environ['SPACK_ENV_PATH'] = "test"
- os.environ['SPACK_DEBUG_LOG_DIR'] = "."
- os.environ['SPACK_DEBUG_LOG_ID'] = "foo-hashabc"
- os.environ['SPACK_COMPILER_SPEC'] = "gcc@4.4.7"
- os.environ['SPACK_SHORT_SPEC'] = (
- "foo@1.2 arch=linux-rhel6-x86_64 /hashabc")
-
- os.environ['SPACK_CC_RPATH_ARG'] = "-Wl,-rpath,"
- os.environ['SPACK_CXX_RPATH_ARG'] = "-Wl,-rpath,"
- os.environ['SPACK_F77_RPATH_ARG'] = "-Wl,-rpath,"
- os.environ['SPACK_FC_RPATH_ARG'] = "-Wl,-rpath,"
-
- # Make some fake dependencies
- self.tmp_deps = tempfile.mkdtemp()
- self.dep1 = join_path(self.tmp_deps, 'dep1')
- self.dep2 = join_path(self.tmp_deps, 'dep2')
- self.dep3 = join_path(self.tmp_deps, 'dep3')
- self.dep4 = join_path(self.tmp_deps, 'dep4')
-
- mkdirp(join_path(self.dep1, 'include'))
- mkdirp(join_path(self.dep1, 'lib'))
-
- mkdirp(join_path(self.dep2, 'lib64'))
-
- mkdirp(join_path(self.dep3, 'include'))
- mkdirp(join_path(self.dep3, 'lib64'))
-
- mkdirp(join_path(self.dep4, 'include'))
-
- if 'SPACK_DEPENDENCIES' in os.environ:
- del os.environ['SPACK_DEPENDENCIES']
-
- def tearDown(self):
- shutil.rmtree(self.tmp_deps, True)
-
- def check_cc(self, command, args, expected):
- os.environ['SPACK_TEST_COMMAND'] = command
- self.assertEqual(self.cc(*args, output=str).strip(), expected)
-
- def check_cxx(self, command, args, expected):
- os.environ['SPACK_TEST_COMMAND'] = command
- self.assertEqual(self.cxx(*args, output=str).strip(), expected)
-
- def check_fc(self, command, args, expected):
- os.environ['SPACK_TEST_COMMAND'] = command
- self.assertEqual(self.fc(*args, output=str).strip(), expected)
-
- def check_ld(self, command, args, expected):
- os.environ['SPACK_TEST_COMMAND'] = command
- self.assertEqual(self.ld(*args, output=str).strip(), expected)
-
- def check_cpp(self, command, args, expected):
- os.environ['SPACK_TEST_COMMAND'] = command
- self.assertEqual(self.cpp(*args, output=str).strip(), expected)
-
- def test_vcheck_mode(self):
- self.check_cc('dump-mode', ['-I/include', '--version'], "vcheck")
- self.check_cc('dump-mode', ['-I/include', '-V'], "vcheck")
- self.check_cc('dump-mode', ['-I/include', '-v'], "vcheck")
- self.check_cc('dump-mode', ['-I/include', '-dumpversion'], "vcheck")
- self.check_cc('dump-mode', ['-I/include', '--version', '-c'], "vcheck")
- self.check_cc('dump-mode', ['-I/include',
- '-V', '-o', 'output'], "vcheck")
-
- def test_cpp_mode(self):
- self.check_cc('dump-mode', ['-E'], "cpp")
- self.check_cpp('dump-mode', [], "cpp")
-
- def test_as_mode(self):
- self.check_cc('dump-mode', ['-S'], "as")
-
- def test_ccld_mode(self):
- self.check_cc('dump-mode', [], "ccld")
- self.check_cc('dump-mode', ['foo.c', '-o', 'foo'], "ccld")
- self.check_cc('dump-mode', ['foo.c', '-o',
- 'foo', '-Wl,-rpath,foo'], "ccld")
- self.check_cc(
- 'dump-mode',
- ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'],
- "ccld")
-
- def test_ld_mode(self):
- self.check_ld('dump-mode', [], "ld")
- self.check_ld(
- 'dump-mode',
- ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'],
- "ld")
-
- def test_flags(self):
- os.environ['SPACK_LDFLAGS'] = '-L foo'
- os.environ['SPACK_LDLIBS'] = '-lfoo'
- os.environ['SPACK_CPPFLAGS'] = '-g -O1'
- os.environ['SPACK_CFLAGS'] = '-Wall'
- os.environ['SPACK_CXXFLAGS'] = '-Werror'
- os.environ['SPACK_FFLAGS'] = '-w'
-
- # Test ldflags added properly in ld mode
- self.check_ld('dump-args', test_command,
- "ld " +
- '-rpath ' + self.prefix + '/lib ' +
- '-rpath ' + self.prefix + '/lib64 ' +
- '-L foo ' +
- ' '.join(test_command) + ' ' +
- '-lfoo')
-
- # Test cppflags added properly in cpp mode
- self.check_cpp('dump-args', test_command,
- "cpp " +
- '-g -O1 ' +
- ' '.join(test_command))
-
- # Test ldflags, cppflags, and language specific flags are added in
- # proper order
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-g -O1 ' +
- '-Wall ' +
- '-L foo ' +
- ' '.join(test_command) + ' ' +
- '-lfoo')
-
- self.check_cxx('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-g -O1 ' +
- '-Werror ' +
- '-L foo ' +
- ' '.join(test_command) + ' ' +
- '-lfoo')
-
- self.check_fc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-w ' +
- '-g -O1 ' +
- '-L foo ' +
- ' '.join(test_command) + ' ' +
- '-lfoo')
-
- del os.environ['SPACK_CFLAGS']
- del os.environ['SPACK_CXXFLAGS']
- del os.environ['SPACK_FFLAGS']
- del os.environ['SPACK_CPPFLAGS']
- del os.environ['SPACK_LDFLAGS']
- del os.environ['SPACK_LDLIBS']
-
- def test_dep_rpath(self):
- """Ensure RPATHs for root package are added."""
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- ' '.join(test_command))
-
- def test_dep_include(self):
- """Ensure a single dependency include directory is added."""
- os.environ['SPACK_DEPENDENCIES'] = self.dep4
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-I' + self.dep4 + '/include ' +
- ' '.join(test_command))
-
- def test_dep_lib(self):
- """Ensure a single dependency RPATH is added."""
- os.environ['SPACK_DEPENDENCIES'] = self.dep2
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-L' + self.dep2 + '/lib64 ' +
- '-Wl,-rpath,' + self.dep2 + '/lib64 ' +
- ' '.join(test_command))
-
- def test_dep_lib_no_rpath(self):
- """Ensure a single dependency link flag is added with no dep RPATH."""
- os.environ['SPACK_DEPENDENCIES'] = self.dep2
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-L' + self.dep2 + '/lib64 ' +
- ' '.join(test_command))
-
- def test_dep_lib_no_lib(self):
- """Ensure a single dependency RPATH is added with no -L."""
- os.environ['SPACK_DEPENDENCIES'] = self.dep2
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
- '-Wl,-rpath,' + self.dep2 + '/lib64 ' +
- ' '.join(test_command))
-
- def test_all_deps(self):
- """Ensure includes and RPATHs for all deps are added. """
- os.environ['SPACK_DEPENDENCIES'] = ':'.join([
- self.dep1, self.dep2, self.dep3, self.dep4])
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
-
- # This is probably more constrained than it needs to be; it
- # checks order within prepended args and doesn't strictly have
- # to. We could loosen that if it becomes necessary
- self.check_cc('dump-args', test_command,
- self.realcc + ' ' +
- '-Wl,-rpath,' + self.prefix + '/lib ' +
- '-Wl,-rpath,' + self.prefix + '/lib64 ' +
-
- '-I' + self.dep4 + '/include ' +
-
- '-L' + self.dep3 + '/lib64 ' +
- '-Wl,-rpath,' + self.dep3 + '/lib64 ' +
- '-I' + self.dep3 + '/include ' +
-
- '-L' + self.dep2 + '/lib64 ' +
- '-Wl,-rpath,' + self.dep2 + '/lib64 ' +
-
- '-L' + self.dep1 + '/lib ' +
- '-Wl,-rpath,' + self.dep1 + '/lib ' +
- '-I' + self.dep1 + '/include ' +
-
- ' '.join(test_command))
-
- def test_ld_deps(self):
- """Ensure no (extra) -I args or -Wl, are passed in ld mode."""
- os.environ['SPACK_DEPENDENCIES'] = ':'.join([
- self.dep1, self.dep2, self.dep3, self.dep4])
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
-
- self.check_ld('dump-args', test_command,
- 'ld ' +
- '-rpath ' + self.prefix + '/lib ' +
- '-rpath ' + self.prefix + '/lib64 ' +
-
- '-L' + self.dep3 + '/lib64 ' +
- '-rpath ' + self.dep3 + '/lib64 ' +
-
- '-L' + self.dep2 + '/lib64 ' +
- '-rpath ' + self.dep2 + '/lib64 ' +
-
- '-L' + self.dep1 + '/lib ' +
- '-rpath ' + self.dep1 + '/lib ' +
-
- ' '.join(test_command))
-
- def test_ld_deps_no_rpath(self):
- """Ensure SPACK_RPATH_DEPS controls RPATHs for ld."""
- os.environ['SPACK_DEPENDENCIES'] = ':'.join([
- self.dep1, self.dep2, self.dep3, self.dep4])
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
-
- self.check_ld('dump-args', test_command,
- 'ld ' +
- '-rpath ' + self.prefix + '/lib ' +
- '-rpath ' + self.prefix + '/lib64 ' +
-
- '-L' + self.dep3 + '/lib64 ' +
- '-L' + self.dep2 + '/lib64 ' +
- '-L' + self.dep1 + '/lib ' +
-
- ' '.join(test_command))
-
- def test_ld_deps_no_link(self):
- """Ensure SPACK_LINK_DEPS controls -L for ld."""
- os.environ['SPACK_DEPENDENCIES'] = ':'.join([
- self.dep1, self.dep2, self.dep3, self.dep4])
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
-
- self.check_ld('dump-args', test_command,
- 'ld ' +
- '-rpath ' + self.prefix + '/lib ' +
- '-rpath ' + self.prefix + '/lib64 ' +
-
- '-rpath ' + self.dep3 + '/lib64 ' +
- '-rpath ' + self.dep2 + '/lib64 ' +
- '-rpath ' + self.dep1 + '/lib ' +
-
- ' '.join(test_command))
-
- def test_ld_deps_reentrant(self):
- """Make sure ld -r is handled correctly on OS's where it doesn't
- support rpaths."""
- os.environ['SPACK_DEPENDENCIES'] = ':'.join([self.dep1])
- os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
- os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+test_wl_rpaths = [
+ '-Wl,-rpath,/first/rpath', '-Wl,-rpath,/second/rpath',
+ '-Wl,-rpath,/third/rpath', '-Wl,-rpath,/fourth/rpath']
- os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=linux-x86_64"
- reentrant_test_command = ['-r'] + test_command
- self.check_ld('dump-args', reentrant_test_command,
- 'ld ' +
- '-rpath ' + self.prefix + '/lib ' +
- '-rpath ' + self.prefix + '/lib64 ' +
+test_rpaths = [
+ '-rpath', '/first/rpath', '-rpath', '/second/rpath',
+ '-rpath', '/third/rpath', '-rpath', '/fourth/rpath']
- '-L' + self.dep1 + '/lib ' +
- '-rpath ' + self.dep1 + '/lib ' +
+test_args_without_paths = [
+ 'arg1',
+ '-Wl,--start-group',
+ 'arg2', 'arg3', '-llib1', '-llib2', 'arg4',
+ '-Wl,--end-group',
+ '-llib3', '-llib4', 'arg5', 'arg6']
- '-r ' +
- ' '.join(test_command))
+#: The prefix of the package being mock installed
+pkg_prefix = '/spack-test-prefix'
+#
+# Expected RPATHs for the package itself. The package is expected to
+# have only one of /lib or /lib64, but we add both b/c we can't know
+# before installing.
+#
+pkg_wl_rpaths = [
+ '-Wl,-rpath,' + pkg_prefix + '/lib',
+ '-Wl,-rpath,' + pkg_prefix + '/lib64']
+
+pkg_rpaths = [
+ '-rpath', '/spack-test-prefix/lib',
+ '-rpath', '/spack-test-prefix/lib64']
+
+# Compilers to use during tests
+cc = Executable(os.path.join(build_env_path, "cc"))
+ld = Executable(os.path.join(build_env_path, "ld"))
+cpp = Executable(os.path.join(build_env_path, "cpp"))
+cxx = Executable(os.path.join(build_env_path, "c++"))
+fc = Executable(os.path.join(build_env_path, "fc"))
+
+#: the "real" compiler the wrapper is expected to invoke
+real_cc = '/bin/mycc'
+
+# mock flags to use in the wrapper environment
+spack_cppflags = ['-g', '-O1', '-DVAR=VALUE']
+spack_cflags = ['-Wall']
+spack_cxxflags = ['-Werror']
+spack_fflags = ['-w']
+spack_ldflags = ['-L', 'foo']
+spack_ldlibs = ['-lfoo']
+
+
+@pytest.fixture(scope='session')
+def wrapper_environment():
+ with set_env(
+ SPACK_CC=real_cc,
+ SPACK_CXX=real_cc,
+ SPACK_FC=real_cc,
+ SPACK_PREFIX=pkg_prefix,
+ SPACK_ENV_PATH='test',
+ SPACK_DEBUG_LOG_DIR='.',
+ SPACK_DEBUG_LOG_ID='foo-hashabc',
+ SPACK_COMPILER_SPEC='gcc@4.4.7',
+ SPACK_SHORT_SPEC='foo@1.2 arch=linux-rhel6-x86_64 /hashabc',
+ SPACK_SYSTEM_DIRS=':'.join(system_dirs),
+ SPACK_CC_RPATH_ARG='-Wl,-rpath,',
+ SPACK_CXX_RPATH_ARG='-Wl,-rpath,',
+ SPACK_F77_RPATH_ARG='-Wl,-rpath,',
+ SPACK_FC_RPATH_ARG='-Wl,-rpath,',
+ SPACK_DEPENDENCIES=None):
+ yield
+
+
+@pytest.fixture()
+def wrapper_flags():
+ with set_env(
+ SPACK_CPPFLAGS=' '.join(spack_cppflags),
+ SPACK_CFLAGS=' '.join(spack_cflags),
+ SPACK_CXXFLAGS=' '.join(spack_cxxflags),
+ SPACK_FFLAGS=' '.join(spack_fflags),
+ SPACK_LDFLAGS=' '.join(spack_ldflags),
+ SPACK_LDLIBS=' '.join(spack_ldlibs)):
+ yield
+
+
+@pytest.fixture(scope='session')
+def dep1(tmpdir_factory):
+ path = tmpdir_factory.mktemp('cc-dep1')
+ path.mkdir('include')
+ path.mkdir('lib')
+ yield str(path)
+
+
+@pytest.fixture(scope='session')
+def dep2(tmpdir_factory):
+ path = tmpdir_factory.mktemp('cc-dep2')
+ path.mkdir('lib64')
+ yield str(path)
+
+
+@pytest.fixture(scope='session')
+def dep3(tmpdir_factory):
+ path = tmpdir_factory.mktemp('cc-dep3')
+ path.mkdir('include')
+ path.mkdir('lib64')
+ yield str(path)
+
+
+@pytest.fixture(scope='session')
+def dep4(tmpdir_factory):
+ path = tmpdir_factory.mktemp('cc-dep4')
+ path.mkdir('include')
+ yield str(path)
+
+
+pytestmark = pytest.mark.usefixtures('wrapper_environment')
+
+
+def check_args(cc, args, expected):
+ """Check output arguments that cc produces when called with args.
+
+ This assumes that cc will print debug command output with one element
+ per line, so that we see whether arguments that should (or shouldn't)
+ contain spaces are parsed correctly.
+ """
+ with set_env(SPACK_TEST_COMMAND='dump-args'):
+ assert expected == cc(*args, output=str).strip().split('\n')
+
+
+def dump_mode(cc, args):
+ """Make cc dump the mode it detects, and return it."""
+ with set_env(SPACK_TEST_COMMAND='dump-mode'):
+ return cc(*args, output=str).strip()
+
+
+def test_vcheck_mode():
+ assert dump_mode(cc, ['-I/include', '--version']) == 'vcheck'
+ assert dump_mode(cc, ['-I/include', '-V']) == 'vcheck'
+ assert dump_mode(cc, ['-I/include', '-v']) == 'vcheck'
+ assert dump_mode(cc, ['-I/include', '-dumpversion']) == 'vcheck'
+ assert dump_mode(cc, ['-I/include', '--version', '-c']) == 'vcheck'
+ assert dump_mode(cc, ['-I/include', '-V', '-o', 'output']) == 'vcheck'
+
+
+def test_cpp_mode():
+ assert dump_mode(cc, ['-E']) == 'cpp'
+ assert dump_mode(cxx, ['-E']) == 'cpp'
+ assert dump_mode(cpp, []) == 'cpp'
+
+
+def test_as_mode():
+ assert dump_mode(cc, ['-S']) == 'as'
+
+
+def test_ccld_mode():
+ assert dump_mode(cc, []) == 'ccld'
+ assert dump_mode(cc, ['foo.c', '-o', 'foo']) == 'ccld'
+ assert dump_mode(cc, ['foo.c', '-o', 'foo', '-Wl,-rpath,foo']) == 'ccld'
+ assert dump_mode(cc, [
+ 'foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo']) == 'ccld'
+
+
+def test_ld_mode():
+ assert dump_mode(ld, []) == 'ld'
+ assert dump_mode(ld, [
+ 'foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo']) == 'ld'
+
+
+def test_ld_flags(wrapper_flags):
+ check_args(
+ ld, test_args,
+ ['ld'] +
+ spack_ldflags +
+ test_include_paths +
+ test_library_paths +
+ test_rpaths +
+ pkg_rpaths +
+ test_args_without_paths +
+ spack_ldlibs)
+
+
+def test_cpp_flags(wrapper_flags):
+ check_args(
+ cpp, test_args,
+ ['cpp'] +
+ spack_cppflags +
+ test_include_paths +
+ test_library_paths +
+ test_args_without_paths)
+
+
+def test_cc_flags(wrapper_flags):
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ spack_cppflags +
+ spack_cflags +
+ spack_ldflags +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths +
+ spack_ldlibs)
+
+
+def test_cxx_flags(wrapper_flags):
+ check_args(
+ cxx, test_args,
+ [real_cc] +
+ spack_cppflags +
+ spack_cxxflags +
+ spack_ldflags +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths +
+ spack_ldlibs)
+
+
+def test_fc_flags(wrapper_flags):
+ check_args(
+ fc, test_args,
+ [real_cc] +
+ spack_fflags +
+ spack_cppflags +
+ spack_ldflags +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths +
+ spack_ldlibs)
+
+
+def test_dep_rpath():
+ """Ensure RPATHs for root package are added."""
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths)
+
+
+def test_dep_include(dep4):
+ """Ensure a single dependency include directory is added."""
+ with set_env(SPACK_DEPENDENCIES=dep4,
+ SPACK_RPATH_DEPS=dep4,
+ SPACK_LINK_DEPS=dep4):
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ test_include_paths +
+ ['-I' + dep4 + '/include'] +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths)
+
+
+def test_dep_lib(dep2):
+ """Ensure a single dependency RPATH is added."""
+ with set_env(SPACK_DEPENDENCIES=dep2,
+ SPACK_RPATH_DEPS=dep2,
+ SPACK_LINK_DEPS=dep2):
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ test_include_paths +
+ test_library_paths +
+ ['-L' + dep2 + '/lib64'] +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ ['-Wl,-rpath,' + dep2 + '/lib64'] +
+ test_args_without_paths)
+
+
+def test_dep_lib_no_rpath(dep2):
+ """Ensure a single dependency link flag is added with no dep RPATH."""
+ with set_env(SPACK_DEPENDENCIES=dep2,
+ SPACK_LINK_DEPS=dep2):
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ test_include_paths +
+ test_library_paths +
+ ['-L' + dep2 + '/lib64'] +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths)
+
+
+def test_dep_lib_no_lib(dep2):
+ """Ensure a single dependency RPATH is added with no -L."""
+ with set_env(SPACK_DEPENDENCIES=dep2,
+ SPACK_RPATH_DEPS=dep2):
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ ['-Wl,-rpath,' + dep2 + '/lib64'] +
+ test_args_without_paths)
+
+
+def test_ccld_deps(dep1, dep2, dep3, dep4):
+ """Ensure all flags are added in ccld mode."""
+ deps = ':'.join((dep1, dep2, dep3, dep4))
+ with set_env(SPACK_DEPENDENCIES=deps,
+ SPACK_RPATH_DEPS=deps,
+ SPACK_LINK_DEPS=deps):
+ check_args(
+ cc, test_args,
+ [real_cc] +
+ test_include_paths +
+ ['-I' + dep1 + '/include',
+ '-I' + dep3 + '/include',
+ '-I' + dep4 + '/include'] +
+ test_library_paths +
+ ['-L' + dep1 + '/lib',
+ '-L' + dep2 + '/lib64',
+ '-L' + dep3 + '/lib64'] +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ ['-Wl,-rpath,' + dep1 + '/lib',
+ '-Wl,-rpath,' + dep2 + '/lib64',
+ '-Wl,-rpath,' + dep3 + '/lib64'] +
+ test_args_without_paths)
+
+
+def test_cc_deps(dep1, dep2, dep3, dep4):
+ """Ensure -L and RPATHs are not added in cc mode."""
+ deps = ':'.join((dep1, dep2, dep3, dep4))
+ with set_env(SPACK_DEPENDENCIES=deps,
+ SPACK_RPATH_DEPS=deps,
+ SPACK_LINK_DEPS=deps):
+ check_args(
+ cc, ['-c'] + test_args,
+ [real_cc] +
+ test_include_paths +
+ ['-I' + dep1 + '/include',
+ '-I' + dep3 + '/include',
+ '-I' + dep4 + '/include'] +
+ test_library_paths +
+ ['-c'] +
+ test_args_without_paths)
+
+
+def test_ccld_with_system_dirs(dep1, dep2, dep3, dep4):
+ """Ensure all flags are added in ccld mode."""
+ deps = ':'.join((dep1, dep2, dep3, dep4))
+ with set_env(SPACK_DEPENDENCIES=deps,
+ SPACK_RPATH_DEPS=deps,
+ SPACK_LINK_DEPS=deps):
+
+ sys_path_args = ['-I/usr/include',
+ '-L/usr/local/lib',
+ '-Wl,-rpath,/usr/lib64',
+ '-I/usr/local/include',
+ '-L/lib64/']
+ check_args(
+ cc, sys_path_args + test_args,
+ [real_cc] +
+ test_include_paths +
+ ['-I' + dep1 + '/include',
+ '-I' + dep3 + '/include',
+ '-I' + dep4 + '/include'] +
+ ['-I/usr/include',
+ '-I/usr/local/include'] +
+ test_library_paths +
+ ['-L' + dep1 + '/lib',
+ '-L' + dep2 + '/lib64',
+ '-L' + dep3 + '/lib64'] +
+ ['-L/usr/local/lib',
+ '-L/lib64/'] +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ ['-Wl,-rpath,' + dep1 + '/lib',
+ '-Wl,-rpath,' + dep2 + '/lib64',
+ '-Wl,-rpath,' + dep3 + '/lib64'] +
+ ['-Wl,-rpath,/usr/lib64'] +
+ test_args_without_paths)
+
+
+def test_ld_deps(dep1, dep2, dep3, dep4):
+ """Ensure no (extra) -I args or -Wl, are passed in ld mode."""
+ deps = ':'.join((dep1, dep2, dep3, dep4))
+ with set_env(SPACK_DEPENDENCIES=deps,
+ SPACK_RPATH_DEPS=deps,
+ SPACK_LINK_DEPS=deps):
+ check_args(
+ ld, test_args,
+ ['ld'] +
+ test_include_paths +
+ test_library_paths +
+ ['-L' + dep1 + '/lib',
+ '-L' + dep2 + '/lib64',
+ '-L' + dep3 + '/lib64'] +
+ test_rpaths +
+ pkg_rpaths +
+ ['-rpath', dep1 + '/lib',
+ '-rpath', dep2 + '/lib64',
+ '-rpath', dep3 + '/lib64'] +
+ test_args_without_paths)
+
+
+def test_ld_deps_no_rpath(dep1, dep2, dep3, dep4):
+ """Ensure SPACK_LINK_DEPS controls -L for ld."""
+ deps = ':'.join((dep1, dep2, dep3, dep4))
+ with set_env(SPACK_DEPENDENCIES=deps,
+ SPACK_LINK_DEPS=deps):
+ check_args(
+ ld, test_args,
+ ['ld'] +
+ test_include_paths +
+ test_library_paths +
+ ['-L' + dep1 + '/lib',
+ '-L' + dep2 + '/lib64',
+ '-L' + dep3 + '/lib64'] +
+ test_rpaths +
+ pkg_rpaths +
+ test_args_without_paths)
+
+
+def test_ld_deps_no_link(dep1, dep2, dep3, dep4):
+ """Ensure SPACK_RPATH_DEPS controls -rpath for ld."""
+ deps = ':'.join((dep1, dep2, dep3, dep4))
+ with set_env(SPACK_DEPENDENCIES=deps,
+ SPACK_RPATH_DEPS=deps):
+ check_args(
+ ld, test_args,
+ ['ld'] +
+ test_include_paths +
+ test_library_paths +
+ test_rpaths +
+ pkg_rpaths +
+ ['-rpath', dep1 + '/lib',
+ '-rpath', dep2 + '/lib64',
+ '-rpath', dep3 + '/lib64'] +
+ test_args_without_paths)
+
+
+def test_ld_deps_partial(dep1):
+ """Make sure ld -r (partial link) is handled correctly on OS's where it
+ doesn't accept rpaths.
+ """
+ with set_env(SPACK_DEPENDENCIES=dep1,
+ SPACK_RPATH_DEPS=dep1,
+ SPACK_LINK_DEPS=dep1):
+ # TODO: do we need to add RPATHs on other platforms like Linux?
+ # TODO: Can't we treat them the same?
+ os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=linux-x86_64"
+ check_args(
+ ld, ['-r'] + test_args,
+ ['ld'] +
+ test_include_paths +
+ test_library_paths +
+ ['-L' + dep1 + '/lib'] +
+ test_rpaths +
+ pkg_rpaths +
+ ['-rpath', dep1 + '/lib'] +
+ ['-r'] +
+ test_args_without_paths)
+
+ # rpaths from the underlying command will still appear
+ # Spack will not add its own rpaths.
os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=darwin-x86_64"
- self.check_ld('dump-args', reentrant_test_command,
- 'ld ' +
- '-L' + self.dep1 + '/lib ' +
- '-r ' +
- ' '.join(test_command))
+ check_args(
+ ld, ['-r'] + test_args,
+ ['ld'] +
+ test_include_paths +
+ test_library_paths +
+ ['-L' + dep1 + '/lib'] +
+ test_rpaths +
+ ['-r'] +
+ test_args_without_paths)
+
+
+def test_ccache_prepend_for_cc():
+ with set_env(SPACK_CCACHE_BINARY='ccache'):
+ check_args(
+ cc, test_args,
+ ['ccache'] + # ccache prepended in cc mode
+ [real_cc] +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths)
+
+
+def test_no_ccache_prepend_for_fc():
+ check_args(
+ fc, test_args,
+ # no ccache for Fortran
+ [real_cc] +
+ test_include_paths +
+ test_library_paths +
+ test_wl_rpaths +
+ pkg_wl_rpaths +
+ test_args_without_paths)
diff --git a/lib/spack/spack/test/cmd/__init__.py b/lib/spack/spack/test/cmd/__init__.py
deleted file mode 100644
index 8922701e9f..0000000000
--- a/lib/spack/spack/test/cmd/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
diff --git a/lib/spack/spack/test/cmd/activate.py b/lib/spack/spack/test/cmd/activate.py
new file mode 100644
index 0000000000..86abd80342
--- /dev/null
+++ b/lib/spack/spack/test/cmd/activate.py
@@ -0,0 +1,42 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.main import SpackCommand
+
+activate = SpackCommand('activate')
+deactivate = SpackCommand('deactivate')
+install = SpackCommand('install')
+extensions = SpackCommand('extensions')
+
+
+def test_activate(
+ mock_packages, mock_archive, mock_fetch, config,
+ install_mockery):
+ install('extension1')
+ activate('extension1')
+ output = extensions('--show', 'activated', 'extendee')
+ assert 'extension1' in output
+
+
+def test_deactivate(
+ mock_packages, mock_archive, mock_fetch, config,
+ install_mockery):
+ install('extension1')
+ activate('extension1')
+ deactivate('extension1')
+ output = extensions('--show', 'activated', 'extendee')
+ assert 'extension1' not in output
+
+
+def test_deactivate_all(
+ mock_packages, mock_archive, mock_fetch, config,
+ install_mockery):
+ install('extension1')
+ install('extension2')
+ activate('extension1')
+ activate('extension2')
+ deactivate('--all', 'extendee')
+ output = extensions('--show', 'activated', 'extendee')
+ assert 'extension1' not in output
diff --git a/lib/spack/spack/test/cmd/arch.py b/lib/spack/spack/test/cmd/arch.py
new file mode 100644
index 0000000000..1f3c14f059
--- /dev/null
+++ b/lib/spack/spack/test/cmd/arch.py
@@ -0,0 +1,36 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.main import SpackCommand
+
+
+arch = SpackCommand('arch')
+
+
+def test_arch():
+ """Sanity check ``spack arch`` to make sure it works."""
+
+ arch()
+
+
+def test_arch_platform():
+ """Sanity check ``spack arch --platform`` to make sure it works."""
+
+ arch('-p')
+ arch('--platform')
+
+
+def test_arch_operating_system():
+ """Sanity check ``spack arch --operating-system`` to make sure it works."""
+
+ arch('-o')
+ arch('--operating-system')
+
+
+def test_arch_target():
+ """Sanity check ``spack arch --target`` to make sure it works."""
+
+ arch('-t')
+ arch('--target')
diff --git a/lib/spack/spack/test/cmd/blame.py b/lib/spack/spack/test/cmd/blame.py
index 1f7d9e81a8..244fd14a6a 100644
--- a/lib/spack/spack/test/cmd/blame.py
+++ b/lib/spack/spack/test/cmd/blame.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
from llnl.util.filesystem import working_dir
-import spack
+import spack.paths
import spack.cmd
from spack.main import SpackCommand
from spack.util.executable import which
@@ -38,7 +19,7 @@ pytestmark = pytest.mark.skipif(
blame = SpackCommand('blame')
-def test_blame_by_modtime(builtin_mock):
+def test_blame_by_modtime(mock_packages):
"""Sanity check the blame command to make sure it works."""
out = blame('--time', 'mpich')
assert 'LAST_COMMIT' in out
@@ -46,7 +27,7 @@ def test_blame_by_modtime(builtin_mock):
assert 'EMAIL' in out
-def test_blame_by_percent(builtin_mock):
+def test_blame_by_percent(mock_packages):
"""Sanity check the blame command to make sure it works."""
out = blame('--percent', 'mpich')
assert 'LAST_COMMIT' in out
@@ -54,16 +35,16 @@ def test_blame_by_percent(builtin_mock):
assert 'EMAIL' in out
-def test_blame_file(builtin_mock):
+def test_blame_file(mock_packages):
"""Sanity check the blame command to make sure it works."""
- with working_dir(spack.prefix):
+ with working_dir(spack.paths.prefix):
out = blame('bin/spack')
assert 'LAST_COMMIT' in out
assert 'AUTHOR' in out
assert 'EMAIL' in out
-def test_blame_by_git(builtin_mock, capfd):
+def test_blame_by_git(mock_packages, capfd):
"""Sanity check the blame command to make sure it works."""
with capfd.disabled():
out = blame('--git', 'mpich')
diff --git a/lib/spack/spack/test/cmd/build_env.py b/lib/spack/spack/test/cmd/build_env.py
new file mode 100644
index 0000000000..a84d2b8ff5
--- /dev/null
+++ b/lib/spack/spack/test/cmd/build_env.py
@@ -0,0 +1,29 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import pytest
+
+from spack.main import SpackCommand, SpackCommandError
+
+info = SpackCommand('build-env')
+
+
+@pytest.mark.parametrize('pkg', [
+ ('zlib',),
+ ('zlib', '--')
+])
+@pytest.mark.usefixtures('config')
+def test_it_just_runs(pkg):
+ info(*pkg)
+
+
+@pytest.mark.parametrize('pkg,error_cls', [
+ ('zlib libszip', SpackCommandError),
+ ('', IndexError)
+])
+@pytest.mark.usefixtures('config')
+def test_it_just_fails(pkg, error_cls):
+ with pytest.raises(error_cls):
+ info(pkg)
diff --git a/lib/spack/spack/test/cmd/cd.py b/lib/spack/spack/test/cmd/cd.py
new file mode 100644
index 0000000000..cab460012a
--- /dev/null
+++ b/lib/spack/spack/test/cmd/cd.py
@@ -0,0 +1,17 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.main import SpackCommand
+
+
+cd = SpackCommand('cd')
+
+
+def test_cd():
+ """Sanity check the cd command to make sure it works."""
+
+ out = cd()
+
+ assert "To initialize spack's shell commands:" in out
diff --git a/lib/spack/spack/test/cmd/clean.py b/lib/spack/spack/test/cmd/clean.py
index 3cb5044949..edc2c111f6 100644
--- a/lib/spack/spack/test/cmd/clean.py
+++ b/lib/spack/spack/test/cmd/clean.py
@@ -1,29 +1,11 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
-import spack
+import spack.stage
+import spack.caches
import spack.main
import spack.package
@@ -42,18 +24,22 @@ def mock_calls_for_clean(monkeypatch):
monkeypatch.setattr(spack.package.PackageBase, 'do_clean', Counter())
monkeypatch.setattr(spack.stage, 'purge', Counter())
- monkeypatch.setattr(spack.fetch_cache, 'destroy', Counter(), raising=False)
- monkeypatch.setattr(spack.misc_cache, 'destroy', Counter())
+ monkeypatch.setattr(
+ spack.caches.fetch_cache, 'destroy', Counter(), raising=False)
+ monkeypatch.setattr(
+ spack.caches.misc_cache, 'destroy', Counter())
@pytest.mark.usefixtures(
- 'builtin_mock', 'config', 'mock_calls_for_clean'
+ 'mock_packages', 'config', 'mock_calls_for_clean'
)
@pytest.mark.parametrize('command_line,counters', [
('mpileaks', [1, 0, 0, 0]),
- ('-s', [0, 1, 0, 0]),
- ('-sd', [0, 1, 1, 0]),
- ('-a', [0, 1, 1, 1]),
+ ('-s', [0, 1, 0, 0]),
+ ('-sd', [0, 1, 1, 0]),
+ ('-m', [0, 0, 0, 1]),
+ ('-a', [0, 1, 1, 1]),
+ ('', [0, 0, 0, 0]),
])
def test_function_calls(command_line, counters):
@@ -64,5 +50,5 @@ def test_function_calls(command_line, counters):
# number of times
assert spack.package.PackageBase.do_clean.call_count == counters[0]
assert spack.stage.purge.call_count == counters[1]
- assert spack.fetch_cache.destroy.call_count == counters[2]
- assert spack.misc_cache.destroy.call_count == counters[3]
+ assert spack.caches.fetch_cache.destroy.call_count == counters[2]
+ assert spack.caches.misc_cache.destroy.call_count == counters[3]
diff --git a/lib/spack/spack/test/cmd/commands.py b/lib/spack/spack/test/cmd/commands.py
new file mode 100644
index 0000000000..0b693a1bab
--- /dev/null
+++ b/lib/spack/spack/test/cmd/commands.py
@@ -0,0 +1,51 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import re
+
+from llnl.util.argparsewriter import ArgparseWriter
+
+import spack.cmd
+import spack.main
+from spack.main import SpackCommand
+
+commands = SpackCommand('commands')
+
+parser = spack.main.make_argument_parser()
+spack.main.add_all_commands(parser)
+
+
+def test_commands_by_name():
+ """Test default output of spack commands."""
+ out = commands()
+ assert out.strip().split('\n') == sorted(spack.cmd.all_commands())
+
+
+def test_subcommands():
+ """Test subcommand traversal."""
+ out = commands('--format=subcommands')
+ assert 'spack mirror create' in out
+ assert 'spack buildcache list' in out
+ assert 'spack repo add' in out
+ assert 'spack pkg diff' in out
+ assert 'spack url parse' in out
+ assert 'spack view symlink' in out
+
+ class Subcommands(ArgparseWriter):
+ def begin_command(self, prog):
+ assert prog in out
+
+ Subcommands().write(parser)
+
+
+def test_rst():
+ """Do some simple sanity checks of the rst writer."""
+ out = commands('--format=rst')
+
+ class Subcommands(ArgparseWriter):
+ def begin_command(self, prog):
+ assert prog in out
+ assert re.sub(r' ', '-', prog) in out
+ Subcommands().write(parser)
diff --git a/lib/spack/spack/test/cmd/config.py b/lib/spack/spack/test/cmd/config.py
new file mode 100644
index 0000000000..493236709b
--- /dev/null
+++ b/lib/spack/spack/test/cmd/config.py
@@ -0,0 +1,93 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+
+from llnl.util.filesystem import mkdirp
+
+import spack.config
+import spack.environment as ev
+from spack.main import SpackCommand
+
+config = SpackCommand('config')
+
+
+def test_get_config_scope(mock_config):
+ assert config('get', 'compilers').strip() == 'compilers: {}'
+
+
+def test_get_config_scope_merged(mock_config):
+ low_path = mock_config.scopes['low'].path
+ high_path = mock_config.scopes['high'].path
+
+ mkdirp(low_path)
+ mkdirp(high_path)
+
+ with open(os.path.join(low_path, 'repos.yaml'), 'w') as f:
+ f.write('''\
+repos:
+- repo3
+''')
+
+ with open(os.path.join(high_path, 'repos.yaml'), 'w') as f:
+ f.write('''\
+repos:
+- repo1
+- repo2
+''')
+
+ assert config('get', 'repos').strip() == '''repos:
+- repo1
+- repo2
+- repo3'''
+
+
+def test_config_edit():
+ """Ensure `spack config edit` edits the right paths."""
+ dms = spack.config.default_modify_scope()
+ dms_path = spack.config.config.scopes[dms].path
+ user_path = spack.config.config.scopes['user'].path
+
+ comp_path = os.path.join(dms_path, 'compilers.yaml')
+ repos_path = os.path.join(user_path, 'repos.yaml')
+
+ assert config('edit', '--print-file', 'compilers').strip() == comp_path
+ assert config('edit', '--print-file', 'repos').strip() == repos_path
+
+
+def test_config_get_gets_spack_yaml(mutable_mock_env_path):
+ env = ev.create('test')
+
+ config('get', fail_on_error=False)
+ assert config.returncode == 1
+
+ with env:
+ config('get', fail_on_error=False)
+ assert config.returncode == 1
+
+ env.write()
+
+ assert 'mpileaks' not in config('get')
+
+ env.add('mpileaks')
+ env.write()
+
+ assert 'mpileaks' in config('get')
+
+
+def test_config_edit_edits_spack_yaml(mutable_mock_env_path):
+ env = ev.create('test')
+ with env:
+ assert config('edit', '--print-file').strip() == env.manifest_path
+
+
+def test_config_edit_fails_correctly_with_no_env(mutable_mock_env_path):
+ output = config('edit', '--print-file', fail_on_error=False)
+ assert "requires a section argument or an active environment" in output
+
+
+def test_config_get_fails_correctly_with_no_env(mutable_mock_env_path):
+ output = config('get', fail_on_error=False)
+ assert "requires a section argument or an active environment" in output
diff --git a/lib/spack/spack/test/cmd/debug.py b/lib/spack/spack/test/cmd/debug.py
new file mode 100644
index 0000000000..5189487265
--- /dev/null
+++ b/lib/spack/spack/test/cmd/debug.py
@@ -0,0 +1,40 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+import os.path
+
+from spack.main import SpackCommand
+from spack.util.executable import which
+
+debug = SpackCommand('debug')
+
+
+def test_create_db_tarball(tmpdir, database):
+ with tmpdir.as_cwd():
+ debug('create-db-tarball')
+
+ # get the first non-dotfile to avoid coverage files in the directory
+ files = os.listdir(os.getcwd())
+ tarball_name = next(f for f in files if not f.startswith('.'))
+
+ # debug command made an archive
+ assert os.path.exists(tarball_name)
+
+ # print contents of archive
+ tar = which('tar')
+ contents = tar('tzf', tarball_name, output=str)
+
+ # DB file is included
+ assert 'index.json' in contents
+
+ # spec.yamls from all installs are included
+ for spec in database.query():
+ # externals won't have a spec.yaml
+ if spec.external:
+ continue
+
+ spec_suffix = '%s/.spack/spec.yaml' % spec.dag_hash()
+ assert spec_suffix in contents
diff --git a/lib/spack/spack/test/cmd/dependencies.py b/lib/spack/spack/test/cmd/dependencies.py
index 737a74caae..0583050812 100644
--- a/lib/spack/spack/test/cmd/dependencies.py
+++ b/lib/spack/spack/test/cmd/dependencies.py
@@ -1,32 +1,14 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
+import pytest
from llnl.util.tty.color import color_when
-import spack
+import spack.store
from spack.main import SpackCommand
dependencies = SpackCommand('dependencies')
@@ -35,14 +17,14 @@ mpis = ['mpich', 'mpich2', 'multi-provider-mpi', 'zmpi']
mpi_deps = ['fake']
-def test_immediate_dependencies(builtin_mock):
+def test_immediate_dependencies(mock_packages):
out = dependencies('mpileaks')
actual = set(re.split(r'\s+', out.strip()))
expected = set(['callpath'] + mpis)
assert expected == actual
-def test_transitive_dependencies(builtin_mock):
+def test_transitive_dependencies(mock_packages):
out = dependencies('--transitive', 'mpileaks')
actual = set(re.split(r'\s+', out.strip()))
expected = set(
@@ -50,7 +32,8 @@ def test_transitive_dependencies(builtin_mock):
assert expected == actual
-def test_immediate_installed_dependencies(builtin_mock, database):
+@pytest.mark.db
+def test_immediate_installed_dependencies(mock_packages, database):
with color_when(False):
out = dependencies('--installed', 'mpileaks^mpich')
@@ -63,7 +46,8 @@ def test_immediate_installed_dependencies(builtin_mock, database):
assert expected == hashes
-def test_transitive_installed_dependencies(builtin_mock, database):
+@pytest.mark.db
+def test_transitive_installed_dependencies(mock_packages, database):
with color_when(False):
out = dependencies('--installed', '--transitive', 'mpileaks^zmpi')
diff --git a/lib/spack/spack/test/cmd/dependents.py b/lib/spack/spack/test/cmd/dependents.py
index acd64ec3d4..70019aa476 100644
--- a/lib/spack/spack/test/cmd/dependents.py
+++ b/lib/spack/spack/test/cmd/dependents.py
@@ -1,45 +1,28 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
+import pytest
+
from llnl.util.tty.color import color_when
-import spack
+import spack.store
from spack.main import SpackCommand
dependents = SpackCommand('dependents')
-def test_immediate_dependents(builtin_mock):
+def test_immediate_dependents(mock_packages):
out = dependents('libelf')
actual = set(re.split(r'\s+', out.strip()))
assert actual == set(['dyninst', 'libdwarf',
'patch-a-dependency', 'patch-several-dependencies'])
-def test_transitive_dependents(builtin_mock):
+def test_transitive_dependents(mock_packages):
out = dependents('--transitive', 'libelf')
actual = set(re.split(r'\s+', out.strip()))
assert actual == set(
@@ -48,7 +31,8 @@ def test_transitive_dependents(builtin_mock):
'patch-a-dependency', 'patch-several-dependencies'])
-def test_immediate_installed_dependents(builtin_mock, database):
+@pytest.mark.db
+def test_immediate_installed_dependents(mock_packages, database):
with color_when(False):
out = dependents('--installed', 'libelf')
@@ -64,7 +48,8 @@ def test_immediate_installed_dependents(builtin_mock, database):
assert expected == hashes
-def test_transitive_installed_dependents(builtin_mock, database):
+@pytest.mark.db
+def test_transitive_installed_dependents(mock_packages, database):
with color_when(False):
out = dependents('--installed', '--transitive', 'fake')
diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py
index 18d64b454b..76210bc562 100644
--- a/lib/spack/spack/test/cmd/env.py
+++ b/lib/spack/spack/test/cmd/env.py
@@ -1,48 +1,596 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+from six import StringIO
+
import pytest
-from spack.main import SpackCommand, SpackCommandError
+import llnl.util.filesystem as fs
+
+import spack.modules
+import spack.environment as ev
+from spack.cmd.env import _env_create
+from spack.spec import Spec
+from spack.main import SpackCommand
+
+
+# everything here uses the mock_env_path
+pytestmark = pytest.mark.usefixtures(
+ 'mutable_mock_env_path', 'config', 'mutable_mock_packages')
+
+env = SpackCommand('env')
+install = SpackCommand('install')
+add = SpackCommand('add')
+remove = SpackCommand('remove')
+concretize = SpackCommand('concretize')
+stage = SpackCommand('stage')
+uninstall = SpackCommand('uninstall')
+find = SpackCommand('find')
+
+
+def test_add():
+ e = ev.create('test')
+ e.add('mpileaks')
+ assert Spec('mpileaks') in e.user_specs
+
+
+def test_env_list():
+ env('create', 'foo')
+ env('create', 'bar')
+ env('create', 'baz')
+
+ out = env('list')
+
+ assert 'foo' in out
+ assert 'bar' in out
+ assert 'baz' in out
+
+
+def test_env_remove(capfd):
+ env('create', 'foo')
+ env('create', 'bar')
+
+ out = env('list')
+ assert 'foo' in out
+ assert 'bar' in out
+
+ foo = ev.read('foo')
+ with foo:
+ with pytest.raises(spack.main.SpackCommandError):
+ with capfd.disabled():
+ env('remove', '-y', 'foo')
+ assert 'foo' in env('list')
+
+ env('remove', '-y', 'foo')
+ out = env('list')
+ assert 'foo' not in out
+ assert 'bar' in out
+
+ env('remove', '-y', 'bar')
+ out = env('list')
+ assert 'foo' not in out
+ assert 'bar' not in out
+
+
+def test_concretize():
+ e = ev.create('test')
+ e.add('mpileaks')
+ e.concretize()
+ env_specs = e._get_environment_specs()
+ assert any(x.name == 'mpileaks' for x in env_specs)
+
+
+def test_env_install_all(install_mockery, mock_fetch):
+ e = ev.create('test')
+ e.add('cmake-client')
+ e.concretize()
+ e.install_all()
+ env_specs = e._get_environment_specs()
+ spec = next(x for x in env_specs if x.name == 'cmake-client')
+ assert spec.package.installed
+
+
+def test_env_install_single_spec(install_mockery, mock_fetch):
+ env('create', 'test')
+ install = SpackCommand('install')
+
+ e = ev.read('test')
+ with e:
+ install('cmake-client')
+
+ e = ev.read('test')
+ assert e.user_specs[0].name == 'cmake-client'
+ assert e.concretized_user_specs[0].name == 'cmake-client'
+ assert e.specs_by_hash[e.concretized_order[0]].name == 'cmake-client'
+
+
+def test_env_install_same_spec_twice(install_mockery, mock_fetch, capfd):
+ env('create', 'test')
+
+ e = ev.read('test')
+ with capfd.disabled():
+ with e:
+ install('cmake-client')
+ out = install('cmake-client')
+ assert 'is already installed in' in out
+
+
+def test_remove_after_concretize():
+ e = ev.create('test')
+
+ e.add('mpileaks')
+ e.concretize()
+
+ e.add('python')
+ e.concretize()
+
+ e.remove('mpileaks')
+ assert Spec('mpileaks') not in e.user_specs
+ env_specs = e._get_environment_specs()
+ assert any(s.name == 'mpileaks' for s in env_specs)
+
+ e.add('mpileaks')
+ assert any(s.name == 'mpileaks' for s in e.user_specs)
+
+ e.remove('mpileaks', force=True)
+ assert Spec('mpileaks') not in e.user_specs
+ env_specs = e._get_environment_specs()
+ assert not any(s.name == 'mpileaks' for s in env_specs)
+
+
+def test_remove_command():
+ env('create', 'test')
+ assert 'test' in env('list')
+
+ with ev.read('test'):
+ add('mpileaks')
+ assert 'mpileaks' in find()
+ assert 'mpileaks@' not in find()
+ assert 'mpileaks@' not in find('--show-concretized')
+
+ with ev.read('test'):
+ remove('mpileaks')
+ assert 'mpileaks' not in find()
+ assert 'mpileaks@' not in find()
+ assert 'mpileaks@' not in find('--show-concretized')
+
+ with ev.read('test'):
+ add('mpileaks')
+ assert 'mpileaks' in find()
+ assert 'mpileaks@' not in find()
+ assert 'mpileaks@' not in find('--show-concretized')
+
+ with ev.read('test'):
+ concretize()
+ assert 'mpileaks' in find()
+ assert 'mpileaks@' not in find()
+ assert 'mpileaks@' in find('--show-concretized')
+
+ with ev.read('test'):
+ remove('mpileaks')
+ assert 'mpileaks' not in find()
+ # removed but still in last concretized specs
+ assert 'mpileaks@' in find('--show-concretized')
+
+ with ev.read('test'):
+ concretize()
+ assert 'mpileaks' not in find()
+ assert 'mpileaks@' not in find()
+ # now the lockfile is regenerated and it's gone.
+ assert 'mpileaks@' not in find('--show-concretized')
+
+
+def test_environment_status(capfd, tmpdir):
+ with capfd.disabled():
+ with tmpdir.as_cwd():
+ assert 'No active environment' in env('status')
+
+ with ev.create('test'):
+ assert 'In environment test' in env('status')
+
+ with ev.Environment('local_dir'):
+ assert os.path.join(os.getcwd(), 'local_dir') in env('status')
+
+ e = ev.Environment('myproject')
+ e.write()
+ with tmpdir.join('myproject').as_cwd():
+ with e:
+ assert 'in current directory' in env('status')
+
+
+def test_to_lockfile_dict():
+ e = ev.create('test')
+ e.add('mpileaks')
+ e.concretize()
+ context_dict = e._to_lockfile_dict()
+
+ e_copy = ev.create('test_copy')
+
+ e_copy._read_lockfile_dict(context_dict)
+ assert e.specs_by_hash == e_copy.specs_by_hash
+
+
+def test_env_repo():
+ e = ev.create('test')
+ e.add('mpileaks')
+ e.write()
+
+ with ev.read('test'):
+ concretize()
+
+ package = e.repo.get('mpileaks')
+ assert package.name == 'mpileaks'
+ assert package.namespace == 'spack.pkg.builtin.mock'
+
+
+def test_user_removed_spec():
+ """Ensure a user can remove from any position in the spack.yaml file."""
+ initial_yaml = StringIO("""\
+env:
+ specs:
+ - mpileaks
+ - hypre
+ - libelf
+""")
+
+ before = ev.create('test', initial_yaml)
+ before.concretize()
+ before.write()
+
+ # user modifies yaml externally to spack and removes hypre
+ with open(before.manifest_path, 'w') as f:
+ f.write("""\
+env:
+ specs:
+ - mpileaks
+ - libelf
+""")
+
+ after = ev.read('test')
+ after.concretize()
+ after.write()
+
+ env_specs = after._get_environment_specs()
+ read = ev.read('test')
+ env_specs = read._get_environment_specs()
+
+ assert not any(x.name == 'hypre' for x in env_specs)
+
+
+def test_init_from_lockfile(tmpdir):
+ """Test that an environment can be instantiated from a lockfile."""
+ initial_yaml = StringIO("""\
+env:
+ specs:
+ - mpileaks
+ - hypre
+ - libelf
+""")
+ e1 = ev.create('test', initial_yaml)
+ e1.concretize()
+ e1.write()
+
+ e2 = ev.Environment(str(tmpdir), e1.lock_path)
+
+ for s1, s2 in zip(e1.user_specs, e2.user_specs):
+ assert s1 == s2
+
+ for h1, h2 in zip(e1.concretized_order, e2.concretized_order):
+ assert h1 == h2
+ assert e1.specs_by_hash[h1] == e2.specs_by_hash[h2]
+
+ for s1, s2 in zip(e1.concretized_user_specs, e2.concretized_user_specs):
+ assert s1 == s2
+
+
+def test_init_from_yaml(tmpdir):
+ """Test that an environment can be instantiated from a lockfile."""
+ initial_yaml = StringIO("""\
+env:
+ specs:
+ - mpileaks
+ - hypre
+ - libelf
+""")
+ e1 = ev.create('test', initial_yaml)
+ e1.concretize()
+ e1.write()
+
+ e2 = ev.Environment(str(tmpdir), e1.manifest_path)
+
+ for s1, s2 in zip(e1.user_specs, e2.user_specs):
+ assert s1 == s2
+
+ assert not e2.concretized_order
+ assert not e2.concretized_user_specs
+ assert not e2.specs_by_hash
+
+
+def test_init_with_file_and_remove(tmpdir):
+ """Ensure a user can remove from any position in the spack.yaml file."""
+ path = tmpdir.join('spack.yaml')
+
+ with tmpdir.as_cwd():
+ with open(str(path), 'w') as f:
+ f.write("""\
+env:
+ specs:
+ - mpileaks
+""")
+
+ env('create', 'test', 'spack.yaml')
+
+ out = env('list')
+ assert 'test' in out
+
+ with ev.read('test'):
+ assert 'mpileaks' in find()
+
+ env('remove', '-y', 'test')
+
+ out = env('list')
+ assert 'test' not in out
+
+
+def test_env_with_config():
+ test_config = """\
+env:
+ specs:
+ - mpileaks
+ packages:
+ mpileaks:
+ version: [2.2]
+"""
+ spack.package_prefs.PackagePrefs.clear_caches()
+
+ _env_create('test', StringIO(test_config))
+
+ e = ev.read('test')
+ ev.prepare_config_scope(e)
+ e.concretize()
+
+ assert any(x.satisfies('mpileaks@2.2')
+ for x in e._get_environment_specs())
+
+
+def test_env_with_included_config_file():
+ test_config = """\
+env:
+ include:
+ - ./included-config.yaml
+ specs:
+ - mpileaks
+"""
+ spack.package_prefs.PackagePrefs.clear_caches()
+
+ _env_create('test', StringIO(test_config))
+ e = ev.read('test')
+
+ with open(os.path.join(e.path, 'included-config.yaml'), 'w') as f:
+ f.write("""\
+packages:
+ mpileaks:
+ version: [2.2]
+""")
+
+ ev.prepare_config_scope(e)
+ e.concretize()
+
+ assert any(x.satisfies('mpileaks@2.2')
+ for x in e._get_environment_specs())
+
+
+def test_env_with_included_config_scope():
+ config_scope_path = os.path.join(ev.root('test'), 'config')
+ test_config = """\
+env:
+ include:
+ - %s
+ specs:
+ - mpileaks
+""" % config_scope_path
+
+ spack.package_prefs.PackagePrefs.clear_caches()
+ _env_create('test', StringIO(test_config))
+
+ e = ev.read('test')
+
+ fs.mkdirp(config_scope_path)
+ with open(os.path.join(config_scope_path, 'packages.yaml'), 'w') as f:
+ f.write("""\
+packages:
+ mpileaks:
+ version: [2.2]
+""")
+
+ ev.prepare_config_scope(e)
+ e.concretize()
+
+ assert any(x.satisfies('mpileaks@2.2')
+ for x in e._get_environment_specs())
+
+
+def test_env_config_precedence():
+ test_config = """\
+env:
+ packages:
+ libelf:
+ version: [0.8.12]
+ include:
+ - ./included-config.yaml
+ specs:
+ - mpileaks
+"""
+
+ spack.package_prefs.PackagePrefs.clear_caches()
+
+ _env_create('test', StringIO(test_config))
+ e = ev.read('test')
+
+ with open(os.path.join(e.path, 'included-config.yaml'), 'w') as f:
+ f.write("""\
+packages:
+ mpileaks:
+ version: [2.2]
+ libelf:
+ version: [0.8.11]
+""")
+
+ ev.prepare_config_scope(e)
+ e.concretize()
+
+ # ensure included scope took effect
+ assert any(
+ x.satisfies('mpileaks@2.2') for x in e._get_environment_specs())
+
+ # ensure env file takes precedence
+ assert any(
+ x.satisfies('libelf@0.8.12') for x in e._get_environment_specs())
+
+
+def test_included_config_precedence():
+ test_config = """\
+env:
+ include:
+ - ./high-config.yaml # this one should take precedence
+ - ./low-config.yaml
+ specs:
+ - mpileaks
+"""
+ spack.package_prefs.PackagePrefs.clear_caches()
+
+ _env_create('test', StringIO(test_config))
+ e = ev.read('test')
+
+ with open(os.path.join(e.path, 'high-config.yaml'), 'w') as f:
+ f.write("""\
+packages:
+ libelf:
+ version: [0.8.10] # this should override libelf version below
+""")
+
+ with open(os.path.join(e.path, 'low-config.yaml'), 'w') as f:
+ f.write("""\
+packages:
+ mpileaks:
+ version: [2.2]
+ libelf:
+ version: [0.8.12]
+""")
+
+ ev.prepare_config_scope(e)
+ e.concretize()
+
+ assert any(
+ x.satisfies('mpileaks@2.2') for x in e._get_environment_specs())
+
+ assert any(
+ [x.satisfies('libelf@0.8.10') for x in e._get_environment_specs()])
+
+
+def test_bad_env_yaml_format(tmpdir):
+ filename = str(tmpdir.join('spack.yaml'))
+ with open(filename, 'w') as f:
+ f.write("""\
+env:
+ spacks:
+ - mpileaks
+""")
+
+ with tmpdir.as_cwd():
+ with pytest.raises(spack.config.ConfigFormatError) as e:
+ env('create', 'test', './spack.yaml')
+ assert './spack.yaml:2' in str(e)
+ assert "'spacks' was unexpected" in str(e)
+
+
+def test_env_loads(install_mockery, mock_fetch):
+ env('create', 'test')
+
+ with ev.read('test'):
+ add('mpileaks')
+ concretize()
+ install('--fake')
+
+ with ev.read('test'):
+ env('loads', 'test')
+
+ e = ev.read('test')
+
+ loads_file = os.path.join(e.path, 'loads')
+ assert os.path.exists(loads_file)
+
+ with open(loads_file) as f:
+ contents = f.read()
+ assert 'module load mpileaks' in contents
+
+
+@pytest.mark.disable_clean_stage_check
+def test_stage(mock_stage, mock_fetch, install_mockery):
+ env('create', 'test')
+ with ev.read('test'):
+ add('mpileaks')
+ add('zmpi')
+ concretize()
+ stage()
+
+ root = str(mock_stage)
+
+ def check_stage(spec):
+ spec = Spec(spec).concretized()
+ for dep in spec.traverse():
+ stage_name = "%s-%s-%s" % (dep.name, dep.version, dep.dag_hash())
+ assert os.path.isdir(os.path.join(root, stage_name))
+
+ check_stage('mpileaks')
+ check_stage('zmpi')
+
+
+def test_env_commands_die_with_no_env_arg():
+ # these fail in argparse when given no arg
+ with pytest.raises(SystemExit):
+ env('create')
+ with pytest.raises(SystemExit):
+ env('remove')
+
+ # these have an optional env arg and raise errors via tty.die
+ with pytest.raises(spack.main.SpackCommandError):
+ env('loads')
+
+ # This should NOT raise an error with no environment
+ # it just tells the user there isn't an environment
+ env('status')
+
+
+def test_env_blocks_uninstall(mock_stage, mock_fetch, install_mockery):
+ env('create', 'test')
+ with ev.read('test'):
+ add('mpileaks')
+ install('--fake')
+
+ out = uninstall('mpileaks', fail_on_error=False)
+ assert uninstall.returncode == 1
+ assert 'used by the following environments' in out
-info = SpackCommand('env')
+def test_uninstall_removes_from_env(mock_stage, mock_fetch, install_mockery):
+ env('create', 'test')
+ with ev.read('test'):
+ add('mpileaks')
+ add('libelf')
+ install('--fake')
-@pytest.mark.parametrize('pkg', [
- ('zlib',),
- ('zlib', '--')
-])
-@pytest.mark.usefixtures('config')
-def test_it_just_runs(pkg):
- info(*pkg)
+ test = ev.read('test')
+ assert any(s.name == 'mpileaks' for s in test.specs_by_hash.values())
+ assert any(s.name == 'libelf' for s in test.specs_by_hash.values())
+ with ev.read('test'):
+ uninstall('-ya')
-@pytest.mark.parametrize('pkg,error_cls', [
- ('zlib libszip', SpackCommandError),
- ('', IndexError)
-])
-@pytest.mark.usefixtures('config')
-def test_it_just_fails(pkg, error_cls):
- with pytest.raises(error_cls):
- info(pkg)
+ test = ev.read('test')
+ assert not test.specs_by_hash
+ assert not test.concretized_order
+ assert not test.user_specs
diff --git a/lib/spack/spack/test/cmd/find.py b/lib/spack/spack/test/cmd/find.py
index 69973e715b..6beaaa9b7e 100644
--- a/lib/spack/spack/test/cmd/find.py
+++ b/lib/spack/spack/test/cmd/find.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import pytest
@@ -62,7 +43,9 @@ def test_query_arguments():
missing=False,
unknown=False,
explicit=False,
- implicit=False
+ implicit=False,
+ start_date="2018-02-23",
+ end_date=None
)
q_args = query_arguments(args)
@@ -72,6 +55,8 @@ def test_query_arguments():
assert q_args['installed'] is True
assert q_args['known'] is any
assert q_args['explicit'] is any
+ assert 'start_date' in q_args
+ assert 'end_date' not in q_args
# Check that explicit works correctly
args.explicit = True
@@ -84,27 +69,32 @@ def test_query_arguments():
assert q_args['explicit'] is False
+@pytest.mark.db
@pytest.mark.usefixtures('database', 'mock_display')
-class TestFindWithTags(object):
+def test_tag1(parser, specs):
+
+ args = parser.parse_args(['--tags', 'tag1'])
+ spack.cmd.find.find(parser, args)
- def test_tag1(self, parser, specs):
+ assert len(specs) == 2
+ assert 'mpich' in [x.name for x in specs]
+ assert 'mpich2' in [x.name for x in specs]
- args = parser.parse_args(['--tags', 'tag1'])
- spack.cmd.find.find(parser, args)
- assert len(specs) == 2
- assert 'mpich' in [x.name for x in specs]
- assert 'mpich2' in [x.name for x in specs]
+@pytest.mark.db
+@pytest.mark.usefixtures('database', 'mock_display')
+def test_tag2(parser, specs):
+ args = parser.parse_args(['--tags', 'tag2'])
+ spack.cmd.find.find(parser, args)
- def test_tag2(self, parser, specs):
- args = parser.parse_args(['--tags', 'tag2'])
- spack.cmd.find.find(parser, args)
+ assert len(specs) == 1
+ assert 'mpich' in [x.name for x in specs]
- assert len(specs) == 1
- assert 'mpich' in [x.name for x in specs]
- def test_tag2_tag3(self, parser, specs):
- args = parser.parse_args(['--tags', 'tag2', '--tags', 'tag3'])
- spack.cmd.find.find(parser, args)
+@pytest.mark.db
+@pytest.mark.usefixtures('database', 'mock_display')
+def test_tag2_tag3(parser, specs):
+ args = parser.parse_args(['--tags', 'tag2', '--tags', 'tag3'])
+ spack.cmd.find.find(parser, args)
- assert len(specs) == 0
+ assert len(specs) == 0
diff --git a/lib/spack/spack/test/cmd/flake8.py b/lib/spack/spack/test/cmd/flake8.py
index 632351601d..295b1c544b 100644
--- a/lib/spack/spack/test/cmd/flake8.py
+++ b/lib/spack/spack/test/cmd/flake8.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import os
import pytest
@@ -29,9 +10,9 @@ import sys
from llnl.util.filesystem import FileFilter
-import spack
+import spack.paths
from spack.cmd.flake8 import flake8, setup_parser, changed_files
-from spack.repository import Repo
+from spack.repo import Repo
from spack.util.executable import which
@@ -50,7 +31,7 @@ def flake8_package():
mock package, yields the filename, then undoes the
change on cleanup.
"""
- repo = Repo(spack.mock_packages_path)
+ repo = Repo(spack.paths.mock_packages_path)
filename = repo.filename_for_package_name('flake8')
package = FileFilter(filename)
@@ -69,7 +50,7 @@ def test_changed_files(parser, flake8_package):
# changed_files returns file paths relative to the root
# directory of Spack. Convert to absolute file paths.
files = changed_files(args)
- files = [os.path.join(spack.spack_root, path) for path in files]
+ files = [os.path.join(spack.paths.prefix, path) for path in files]
# There will likely be other files that have changed
# when these tests are run
diff --git a/lib/spack/spack/test/cmd/gpg.py b/lib/spack/spack/test/cmd/gpg.py
index ef2f64211a..e962b24c3f 100644
--- a/lib/spack/spack/test/cmd/gpg.py
+++ b/lib/spack/spack/test/cmd/gpg.py
@@ -1,31 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack
+
+from spack.paths import mock_gpg_data_path, mock_gpg_keys_path
import spack.util.gpg as gpg_util
from spack.main import SpackCommand
from spack.util.executable import ProcessError
@@ -52,15 +34,16 @@ def has_gnupg2():
return False
+@pytest.mark.maybeslow
@pytest.mark.skipif(not has_gnupg2(),
reason='These tests require gnupg2')
def test_gpg(gpg, tmpdir, testing_gpg_directory):
# Verify a file with an empty keyring.
with pytest.raises(ProcessError):
- gpg('verify', os.path.join(spack.mock_gpg_data_path, 'content.txt'))
+ gpg('verify', os.path.join(mock_gpg_data_path, 'content.txt'))
# Import the default key.
- gpg('init', '--from', spack.mock_gpg_keys_path)
+ gpg('init', '--from', mock_gpg_keys_path)
# List the keys.
# TODO: Test the output here.
@@ -68,14 +51,14 @@ def test_gpg(gpg, tmpdir, testing_gpg_directory):
gpg('list', '--signing')
# Verify the file now that the key has been trusted.
- gpg('verify', os.path.join(spack.mock_gpg_data_path, 'content.txt'))
+ gpg('verify', os.path.join(mock_gpg_data_path, 'content.txt'))
# Untrust the default key.
gpg('untrust', 'Spack testing')
# Now that the key is untrusted, verification should fail.
with pytest.raises(ProcessError):
- gpg('verify', os.path.join(spack.mock_gpg_data_path, 'content.txt'))
+ gpg('verify', os.path.join(mock_gpg_data_path, 'content.txt'))
# Create a file to test signing.
test_path = tmpdir.join('to-sign.txt')
diff --git a/lib/spack/spack/test/cmd/graph.py b/lib/spack/spack/test/cmd/graph.py
new file mode 100644
index 0000000000..1601f24f92
--- /dev/null
+++ b/lib/spack/spack/test/cmd/graph.py
@@ -0,0 +1,64 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.main import SpackCommand, SpackCommandError
+
+import pytest
+
+
+graph = SpackCommand('graph')
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('mock_packages', 'database')
+def test_graph_ascii():
+ """Tests spack graph --ascii"""
+ graph('--ascii', 'dt-diamond')
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('mock_packages', 'database')
+def test_graph_dot():
+ """Tests spack graph --dot"""
+ graph('--dot', 'dt-diamond')
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('mock_packages', 'database')
+def test_graph_normalize():
+ """Tests spack graph --normalize"""
+ graph('--normalize', 'dt-diamond')
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('mock_packages', 'database')
+def test_graph_static():
+ """Tests spack graph --static"""
+ graph('--static', 'dt-diamond')
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('mock_packages', 'database')
+def test_graph_installed():
+ """Tests spack graph --installed"""
+
+ graph('--installed')
+
+ with pytest.raises(SpackCommandError):
+ graph('--installed', 'dt-diamond')
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('mock_packages', 'database')
+def test_graph_deptype():
+ """Tests spack graph --deptype"""
+ graph('--deptype', 'all', 'dt-diamond')
+
+
+def test_graph_no_specs():
+ """Tests spack graph with no arguments"""
+
+ with pytest.raises(SpackCommandError):
+ graph()
diff --git a/lib/spack/spack/test/cmd/help.py b/lib/spack/spack/test/cmd/help.py
new file mode 100644
index 0000000000..9747314403
--- /dev/null
+++ b/lib/spack/spack/test/cmd/help.py
@@ -0,0 +1,56 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import pytest
+
+from spack.main import SpackCommand
+
+
+@pytest.mark.xfail
+def test_reuse_after_help():
+ """Test `spack help` can be called twice with the same SpackCommand."""
+ help_cmd = SpackCommand('help')
+ help_cmd()
+
+ # This second invocation will somehow fail because the parser no
+ # longer works after add_all_commands() is called in
+ # SpackArgumentParser.format_help_sections().
+ #
+ # TODO: figure out why this doesn't work properly and change this
+ # test to use a single SpackCommand.
+ #
+ # It seems that parse_known_args() finds "too few arguments" the
+ # second time through b/c add_all_commands() ends up leaving extra
+ # positionals in the parser. But this used to work before we loaded
+ # commands lazily.
+ help_cmd()
+
+
+def test_help():
+ """Sanity check the help command to make sure it works."""
+ help_cmd = SpackCommand('help')
+ out = help_cmd()
+ assert 'These are common spack commands:' in out
+
+
+def test_help_all():
+ """Test the spack help --all flag"""
+ help_cmd = SpackCommand('help')
+ out = help_cmd('--all')
+ assert 'Complete list of spack commands:' in out
+
+
+def test_help_spec():
+ """Test the spack help --spec flag"""
+ help_cmd = SpackCommand('help')
+ out = help_cmd('--spec')
+ assert 'spec expression syntax:' in out
+
+
+def test_help_subcommand():
+ """Test the spack help subcommand argument"""
+ help_cmd = SpackCommand('help')
+ out = help_cmd('help')
+ assert 'get help on spack and its commands' in out
diff --git a/lib/spack/spack/test/cmd/info.py b/lib/spack/spack/test/cmd/info.py
index c406f6f78e..404c11befd 100644
--- a/lib/spack/spack/test/cmd/info.py
+++ b/lib/spack/spack/test/cmd/info.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import pytest
diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py
index 7bd6ebc160..904472f243 100644
--- a/lib/spack/spack/test/cmd/install.py
+++ b/lib/spack/spack/test/cmd/install.py
@@ -1,40 +1,26 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import argparse
import os
import filecmp
+from six.moves import builtins
import pytest
import llnl.util.filesystem as fs
-import spack
+import spack.config
+import spack.package
import spack.cmd.install
+from spack.error import SpackError
from spack.spec import Spec
from spack.main import SpackCommand
+from six.moves.urllib.error import HTTPError, URLError
+
install = SpackCommand('install')
@@ -48,15 +34,13 @@ def parser():
@pytest.fixture()
def noop_install(monkeypatch):
-
def noop(*args, **kwargs):
- return
-
+ pass
monkeypatch.setattr(spack.package.PackageBase, 'do_install', noop)
def test_install_package_and_dependency(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
with tmpdir.as_cwd():
@@ -71,39 +55,36 @@ def test_install_package_and_dependency(
assert 'failures="0"' in content
assert 'errors="0"' in content
- s = Spec('libdwarf').concretized()
- assert not spack.repo.get(s).stage.created
+
+@pytest.mark.disable_clean_stage_check
+def test_install_runtests_notests(monkeypatch, mock_packages, install_mockery):
+ def check(pkg):
+ assert not pkg.run_tests
+ monkeypatch.setattr(spack.package.PackageBase, 'unit_test_check', check)
+ install('-v', 'dttop')
-@pytest.mark.usefixtures('noop_install', 'builtin_mock', 'config')
-def test_install_runtests():
- assert not spack.package_testing._test_all
- assert not spack.package_testing.packages_to_test
+@pytest.mark.disable_clean_stage_check
+def test_install_runtests_root(monkeypatch, mock_packages, install_mockery):
+ def check(pkg):
+ assert pkg.run_tests == (pkg.name == 'dttop')
+ monkeypatch.setattr(spack.package.PackageBase, 'unit_test_check', check)
install('--test=root', 'dttop')
- assert not spack.package_testing._test_all
- assert spack.package_testing.packages_to_test == set(['dttop'])
-
- spack.package_testing.clear()
- install('--test=all', 'a')
- assert spack.package_testing._test_all
- assert not spack.package_testing.packages_to_test
- spack.package_testing.clear()
+@pytest.mark.disable_clean_stage_check
+def test_install_runtests_all(monkeypatch, mock_packages, install_mockery):
+ def check(pkg):
+ assert pkg.run_tests
+ monkeypatch.setattr(spack.package.PackageBase, 'unit_test_check', check)
+ install('--test=all', 'a')
install('--run-tests', 'a')
- assert spack.package_testing._test_all
- assert not spack.package_testing.packages_to_test
-
- spack.package_testing.clear()
-
- assert not spack.package_testing._test_all
- assert not spack.package_testing.packages_to_test
def test_install_package_already_installed(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
with tmpdir.as_cwd():
@@ -124,7 +105,7 @@ def test_install_package_already_installed(
@pytest.mark.parametrize('arguments,expected', [
- ([], spack.dirty), # The default read from configuration file
+ ([], spack.config.get('config:dirty')), # default from config file
(['--clean'], False),
(['--dirty'], True),
])
@@ -153,7 +134,7 @@ def test_package_output(tmpdir, capsys, install_mockery, mock_fetch):
@pytest.mark.disable_clean_stage_check
-def test_install_output_on_build_error(builtin_mock, mock_archive, mock_fetch,
+def test_install_output_on_build_error(mock_packages, mock_archive, mock_fetch,
config, install_mockery, capfd):
# capfd interferes with Spack's capturing
with capfd.disabled():
@@ -165,8 +146,8 @@ def test_install_output_on_build_error(builtin_mock, mock_archive, mock_fetch,
@pytest.mark.disable_clean_stage_check
-def test_install_output_on_python_error(builtin_mock, mock_archive, mock_fetch,
- config, install_mockery):
+def test_install_output_on_python_error(
+ mock_packages, mock_archive, mock_fetch, config, install_mockery):
out = install('failing-build', fail_on_error=False)
assert isinstance(install.error, spack.build_environment.ChildError)
assert install.error.name == 'InstallError'
@@ -175,7 +156,7 @@ def test_install_output_on_python_error(builtin_mock, mock_archive, mock_fetch,
@pytest.mark.disable_clean_stage_check
def test_install_with_source(
- builtin_mock, mock_archive, mock_fetch, config, install_mockery):
+ mock_packages, mock_archive, mock_fetch, config, install_mockery):
"""Verify that source has been copied into place."""
install('--source', '--keep-stage', 'trivial-install-test-package')
spec = Spec('trivial-install-test-package').concretized()
@@ -186,7 +167,7 @@ def test_install_with_source(
@pytest.mark.disable_clean_stage_check
-def test_show_log_on_error(builtin_mock, mock_archive, mock_fetch,
+def test_show_log_on_error(mock_packages, mock_archive, mock_fetch,
config, install_mockery, capfd):
"""Make sure --show-log-on-error works."""
with capfd.disabled():
@@ -202,7 +183,7 @@ def test_show_log_on_error(builtin_mock, mock_archive, mock_fetch,
def test_install_overwrite(
- builtin_mock, mock_archive, mock_fetch, config, install_mockery
+ mock_packages, mock_archive, mock_fetch, config, install_mockery
):
# It's not possible to overwrite something that is not yet installed
with pytest.raises(AssertionError):
@@ -234,3 +215,245 @@ def test_install_overwrite(
assert os.path.exists(spec.prefix)
assert fs.hash_directory(spec.prefix) == expected_md5
assert fs.hash_directory(spec.prefix) != bad_md5
+
+
+@pytest.mark.usefixtures(
+ 'mock_packages', 'mock_archive', 'mock_fetch', 'config', 'install_mockery',
+)
+def test_install_conflicts(conflict_spec):
+ # Make sure that spec with conflicts raises a SpackError
+ with pytest.raises(SpackError):
+ install(conflict_spec)
+
+
+@pytest.mark.usefixtures(
+ 'mock_packages', 'mock_archive', 'mock_fetch', 'config', 'install_mockery',
+)
+def test_install_invalid_spec(invalid_spec):
+ # Make sure that invalid specs raise a SpackError
+ with pytest.raises(SpackError, match='Unexpected token'):
+ install(invalid_spec)
+
+
+@pytest.mark.usefixtures('noop_install', 'config')
+@pytest.mark.parametrize('spec,concretize,error_code', [
+ (Spec('mpi'), False, 1),
+ (Spec('mpi'), True, 0),
+ (Spec('boost'), False, 1),
+ (Spec('boost'), True, 0)
+])
+def test_install_from_file(spec, concretize, error_code, tmpdir):
+
+ if concretize:
+ spec.concretize()
+
+ specfile = tmpdir.join('spec.yaml')
+
+ with specfile.open('w') as f:
+ spec.to_yaml(f)
+
+ # Relative path to specfile (regression for #6906)
+ with fs.working_dir(specfile.dirname):
+ # A non-concrete spec will fail to be installed
+ install('-f', specfile.basename, fail_on_error=False)
+ assert install.returncode == error_code
+
+ # Absolute path to specfile (regression for #6983)
+ install('-f', str(specfile), fail_on_error=False)
+ assert install.returncode == error_code
+
+
+@pytest.mark.disable_clean_stage_check
+@pytest.mark.usefixtures(
+ 'mock_packages', 'mock_archive', 'mock_fetch', 'config', 'install_mockery'
+)
+@pytest.mark.parametrize('exc_typename,msg', [
+ ('RuntimeError', 'something weird happened'),
+ ('ValueError', 'spec is not concrete')
+])
+def test_junit_output_with_failures(tmpdir, exc_typename, msg):
+ with tmpdir.as_cwd():
+ install(
+ '--log-format=junit', '--log-file=test.xml',
+ 'raiser',
+ 'exc_type={0}'.format(exc_typename),
+ 'msg="{0}"'.format(msg)
+ )
+
+ files = tmpdir.listdir()
+ filename = tmpdir.join('test.xml')
+ assert filename in files
+
+ content = filename.open().read()
+
+ # Count failures and errors correctly
+ assert 'tests="1"' in content
+ assert 'failures="1"' in content
+ assert 'errors="0"' in content
+
+ # We want to have both stdout and stderr
+ assert '<system-out>' in content
+ assert msg in content
+
+
+@pytest.mark.disable_clean_stage_check
+@pytest.mark.parametrize('exc_typename,msg', [
+ ('RuntimeError', 'something weird happened'),
+ ('KeyboardInterrupt', 'Ctrl-C strikes again')
+])
+def test_junit_output_with_errors(
+ exc_typename, msg,
+ mock_packages, mock_archive, mock_fetch, install_mockery,
+ config, tmpdir, monkeypatch):
+
+ def just_throw(*args, **kwargs):
+ exc_type = getattr(builtins, exc_typename)
+ raise exc_type(msg)
+
+ monkeypatch.setattr(spack.package.PackageBase, 'do_install', just_throw)
+
+ with tmpdir.as_cwd():
+ install('--log-format=junit', '--log-file=test.xml', 'libdwarf')
+
+ files = tmpdir.listdir()
+ filename = tmpdir.join('test.xml')
+ assert filename in files
+
+ content = filename.open().read()
+
+ # Count failures and errors correctly
+ assert 'tests="1"' in content
+ assert 'failures="0"' in content
+ assert 'errors="1"' in content
+
+ # We want to have both stdout and stderr
+ assert '<system-out>' in content
+ assert msg in content
+
+
+@pytest.mark.usefixtures('noop_install', 'config')
+@pytest.mark.parametrize('clispecs,filespecs', [
+ [[], ['mpi']],
+ [[], ['mpi', 'boost']],
+ [['cmake'], ['mpi']],
+ [['cmake', 'libelf'], []],
+ [['cmake', 'libelf'], ['mpi', 'boost']],
+])
+def test_install_mix_cli_and_files(clispecs, filespecs, tmpdir):
+
+ args = clispecs
+
+ for spec in filespecs:
+ filepath = tmpdir.join(spec + '.yaml')
+ args = ['-f', str(filepath)] + args
+ s = Spec(spec)
+ s.concretize()
+ with filepath.open('w') as f:
+ s.to_yaml(f)
+
+ install(*args, fail_on_error=False)
+ assert install.returncode == 0
+
+
+def test_extra_files_are_archived(mock_packages, mock_archive, mock_fetch,
+ config, install_mockery):
+ s = Spec('archive-files')
+ s.concretize()
+
+ install('archive-files')
+
+ archive_dir = os.path.join(
+ spack.store.layout.metadata_path(s), 'archived-files'
+ )
+ config_log = os.path.join(archive_dir, 'config.log')
+ assert os.path.exists(config_log)
+
+ errors_txt = os.path.join(archive_dir, 'errors.txt')
+ assert os.path.exists(errors_txt)
+
+
+@pytest.mark.disable_clean_stage_check
+def test_cdash_report_concretization_error(tmpdir, mock_fetch, install_mockery,
+ capfd, conflict_spec):
+ # capfd interferes with Spack's capturing
+ with capfd.disabled():
+ with tmpdir.as_cwd():
+ with pytest.raises(SpackError):
+ install(
+ '--log-format=cdash',
+ '--log-file=cdash_reports',
+ conflict_spec)
+ report_dir = tmpdir.join('cdash_reports')
+ assert report_dir in tmpdir.listdir()
+ report_file = report_dir.join('Update.xml')
+ assert report_file in report_dir.listdir()
+ content = report_file.open().read()
+ assert '<UpdateReturnStatus>Conflicts in concretized spec' \
+ in content
+
+
+@pytest.mark.disable_clean_stage_check
+def test_cdash_upload_build_error(tmpdir, mock_fetch, install_mockery,
+ capfd):
+ # capfd interferes with Spack's capturing
+ with capfd.disabled():
+ with tmpdir.as_cwd():
+ with pytest.raises((HTTPError, URLError)):
+ install(
+ '--log-format=cdash',
+ '--log-file=cdash_reports',
+ '--cdash-upload-url=http://localhost/fakeurl/submit.php?project=Spack',
+ 'build-error')
+ report_dir = tmpdir.join('cdash_reports')
+ assert report_dir in tmpdir.listdir()
+ report_file = report_dir.join('Build.xml')
+ assert report_file in report_dir.listdir()
+ content = report_file.open().read()
+ assert '<Text>configure: error: in /path/to/some/file:</Text>' in content
+
+
+@pytest.mark.disable_clean_stage_check
+def test_cdash_upload_clean_build(tmpdir, mock_fetch, install_mockery,
+ capfd):
+ # capfd interferes with Spack's capturing
+ with capfd.disabled():
+ with tmpdir.as_cwd():
+ with pytest.raises((HTTPError, URLError)):
+ install(
+ '--log-file=cdash_reports',
+ '--cdash-upload-url=http://localhost/fakeurl/submit.php?project=Spack',
+ 'a')
+ report_dir = tmpdir.join('cdash_reports')
+ assert report_dir in tmpdir.listdir()
+ report_file = report_dir.join('Build.xml')
+ assert report_file in report_dir.listdir()
+ content = report_file.open().read()
+ assert '</Build>' in content
+ assert '<Text>' not in content
+
+
+@pytest.mark.disable_clean_stage_check
+def test_build_error_output(tmpdir, mock_fetch, install_mockery, capfd):
+ with capfd.disabled():
+ msg = ''
+ try:
+ install('build-error')
+ assert False, "no exception was raised!"
+ except spack.build_environment.ChildError as e:
+ msg = e.long_message
+
+ assert 'configure: error: in /path/to/some/file:' in msg
+ assert 'configure: error: cannot run C compiled programs.' in msg
+
+
+@pytest.mark.disable_clean_stage_check
+def test_build_warning_output(tmpdir, mock_fetch, install_mockery, capfd):
+ with capfd.disabled():
+ msg = ''
+ try:
+ install('build-warnings')
+ except spack.build_environment.ChildError as e:
+ msg = e.long_message
+
+ assert 'WARNING: ALL CAPITAL WARNING!' in msg
+ assert 'foo.c:89: warning: some weird warning!' in msg
diff --git a/lib/spack/spack/test/cmd/license.py b/lib/spack/spack/test/cmd/license.py
new file mode 100644
index 0000000000..6294309c86
--- /dev/null
+++ b/lib/spack/spack/test/cmd/license.py
@@ -0,0 +1,68 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os.path
+import re
+
+from llnl.util.filesystem import touch, mkdirp
+
+import spack.paths
+from spack.main import SpackCommand
+
+license = SpackCommand('license')
+
+
+def test_list_files():
+ files = license('list-files').strip().split('\n')
+ assert all(f.startswith(spack.paths.prefix) for f in files)
+ assert os.path.join(spack.paths.bin_path, 'spack') in files
+ assert os.path.abspath(__file__) in files
+
+
+def test_verify(tmpdir):
+ source_dir = tmpdir.join('lib', 'spack', 'spack')
+ mkdirp(str(source_dir))
+
+ no_header = source_dir.join('no_header.py')
+ touch(str(no_header))
+
+ lgpl_header = source_dir.join('lgpl_header.py')
+ with lgpl_header.open('w') as f:
+ f.write("""\
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+""")
+
+ old_lgpl_header = source_dir.join('old_lgpl_header.py')
+ with old_lgpl_header.open('w') as f:
+ f.write("""\
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License (as
+# published by the Free Software Foundation) version 2.1, February 1999.
+""")
+
+ correct_header = source_dir.join('correct_header.py')
+ with correct_header.open('w') as f:
+ f.write("""\
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+""")
+
+ out = license('verify', '--root', str(tmpdir), fail_on_error=False)
+
+ assert str(no_header) in out
+ assert str(lgpl_header) in out
+ assert str(old_lgpl_header) in out
+ assert str(correct_header) not in out
+ assert '3 improperly licensed files' in out
+ assert re.search('files with no SPDX-License-Identifier:\s*1', out)
+ assert re.search('files with wrong SPDX-License-Identifier:\s*1', out)
+ assert re.search('files with old license header:\s*1', out)
+
+ assert license.returncode == 1
diff --git a/lib/spack/spack/test/cmd/list.py b/lib/spack/spack/test/cmd/list.py
index 9fe335a6e3..a05ac8f04f 100644
--- a/lib/spack/spack/test/cmd/list.py
+++ b/lib/spack/spack/test/cmd/list.py
@@ -1,73 +1,61 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import argparse
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import pytest
-import spack.cmd.list
+from spack.main import SpackCommand
+
+list = SpackCommand('list')
+
+
+def test_list():
+ output = list()
+ assert 'cloverleaf3d' in output
+ assert 'hdf5' in output
-@pytest.fixture(scope='module')
-def parser():
- """Returns the parser for the module command"""
- prs = argparse.ArgumentParser()
- spack.cmd.list.setup_parser(prs)
- return prs
+def test_list_filter():
+ output = list('py-*')
+ assert 'py-numpy' in output
+ assert 'perl-file-copy-recursive' not in output
-@pytest.fixture()
-def pkg_names():
- pkg_names = []
- return pkg_names
+ output = list('py-')
+ assert 'py-numpy' in output
+ assert 'perl-file-copy-recursive' in output
-@pytest.fixture()
-def mock_name_only(monkeypatch, pkg_names):
+@pytest.mark.maybeslow
+def test_list_search_description():
+ output = list('--search-description', 'xml')
+ assert 'expat' in output
- def name_only(x):
- pkg_names.extend(x)
- monkeypatch.setattr(spack.cmd.list, 'name_only', name_only)
- monkeypatch.setitem(spack.cmd.list.formatters, 'name_only', name_only)
+def test_list_tags():
+ output = list('--tags', 'proxy-app')
+ assert 'cloverleaf3d' in output
+ assert 'hdf5' not in output
-@pytest.mark.usefixtures('mock_name_only')
-class TestListCommand(object):
+def test_list_format_name_only():
+ output = list('--format', 'name_only')
+ assert 'cloverleaf3d' in output
+ assert 'hdf5' in output
- def test_list_without_filters(self, parser, pkg_names):
- args = parser.parse_args([])
- spack.cmd.list.list(parser, args)
+@pytest.mark.maybeslow
+def test_list_format_rst():
+ output = list('--format', 'rst')
+ assert '.. _cloverleaf3d:' in output
+ assert '.. _hdf5:' in output
- assert pkg_names
- assert 'cloverleaf3d' in pkg_names
- assert 'hdf5' in pkg_names
- def test_list_with_filters(self, parser, pkg_names):
- args = parser.parse_args(['--tags', 'proxy-app'])
- spack.cmd.list.list(parser, args)
+@pytest.mark.maybeslow
+def test_list_format_html():
+ output = list('--format', 'html')
+ assert '<div class="section" id="cloverleaf3d">' in output
+ assert '<h1>cloverleaf3d' in output
- assert pkg_names
- assert 'cloverleaf3d' in pkg_names
- assert 'hdf5' not in pkg_names
+ assert '<div class="section" id="hdf5">' in output
+ assert '<h1>hdf5' in output
diff --git a/lib/spack/spack/test/cmd/mirror.py b/lib/spack/spack/test/cmd/mirror.py
new file mode 100644
index 0000000000..5122bf69b8
--- /dev/null
+++ b/lib/spack/spack/test/cmd/mirror.py
@@ -0,0 +1,19 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import pytest
+
+from spack.main import SpackCommand
+
+mirror = SpackCommand('mirror')
+
+
+@pytest.mark.disable_clean_stage_check
+@pytest.mark.regression('8083')
+def test_regression_8083(tmpdir, capfd, mock_packages, mock_fetch, config):
+ with capfd.disabled():
+ output = mirror('create', '-d', str(tmpdir), 'externaltool')
+ assert 'Skipping' in output
+ assert 'as it is an external spec' in output
diff --git a/lib/spack/spack/test/cmd/module.py b/lib/spack/spack/test/cmd/module.py
index 0aa08b9aa6..3151594ea3 100644
--- a/lib/spack/spack/test/cmd/module.py
+++ b/lib/spack/spack/test/cmd/module.py
@@ -1,52 +1,22 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import argparse
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os.path
import pytest
-import spack.cmd.module as module
-import spack.modules as modules
-
-
-def _get_module_files(args):
- files = []
- specs = args.specs()
+import spack.main
+import spack.modules
- for module_type in args.module_type:
- writer_cls = modules.module_types[module_type]
- files.extend([writer_cls(spec).layout.filename for spec in specs])
- return files
+module = spack.main.SpackCommand('module')
-@pytest.fixture(scope='module')
-def parser():
- """Returns the parser for the module command"""
- parser = argparse.ArgumentParser()
- module.setup_parser(parser)
- return parser
+def _module_files(module_type, *specs):
+ specs = [spack.spec.Spec(x).concretized() for x in specs]
+ writer_cls = spack.modules.module_types[module_type]
+ return [writer_cls(spec).layout.filename for spec in specs]
@pytest.fixture(
@@ -54,8 +24,7 @@ def parser():
['rm', 'doesnotexist'], # Try to remove a non existing module
['find', 'mpileaks'], # Try to find a module with multiple matches
['find', 'doesnotexist'], # Try to find a module with no matches
- # Try to find a module specifying more than one type
- ['find', '-m', 'tcl', '-m', 'lmod', 'libelf'],
+ ['find', '--unkown_args'], # Try to give an unknown argument
]
)
def failure_args(request):
@@ -63,62 +32,160 @@ def failure_args(request):
return request.param
+@pytest.fixture(
+ params=['dotkit', 'tcl', 'lmod']
+)
+def module_type(request):
+ return request.param
+
+
# TODO : test the --delete-tree option
# TODO : this requires having a separate directory for test modules
# TODO : add tests for loads and find to check the prompt format
+@pytest.mark.db
+def test_exit_with_failure(database, module_type, failure_args):
+ with pytest.raises(spack.main.SpackCommandError):
+ module(module_type, *failure_args)
+
-def test_exit_with_failure(database, parser, failure_args):
- args = parser.parse_args(failure_args)
- with pytest.raises(SystemExit):
- module.module(parser, args)
+@pytest.mark.db
+@pytest.mark.parametrize('deprecated_command', [
+ ('refresh', '-m', 'tcl', 'mpileaks'),
+ ('rm', '-m', 'tcl', '-m', 'lmod', 'mpileaks'),
+ ('find', 'mpileaks'),
+])
+def test_deprecated_command(database, deprecated_command):
+ with pytest.raises(spack.main.SpackCommandError):
+ module(*deprecated_command)
-def test_remove_and_add_tcl(database, parser):
+@pytest.mark.db
+def test_remove_and_add(database, module_type):
"""Tests adding and removing a tcl module file."""
- # Remove existing modules [tcl]
- args = parser.parse_args(['rm', '-y', '-m', 'tcl', 'mpileaks'])
- module_files = _get_module_files(args)
+ if module_type == 'lmod':
+ # TODO: Testing this with lmod requires mocking
+ # TODO: the core compilers
+ return
+ rm_cli_args = ['rm', '-y', 'mpileaks']
+ module_files = _module_files(module_type, 'mpileaks')
for item in module_files:
assert os.path.exists(item)
- module.module(parser, args)
-
+ module(module_type, *rm_cli_args)
for item in module_files:
assert not os.path.exists(item)
- # Add them back [tcl]
- args = parser.parse_args(['refresh', '-y', '-m', 'tcl', 'mpileaks'])
- module.module(parser, args)
-
+ module(module_type, 'refresh', '-y', 'mpileaks')
for item in module_files:
assert os.path.exists(item)
-def test_find(database, parser):
- """Tests the 'spack module find' under a few common scenarios."""
-
- # Try to find it for tcl module files
- args = parser.parse_args(['find', '--module-type', 'tcl', 'libelf'])
- module.module(parser, args)
-
-
-def test_remove_and_add_dotkit(database, parser):
- """Tests adding and removing a dotkit module file."""
-
- # Remove existing modules [dotkit]
- args = parser.parse_args(['rm', '-y', '-m', 'dotkit', 'mpileaks'])
- module_files = _get_module_files(args)
- for item in module_files:
- assert os.path.exists(item)
- module.module(parser, args)
- for item in module_files:
- assert not os.path.exists(item)
-
- # Add them back [dotkit]
- args = parser.parse_args(['refresh', '-y', '-m', 'dotkit', 'mpileaks'])
- module.module(parser, args)
- for item in module_files:
- assert os.path.exists(item)
+@pytest.mark.db
+@pytest.mark.parametrize('cli_args', [
+ ['libelf'],
+ ['--full-path', 'libelf']
+])
+def test_find(database, cli_args, module_type):
+ if module_type == 'lmod':
+ # TODO: Testing this with lmod requires mocking
+ # TODO: the core compilers
+ return
+
+ module(module_type, *(['find'] + cli_args))
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('database')
+@pytest.mark.regression('2215')
+def test_find_fails_on_multiple_matches():
+ # As we installed multiple versions of mpileaks, the command will
+ # fail because of multiple matches
+ out = module('tcl', 'find', 'mpileaks', fail_on_error=False)
+ assert module.returncode == 1
+ assert 'matches multiple packages' in out
+
+ # Passing multiple packages from the command line also results in the
+ # same failure
+ out = module(
+ 'tcl', 'find', 'mpileaks ^mpich', 'libelf', fail_on_error=False
+ )
+ assert module.returncode == 1
+ assert 'matches multiple packages' in out
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('database')
+@pytest.mark.regression('2570')
+def test_find_fails_on_non_existing_packages():
+ # Another way the command might fail is if the package does not exist
+ out = module('tcl', 'find', 'doesnotexist', fail_on_error=False)
+ assert module.returncode == 1
+ assert 'matches no package' in out
+
+
+@pytest.mark.db
+@pytest.mark.usefixtures('database')
+def test_find_recursive():
+ # If we call find without options it should return only one module
+ out = module('tcl', 'find', 'mpileaks ^zmpi')
+ assert len(out.split()) == 1
+
+ # If instead we call it with the recursive option the length should
+ # be greater
+ out = module('tcl', 'find', '-r', 'mpileaks ^zmpi')
+ assert len(out.split()) > 1
+
+
+# Needed to make the 'module_configuration' fixture below work
+writer_cls = spack.modules.lmod.LmodModulefileWriter
+
+
+@pytest.mark.db
+def test_setdefault_command(
+ mutable_database, module_configuration
+):
+ module_configuration('autoload_direct')
+
+ # Install two different versions of a package
+ other_spec, preferred = 'a@1.0', 'a@2.0'
+
+ spack.spec.Spec(other_spec).concretized().package.do_install(fake=True)
+ spack.spec.Spec(preferred).concretized().package.do_install(fake=True)
+
+ writers = {
+ preferred: writer_cls(spack.spec.Spec(preferred).concretized()),
+ other_spec: writer_cls(spack.spec.Spec(other_spec).concretized())
+ }
+
+ # Create two module files for the same software
+ module('lmod', 'refresh', '-y', '--delete-tree', preferred, other_spec)
+
+ # Assert initial directory state: no link and all module files present
+ link_name = os.path.join(
+ os.path.dirname(writers[preferred].layout.filename),
+ 'default'
+ )
+ for k in preferred, other_spec:
+ assert os.path.exists(writers[k].layout.filename)
+ assert not os.path.exists(link_name)
+
+ # Set the default to be the other spec
+ module('lmod', 'setdefault', other_spec)
+
+ # Check that a link named 'default' exists, and points to the right file
+ for k in preferred, other_spec:
+ assert os.path.exists(writers[k].layout.filename)
+ assert os.path.exists(link_name) and os.path.islink(link_name)
+ assert os.path.realpath(link_name) == writers[other_spec].layout.filename
+
+ # Reset the default to be the preferred spec
+ module('lmod', 'setdefault', preferred)
+
+ # Check that a link named 'default' exists, and points to the right file
+ for k in preferred, other_spec:
+ assert os.path.exists(writers[k].layout.filename)
+ assert os.path.exists(link_name) and os.path.islink(link_name)
+ assert os.path.realpath(link_name) == writers[preferred].layout.filename
diff --git a/lib/spack/spack/test/cmd/print_shell_vars.py b/lib/spack/spack/test/cmd/print_shell_vars.py
new file mode 100644
index 0000000000..3630c86a71
--- /dev/null
+++ b/lib/spack/spack/test/cmd/print_shell_vars.py
@@ -0,0 +1,46 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.main import print_setup_info
+
+
+def test_print_shell_vars_sh(capsys):
+ print_setup_info('sh')
+ out, _ = capsys.readouterr()
+
+ assert "_sp_sys_type=" in out
+ assert "_sp_tcl_root=" in out
+ assert "_sp_lmod_root=" in out
+ assert "_sp_module_prefix" not in out
+
+
+def test_print_shell_vars_csh(capsys):
+ print_setup_info('csh')
+ out, _ = capsys.readouterr()
+
+ assert "set _sp_sys_type = " in out
+ assert "set _sp_tcl_root = " in out
+ assert "set _sp_lmod_root = " in out
+ assert "set _sp_module_prefix = " not in out
+
+
+def test_print_shell_vars_sh_modules(capsys):
+ print_setup_info('sh', 'modules')
+ out, _ = capsys.readouterr()
+
+ assert "_sp_sys_type=" in out
+ assert "_sp_tcl_root=" in out
+ assert "_sp_lmod_root=" in out
+ assert "_sp_module_prefix=" in out
+
+
+def test_print_shell_vars_csh_modules(capsys):
+ print_setup_info('csh', 'modules')
+ out, _ = capsys.readouterr()
+
+ assert "set _sp_sys_type = " in out
+ assert "set _sp_tcl_root = " in out
+ assert "set _sp_lmod_root = " in out
+ assert "set _sp_module_prefix = " in out
diff --git a/lib/spack/spack/test/cmd/providers.py b/lib/spack/spack/test/cmd/providers.py
new file mode 100644
index 0000000000..f547607315
--- /dev/null
+++ b/lib/spack/spack/test/cmd/providers.py
@@ -0,0 +1,50 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
+import pytest
+
+from spack.main import SpackCommand
+
+providers = SpackCommand('providers')
+
+
+@pytest.mark.parametrize('pkg', [
+ ('mpi',),
+ ('mpi@2',),
+ ('mpi', 'lapack'),
+ ('',) # Lists all the available virtual packages
+])
+def test_it_just_runs(pkg):
+ providers(*pkg)
+
+
+@pytest.mark.parametrize('vpkg,provider_list', [
+ (('mpi',), ['intel-mpi',
+ 'intel-parallel-studio',
+ 'mpich',
+ 'mpich@1:',
+ 'mpich@3:',
+ 'mvapich2',
+ 'openmpi',
+ 'openmpi@1.6.5',
+ 'openmpi@1.7.5:',
+ 'openmpi@2.0.0:',
+ 'spectrum-mpi']),
+ (('D', 'awk'), ['ldc', 'gawk', 'mawk']) # Call 2 virtual packages at once
+])
+def test_provider_lists(vpkg, provider_list):
+ output = providers(*vpkg)
+ for item in provider_list:
+ assert item in output
+
+
+@pytest.mark.parametrize('pkg,error_cls', [
+ ('zlib', ValueError),
+ ('foo', ValueError) # Trying to call with a package that does not exist
+])
+def test_it_just_fails(pkg, error_cls):
+ with pytest.raises(error_cls):
+ providers(pkg)
diff --git a/lib/spack/spack/test/cmd/python.py b/lib/spack/spack/test/cmd/python.py
index 000535af8e..edfffb879c 100644
--- a/lib/spack/spack/test/cmd/python.py
+++ b/lib/spack/spack/test/cmd/python.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import spack
from spack.main import SpackCommand
@@ -30,4 +11,4 @@ python = SpackCommand('python')
def test_python():
out = python('-c', 'import spack; print(spack.spack_version)')
- assert out.strip() == str(spack.spack_version)
+ assert out.strip() == spack.spack_version
diff --git a/lib/spack/spack/test/cmd/spec.py b/lib/spack/spack/test/cmd/spec.py
new file mode 100644
index 0000000000..b67d2fd4d8
--- /dev/null
+++ b/lib/spack/spack/test/cmd/spec.py
@@ -0,0 +1,77 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import re
+import pytest
+
+import spack.spec
+from spack.main import SpackCommand
+
+pytestmark = pytest.mark.usefixtures('config', 'mutable_mock_packages')
+
+spec = SpackCommand('spec')
+
+
+def test_spec():
+ output = spec('mpileaks')
+
+ assert 'mpileaks@2.3' in output
+ assert 'callpath@1.0' in output
+ assert 'dyninst@8.2' in output
+ assert 'libdwarf@20130729' in output
+ assert 'libelf@0.8.1' in output
+ assert 'mpich@3.0.4' in output
+
+
+def test_spec_yaml():
+ output = spec('--yaml', 'mpileaks')
+
+ mpileaks = spack.spec.Spec.from_yaml(output)
+ assert 'mpileaks' in mpileaks
+ assert 'callpath' in mpileaks
+ assert 'dyninst' in mpileaks
+ assert 'libdwarf' in mpileaks
+ assert 'libelf' in mpileaks
+ assert 'mpich' in mpileaks
+
+
+def _parse_types(string):
+ """Parse deptypes for specs from `spack spec -t` output."""
+ lines = string.strip().split('\n')
+
+ result = {}
+ for line in lines:
+ match = re.match(r'\[([^]]*)\]\s*\^?([^@]*)@', line)
+ if match:
+ types, name = match.groups()
+ result.setdefault(name, []).append(types)
+ result[name] = sorted(result[name])
+ return result
+
+
+def test_spec_deptypes_nodes():
+ output = spec('--types', '--cover', 'nodes', 'dt-diamond')
+ types = _parse_types(output)
+
+ assert types['dt-diamond'] == [' ']
+ assert types['dt-diamond-left'] == ['bl ']
+ assert types['dt-diamond-right'] == ['bl ']
+ assert types['dt-diamond-bottom'] == ['blr ']
+
+
+def test_spec_deptypes_edges():
+ output = spec('--types', '--cover', 'edges', 'dt-diamond')
+ types = _parse_types(output)
+
+ assert types['dt-diamond'] == [' ']
+ assert types['dt-diamond-left'] == ['bl ']
+ assert types['dt-diamond-right'] == ['bl ']
+ assert types['dt-diamond-bottom'] == ['b ', 'blr ']
+
+
+def test_spec_returncode():
+ with pytest.raises(spack.main.SpackCommandError):
+ spec()
+ assert spec.returncode == 1
diff --git a/lib/spack/spack/test/cmd/test_compiler_cmd.py b/lib/spack/spack/test/cmd/test_compiler_cmd.py
index e7a2186344..3ef12769f4 100644
--- a/lib/spack/spack/test/cmd/test_compiler_cmd.py
+++ b/lib/spack/spack/test/cmd/test_compiler_cmd.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import llnl.util.filesystem
@@ -63,7 +44,7 @@ done
return str(tmpdir)
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestCompilerCommand(object):
def test_compiler_remove(self):
diff --git a/lib/spack/spack/test/cmd/uninstall.py b/lib/spack/spack/test/cmd/uninstall.py
index 096dfe74e4..1acf1ff20b 100644
--- a/lib/spack/spack/test/cmd/uninstall.py
+++ b/lib/spack/spack/test/cmd/uninstall.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.store
from spack.main import SpackCommand, SpackCommandError
@@ -39,19 +20,25 @@ class MockArgs(object):
self.yes_to_all = True
-def test_multiple_matches(database):
+@pytest.mark.db
+@pytest.mark.usefixtures('database')
+def test_multiple_matches():
"""Test unable to uninstall when multiple matches."""
with pytest.raises(SpackCommandError):
uninstall('-y', 'mpileaks')
-def test_installed_dependents(database):
+@pytest.mark.db
+@pytest.mark.usefixtures('database')
+def test_installed_dependents():
"""Test can't uninstall when ther are installed dependents."""
with pytest.raises(SpackCommandError):
uninstall('-y', 'libelf')
-def test_recursive_uninstall(database):
+@pytest.mark.db
+@pytest.mark.usefixtures('database')
+def test_recursive_uninstall():
"""Test recursive uninstall."""
uninstall('-y', '-a', '--dependents', 'callpath')
diff --git a/lib/spack/spack/test/cmd/url.py b/lib/spack/spack/test/cmd/url.py
index 84fcf90135..53f53a1b78 100644
--- a/lib/spack/spack/test/cmd/url.py
+++ b/lib/spack/spack/test/cmd/url.py
@@ -1,29 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
import pytest
+
+import spack.repo
from spack.url import UndetectableVersionError
from spack.main import SpackCommand
from spack.cmd.url import name_parsed_correctly, version_parsed_correctly
@@ -44,8 +27,9 @@ def test_name_parsed_correctly():
assert name_parsed_correctly(MyPackage('r-devtools', []), 'devtools')
assert name_parsed_correctly(MyPackage('py-numpy', []), 'numpy')
assert name_parsed_correctly(MyPackage('octave-splines', []), 'splines')
- assert name_parsed_correctly(MyPackage('imagemagick', []), 'ImageMagick') # noqa
assert name_parsed_correctly(MyPackage('th-data', []), 'TH.data')
+ assert name_parsed_correctly(
+ MyPackage('imagemagick', []), 'ImageMagick')
# Expected False
assert not name_parsed_correctly(MyPackage('', []), 'hdf5')
@@ -53,7 +37,8 @@ def test_name_parsed_correctly():
assert not name_parsed_correctly(MyPackage('yaml-cpp', []), 'yamlcpp')
assert not name_parsed_correctly(MyPackage('yamlcpp', []), 'yaml-cpp')
assert not name_parsed_correctly(MyPackage('r-py-parser', []), 'parser')
- assert not name_parsed_correctly(MyPackage('oce', []), 'oce-0.18.0') # noqa
+ assert not name_parsed_correctly(
+ MyPackage('oce', []), 'oce-0.18.0')
def test_version_parsed_correctly():
@@ -70,7 +55,8 @@ def test_version_parsed_correctly():
assert not version_parsed_correctly(MyPackage('', ['1.2.3']), '1.2.4')
assert not version_parsed_correctly(MyPackage('', ['3.4a']), '3.4')
assert not version_parsed_correctly(MyPackage('', ['3.4']), '3.4b')
- assert not version_parsed_correctly(MyPackage('', ['0.18.0']), 'oce-0.18.0') # noqa
+ assert not version_parsed_correctly(
+ MyPackage('', ['0.18.0']), 'oce-0.18.0')
def test_url_parse():
@@ -83,6 +69,7 @@ def test_url_with_no_version_fails():
url('parse', 'http://www.netlib.org/voronoi/triangle.zip')
+@pytest.mark.network
def test_url_list():
out = url('list')
total_urls = len(out.split('\n'))
@@ -112,14 +99,17 @@ def test_url_list():
assert 0 < correct_version_urls < total_urls
+@pytest.mark.network
def test_url_summary():
"""Test the URL summary command."""
# test url_summary, the internal function that does the work
(total_urls, correct_names, correct_versions,
name_count_dict, version_count_dict) = url_summary(None)
- assert 0 < correct_names <= sum(name_count_dict.values()) <= total_urls # noqa
- assert 0 < correct_versions <= sum(version_count_dict.values()) <= total_urls # noqa
+ assert (0 < correct_names <=
+ sum(name_count_dict.values()) <= total_urls)
+ assert (0 < correct_versions <=
+ sum(version_count_dict.values()) <= total_urls)
# make sure it agrees with the actual command.
out = url('summary')
@@ -134,3 +124,11 @@ def test_url_summary():
out_correct_versions = int(
re.search(r'Versions correctly parsed:\s*(\d+)', out).group(1))
assert out_correct_versions == correct_versions
+
+
+def test_url_stats(capfd):
+ with capfd.disabled():
+ output = url('stats')
+ npkgs = '%d packages' % len(spack.repo.all_package_names())
+ assert npkgs in output
+ assert 'total versions' in output
diff --git a/lib/spack/spack/test/cmd/versions.py b/lib/spack/spack/test/cmd/versions.py
new file mode 100644
index 0000000000..45b62a14d6
--- /dev/null
+++ b/lib/spack/spack/test/cmd/versions.py
@@ -0,0 +1,45 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import pytest
+
+from spack.main import SpackCommand
+
+versions = SpackCommand('versions')
+
+
+@pytest.mark.network
+def test_remote_versions():
+ """Test a package for which remote versions should be available."""
+
+ versions('zlib')
+
+
+@pytest.mark.network
+def test_no_versions():
+ """Test a package for which no remote versions are available."""
+
+ versions('converge')
+
+
+@pytest.mark.network
+def test_no_unchecksummed_versions():
+ """Test a package for which no unchecksummed versions are available."""
+
+ versions('bzip2')
+
+
+@pytest.mark.network
+def test_versions_no_url():
+ """Test a package with versions but without a ``url`` attribute."""
+
+ versions('graphviz')
+
+
+@pytest.mark.network
+def test_no_versions_no_url():
+ """Test a package without versions or a ``url`` attribute."""
+
+ versions('opengl')
diff --git a/lib/spack/spack/test/cmd/view.py b/lib/spack/spack/test/cmd/view.py
index 9ab3e528d2..df6d7b92cc 100644
--- a/lib/spack/spack/test/cmd/view.py
+++ b/lib/spack/spack/test/cmd/view.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from spack.main import SpackCommand
import os.path
import pytest
@@ -34,7 +15,7 @@ view = SpackCommand('view')
@pytest.mark.parametrize('cmd', ['hardlink', 'symlink', 'hard', 'add'])
def test_view_link_type(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery, cmd):
install('libdwarf')
viewpath = str(tmpdir.mkdir('view_{0}'.format(cmd)))
@@ -45,7 +26,7 @@ def test_view_link_type(
def test_view_external(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('externaltool')
viewpath = str(tmpdir.mkdir('view'))
@@ -54,7 +35,7 @@ def test_view_external(
def test_view_extension(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('extendee')
install('extension1@1.0')
@@ -80,7 +61,7 @@ def test_view_extension(
def test_view_extension_remove(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('extendee')
install('extension1@1.0')
@@ -99,7 +80,7 @@ def test_view_extension_remove(
def test_view_extension_conflict(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('extendee')
install('extension1@1.0')
@@ -111,7 +92,7 @@ def test_view_extension_conflict(
def test_view_extension_conflict_ignored(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('extendee')
install('extension1@1.0')
@@ -124,7 +105,7 @@ def test_view_extension_conflict_ignored(
def test_view_extension_global_activation(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('extendee')
install('extension1@1.0')
@@ -153,7 +134,7 @@ def test_view_extension_global_activation(
def test_view_extendee_with_global_activations(
- tmpdir, builtin_mock, mock_archive, mock_fetch, config,
+ tmpdir, mock_packages, mock_archive, mock_fetch, config,
install_mockery):
install('extendee')
install('extension1@1.0')
diff --git a/lib/spack/spack/test/compilers.py b/lib/spack/spack/test/compilers.py
index d172d56638..d7a1fa6743 100644
--- a/lib/spack/spack/test/compilers.py
+++ b/lib/spack/spack/test/compilers.py
@@ -1,52 +1,46 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import pytest
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from copy import copy
from six import iteritems
import spack.spec
import spack.compilers as compilers
+from spack.compiler import _get_versioned_tuple, Compiler
+
+def test_get_compiler_duplicates(config):
+ # In this case there is only one instance of the specified compiler in
+ # the test configuration (so it is not actually a duplicate), but the
+ # method behaves the same.
+ cfg_file_to_duplicates = compilers.get_compiler_duplicates(
+ 'gcc@4.5.0', spack.spec.ArchSpec('cray-CNL-xeon'))
-@pytest.mark.usefixtures('config')
-class TestCompilers(object):
+ assert len(cfg_file_to_duplicates) == 1
+ cfg_file, duplicates = next(iteritems(cfg_file_to_duplicates))
+ assert len(duplicates) == 1
- def test_get_compiler_duplicates(self):
- # In this case there is only one instance of the specified compiler in
- # the test configuration (so it is not actually a duplicate), but the
- # method behaves the same.
- cfg_file_to_duplicates = compilers.get_compiler_duplicates(
- 'gcc@4.5.0', spack.spec.ArchSpec('cray-CNL-xeon'))
- assert len(cfg_file_to_duplicates) == 1
- cfg_file, duplicates = next(iteritems(cfg_file_to_duplicates))
- assert len(duplicates) == 1
- def test_all_compilers(self):
- all_compilers = compilers.all_compilers()
- filtered = [x for x in all_compilers if str(x.spec) == 'clang@3.3']
- filtered = [x for x in filtered if x.operating_system == 'SuSE11']
- assert len(filtered) == 1
+def test_all_compilers(config):
+ all_compilers = compilers.all_compilers()
+ filtered = [x for x in all_compilers if str(x.spec) == 'clang@3.3']
+ filtered = [x for x in filtered if x.operating_system == 'SuSE11']
+ assert len(filtered) == 1
+
+
+def test_version_detection_is_empty():
+ no_version = lambda x: None
+ compiler_check_tuple = ('/usr/bin/gcc', '', r'\d\d', no_version)
+ assert not _get_versioned_tuple(compiler_check_tuple)
+
+
+def test_version_detection_is_successful():
+ version = lambda x: '4.9'
+ compiler_check_tuple = ('/usr/bin/gcc', '', r'\d\d', version)
+ assert _get_versioned_tuple(compiler_check_tuple) == (
+ '4.9', '', r'\d\d', '/usr/bin/gcc')
def test_compiler_flags_from_config_are_grouped():
@@ -67,3 +61,169 @@ def test_compiler_flags_from_config_are_grouped():
compiler = compilers.compiler_from_config_entry(compiler_entry)
assert any(x == '-foo-flag foo-val' for x in compiler.flags['cflags'])
+
+
+# Test behavior of flags and UnsupportedCompilerFlag.
+
+# Utility function to test most flags.
+default_compiler_entry = {
+ 'spec': 'clang@2.0.0-apple',
+ 'operating_system': 'foo-os',
+ 'paths': {
+ 'cc': 'cc-path',
+ 'cxx': 'cxx-path',
+ 'fc': None,
+ 'f77': None
+ },
+ 'flags': {},
+ 'modules': None
+}
+
+
+# Fake up a mock compiler where everything is defaulted.
+class MockCompiler(Compiler):
+ def __init__(self):
+ super(MockCompiler, self).__init__(
+ "badcompiler@1.0.0",
+ default_compiler_entry['operating_system'],
+ None,
+ [default_compiler_entry['paths']['cc'],
+ default_compiler_entry['paths']['cxx'],
+ default_compiler_entry['paths']['fc'],
+ default_compiler_entry['paths']['f77']])
+
+ @property
+ def name(self):
+ return "mockcompiler"
+
+ @property
+ def version(self):
+ return "1.0.0"
+
+
+# Get the desired flag from the specified compiler spec.
+def flag_value(flag, spec):
+ compiler = None
+ if spec is None:
+ compiler = MockCompiler()
+ else:
+ compiler_entry = copy(default_compiler_entry)
+ compiler_entry['spec'] = spec
+ # Disable faulty id()-based cache (issue #7647).
+ compilers._compiler_cache = {}
+ compiler = compilers.compiler_from_config_entry(compiler_entry)
+
+ return getattr(compiler, flag)
+
+
+# Utility function to verify that the expected exception is thrown for
+# an unsupported flag.
+def unsupported_flag_test(flag, spec=None):
+ caught_exception = None
+ try:
+ flag_value(flag, spec)
+ except spack.compiler.UnsupportedCompilerFlag:
+ caught_exception = True
+
+ assert(caught_exception and "Expected exception not thrown.")
+
+
+# Verify the expected flag value for the give compiler spec.
+def supported_flag_test(flag, flag_value_ref, spec=None):
+ assert(flag_value(flag, spec) == flag_value_ref)
+
+
+# Tests for UnsupportedCompilerFlag exceptions from default
+# implementations of flags.
+def test_default_flags():
+ unsupported_flag_test("openmp_flag")
+ unsupported_flag_test("cxx11_flag")
+ unsupported_flag_test("cxx14_flag")
+ unsupported_flag_test("cxx17_flag")
+ supported_flag_test("cxx98_flag", "")
+
+
+# Verify behavior of particular compiler definitions.
+def test_clang_flags():
+ # Common
+ supported_flag_test("pic_flag", "-fPIC", "gcc@4.0")
+
+ # Apple Clang.
+ unsupported_flag_test("openmp_flag", "clang@2.0.0-apple")
+ unsupported_flag_test("cxx11_flag", "clang@2.0.0-apple")
+ supported_flag_test("cxx11_flag", "-std=c++11", "clang@4.0.0-apple")
+ unsupported_flag_test("cxx14_flag", "clang@5.0.0-apple")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "clang@5.1.0-apple")
+ supported_flag_test("cxx14_flag", "-std=c++14", "clang@6.1.0-apple")
+ unsupported_flag_test("cxx17_flag", "clang@6.0.0-apple")
+ supported_flag_test("cxx17_flag", "-std=c++1z", "clang@6.1.0-apple")
+
+ # non-Apple Clang.
+ supported_flag_test("openmp_flag", "-fopenmp", "clang@3.3")
+ unsupported_flag_test("cxx11_flag", "clang@3.2")
+ supported_flag_test("cxx11_flag", "-std=c++11", "clang@3.3")
+ unsupported_flag_test("cxx14_flag", "clang@3.3")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "clang@3.4")
+ supported_flag_test("cxx14_flag", "-std=c++14", "clang@3.5")
+ unsupported_flag_test("cxx17_flag", "clang@3.4")
+ supported_flag_test("cxx17_flag", "-std=c++1z", "clang@3.5")
+ supported_flag_test("cxx17_flag", "-std=c++17", "clang@5.0")
+
+
+def test_cce_flags():
+ supported_flag_test("openmp_flag", "-h omp", "cce@1.0")
+ supported_flag_test("cxx11_flag", "-h std=c++11", "cce@1.0")
+ supported_flag_test("pic_flag", "-h PIC", "cce@1.0")
+
+
+def test_gcc_flags():
+ supported_flag_test("openmp_flag", "-fopenmp", "gcc@4.1")
+ supported_flag_test("cxx98_flag", "", "gcc@5.2")
+ supported_flag_test("cxx98_flag", "-std=c++98", "gcc@6.0")
+ unsupported_flag_test("cxx11_flag", "gcc@4.2")
+ supported_flag_test("cxx11_flag", "-std=c++0x", "gcc@4.3")
+ supported_flag_test("cxx11_flag", "-std=c++11", "gcc@4.7")
+ unsupported_flag_test("cxx14_flag", "gcc@4.7")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "gcc@4.8")
+ supported_flag_test("cxx14_flag", "-std=c++14", "gcc@4.9")
+ supported_flag_test("cxx14_flag", "", "gcc@6.0")
+ unsupported_flag_test("cxx17_flag", "gcc@4.9")
+ supported_flag_test("pic_flag", "-fPIC", "gcc@4.0")
+
+
+def test_intel_flags():
+ supported_flag_test("openmp_flag", "-openmp", "intel@15.0")
+ supported_flag_test("openmp_flag", "-qopenmp", "intel@16.0")
+ unsupported_flag_test("cxx11_flag", "intel@11.0")
+ supported_flag_test("cxx11_flag", "-std=c++0x", "intel@12.0")
+ supported_flag_test("cxx11_flag", "-std=c++11", "intel@13")
+ unsupported_flag_test("cxx14_flag", "intel@14.0")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "intel@15.0")
+ supported_flag_test("cxx14_flag", "-std=c++14", "intel@15.0.2")
+ supported_flag_test("pic_flag", "-fPIC", "intel@1.0")
+
+
+def test_nag_flags():
+ supported_flag_test("openmp_flag", "-openmp", "nag@1.0")
+ supported_flag_test("cxx11_flag", "-std=c++11", "nag@1.0")
+ supported_flag_test("pic_flag", "-PIC", "nag@1.0")
+
+
+def test_pgi_flags():
+ supported_flag_test("openmp_flag", "-mp", "pgi@1.0")
+ supported_flag_test("cxx11_flag", "-std=c++11", "pgi@1.0")
+ supported_flag_test("pic_flag", "-fpic", "pgi@1.0")
+
+
+def test_xl_flags():
+ supported_flag_test("openmp_flag", "-qsmp=omp", "xl@1.0")
+ unsupported_flag_test("cxx11_flag", "xl@13.0")
+ supported_flag_test("cxx11_flag", "-qlanglvl=extended0x", "xl@13.1")
+ supported_flag_test("pic_flag", "-qpic", "xl@1.0")
+
+
+def test_xl_r_flags():
+ supported_flag_test("openmp_flag", "-qsmp=omp", "xl_r@1.0")
+ unsupported_flag_test("cxx11_flag", "xl_r@13.0")
+ supported_flag_test("cxx11_flag", "-qlanglvl=extended0x", "xl_r@13.1")
+ supported_flag_test("pic_flag", "-qpic", "xl_r@1.0")
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index f0d5ae131f..d0574794b2 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -1,34 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
-import spack
+import llnl.util.lang
+
import spack.architecture
+import spack.repo
+
from spack.concretize import find_spec
from spack.spec import Spec, CompilerSpec
from spack.spec import ConflictsInSpecError, SpecError
from spack.version import ver
+from spack.test.conftest import MockPackage, MockPackageMultiRepo
def check_spec(abstract, concrete):
@@ -94,20 +79,7 @@ def spec(request):
return request.param
-@pytest.fixture(
- params=[
- 'conflict%clang',
- 'conflict%clang+foo',
- 'conflict-parent%clang',
- 'conflict-parent@0.9^conflict~foo'
- ]
-)
-def conflict_spec(request):
- """Spec to be concretized"""
- return request.param
-
-
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestConcretize(object):
def test_concretize(self, spec):
check_concretize(spec)
@@ -158,11 +130,20 @@ class TestConcretize(object):
concrete = check_concretize('mpileaks ^mpich2@1.3.1:1.4')
assert concrete['mpich2'].satisfies('mpich2@1.3.1:1.4')
+ def test_concretize_disable_compiler_existence_check(self):
+ with pytest.raises(spack.concretize.UnavailableCompilerVersionError):
+ check_concretize('dttop %gcc@100.100')
+
+ with spack.concretize.concretizer.disable_compiler_existence_check():
+ spec = check_concretize('dttop %gcc@100.100')
+ assert spec.satisfies('%gcc@100.100')
+ assert spec['dtlink3'].satisfies('%gcc@100.100')
+
def test_concretize_with_provides_when(self):
"""Make sure insufficient versions of MPI are not in providers list when
we ask for some advanced version.
"""
- repo = spack.repo
+ repo = spack.repo.path
assert not any(
s.satisfies('mpich2@:1.0') for s in repo.providers_for('mpi@2.1')
)
@@ -182,7 +163,7 @@ class TestConcretize(object):
def test_provides_handles_multiple_providers_of_same_vesrion(self):
"""
"""
- providers = spack.repo.providers_for('mpi@3.0')
+ providers = spack.repo.path.providers_for('mpi@3.0')
# Note that providers are repo-specific, so we don't misinterpret
# providers, but vdeps are not namespace-specific, so we can
@@ -203,6 +184,35 @@ class TestConcretize(object):
assert set(client.compiler_flags['fflags']) == set(['-O0'])
assert not set(cmake.compiler_flags['fflags'])
+ def test_architecture_inheritance(self):
+ """test_architecture_inheritance is likely to fail with an
+ UnavailableCompilerVersionError if the architecture is concretized
+ incorrectly.
+ """
+ spec = Spec('cmake-client %gcc@4.7.2 os=fe ^ cmake')
+ spec.concretize()
+ assert spec['cmake'].architecture == spec.architecture
+
+ def test_architecture_deep_inheritance(self):
+ """Make sure that indirect dependencies receive architecture
+ information from the root even when partial architecture information
+ is provided by an intermediate dependency.
+ """
+ default_dep = ('link', 'build')
+
+ bazpkg = MockPackage('bazpkg', [], [])
+ barpkg = MockPackage('barpkg', [bazpkg], [default_dep])
+ foopkg = MockPackage('foopkg', [barpkg], [default_dep])
+ mock_repo = MockPackageMultiRepo([foopkg, barpkg, bazpkg])
+
+ with spack.repo.swap(mock_repo):
+ spec = Spec('foopkg %clang@3.3 os=CNL target=footar' +
+ ' ^barpkg os=SuSE11 ^bazpkg os=be')
+ spec.concretize()
+
+ for s in spec.traverse(root=False):
+ assert s.architecture.target == spec.architecture.target
+
def test_compiler_flags_from_user_are_grouped(self):
spec = Spec('a%gcc cflags="-O -foo-flag foo-val" platform=test')
spec.concretize()
@@ -215,11 +225,12 @@ class TestConcretize(object):
assert s['mpi'].version == ver('1.10.3')
def test_concretize_two_virtuals(self):
+
"""Test a package with multiple virtual dependencies."""
Spec('hypre').concretize()
def test_concretize_two_virtuals_with_one_bound(
- self, refresh_builtin_mock
+ self, mutable_mock_packages
):
"""Test a package with multiple virtual dependencies and one preset."""
Spec('hypre ^openblas').concretize()
@@ -457,3 +468,44 @@ class TestConcretize(object):
s._concrete = False
assert not s.concrete
+
+ @pytest.mark.regression('7239')
+ def test_regression_issue_7239(self):
+ # Constructing a SpecBuildInterface from another SpecBuildInterface
+ # results in an inconsistent MRO
+
+ # Normal Spec
+ s = Spec('mpileaks')
+ s.concretize()
+
+ assert llnl.util.lang.ObjectWrapper not in type(s).__mro__
+
+ # Spec wrapped in a build interface
+ build_interface = s['mpileaks']
+ assert llnl.util.lang.ObjectWrapper in type(build_interface).__mro__
+
+ # Mimics asking the build interface from a build interface
+ build_interface = s['mpileaks']['mpileaks']
+ assert llnl.util.lang.ObjectWrapper in type(build_interface).__mro__
+
+ @pytest.mark.regression('7705')
+ def test_regression_issue_7705(self):
+ # spec.package.provides(name) doesn't account for conditional
+ # constraints in the concretized spec
+ s = Spec('simple-inheritance~openblas')
+ s.concretize()
+
+ assert not s.package.provides('lapack')
+
+ @pytest.mark.regression('7941')
+ def test_regression_issue_7941(self):
+ # The string representation of a spec containing
+ # an explicit multi-valued variant and a dependency
+ # might be parsed differently than the originating spec
+ s = Spec('a foobar=bar ^b')
+ t = Spec(str(s))
+
+ s.concretize()
+ t.concretize()
+
+ assert s.dag_hash() == t.dag_hash()
diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py
index 164b21e072..dbf2b828ce 100644
--- a/lib/spack/spack/test/concretize_preferences.py
+++ b/lib/spack/spack/test/concretize_preferences.py
@@ -1,50 +1,55 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
+import stat
-import spack
+import spack.package_prefs
+import spack.repo
import spack.util.spack_yaml as syaml
+from spack.config import ConfigScope, ConfigError
from spack.spec import Spec
-import spack.package_prefs
@pytest.fixture()
def concretize_scope(config, tmpdir):
"""Adds a scope for concretization preferences"""
tmpdir.ensure_dir('concretize')
- spack.config.ConfigScope(
- 'concretize', str(tmpdir.join('concretize'))
- )
+ config.push_scope(
+ ConfigScope('concretize', str(tmpdir.join('concretize'))))
+
yield
- # This is kind of weird, but that's how config scopes are
- # set in ConfigScope.__init__
- spack.config.config_scopes.pop('concretize')
+
+ config.pop_scope()
spack.package_prefs.PackagePrefs.clear_caches()
+ spack.repo.path._provider_index = None
- # reset provider index each time, too
- spack.repo._provider_index = None
+
+@pytest.fixture()
+def configure_permissions():
+ conf = syaml.load("""\
+all:
+ permissions:
+ read: group
+ write: group
+ group: all
+mpich:
+ permissions:
+ read: user
+ write: user
+mpileaks:
+ permissions:
+ write: user
+ group: mpileaks
+callpath:
+ permissions:
+ write: world
+""")
+ spack.config.set('packages', conf, scope='concretize')
+
+ yield
def concretize(abstract_spec):
@@ -54,7 +59,7 @@ def concretize(abstract_spec):
def update_packages(pkgname, section, value):
"""Update config and reread package list"""
conf = {pkgname: {section: value}}
- spack.config.update_config('packages', conf, 'concretize')
+ spack.config.set('packages', conf, scope='concretize')
spack.package_prefs.PackagePrefs.clear_caches()
@@ -64,7 +69,7 @@ def assert_variant_values(spec, **variants):
assert concrete.variants[variant].value == value
-@pytest.mark.usefixtures('concretize_scope', 'builtin_mock')
+@pytest.mark.usefixtures('concretize_scope', 'mock_packages')
class TestConcretizePreferences(object):
def test_preferred_variants(self):
"""Test preferred variants are applied correctly
@@ -80,7 +85,7 @@ class TestConcretizePreferences(object):
'mpileaks', debug=True, opt=True, shared=False, static=False
)
- def test_preferred_compilers(self, refresh_builtin_mock):
+ def test_preferred_compilers(self, mutable_mock_packages):
"""Test preferred compilers are applied correctly
"""
update_packages('mpileaks', 'compiler', ['clang@3.3'])
@@ -136,7 +141,7 @@ mpi:
paths:
mpi-with-lapack@2.1: /path/to/lapack
""")
- spack.config.update_config('packages', conf, 'concretize')
+ spack.config.set('packages', conf, scope='concretize')
# now when we get the packages.yaml config, there should be an error
with pytest.raises(spack.package_prefs.VirtualInPackagesYAMLError):
@@ -148,7 +153,7 @@ mpi:
all:
variants: [+mpi]
""")
- spack.config.update_config('packages', conf, 'concretize')
+ spack.config.set('packages', conf, scope='concretize')
# should be no error for 'all':
spack.package_prefs.PackagePrefs.clear_caches()
@@ -170,9 +175,56 @@ mpich:
paths:
mpich@3.0.4: /dummy/path
""")
- spack.config.update_config('packages', conf, 'concretize')
+ spack.config.set('packages', conf, scope='concretize')
# ensure that once config is in place, external is used
spec = Spec('mpi')
spec.concretize()
assert spec['mpich'].external_path == '/dummy/path'
+
+ def test_config_permissions_from_all(self, configure_permissions):
+ # Although these aren't strictly about concretization, they are
+ # configured in the same file and therefore convenient to test here.
+ # Make sure we can configure readable and writable
+
+ # Test inheriting from 'all'
+ spec = Spec('zmpi')
+ perms = spack.package_prefs.get_package_permissions(spec)
+ assert perms == stat.S_IRWXU | stat.S_IRWXG
+
+ dir_perms = spack.package_prefs.get_package_dir_permissions(spec)
+ assert dir_perms == stat.S_IRWXU | stat.S_IRWXG | stat.S_ISGID
+
+ group = spack.package_prefs.get_package_group(spec)
+ assert group == 'all'
+
+ def test_config_permissions_from_package(self, configure_permissions):
+ # Test overriding 'all'
+ spec = Spec('mpich')
+ perms = spack.package_prefs.get_package_permissions(spec)
+ assert perms == stat.S_IRWXU
+
+ dir_perms = spack.package_prefs.get_package_dir_permissions(spec)
+ assert dir_perms == stat.S_IRWXU
+
+ group = spack.package_prefs.get_package_group(spec)
+ assert group == 'all'
+
+ def test_config_permissions_differ_read_write(self, configure_permissions):
+ # Test overriding group from 'all' and different readable/writable
+ spec = Spec('mpileaks')
+ perms = spack.package_prefs.get_package_permissions(spec)
+ assert perms == stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP
+
+ dir_perms = spack.package_prefs.get_package_dir_permissions(spec)
+ expected = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_ISGID
+ assert dir_perms == expected
+
+ group = spack.package_prefs.get_package_group(spec)
+ assert group == 'mpileaks'
+
+ def test_config_perms_fail_write_gt_read(self, configure_permissions):
+ # Test failure for writable more permissive than readable
+ spec = Spec('callpath')
+ with pytest.raises(ConfigError):
+ spack.package_prefs.get_package_permissions(spec)
diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py
index 2b7a7a5c08..1235d57f30 100644
--- a/lib/spack/spack/test/config.py
+++ b/lib/spack/spack/test/config.py
@@ -1,40 +1,94 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
import collections
import getpass
-import os
import tempfile
+from six import StringIO
+
+from llnl.util.filesystem import touch, mkdirp
-import ordereddict_backport
import pytest
-import spack
+import ruamel.yaml as yaml
+
+import spack.paths
import spack.config
-import yaml
+import spack.schema.compilers
+import spack.schema.config
+import spack.schema.env
+import spack.schema.packages
+import spack.schema.mirrors
+import spack.schema.repos
+import spack.util.spack_yaml as syaml
from spack.util.path import canonicalize_path
-# Some sample compiler config data
+
+# sample config data
+config_low = {
+ 'config': {
+ 'install_tree': 'install_tree_path',
+ 'build_stage': ['path1', 'path2', 'path3']}}
+
+config_override_all = {
+ 'config:': {
+ 'install_tree:': 'override_all'}}
+
+config_override_key = {
+ 'config': {
+ 'install_tree:': 'override_key'}}
+
+config_merge_list = {
+ 'config': {
+ 'build_stage': ['patha', 'pathb']}}
+
+config_override_list = {
+ 'config': {
+ 'build_stage:': ['patha', 'pathb']}}
+
+
+@pytest.fixture()
+def write_config_file(tmpdir):
+ """Returns a function that writes a config file."""
+ def _write(config, data, scope):
+ config_yaml = tmpdir.join(scope, config + '.yaml')
+ config_yaml.ensure()
+ with config_yaml.open('w') as f:
+ yaml.dump(data, f)
+ return _write
+
+
+def check_compiler_config(comps, *compiler_names):
+ """Check that named compilers in comps match Spack's config."""
+ config = spack.config.get('compilers')
+ compiler_list = ['cc', 'cxx', 'f77', 'fc']
+ flag_list = ['cflags', 'cxxflags', 'fflags', 'cppflags',
+ 'ldflags', 'ldlibs']
+ param_list = ['modules', 'paths', 'spec', 'operating_system']
+ for compiler in config:
+ conf = compiler['compiler']
+ if conf['spec'] in compiler_names:
+ comp = next((c['compiler'] for c in comps if
+ c['compiler']['spec'] == conf['spec']), None)
+ if not comp:
+ raise ValueError('Bad config spec')
+ for p in param_list:
+ assert conf[p] == comp[p]
+ for f in flag_list:
+ expected = comp.get('flags', {}).get(f, None)
+ actual = conf.get('flags', {}).get(f, None)
+ assert expected == actual
+ for c in compiler_list:
+ expected = comp['paths'][c]
+ actual = conf['paths'][c]
+ assert expected == actual
+
+
+#
+# Some sample compiler config data and tests.
+#
a_comps = {
'compilers': [
{'compiler': {
@@ -139,240 +193,309 @@ b_comps = {
]
}
-# Some Sample repo data
+
+@pytest.fixture()
+def compiler_specs():
+ """Returns a couple of compiler specs needed for the tests"""
+ a = [ac['compiler']['spec'] for ac in a_comps['compilers']]
+ b = [bc['compiler']['spec'] for bc in b_comps['compilers']]
+ CompilerSpecs = collections.namedtuple('CompilerSpecs', ['a', 'b'])
+ return CompilerSpecs(a=a, b=b)
+
+
+def test_write_key_in_memory(mock_config, compiler_specs):
+ # Write b_comps "on top of" a_comps.
+ spack.config.set('compilers', a_comps['compilers'], scope='low')
+ spack.config.set('compilers', b_comps['compilers'], scope='high')
+
+ # Make sure the config looks how we expect.
+ check_compiler_config(a_comps['compilers'], *compiler_specs.a)
+ check_compiler_config(b_comps['compilers'], *compiler_specs.b)
+
+
+def test_write_key_to_disk(mock_config, compiler_specs):
+ # Write b_comps "on top of" a_comps.
+ spack.config.set('compilers', a_comps['compilers'], scope='low')
+ spack.config.set('compilers', b_comps['compilers'], scope='high')
+
+ # Clear caches so we're forced to read from disk.
+ spack.config.config.clear_caches()
+
+ # Same check again, to ensure consistency.
+ check_compiler_config(a_comps['compilers'], *compiler_specs.a)
+ check_compiler_config(b_comps['compilers'], *compiler_specs.b)
+
+
+def test_write_to_same_priority_file(mock_config, compiler_specs):
+ # Write b_comps in the same file as a_comps.
+ spack.config.set('compilers', a_comps['compilers'], scope='low')
+ spack.config.set('compilers', b_comps['compilers'], scope='low')
+
+ # Clear caches so we're forced to read from disk.
+ spack.config.config.clear_caches()
+
+ # Same check again, to ensure consistency.
+ check_compiler_config(a_comps['compilers'], *compiler_specs.a)
+ check_compiler_config(b_comps['compilers'], *compiler_specs.b)
+
+
+#
+# Sample repo data and tests
+#
repos_low = {'repos': ["/some/path"]}
repos_high = {'repos': ["/some/other/path"]}
-# sample config data
-config_low = {
- 'config': {
+# repos
+def test_write_list_in_memory(mock_config):
+ spack.config.set('repos', repos_low['repos'], scope='low')
+ spack.config.set('repos', repos_high['repos'], scope='high')
+
+ config = spack.config.get('repos')
+ assert config == repos_high['repos'] + repos_low['repos']
+
+
+def test_substitute_config_variables(mock_config):
+ prefix = spack.paths.prefix.lstrip('/')
+
+ assert os.path.join(
+ '/foo/bar/baz', prefix
+ ) == canonicalize_path('/foo/bar/baz/$spack')
+
+ assert os.path.join(
+ spack.paths.prefix, 'foo/bar/baz'
+ ) == canonicalize_path('$spack/foo/bar/baz/')
+
+ assert os.path.join(
+ '/foo/bar/baz', prefix, 'foo/bar/baz'
+ ) == canonicalize_path('/foo/bar/baz/$spack/foo/bar/baz/')
+
+ assert os.path.join(
+ '/foo/bar/baz', prefix
+ ) == canonicalize_path('/foo/bar/baz/${spack}')
+
+ assert os.path.join(
+ spack.paths.prefix, 'foo/bar/baz'
+ ) == canonicalize_path('${spack}/foo/bar/baz/')
+
+ assert os.path.join(
+ '/foo/bar/baz', prefix, 'foo/bar/baz'
+ ) == canonicalize_path('/foo/bar/baz/${spack}/foo/bar/baz/')
+
+ assert os.path.join(
+ '/foo/bar/baz', prefix, 'foo/bar/baz'
+ ) != canonicalize_path('/foo/bar/baz/${spack/foo/bar/baz/')
+
+
+packages_merge_low = {
+ 'packages': {
+ 'foo': {
+ 'variants': ['+v1']
+ },
+ 'bar': {
+ 'variants': ['+v2']
+ }
+ }
+}
+
+packages_merge_high = {
+ 'packages': {
+ 'foo': {
+ 'version': ['a']
+ },
+ 'bar': {
+ 'version': ['b'],
+ 'variants': ['+v3']
+ },
+ 'baz': {
+ 'version': ['c']
+ }
+ }
+}
+
+
+@pytest.mark.regression('7924')
+def test_merge_with_defaults(mock_config, write_config_file):
+ """This ensures that specified preferences merge with defaults as
+ expected. Originally all defaults were initialized with the
+ exact same object, which led to aliasing problems. Therefore
+ the test configs used here leave 'version' blank for multiple
+ packages in 'packages_merge_low'.
+ """
+ write_config_file('packages', packages_merge_low, 'low')
+ write_config_file('packages', packages_merge_high, 'high')
+ cfg = spack.config.get('packages')
+
+ assert cfg['foo']['version'] == ['a']
+ assert cfg['bar']['version'] == ['b']
+ assert cfg['baz']['version'] == ['c']
+
+
+def test_substitute_user(mock_config):
+ user = getpass.getuser()
+ assert '/foo/bar/' + user + '/baz' == canonicalize_path(
+ '/foo/bar/$user/baz'
+ )
+
+
+def test_substitute_tempdir(mock_config):
+ tempdir = tempfile.gettempdir()
+ assert tempdir == canonicalize_path('$tempdir')
+ assert tempdir + '/foo/bar/baz' == canonicalize_path(
+ '$tempdir/foo/bar/baz'
+ )
+
+
+def test_read_config(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ assert spack.config.get('config') == config_low['config']
+
+
+def test_read_config_override_all(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ write_config_file('config', config_override_all, 'high')
+ assert spack.config.get('config') == {
+ 'install_tree': 'override_all'
+ }
+
+
+def test_read_config_override_key(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ write_config_file('config', config_override_key, 'high')
+ assert spack.config.get('config') == {
+ 'install_tree': 'override_key',
+ 'build_stage': ['path1', 'path2', 'path3']
+ }
+
+
+def test_read_config_merge_list(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ write_config_file('config', config_merge_list, 'high')
+ assert spack.config.get('config') == {
'install_tree': 'install_tree_path',
- 'build_stage': ['path1', 'path2', 'path3']}}
+ 'build_stage': ['patha', 'pathb', 'path1', 'path2', 'path3']
+ }
-config_override_all = {
- 'config:': {
- 'install_tree:': 'override_all'}}
-config_override_key = {
- 'config': {
- 'install_tree:': 'override_key'}}
+def test_read_config_override_list(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ write_config_file('config', config_override_list, 'high')
+ assert spack.config.get('config') == {
+ 'install_tree': 'install_tree_path',
+ 'build_stage': ['patha', 'pathb']
+ }
-config_merge_list = {
- 'config': {
- 'build_stage': ['patha', 'pathb']}}
-config_override_list = {
- 'config': {
- 'build_stage:': ['patha', 'pathb']}}
+def test_internal_config_update(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ before = mock_config.get('config')
+ assert before['install_tree'] == 'install_tree_path'
-def check_compiler_config(comps, *compiler_names):
- """Check that named compilers in comps match Spack's config."""
- config = spack.config.get_config('compilers')
- compiler_list = ['cc', 'cxx', 'f77', 'fc']
- flag_list = ['cflags', 'cxxflags', 'fflags', 'cppflags',
- 'ldflags', 'ldlibs']
- param_list = ['modules', 'paths', 'spec', 'operating_system']
- for compiler in config:
- conf = compiler['compiler']
- if conf['spec'] in compiler_names:
- comp = next((c['compiler'] for c in comps if
- c['compiler']['spec'] == conf['spec']), None)
- if not comp:
- raise ValueError('Bad config spec')
- for p in param_list:
- assert conf[p] == comp[p]
- for f in flag_list:
- expected = comp.get('flags', {}).get(f, None)
- actual = conf.get('flags', {}).get(f, None)
- assert expected == actual
- for c in compiler_list:
- expected = comp['paths'][c]
- actual = conf['paths'][c]
- assert expected == actual
+ # add an internal configuration scope
+ scope = spack.config.InternalConfigScope('command_line')
+ assert 'InternalConfigScope' in repr(scope)
+ mock_config.push_scope(scope)
-@pytest.fixture()
-def config(tmpdir):
- """Mocks the configuration scope."""
- spack.config.clear_config_caches()
- real_scope = spack.config.config_scopes
- spack.config.config_scopes = ordereddict_backport.OrderedDict()
- for priority in ['low', 'high']:
- spack.config.ConfigScope(priority, str(tmpdir.join(priority)))
- Config = collections.namedtuple('Config', ['real', 'mock'])
- yield Config(real=real_scope, mock=spack.config.config_scopes)
- spack.config.config_scopes = real_scope
- spack.config.clear_config_caches()
+ command_config = mock_config.get('config', scope='command_line')
+ command_config['install_tree'] = 'foo/bar'
+ mock_config.set('config', command_config, scope='command_line')
-@pytest.fixture()
-def write_config_file(tmpdir):
- """Returns a function that writes a config file."""
- def _write(config, data, scope):
- config_yaml = tmpdir.join(scope, config + '.yaml')
- config_yaml.ensure()
- with config_yaml.open('w') as f:
- yaml.dump(data, f)
- return _write
+ after = mock_config.get('config')
+ assert after['install_tree'] == 'foo/bar'
-@pytest.fixture()
-def compiler_specs():
- """Returns a couple of compiler specs needed for the tests"""
- a = [ac['compiler']['spec'] for ac in a_comps['compilers']]
- b = [bc['compiler']['spec'] for bc in b_comps['compilers']]
- CompilerSpecs = collections.namedtuple('CompilerSpecs', ['a', 'b'])
- return CompilerSpecs(a=a, b=b)
+def test_internal_config_filename(mock_config, write_config_file):
+ write_config_file('config', config_low, 'low')
+ mock_config.push_scope(spack.config.InternalConfigScope('command_line'))
+ with pytest.raises(NotImplementedError):
+ mock_config.get_config_filename('command_line', 'config')
-@pytest.mark.usefixtures('config')
-class TestConfig(object):
-
- def test_write_list_in_memory(self):
- spack.config.update_config('repos', repos_low['repos'], scope='low')
- spack.config.update_config('repos', repos_high['repos'], scope='high')
-
- config = spack.config.get_config('repos')
- assert config == repos_high['repos'] + repos_low['repos']
-
- def test_write_key_in_memory(self, compiler_specs):
- # Write b_comps "on top of" a_comps.
- spack.config.update_config(
- 'compilers', a_comps['compilers'], scope='low'
- )
- spack.config.update_config(
- 'compilers', b_comps['compilers'], scope='high'
- )
- # Make sure the config looks how we expect.
- check_compiler_config(a_comps['compilers'], *compiler_specs.a)
- check_compiler_config(b_comps['compilers'], *compiler_specs.b)
-
- def test_write_key_to_disk(self, compiler_specs):
- # Write b_comps "on top of" a_comps.
- spack.config.update_config(
- 'compilers', a_comps['compilers'], scope='low'
- )
- spack.config.update_config(
- 'compilers', b_comps['compilers'], scope='high'
- )
- # Clear caches so we're forced to read from disk.
- spack.config.clear_config_caches()
- # Same check again, to ensure consistency.
- check_compiler_config(a_comps['compilers'], *compiler_specs.a)
- check_compiler_config(b_comps['compilers'], *compiler_specs.b)
-
- def test_write_to_same_priority_file(self, compiler_specs):
- # Write b_comps in the same file as a_comps.
- spack.config.update_config(
- 'compilers', a_comps['compilers'], scope='low'
- )
- spack.config.update_config(
- 'compilers', b_comps['compilers'], scope='low'
- )
- # Clear caches so we're forced to read from disk.
- spack.config.clear_config_caches()
- # Same check again, to ensure consistency.
- check_compiler_config(a_comps['compilers'], *compiler_specs.a)
- check_compiler_config(b_comps['compilers'], *compiler_specs.b)
-
- def check_canonical(self, var, expected):
- """Ensure that <expected> is substituted properly for <var> in strings
- containing <var> in various positions."""
- path = '/foo/bar/baz'
-
- self.assertEqual(canonicalize_path(var + path),
- expected + path)
-
- self.assertEqual(canonicalize_path(path + var),
- path + '/' + expected)
-
- self.assertEqual(canonicalize_path(path + var + path),
- expected + path)
-
- def test_substitute_config_variables(self):
- prefix = spack.prefix.lstrip('/')
-
- assert os.path.join(
- '/foo/bar/baz', prefix
- ) == canonicalize_path('/foo/bar/baz/$spack')
-
- assert os.path.join(
- spack.prefix, 'foo/bar/baz'
- ) == canonicalize_path('$spack/foo/bar/baz/')
-
- assert os.path.join(
- '/foo/bar/baz', prefix, 'foo/bar/baz'
- ) == canonicalize_path('/foo/bar/baz/$spack/foo/bar/baz/')
-
- assert os.path.join(
- '/foo/bar/baz', prefix
- ) == canonicalize_path('/foo/bar/baz/${spack}')
-
- assert os.path.join(
- spack.prefix, 'foo/bar/baz'
- ) == canonicalize_path('${spack}/foo/bar/baz/')
-
- assert os.path.join(
- '/foo/bar/baz', prefix, 'foo/bar/baz'
- ) == canonicalize_path('/foo/bar/baz/${spack}/foo/bar/baz/')
-
- assert os.path.join(
- '/foo/bar/baz', prefix, 'foo/bar/baz'
- ) != canonicalize_path('/foo/bar/baz/${spack/foo/bar/baz/')
-
- def test_substitute_user(self):
- user = getpass.getuser()
- assert '/foo/bar/' + user + '/baz' == canonicalize_path(
- '/foo/bar/$user/baz'
- )
-
- def test_substitute_tempdir(self):
- tempdir = tempfile.gettempdir()
- assert tempdir == canonicalize_path('$tempdir')
- assert tempdir + '/foo/bar/baz' == canonicalize_path(
- '$tempdir/foo/bar/baz'
- )
-
- def test_read_config(self, write_config_file):
- write_config_file('config', config_low, 'low')
- assert spack.config.get_config('config') == config_low['config']
-
- def test_read_config_override_all(self, write_config_file):
- write_config_file('config', config_low, 'low')
- write_config_file('config', config_override_all, 'high')
- assert spack.config.get_config('config') == {
- 'install_tree': 'override_all'
- }
- def test_read_config_override_key(self, write_config_file):
- write_config_file('config', config_low, 'low')
- write_config_file('config', config_override_key, 'high')
- assert spack.config.get_config('config') == {
- 'install_tree': 'override_key',
- 'build_stage': ['path1', 'path2', 'path3']
+def test_mark_internal():
+ data = {
+ 'config': {
+ 'bool': False,
+ 'int': 6,
+ 'numbers': [1, 2, 3],
+ 'string': 'foo',
+ 'dict': {
+ 'more_numbers': [1, 2, 3],
+ 'another_string': 'foo',
+ 'another_int': 7,
+ }
}
+ }
+
+ marked = spack.config._mark_internal(data, 'x')
+
+ # marked version should be equal to the original
+ assert data == marked
+
+ def assert_marked(obj):
+ if type(obj) is bool:
+ return # can't subclass bool, so can't mark it
+
+ assert hasattr(obj, '_start_mark') and obj._start_mark.name == 'x'
+ assert hasattr(obj, '_end_mark') and obj._end_mark.name == 'x'
+
+ # everything in the marked version should have marks
+ checks = (marked.keys(), marked.values(),
+ marked['config'].keys(), marked['config'].values(),
+ marked['config']['numbers'],
+ marked['config']['dict'].keys(),
+ marked['config']['dict'].values(),
+ marked['config']['dict']['more_numbers'])
- def test_read_config_merge_list(self, write_config_file):
- write_config_file('config', config_low, 'low')
- write_config_file('config', config_merge_list, 'high')
- assert spack.config.get_config('config') == {
- 'install_tree': 'install_tree_path',
- 'build_stage': ['patha', 'pathb', 'path1', 'path2', 'path3']
+ for seq in checks:
+ for obj in seq:
+ assert_marked(obj)
+
+
+def test_internal_config_from_data():
+ config = spack.config.Configuration()
+
+ # add an internal config initialized from an inline dict
+ config.push_scope(spack.config.InternalConfigScope('_builtin', {
+ 'config': {
+ 'verify_ssl': False,
+ 'build_jobs': 6,
}
+ }))
- def test_read_config_override_list(self, write_config_file):
- write_config_file('config', config_low, 'low')
- write_config_file('config', config_override_list, 'high')
- assert spack.config.get_config('config') == {
- 'install_tree': 'install_tree_path',
- 'build_stage': ['patha', 'pathb']
+ assert config.get('config:verify_ssl', scope='_builtin') is False
+ assert config.get('config:build_jobs', scope='_builtin') == 6
+
+ assert config.get('config:verify_ssl') is False
+ assert config.get('config:build_jobs') == 6
+
+ # push one on top and see what happens.
+ config.push_scope(spack.config.InternalConfigScope('higher', {
+ 'config': {
+ 'checksum': True,
+ 'verify_ssl': True,
}
+ }))
+ assert config.get('config:verify_ssl', scope='_builtin') is False
+ assert config.get('config:build_jobs', scope='_builtin') == 6
-def test_keys_are_ordered():
+ assert config.get('config:verify_ssl', scope='higher') is True
+ assert config.get('config:build_jobs', scope='higher') is None
+ assert config.get('config:verify_ssl') is True
+ assert config.get('config:build_jobs') == 6
+ assert config.get('config:checksum') is True
+
+ assert config.get('config:checksum', scope='_builtin') is None
+ assert config.get('config:checksum', scope='higher') is True
+
+
+def test_keys_are_ordered():
+ """Test that keys in Spack YAML files retain their order from the file."""
expected_order = (
'bin',
'man',
@@ -388,7 +511,7 @@ def test_keys_are_ordered():
config_scope = spack.config.ConfigScope(
'modules',
- os.path.join(spack.test_path, 'data', 'config')
+ os.path.join(spack.paths.test_path, 'data', 'config')
)
data = config_scope.get_section('modules')
@@ -397,3 +520,242 @@ def test_keys_are_ordered():
for actual, expected in zip(prefix_inspections, expected_order):
assert actual == expected
+
+
+def test_config_format_error(mutable_config):
+ """This is raised when we try to write a bad configuration."""
+ with pytest.raises(spack.config.ConfigFormatError):
+ spack.config.set('compilers', {'bad': 'data'}, scope='site')
+
+
+def get_config_error(filename, schema, yaml_string):
+ """Parse a YAML string and return the resulting ConfigFormatError.
+
+ Fail if there is no ConfigFormatError
+ """
+ with open(filename, 'w') as f:
+ f.write(yaml_string)
+
+ # parse and return error, or fail.
+ try:
+ spack.config._read_config_file(filename, schema)
+ except spack.config.ConfigFormatError as e:
+ return e
+ else:
+ pytest.fail('ConfigFormatError was not raised!')
+
+
+def test_config_parse_dict_in_list(tmpdir):
+ with tmpdir.as_cwd():
+ e = get_config_error(
+ 'repos.yaml', spack.schema.repos.schema, """\
+repos:
+- https://foobar.com/foo
+- https://foobar.com/bar
+- error:
+ - abcdef
+- https://foobar.com/baz
+""")
+ assert "repos.yaml:4" in str(e)
+
+
+def test_config_parse_str_not_bool(tmpdir):
+ with tmpdir.as_cwd():
+ e = get_config_error(
+ 'config.yaml', spack.schema.config.schema, """\
+config:
+ verify_ssl: False
+ checksum: foobar
+ dirty: True
+""")
+ assert "config.yaml:3" in str(e)
+
+
+def test_config_parse_list_in_dict(tmpdir):
+ with tmpdir.as_cwd():
+ e = get_config_error(
+ 'mirrors.yaml', spack.schema.mirrors.schema, """\
+mirrors:
+ foo: http://foobar.com/baz
+ bar: http://barbaz.com/foo
+ baz: http://bazfoo.com/bar
+ travis: [1, 2, 3]
+""")
+ assert "mirrors.yaml:5" in str(e)
+
+
+def test_bad_config_section(mock_config):
+ """Test that getting or setting a bad section gives an error."""
+ with pytest.raises(spack.config.ConfigSectionError):
+ spack.config.set('foobar', 'foobar')
+
+ with pytest.raises(spack.config.ConfigSectionError):
+ spack.config.get('foobar')
+
+
+def test_bad_command_line_scopes(tmpdir, mock_config):
+ cfg = spack.config.Configuration()
+
+ with tmpdir.as_cwd():
+ with pytest.raises(spack.config.ConfigError):
+ spack.config._add_command_line_scopes(cfg, ['bad_path'])
+
+ touch('unreadable_file')
+ with pytest.raises(spack.config.ConfigError):
+ spack.config._add_command_line_scopes(cfg, ['unreadable_file'])
+
+ mkdirp('unreadable_dir')
+ with pytest.raises(spack.config.ConfigError):
+ try:
+ os.chmod('unreadable_dir', 0)
+ spack.config._add_command_line_scopes(cfg, ['unreadable_dir'])
+ finally:
+ os.chmod('unreadable_dir', 0o700) # so tmpdir can be removed
+
+
+def test_add_command_line_scopes(tmpdir, mutable_config):
+ config_yaml = str(tmpdir.join('config.yaml'))
+ with open(config_yaml, 'w') as f:
+ f.write("""\
+config:
+ verify_ssl: False
+ dirty: False
+""")
+
+ spack.config._add_command_line_scopes(mutable_config, [str(tmpdir)])
+
+
+def test_immutable_scope(tmpdir):
+ config_yaml = str(tmpdir.join('config.yaml'))
+ with open(config_yaml, 'w') as f:
+ f.write("""\
+config:
+ install_tree: dummy_tree_value
+""")
+ scope = spack.config.ImmutableConfigScope('test', str(tmpdir))
+
+ data = scope.get_section('config')
+ assert data['config']['install_tree'] == 'dummy_tree_value'
+
+ with pytest.raises(spack.config.ConfigError):
+ scope.write_section('config')
+
+
+def test_single_file_scope(tmpdir, config):
+ env_yaml = str(tmpdir.join("env.yaml"))
+ with open(env_yaml, 'w') as f:
+ f.write("""\
+env:
+ config:
+ verify_ssl: False
+ dirty: False
+ packages:
+ libelf:
+ compiler: [ 'gcc@4.5.3' ]
+ repos:
+ - /x/y/z
+""")
+
+ scope = spack.config.SingleFileScope(
+ 'env', env_yaml, spack.schema.env.schema, ['env'])
+
+ with spack.config.override(scope):
+ # from the single-file config
+ assert spack.config.get('config:verify_ssl') is False
+ assert spack.config.get('config:dirty') is False
+ assert spack.config.get('packages:libelf:compiler') == ['gcc@4.5.3']
+
+ # from the lower config scopes
+ assert spack.config.get('config:checksum') is True
+ assert spack.config.get('config:checksum') is True
+ assert spack.config.get('packages:externalmodule:buildable') is False
+ assert spack.config.get('repos') == [
+ '/x/y/z', '$spack/var/spack/repos/builtin']
+
+
+def check_schema(name, file_contents):
+ """Check a Spack YAML schema against some data"""
+ f = StringIO(file_contents)
+ data = syaml.load(f)
+ spack.config._validate(data, name)
+
+
+def test_good_env_yaml(tmpdir):
+ check_schema(spack.schema.env.schema, """\
+spack:
+ config:
+ verify_ssl: False
+ dirty: False
+ repos:
+ - ~/my/repo/location
+ mirrors:
+ remote: /foo/bar/baz
+ compilers:
+ - compiler:
+ spec: cce@2.1
+ operating_system: cnl
+ modules: []
+ paths:
+ cc: /path/to/cc
+ cxx: /path/to/cxx
+ fc: /path/to/fc
+ f77: /path/to/f77
+""")
+
+
+def test_bad_env_yaml(tmpdir):
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.env.schema, """\
+env:
+ foobar:
+ verify_ssl: False
+ dirty: False
+""")
+
+
+def test_bad_config_yaml(tmpdir):
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.config.schema, """\
+config:
+ verify_ssl: False
+ module_roots:
+ fmod: /some/fake/location
+""")
+
+
+def test_bad_mirrors_yaml(tmpdir):
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.mirrors.schema, """\
+mirrors:
+ local: True
+""")
+
+
+def test_bad_repos_yaml(tmpdir):
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.repos.schema, """\
+repos:
+ True
+""")
+
+
+def test_bad_compilers_yaml(tmpdir):
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.compilers.schema, """\
+compilers:
+ key_instead_of_list: 'value'
+""")
+
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.compilers.schema, """\
+compilers:
+ - shmompiler:
+ environment: /bad/value
+""")
+
+ with pytest.raises(spack.config.ConfigFormatError):
+ check_schema(spack.schema.compilers.schema, """\
+compilers:
+ - compiler:
+ fenfironfent: /bad/value
+""")
diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py
index 5ac4de1851..ad0644da3e 100644
--- a/lib/spack/spack/test/conftest.py
+++ b/lib/spack/spack/test/conftest.py
@@ -1,49 +1,35 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import collections
import copy
+import inspect
import os
+import os.path
import shutil
import re
import ordereddict_backport
-
import py
import pytest
+import ruamel.yaml as yaml
from llnl.util.filesystem import remove_linked_tree
-import spack
import spack.architecture
+import spack.config
+import spack.caches
import spack.database
import spack.directory_layout
+import spack.environment as ev
+import spack.paths
import spack.platforms.test
-import spack.repository
+import spack.repo
import spack.stage
import spack.util.executable
-import spack.util.pattern
+from spack.util.pattern import Bunch
from spack.dependency import Dependency
from spack.package import PackageBase
from spack.fetch_strategy import FetchStrategyComposite, URLFetchStrategy
@@ -53,6 +39,53 @@ from spack.version import Version
#
+# Disable any activate Spack environment BEFORE all tests
+#
+@pytest.fixture(scope='session', autouse=True)
+def clean_user_environment():
+ env_var = ev.spack_env_var in os.environ
+ active = ev._active_environment
+
+ if env_var:
+ spack_env_value = os.environ.pop(ev.spack_env_var)
+ if active:
+ ev.deactivate()
+
+ yield
+
+ if env_var:
+ os.environ[ev.spack_env_var] = spack_env_value
+ if active:
+ ev.activate(active)
+
+
+# Hooks to add command line options or set other custom behaviors.
+# They must be placed here to be found by pytest. See:
+#
+# https://docs.pytest.org/en/latest/writing_plugins.html
+#
+def pytest_addoption(parser):
+ group = parser.getgroup("Spack specific command line options")
+ group.addoption(
+ '--fast', action='store_true', default=False,
+ help='runs only "fast" unit tests, instead of the whole suite')
+
+
+def pytest_collection_modifyitems(config, items):
+ if not config.getoption('--fast'):
+ # --fast not given, run all the tests
+ return
+
+ slow_tests = ['db', 'network', 'maybeslow']
+ skip_as_slow = pytest.mark.skip(
+ reason='skipped slow test [--fast command line option given]'
+ )
+ for item in items:
+ if any(x in item.keywords for x in slow_tests):
+ item.add_marker(skip_as_slow)
+
+
+#
# These fixtures are applied to all tests
#
@pytest.fixture(scope='function', autouse=True)
@@ -77,11 +110,11 @@ def no_chdir():
@pytest.fixture(scope='session', autouse=True)
def mock_stage(tmpdir_factory):
"""Mocks up a fake stage directory for use by tests."""
- stage_path = spack.stage_path
+ stage_path = spack.paths.stage_path
new_stage = str(tmpdir_factory.mktemp('mock_stage'))
- spack.stage_path = new_stage
+ spack.paths.stage_path = new_stage
yield new_stage
- spack.stage_path = stage_path
+ spack.paths.stage_path = stage_path
@pytest.fixture(scope='session')
@@ -118,14 +151,14 @@ def check_for_leftover_stage_files(request, mock_stage, _ignore_stage_files):
yield
files_in_stage = set()
- if os.path.exists(spack.stage_path):
+ if os.path.exists(spack.paths.stage_path):
files_in_stage = set(
- os.listdir(spack.stage_path)) - _ignore_stage_files
+ os.listdir(spack.paths.stage_path)) - _ignore_stage_files
if 'disable_clean_stage_check' in request.keywords:
# clean up after tests that are expected to be dirty
for f in files_in_stage:
- path = os.path.join(spack.stage_path, f)
+ path = os.path.join(spack.paths.stage_path, f)
remove_whatever_it_is(path)
else:
_ignore_stage_files |= files_in_stage
@@ -134,14 +167,14 @@ def check_for_leftover_stage_files(request, mock_stage, _ignore_stage_files):
@pytest.fixture(autouse=True)
def mock_fetch_cache(monkeypatch):
- """Substitutes spack.fetch_cache with a mock object that does nothing
+ """Substitutes spack.paths.fetch_cache with a mock object that does nothing
and raises on fetch.
"""
class MockCache(object):
- def store(self, copyCmd, relativeDst):
+ def store(self, copy_cmd, relative_dest):
pass
- def fetcher(self, targetPath, digest, **kwargs):
+ def fetcher(self, target_path, digest, **kwargs):
return MockCacheFetcher()
class MockCacheFetcher(object):
@@ -154,7 +187,7 @@ def mock_fetch_cache(monkeypatch):
def __str__(self):
return "[mock fetch cache]"
- monkeypatch.setattr(spack, 'fetch_cache', MockCache())
+ monkeypatch.setattr(spack.caches, 'fetch_cache', MockCache())
# FIXME: The lines below should better be added to a fixture with
@@ -171,27 +204,23 @@ spack.architecture.platform = lambda: spack.platforms.test.Test()
@pytest.fixture(scope='session')
def repo_path():
"""Session scoped RepoPath object pointing to the mock repository"""
- return spack.repository.RepoPath(spack.mock_packages_path)
+ return spack.repo.RepoPath(spack.paths.mock_packages_path)
@pytest.fixture(scope='module')
-def builtin_mock(repo_path):
- """Uses the 'builtin.mock' repository instead of 'builtin'"""
+def mock_packages(repo_path):
+ """Use the 'builtin.mock' repository instead of 'builtin'"""
mock_repo = copy.deepcopy(repo_path)
- spack.repo.swap(mock_repo)
- BuiltinMock = collections.namedtuple('BuiltinMock', ['real', 'mock'])
- # Confusing, but we swapped above
- yield BuiltinMock(real=mock_repo, mock=spack.repo)
- spack.repo.swap(mock_repo)
+ with spack.repo.swap(mock_repo):
+ yield
-@pytest.fixture()
-def refresh_builtin_mock(builtin_mock, repo_path):
- """Refreshes the state of spack.repo"""
- # Get back the real repository
+@pytest.fixture(scope='function')
+def mutable_mock_packages(mock_packages, repo_path):
+ """Function-scoped mock packages, for tests that need to modify them."""
mock_repo = copy.deepcopy(repo_path)
- spack.repo.swap(mock_repo)
- return builtin_mock
+ with spack.repo.swap(mock_repo):
+ yield
@pytest.fixture(scope='session')
@@ -215,17 +244,23 @@ def configuration_dir(tmpdir_factory, linux_os):
directory path.
"""
tmpdir = tmpdir_factory.mktemp('configurations')
+
# Name of the yaml files in the test/data folder
- test_path = py.path.local(spack.test_path)
+ test_path = py.path.local(spack.paths.test_path)
compilers_yaml = test_path.join('data', 'compilers.yaml')
packages_yaml = test_path.join('data', 'packages.yaml')
config_yaml = test_path.join('data', 'config.yaml')
+ repos_yaml = test_path.join('data', 'repos.yaml')
+
# Create temporary 'site' and 'user' folders
tmpdir.ensure('site', dir=True)
tmpdir.ensure('user', dir=True)
+
# Copy the configurations that don't need further work
packages_yaml.copy(tmpdir.join('site', 'packages.yaml'))
config_yaml.copy(tmpdir.join('site', 'config.yaml'))
+ repos_yaml.copy(tmpdir.join('site', 'repos.yaml'))
+
# Write the one that needs modifications
content = ''.join(compilers_yaml.read()).format(linux_os)
t = tmpdir.join('site', 'compilers.yaml')
@@ -238,149 +273,143 @@ def config(configuration_dir):
"""Hooks the mock configuration files into spack.config"""
# Set up a mock config scope
spack.package_prefs.PackagePrefs.clear_caches()
- spack.config.clear_config_caches()
- real_scope = spack.config.config_scopes
- spack.config.config_scopes = ordereddict_backport.OrderedDict()
- spack.config.ConfigScope('site', str(configuration_dir.join('site')))
- spack.config.ConfigScope('system', str(configuration_dir.join('system')))
- spack.config.ConfigScope('user', str(configuration_dir.join('user')))
- Config = collections.namedtuple('Config', ['real', 'mock'])
-
- yield Config(real=real_scope, mock=spack.config.config_scopes)
-
- spack.config.config_scopes = real_scope
- spack.config.clear_config_caches()
+
+ real_configuration = spack.config.config
+
+ test_scopes = [
+ spack.config.ConfigScope(name, str(configuration_dir.join(name)))
+ for name in ['site', 'system', 'user']]
+ test_scopes.append(spack.config.InternalConfigScope('command_line'))
+
+ spack.config.config = spack.config.Configuration(*test_scopes)
+
+ yield spack.config.config
+
+ spack.config.config = real_configuration
spack.package_prefs.PackagePrefs.clear_caches()
-@pytest.fixture(scope='module')
-def database(tmpdir_factory, builtin_mock, config):
- """Creates a mock database with some packages installed note that
- the ref count for dyninst here will be 3, as it's recycled
- across each install.
- """
+@pytest.fixture(scope='function')
+def mutable_config(tmpdir_factory, configuration_dir, config):
+ """Like config, but tests can modify the configuration."""
+ spack.package_prefs.PackagePrefs.clear_caches()
- # Here is what the mock DB looks like:
- #
- # o mpileaks o mpileaks' o mpileaks''
- # |\ |\ |\
- # | o callpath | o callpath' | o callpath''
- # |/| |/| |/|
- # o | mpich o | mpich2 o | zmpi
- # | | o | fake
- # | | |
- # | |______________/
- # | .____________/
- # |/
- # o dyninst
- # |\
- # | o libdwarf
- # |/
- # o libelf
+ mutable_dir = tmpdir_factory.mktemp('mutable_config').join('tmp')
+ configuration_dir.copy(mutable_dir)
- # Make a fake install directory
- install_path = tmpdir_factory.mktemp('install_for_database')
- spack_install_path = spack.store.root
+ real_configuration = spack.config.config
- spack.store.root = str(install_path)
- install_layout = spack.directory_layout.YamlDirectoryLayout(
- str(install_path))
- spack_install_layout = spack.store.layout
- spack.store.layout = install_layout
+ spack.config.config = spack.config.Configuration(
+ *[spack.config.ConfigScope(name, str(mutable_dir))
+ for name in ['site', 'system', 'user']])
- # Make fake database and fake install directory.
- install_db = spack.database.Database(str(install_path))
- spack_install_db = spack.store.db
- spack.store.db = install_db
+ yield spack.config.config
- Entry = collections.namedtuple('Entry', ['path', 'layout', 'db'])
- Database = collections.namedtuple(
- 'Database', ['real', 'mock', 'install', 'uninstall', 'refresh'])
+ spack.config.config = real_configuration
+ spack.package_prefs.PackagePrefs.clear_caches()
- real = Entry(
- path=spack_install_path,
- layout=spack_install_layout,
- db=spack_install_db)
- mock = Entry(path=install_path, layout=install_layout, db=install_db)
+@pytest.fixture()
+def mock_config(tmpdir):
+ """Mocks two configuration scopes: 'low' and 'high'."""
+ real_configuration = spack.config.config
+
+ spack.config.config = spack.config.Configuration(
+ *[spack.config.ConfigScope(name, str(tmpdir.join(name)))
+ for name in ['low', 'high']])
+
+ yield spack.config.config
+
+ spack.config.config = real_configuration
+
+
+def _populate(mock_db):
+ r"""Populate a mock database with packages.
+
+ Here is what the mock DB looks like:
+
+ o mpileaks o mpileaks' o mpileaks''
+ |\ |\ |\
+ | o callpath | o callpath' | o callpath''
+ |/| |/| |/|
+ o | mpich o | mpich2 o | zmpi
+ | | o | fake
+ | | |
+ | |______________/
+ | .____________/
+ |/
+ o dyninst
+ |\
+ | o libdwarf
+ |/
+ o libelf
+ """
def _install(spec):
- s = spack.spec.Spec(spec)
- s.concretize()
+ s = spack.spec.Spec(spec).concretized()
pkg = spack.repo.get(s)
- pkg.do_install(fake=True)
-
- def _uninstall(spec):
- spec.package.do_uninstall(spec)
-
- def _refresh():
- with spack.store.db.write_transaction():
- for spec in spack.store.db.query():
- _uninstall(spec)
- _install('mpileaks ^mpich')
- _install('mpileaks ^mpich2')
- _install('mpileaks ^zmpi')
- _install('externaltest')
-
- t = Database(
- real=real,
- mock=mock,
- install=_install,
- uninstall=_uninstall,
- refresh=_refresh)
+ pkg.do_install(fake=True, explicit=True)
# Transaction used to avoid repeated writes.
- with spack.store.db.write_transaction():
- t.install('mpileaks ^mpich')
- t.install('mpileaks ^mpich2')
- t.install('mpileaks ^zmpi')
- t.install('externaltest')
+ with mock_db.write_transaction():
+ _install('mpileaks ^mpich')
+ _install('mpileaks ^mpich2')
+ _install('mpileaks ^zmpi')
+ _install('externaltest')
- yield t
- with spack.store.db.write_transaction():
- for spec in spack.store.db.query():
+@pytest.fixture(scope='module')
+def database(tmpdir_factory, mock_packages, config):
+ """Creates a mock database with some packages installed note that
+ the ref count for dyninst here will be 3, as it's recycled
+ across each install.
+ """
+ # save the real store
+ real_store = spack.store.store
+
+ # Make a fake install directory
+ install_path = tmpdir_factory.mktemp('install_for_database')
+
+ # Make fake store (database and install layout)
+ tmp_store = spack.store.Store(str(install_path))
+ spack.store.store = tmp_store
+
+ _populate(tmp_store.db)
+
+ yield tmp_store.db
+
+ with tmp_store.db.write_transaction():
+ for spec in tmp_store.db.query():
if spec.package.installed:
- t.uninstall(spec)
+ PackageBase.uninstall_by_spec(spec, force=True)
else:
- spack.store.db.remove(spec)
+ tmp_store.db.remove(spec)
install_path.remove(rec=1)
- spack.store.root = spack_install_path
- spack.store.layout = spack_install_layout
- spack.store.db = spack_install_db
+ spack.store.store = real_store
-@pytest.fixture()
-def refresh_db_on_exit(database):
- """"Restores the state of the database after a test."""
- yield
- database.refresh()
+@pytest.fixture(scope='function')
+def mutable_database(database):
+ """For tests that need to modify the database instance."""
+ yield database
+ with database.write_transaction():
+ for spec in spack.store.db.query():
+ PackageBase.uninstall_by_spec(spec, force=True)
+ _populate(database)
-@pytest.fixture()
-def install_mockery(tmpdir, config, builtin_mock):
+@pytest.fixture(scope='function')
+def install_mockery(tmpdir, config, mock_packages):
"""Hooks a fake install directory, DB, and stage directory into Spack."""
- layout = spack.store.layout
- extensions = spack.store.extensions
- db = spack.store.db
- new_opt = str(tmpdir.join('opt'))
-
- # Use a fake install directory to avoid conflicts bt/w
- # installed pkgs and mock packages.
- spack.store.layout = spack.directory_layout.YamlDirectoryLayout(new_opt)
- spack.store.extensions = spack.directory_layout.YamlExtensionsLayout(
- new_opt, spack.store.layout)
- spack.store.db = spack.database.Database(new_opt)
-
- # We use a fake package, so skip the checksum.
- spack.do_checksum = False
- yield
- # Turn checksumming back on
- spack.do_checksum = True
- # Restore Spack's layout.
- spack.store.layout = layout
- spack.store.extensions = extensions
- spack.store.db = db
+ real_store = spack.store.store
+ spack.store.store = spack.store.Store(str(tmpdir.join('opt')))
+
+ # We use a fake package, so temporarily disable checksumming
+ with spack.config.override('config:checksum', False):
+ yield
+
+ tmpdir.join('opt').remove()
+ spack.store.store = real_store
@pytest.fixture()
@@ -399,6 +428,45 @@ def mock_fetch(mock_archive):
PackageBase.fetcher = orig_fn
+@pytest.fixture()
+def module_configuration(monkeypatch, request):
+ """Reads the module configuration file from the mock ones prepared
+ for tests and monkeypatches the right classes to hook it in.
+ """
+ # Class of the module file writer
+ writer_cls = getattr(request.module, 'writer_cls')
+ # Module where the module file writer is defined
+ writer_mod = inspect.getmodule(writer_cls)
+ # Key for specific settings relative to this module type
+ writer_key = str(writer_mod.__name__).split('.')[-1]
+ # Root folder for configuration
+ root_for_conf = os.path.join(
+ spack.paths.test_path, 'data', 'modules', writer_key
+ )
+
+ def _impl(filename):
+
+ file = os.path.join(root_for_conf, filename + '.yaml')
+ with open(file) as f:
+ configuration = yaml.load(f)
+
+ monkeypatch.setattr(
+ spack.modules.common,
+ 'configuration',
+ configuration
+ )
+ monkeypatch.setattr(
+ writer_mod,
+ 'configuration',
+ configuration[writer_key]
+ )
+ monkeypatch.setattr(
+ writer_mod,
+ 'configuration_registry',
+ {}
+ )
+ return _impl
+
##########
# Fake archives and repositories
##########
@@ -503,7 +571,6 @@ def mock_git_repository(tmpdir_factory):
r1 = rev_hash(branch)
r1_file = branch_file
- Bunch = spack.util.pattern.Bunch
checks = {
'master': Bunch(
revision='master', file=r0_file, args={'git': str(repodir)}
@@ -556,7 +623,6 @@ def mock_hg_repository(tmpdir_factory):
hg('commit', '-m' 'revision 1', '-u', 'test')
r1 = get_rev()
- Bunch = spack.util.pattern.Bunch
checks = {
'default': Bunch(
revision=r1, file=r1_file, args={'hg': str(repodir)}
@@ -613,7 +679,6 @@ def mock_svn_repository(tmpdir_factory):
r0 = '1'
r1 = '2'
- Bunch = spack.util.pattern.Bunch
checks = {
'default': Bunch(
revision=r1, file=r1_file, args={'svn': url}),
@@ -634,6 +699,15 @@ def mock_svn_repository(tmpdir_factory):
yield t
+@pytest.fixture()
+def mutable_mock_env_path(tmpdir_factory):
+ """Fixture for mocking the internal spack environments directory."""
+ saved_path = spack.environment.env_path
+ spack.environment.env_path = str(tmpdir_factory.mktemp('mock-env-path'))
+ yield spack.environment.env_path
+ spack.environment.env_path = saved_path
+
+
##########
# Mock packages
##########
@@ -652,7 +726,11 @@ class MockPackage(object):
if not conditions or dep.name not in conditions:
self.dependencies[dep.name] = {Spec(name): d}
else:
- self.dependencies[dep.name] = {Spec(conditions[dep.name]): d}
+ dep_conditions = conditions[dep.name]
+ dep_conditions = dict(
+ (Spec(x), Dependency(self, Spec(y), type=dtype))
+ for x, y in dep_conditions.items())
+ self.dependencies[dep.name] = dep_conditions
if versions:
self.versions = versions
@@ -690,3 +768,33 @@ class MockPackageMultiRepo(object):
import collections
Repo = collections.namedtuple('Repo', ['namespace'])
return Repo('mockrepo')
+
+##########
+# Specs of various kind
+##########
+
+
+@pytest.fixture(
+ params=[
+ 'conflict%clang',
+ 'conflict%clang+foo',
+ 'conflict-parent%clang',
+ 'conflict-parent@0.9^conflict~foo'
+ ]
+)
+def conflict_spec(request):
+ """Specs which violate constraints specified with the "conflicts"
+ directive in the "conflict" package.
+ """
+ return request.param
+
+
+@pytest.fixture(
+ params=[
+ 'conflict%~'
+ ]
+)
+def invalid_spec(request):
+ """Specs that do not parse cleanly due to invalid formatting.
+ """
+ return request.param
diff --git a/lib/spack/spack/test/data/config.yaml b/lib/spack/spack/test/data/config.yaml
index ab925f4f6b..2fcd10ad97 100644
--- a/lib/spack/spack/test/data/config.yaml
+++ b/lib/spack/spack/test/data/config.yaml
@@ -1,7 +1,7 @@
config:
install_tree: $spack/opt/spack
template_dirs:
- - $spack/templates
+ - $spack/share/spack/templates
- $spack/lib/spack/spack/test/data/templates
- $spack/lib/spack/spack/test/data/templates_again
build_stage:
diff --git a/lib/spack/spack/test/data/directory_search/a/foobar.txt b/lib/spack/spack/test/data/directory_search/a/foobar.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/spack/spack/test/data/directory_search/a/foobar.txt
diff --git a/lib/spack/spack/test/data/directory_search/b/bar.txp b/lib/spack/spack/test/data/directory_search/b/bar.txp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/spack/spack/test/data/directory_search/b/bar.txp
diff --git a/lib/spack/spack/test/data/directory_search/c/bar.txt b/lib/spack/spack/test/data/directory_search/c/bar.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/spack/spack/test/data/directory_search/c/bar.txt
diff --git a/lib/spack/spack/test/data/make/affirmative/capital_makefile/Makefile b/lib/spack/spack/test/data/make/affirmative/capital_makefile/Makefile
new file mode 100644
index 0000000000..a580687aa0
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/capital_makefile/Makefile
@@ -0,0 +1,3 @@
+# Tests that Spack checks for Makefile
+
+check:
diff --git a/lib/spack/spack/test/data/make/affirmative/check_test/Makefile b/lib/spack/spack/test/data/make/affirmative/check_test/Makefile
new file mode 100644
index 0000000000..bbd931b84c
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/check_test/Makefile
@@ -0,0 +1,3 @@
+# Tests that Spack detects target when it is the first of two targets
+
+check test:
diff --git a/lib/spack/spack/test/data/make/affirmative/expansion/Makefile b/lib/spack/spack/test/data/make/affirmative/expansion/Makefile
new file mode 100644
index 0000000000..e73101f01a
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/expansion/Makefile
@@ -0,0 +1,5 @@
+# Tests that Spack can handle variable expansion targets
+
+TARGETS = check
+
+$(TARGETS):
diff --git a/lib/spack/spack/test/data/make/affirmative/gnu_makefile/GNUmakefile b/lib/spack/spack/test/data/make/affirmative/gnu_makefile/GNUmakefile
new file mode 100644
index 0000000000..77ea4d0972
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/gnu_makefile/GNUmakefile
@@ -0,0 +1,3 @@
+# Tests that Spack checks for GNUmakefile
+
+check:
diff --git a/lib/spack/spack/test/data/make/affirmative/include/Makefile b/lib/spack/spack/test/data/make/affirmative/include/Makefile
new file mode 100644
index 0000000000..f24ab957cb
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/include/Makefile
@@ -0,0 +1,3 @@
+# Tests that Spack detects targets in include files
+
+include make.mk
diff --git a/lib/spack/spack/test/data/make/affirmative/include/make.mk b/lib/spack/spack/test/data/make/affirmative/include/make.mk
new file mode 100644
index 0000000000..76e4478aae
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/include/make.mk
@@ -0,0 +1 @@
+check:
diff --git a/lib/spack/spack/test/data/make/affirmative/lowercase_makefile/makefile b/lib/spack/spack/test/data/make/affirmative/lowercase_makefile/makefile
new file mode 100644
index 0000000000..942f8ab96e
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/lowercase_makefile/makefile
@@ -0,0 +1,3 @@
+# Tests that Spack checks for makefile
+
+check:
diff --git a/lib/spack/spack/test/data/make/affirmative/prerequisites/Makefile b/lib/spack/spack/test/data/make/affirmative/prerequisites/Makefile
new file mode 100644
index 0000000000..22b42f3f83
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/prerequisites/Makefile
@@ -0,0 +1,5 @@
+# Tests that Spack detects a target even if it is followed by prerequisites
+
+check: check-recursive
+
+check-recursive:
diff --git a/lib/spack/spack/test/data/make/affirmative/spaces/Makefile b/lib/spack/spack/test/data/make/affirmative/spaces/Makefile
new file mode 100644
index 0000000000..c9b5d4d920
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/spaces/Makefile
@@ -0,0 +1,3 @@
+# Tests that Spack allows spaces following the target name
+
+check :
diff --git a/lib/spack/spack/test/data/make/affirmative/test_check/Makefile b/lib/spack/spack/test/data/make/affirmative/test_check/Makefile
new file mode 100644
index 0000000000..5924d7d702
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/test_check/Makefile
@@ -0,0 +1,3 @@
+# Tests that Spack detects target when it is the second of two targets
+
+test check:
diff --git a/lib/spack/spack/test/data/make/affirmative/three_targets/Makefile b/lib/spack/spack/test/data/make/affirmative/three_targets/Makefile
new file mode 100644
index 0000000000..96d7eff3af
--- /dev/null
+++ b/lib/spack/spack/test/data/make/affirmative/three_targets/Makefile
@@ -0,0 +1,3 @@
+# Tests that Spack detects a target if it is in the middle of a list
+
+foo check bar:
diff --git a/lib/spack/spack/test/data/make/negative/no_makefile/readme.txt b/lib/spack/spack/test/data/make/negative/no_makefile/readme.txt
new file mode 100644
index 0000000000..836ad0edb6
--- /dev/null
+++ b/lib/spack/spack/test/data/make/negative/no_makefile/readme.txt
@@ -0,0 +1,3 @@
+# Tests that Spack ignores directories without a Makefile
+
+check:
diff --git a/lib/spack/spack/test/data/make/negative/partial_match/Makefile b/lib/spack/spack/test/data/make/negative/partial_match/Makefile
new file mode 100644
index 0000000000..ea315731eb
--- /dev/null
+++ b/lib/spack/spack/test/data/make/negative/partial_match/Makefile
@@ -0,0 +1,11 @@
+# Tests that Spack ignores targets that contain a partial match
+
+checkinstall:
+
+installcheck:
+
+foo-check-bar:
+
+foo_check_bar:
+
+foo/check/bar:
diff --git a/lib/spack/spack/test/data/make/negative/variable/Makefile b/lib/spack/spack/test/data/make/negative/variable/Makefile
new file mode 100644
index 0000000000..586aea18dc
--- /dev/null
+++ b/lib/spack/spack/test/data/make/negative/variable/Makefile
@@ -0,0 +1,5 @@
+# Tests that Spack ignores variable definitions
+
+check = FOO
+
+check := BAR
diff --git a/lib/spack/spack/test/data/modules/lmod/module_path_separator.yaml b/lib/spack/spack/test/data/modules/lmod/module_path_separator.yaml
new file mode 100644
index 0000000000..208554968f
--- /dev/null
+++ b/lib/spack/spack/test/data/modules/lmod/module_path_separator.yaml
@@ -0,0 +1,5 @@
+enable:
+ - lmod
+lmod:
+ core_compilers:
+ - 'clang@3.3'
diff --git a/lib/spack/spack/test/data/modules/tcl/autoload_with_constraints.yaml b/lib/spack/spack/test/data/modules/tcl/autoload_with_constraints.yaml
new file mode 100644
index 0000000000..52796cad5b
--- /dev/null
+++ b/lib/spack/spack/test/data/modules/tcl/autoload_with_constraints.yaml
@@ -0,0 +1,8 @@
+enable:
+ - tcl
+tcl:
+ ^mpich2:
+ autoload: 'direct'
+
+ ^python:
+ autoload: 'direct'
diff --git a/lib/spack/spack/test/data/modules/tcl/blacklist_implicits.yaml b/lib/spack/spack/test/data/modules/tcl/blacklist_implicits.yaml
new file mode 100644
index 0000000000..4d5fbfb04a
--- /dev/null
+++ b/lib/spack/spack/test/data/modules/tcl/blacklist_implicits.yaml
@@ -0,0 +1,6 @@
+enable:
+ - tcl
+tcl:
+ blacklist_implicits: true
+ all:
+ autoload: 'direct'
diff --git a/lib/spack/spack/test/data/ninja/.gitignore b/lib/spack/spack/test/data/ninja/.gitignore
new file mode 100644
index 0000000000..50e58f24cc
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/.gitignore
@@ -0,0 +1,2 @@
+.ninja_deps
+.ninja_log
diff --git a/lib/spack/spack/test/data/ninja/affirmative/check_test/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/check_test/build.ninja
new file mode 100644
index 0000000000..e3af305dbe
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/check_test/build.ninja
@@ -0,0 +1,6 @@
+# Tests that Spack detects target when it is the first of two targets
+
+rule cc
+ command = true
+
+build check test: cc
diff --git a/lib/spack/spack/test/data/ninja/affirmative/include/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/include/build.ninja
new file mode 100644
index 0000000000..c9ce4e61a6
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/include/build.ninja
@@ -0,0 +1,3 @@
+# Tests that Spack can handle targets in include files
+
+include include.ninja
diff --git a/lib/spack/spack/test/data/ninja/affirmative/include/include.ninja b/lib/spack/spack/test/data/ninja/affirmative/include/include.ninja
new file mode 100644
index 0000000000..8a0d0f7c1d
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/include/include.ninja
@@ -0,0 +1,4 @@
+rule cc
+ command = true
+
+build check: cc
diff --git a/lib/spack/spack/test/data/ninja/affirmative/simple/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/simple/build.ninja
new file mode 100644
index 0000000000..f002938b10
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/simple/build.ninja
@@ -0,0 +1,6 @@
+# Tests that Spack can handle a simple Ninja build script
+
+rule cc
+ command = true
+
+build check: cc
diff --git a/lib/spack/spack/test/data/ninja/affirmative/spaces/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/spaces/build.ninja
new file mode 100644
index 0000000000..dd59a9932f
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/spaces/build.ninja
@@ -0,0 +1,6 @@
+# Tests that Spack allows spaces following the target name
+
+rule cc
+ command = true
+
+build check : cc
diff --git a/lib/spack/spack/test/data/ninja/affirmative/subninja/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/subninja/build.ninja
new file mode 100644
index 0000000000..19ef7e3509
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/subninja/build.ninja
@@ -0,0 +1,3 @@
+# Tests that Spack can handle targets in subninja files
+
+subninja subninja.ninja
diff --git a/lib/spack/spack/test/data/ninja/affirmative/subninja/subninja.ninja b/lib/spack/spack/test/data/ninja/affirmative/subninja/subninja.ninja
new file mode 100644
index 0000000000..8a0d0f7c1d
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/subninja/subninja.ninja
@@ -0,0 +1,4 @@
+rule cc
+ command = true
+
+build check: cc
diff --git a/lib/spack/spack/test/data/ninja/affirmative/test_check/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/test_check/build.ninja
new file mode 100644
index 0000000000..6a3cd0b0ff
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/test_check/build.ninja
@@ -0,0 +1,6 @@
+# Tests that Spack detects target when it is the second of two targets
+
+rule cc
+ command = true
+
+build test check: cc
diff --git a/lib/spack/spack/test/data/ninja/affirmative/three_targets/build.ninja b/lib/spack/spack/test/data/ninja/affirmative/three_targets/build.ninja
new file mode 100644
index 0000000000..bf9e14ed0b
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/affirmative/three_targets/build.ninja
@@ -0,0 +1,6 @@
+# Tests that Spack detects a target if it is in the middle of a list
+
+rule cc
+ command = true
+
+build foo check bar: cc
diff --git a/lib/spack/spack/test/data/ninja/negative/no_ninja/readme.txt b/lib/spack/spack/test/data/ninja/negative/no_ninja/readme.txt
new file mode 100644
index 0000000000..0a85aa7af8
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/negative/no_ninja/readme.txt
@@ -0,0 +1,8 @@
+# Tests that Spack ignores directories without a Ninja build script
+
+cflags = -Wall
+
+rule cc
+ command = gcc $cflags -c $in -o $out
+
+build check: cc foo.c
diff --git a/lib/spack/spack/test/data/ninja/negative/partial_match/build.ninja b/lib/spack/spack/test/data/ninja/negative/partial_match/build.ninja
new file mode 100644
index 0000000000..12efb5839a
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/negative/partial_match/build.ninja
@@ -0,0 +1,16 @@
+# Tests that Spack ignores targets that contain a partial match
+
+cflags = -Wall
+
+rule cc
+ command = gcc $cflags -c $in -o $out
+
+build installcheck: cc foo.c
+
+build checkinstall: cc foo.c
+
+build foo-check-bar: cc foo.c
+
+build foo_check_bar: cc foo.c
+
+build foo/check/bar: cc foo.c
diff --git a/lib/spack/spack/test/data/ninja/negative/rule/build.ninja b/lib/spack/spack/test/data/ninja/negative/rule/build.ninja
new file mode 100644
index 0000000000..2164bda6d9
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/negative/rule/build.ninja
@@ -0,0 +1,8 @@
+# Tests that Spack ignores rule names
+
+cflags = -Wall
+
+rule check
+ command = gcc $cflags -c $in -o $out
+
+build foo: check foo.c
diff --git a/lib/spack/spack/test/data/ninja/negative/variable/build.ninja b/lib/spack/spack/test/data/ninja/negative/variable/build.ninja
new file mode 100644
index 0000000000..73aafbf5bd
--- /dev/null
+++ b/lib/spack/spack/test/data/ninja/negative/variable/build.ninja
@@ -0,0 +1,8 @@
+# Tests that Spack ignores variable definitions
+
+check = -Wall
+
+rule cc
+ command = gcc $check -c $in -o $out
+
+build foo: cc foo.c
diff --git a/lib/spack/spack/test/data/packages.yaml b/lib/spack/spack/test/data/packages.yaml
index 923d63173a..c7256ddb33 100644
--- a/lib/spack/spack/test/data/packages.yaml
+++ b/lib/spack/spack/test/data/packages.yaml
@@ -3,6 +3,7 @@ packages:
buildable: False
paths:
externaltool@1.0%gcc@4.5.0: /path/to/external_tool
+ externaltool@0.9%gcc@4.5.0: /usr
externalvirtual:
buildable: False
paths:
diff --git a/lib/spack/spack/test/data/repos.yaml b/lib/spack/spack/test/data/repos.yaml
new file mode 100644
index 0000000000..4fbbfe9d62
--- /dev/null
+++ b/lib/spack/spack/test/data/repos.yaml
@@ -0,0 +1,2 @@
+repos:
+ - $spack/var/spack/repos/builtin
diff --git a/lib/spack/spack/test/data/sourceme_first.sh b/lib/spack/spack/test/data/sourceme_first.sh
index 7adf35e137..c9c8103816 100644
--- a/lib/spack/spack/test/data/sourceme_first.sh
+++ b/lib/spack/spack/test/data/sourceme_first.sh
@@ -1,29 +1,11 @@
#!/usr/bin/env bash
-
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
export NEW_VAR='new'
export UNSET_ME='overridden'
diff --git a/lib/spack/spack/test/data/sourceme_parameters.sh b/lib/spack/spack/test/data/sourceme_parameters.sh
index 8b60e944b3..1c63e06cd0 100644
--- a/lib/spack/spack/test/data/sourceme_parameters.sh
+++ b/lib/spack/spack/test/data/sourceme_parameters.sh
@@ -1,29 +1,11 @@
#!/usr/bin/env bash
-
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
if [[ "$1" == "intel64" ]] ; then
export FOO='intel64'
diff --git a/lib/spack/spack/test/data/sourceme_second.sh b/lib/spack/spack/test/data/sourceme_second.sh
index 37059707f8..bec2619e0d 100644
--- a/lib/spack/spack/test/data/sourceme_second.sh
+++ b/lib/spack/spack/test/data/sourceme_second.sh
@@ -1,29 +1,11 @@
#!/usr/bin/env bash
-
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
export PATH_LIST='/path/first:/path/second:/path/fourth'
unset EMPTY_PATH_LIST
diff --git a/lib/spack/spack/test/data/sourceme_unicode.sh b/lib/spack/spack/test/data/sourceme_unicode.sh
index b602dadbbc..61bfa19b90 100644
--- a/lib/spack/spack/test/data/sourceme_unicode.sh
+++ b/lib/spack/spack/test/data/sourceme_unicode.sh
@@ -1,29 +1,11 @@
#!/usr/bin/env bash
-
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
# Set an environment variable with some unicode in it to ensure that
# Spack can decode it.
diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py
index 72ae6ad278..cc469301a8 100644
--- a/lib/spack/spack/test/database.py
+++ b/lib/spack/spack/test/database.py
@@ -1,43 +1,46 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
These tests check the database is functioning properly,
both in memory and in its file
"""
+import datetime
+import functools
import multiprocessing
import os
import pytest
from llnl.util.tty.colify import colify
-import spack
+import spack.repo
import spack.store
from spack.test.conftest import MockPackageMultiRepo
from spack.util.executable import Executable
+pytestmark = pytest.mark.db
+
+
+@pytest.fixture()
+def usr_folder_exists(monkeypatch):
+ """The ``/usr`` folder is assumed to be existing in some tests. This
+ fixture makes it such that its existence is mocked, so we have no
+ requirements on the system running tests.
+ """
+ isdir = os.path.isdir
+
+ @functools.wraps(os.path.isdir)
+ def mock_isdir(path):
+ if path == '/usr':
+ return True
+ return isdir(path)
+
+ monkeypatch.setattr(os.path, 'isdir', mock_isdir)
+
+
def _print_ref_counts():
"""Print out all ref counts for the graph used here, for debugging"""
recs = []
@@ -87,10 +90,10 @@ def _check_merkleiness():
assert seen[hash_key] == id(dep)
-def _check_db_sanity(install_db):
+def _check_db_sanity(database):
"""Utiilty function to check db against install layout."""
pkg_in_layout = sorted(spack.store.layout.all_specs())
- actual = sorted(install_db.query())
+ actual = sorted(database.query())
externals = sorted([x for x in actual if x.external])
nexpected = len(pkg_in_layout) + len(externals)
@@ -105,6 +108,36 @@ def _check_db_sanity(install_db):
_check_merkleiness()
+def _check_remove_and_add_package(database, spec):
+ """Remove a spec from the DB, then add it and make sure everything's
+ still ok once it is added. This checks that it was
+ removed, that it's back when added again, and that ref
+ counts are consistent.
+ """
+ original = database.query()
+ database._check_ref_counts()
+
+ # Remove spec
+ concrete_spec = database.remove(spec)
+ database._check_ref_counts()
+ remaining = database.query()
+
+ # ensure spec we removed is gone
+ assert len(original) - 1 == len(remaining)
+ assert all(s in original for s in remaining)
+ assert concrete_spec not in remaining
+
+ # add it back and make sure everything is ok.
+ database.add(concrete_spec, spack.store.layout)
+ installed = database.query()
+ assert concrete_spec in installed
+ assert installed == original
+
+ # sanity check against direcory layout and check ref counts.
+ _check_db_sanity(database)
+ database._check_ref_counts()
+
+
def _mock_install(spec):
s = spack.spec.Spec(spec)
s.concretize()
@@ -120,28 +153,49 @@ def _mock_remove(spec):
def test_default_queries(database):
- install_db = database.mock.db
- rec = install_db.get_record('zmpi')
+ # Testing a package whose name *doesn't* start with 'lib'
+ # to ensure the library has 'lib' prepended to the name
+ rec = database.get_record('zmpi')
spec = rec.spec
libraries = spec['zmpi'].libs
assert len(libraries) == 1
+ assert libraries.names[0] == 'zmpi'
headers = spec['zmpi'].headers
assert len(headers) == 1
+ assert headers.names[0] == 'zmpi'
command = spec['zmpi'].command
assert isinstance(command, Executable)
assert command.name == 'zmpi'
assert os.path.exists(command.path)
+ # Testing a package whose name *does* start with 'lib'
+ # to ensure the library doesn't have a double 'lib' prefix
+ rec = database.get_record('libelf')
+
+ spec = rec.spec
+
+ libraries = spec['libelf'].libs
+ assert len(libraries) == 1
+ assert libraries.names[0] == 'elf'
+
+ headers = spec['libelf'].headers
+ assert len(headers) == 1
+ assert headers.names[0] == 'libelf'
+
+ command = spec['libelf'].command
+ assert isinstance(command, Executable)
+ assert command.name == 'libelf'
+ assert os.path.exists(command.path)
+
def test_005_db_exists(database):
"""Make sure db cache file exists after creating."""
- install_path = database.mock.path
- index_file = install_path.join('.spack-db', 'index.json')
- lock_file = install_path.join('.spack-db', 'lock')
+ index_file = os.path.join(database.root, '.spack-db', 'index.json')
+ lock_file = os.path.join(database.root, '.spack-db', 'lock')
assert os.path.exists(str(index_file))
assert os.path.exists(str(lock_file))
@@ -170,9 +224,15 @@ def test_010_all_install_sanity(database):
assert len(libelf_specs) == 1
# Query by dependency
- assert len([s for s in all_specs if s.satisfies('mpileaks ^mpich')]) == 1
- assert len([s for s in all_specs if s.satisfies('mpileaks ^mpich2')]) == 1
- assert len([s for s in all_specs if s.satisfies('mpileaks ^zmpi')]) == 1
+ assert len(
+ [s for s in all_specs if s.satisfies('mpileaks ^mpich')]
+ ) == 1
+ assert len(
+ [s for s in all_specs if s.satisfies('mpileaks ^mpich2')]
+ ) == 1
+ assert len(
+ [s for s in all_specs if s.satisfies('mpileaks ^zmpi')]
+ ) == 1
def test_015_write_and_read(database):
@@ -191,23 +251,20 @@ def test_015_write_and_read(database):
def test_020_db_sanity(database):
"""Make sure query() returns what's actually in the db."""
- install_db = database.mock.db
- _check_db_sanity(install_db)
+ _check_db_sanity(database)
def test_025_reindex(database):
"""Make sure reindex works and ref counts are valid."""
- install_db = database.mock.db
- spack.store.db.reindex(spack.store.layout)
- _check_db_sanity(install_db)
-
+ spack.store.store.reindex()
+ _check_db_sanity(database)
-def test_030_db_sanity_from_another_process(database, refresh_db_on_exit):
- install_db = database.mock.db
+def test_030_db_sanity_from_another_process(mutable_database):
def read_and_modify():
- _check_db_sanity(install_db) # check that other process can read DB
- with install_db.write_transaction():
+ # check that other process can read DB
+ _check_db_sanity(mutable_database)
+ with mutable_database.write_transaction():
_mock_remove('mpileaks ^zmpi')
p = multiprocessing.Process(target=read_and_modify, args=())
@@ -215,210 +272,181 @@ def test_030_db_sanity_from_another_process(database, refresh_db_on_exit):
p.join()
# ensure child process change is visible in parent process
- with install_db.read_transaction():
- assert len(install_db.query('mpileaks ^zmpi')) == 0
+ with mutable_database.read_transaction():
+ assert len(mutable_database.query('mpileaks ^zmpi')) == 0
def test_040_ref_counts(database):
"""Ensure that we got ref counts right when we read the DB."""
- install_db = database.mock.db
- install_db._check_ref_counts()
+ database._check_ref_counts()
def test_050_basic_query(database):
"""Ensure querying database is consistent with what is installed."""
- install_db = database.mock.db
# query everything
assert len(spack.store.db.query()) == 16
# query specs with multiple configurations
- mpileaks_specs = install_db.query('mpileaks')
- callpath_specs = install_db.query('callpath')
- mpi_specs = install_db.query('mpi')
+ mpileaks_specs = database.query('mpileaks')
+ callpath_specs = database.query('callpath')
+ mpi_specs = database.query('mpi')
assert len(mpileaks_specs) == 3
assert len(callpath_specs) == 3
assert len(mpi_specs) == 3
# query specs with single configurations
- dyninst_specs = install_db.query('dyninst')
- libdwarf_specs = install_db.query('libdwarf')
- libelf_specs = install_db.query('libelf')
+ dyninst_specs = database.query('dyninst')
+ libdwarf_specs = database.query('libdwarf')
+ libelf_specs = database.query('libelf')
assert len(dyninst_specs) == 1
assert len(libdwarf_specs) == 1
assert len(libelf_specs) == 1
# Query by dependency
- assert len(install_db.query('mpileaks ^mpich')) == 1
- assert len(install_db.query('mpileaks ^mpich2')) == 1
- assert len(install_db.query('mpileaks ^zmpi')) == 1
+ assert len(database.query('mpileaks ^mpich')) == 1
+ assert len(database.query('mpileaks ^mpich2')) == 1
+ assert len(database.query('mpileaks ^zmpi')) == 1
-
-def _check_remove_and_add_package(install_db, spec):
- """Remove a spec from the DB, then add it and make sure everything's
- still ok once it is added. This checks that it was
- removed, that it's back when added again, and that ref
- counts are consistent.
- """
- original = install_db.query()
- install_db._check_ref_counts()
-
- # Remove spec
- concrete_spec = install_db.remove(spec)
- install_db._check_ref_counts()
- remaining = install_db.query()
-
- # ensure spec we removed is gone
- assert len(original) - 1 == len(remaining)
- assert all(s in original for s in remaining)
- assert concrete_spec not in remaining
-
- # add it back and make sure everything is ok.
- install_db.add(concrete_spec, spack.store.layout)
- installed = install_db.query()
- assert concrete_spec in installed
- assert installed == original
-
- # sanity check against direcory layout and check ref counts.
- _check_db_sanity(install_db)
- install_db._check_ref_counts()
+ # Query by date
+ assert len(database.query(start_date=datetime.datetime.min)) == 16
+ assert len(database.query(start_date=datetime.datetime.max)) == 0
+ assert len(database.query(end_date=datetime.datetime.min)) == 0
+ assert len(database.query(end_date=datetime.datetime.max)) == 16
def test_060_remove_and_add_root_package(database):
- install_db = database.mock.db
- _check_remove_and_add_package(install_db, 'mpileaks ^mpich')
+ _check_remove_and_add_package(database, 'mpileaks ^mpich')
def test_070_remove_and_add_dependency_package(database):
- install_db = database.mock.db
- _check_remove_and_add_package(install_db, 'dyninst')
+ _check_remove_and_add_package(database, 'dyninst')
def test_080_root_ref_counts(database):
- install_db = database.mock.db
- rec = install_db.get_record('mpileaks ^mpich')
+ rec = database.get_record('mpileaks ^mpich')
# Remove a top-level spec from the DB
- install_db.remove('mpileaks ^mpich')
+ database.remove('mpileaks ^mpich')
# record no longer in DB
- assert install_db.query('mpileaks ^mpich', installed=any) == []
+ assert database.query('mpileaks ^mpich', installed=any) == []
# record's deps have updated ref_counts
- assert install_db.get_record('callpath ^mpich').ref_count == 0
- assert install_db.get_record('mpich').ref_count == 1
+ assert database.get_record('callpath ^mpich').ref_count == 0
+ assert database.get_record('mpich').ref_count == 1
# Put the spec back
- install_db.add(rec.spec, spack.store.layout)
+ database.add(rec.spec, spack.store.layout)
# record is present again
- assert len(install_db.query('mpileaks ^mpich', installed=any)) == 1
+ assert len(database.query('mpileaks ^mpich', installed=any)) == 1
# dependencies have ref counts updated
- assert install_db.get_record('callpath ^mpich').ref_count == 1
- assert install_db.get_record('mpich').ref_count == 2
+ assert database.get_record('callpath ^mpich').ref_count == 1
+ assert database.get_record('mpich').ref_count == 2
def test_090_non_root_ref_counts(database):
- install_db = database.mock.db
-
- install_db.get_record('mpileaks ^mpich')
- install_db.get_record('callpath ^mpich')
+ database.get_record('mpileaks ^mpich')
+ database.get_record('callpath ^mpich')
# "force remove" a non-root spec from the DB
- install_db.remove('callpath ^mpich')
+ database.remove('callpath ^mpich')
# record still in DB but marked uninstalled
- assert install_db.query('callpath ^mpich', installed=True) == []
- assert len(install_db.query('callpath ^mpich', installed=any)) == 1
+ assert database.query('callpath ^mpich', installed=True) == []
+ assert len(database.query('callpath ^mpich', installed=any)) == 1
# record and its deps have same ref_counts
- assert install_db.get_record(
+ assert database.get_record(
'callpath ^mpich', installed=any
).ref_count == 1
- assert install_db.get_record('mpich').ref_count == 2
+ assert database.get_record('mpich').ref_count == 2
# remove only dependent of uninstalled callpath record
- install_db.remove('mpileaks ^mpich')
+ database.remove('mpileaks ^mpich')
# record and parent are completely gone.
- assert install_db.query('mpileaks ^mpich', installed=any) == []
- assert install_db.query('callpath ^mpich', installed=any) == []
+ assert database.query('mpileaks ^mpich', installed=any) == []
+ assert database.query('callpath ^mpich', installed=any) == []
# mpich ref count updated properly.
- mpich_rec = install_db.get_record('mpich')
+ mpich_rec = database.get_record('mpich')
assert mpich_rec.ref_count == 0
def test_100_no_write_with_exception_on_remove(database):
- install_db = database.mock.db
-
def fail_while_writing():
- with install_db.write_transaction():
+ with database.write_transaction():
_mock_remove('mpileaks ^zmpi')
raise Exception()
- with install_db.read_transaction():
- assert len(install_db.query('mpileaks ^zmpi', installed=any)) == 1
+ with database.read_transaction():
+ assert len(database.query('mpileaks ^zmpi', installed=any)) == 1
with pytest.raises(Exception):
fail_while_writing()
# reload DB and make sure zmpi is still there.
- with install_db.read_transaction():
- assert len(install_db.query('mpileaks ^zmpi', installed=any)) == 1
+ with database.read_transaction():
+ assert len(database.query('mpileaks ^zmpi', installed=any)) == 1
def test_110_no_write_with_exception_on_install(database):
- install_db = database.mock.db
-
def fail_while_writing():
- with install_db.write_transaction():
+ with database.write_transaction():
_mock_install('cmake')
raise Exception()
- with install_db.read_transaction():
- assert install_db.query('cmake', installed=any) == []
+ with database.read_transaction():
+ assert database.query('cmake', installed=any) == []
with pytest.raises(Exception):
fail_while_writing()
# reload DB and make sure cmake was not written.
- with install_db.read_transaction():
- assert install_db.query('cmake', installed=any) == []
+ with database.read_transaction():
+ assert database.query('cmake', installed=any) == []
-def test_115_reindex_with_packages_not_in_repo(database, refresh_db_on_exit):
- install_db = database.mock.db
-
- saved_repo = spack.repo
+def test_115_reindex_with_packages_not_in_repo(mutable_database):
# Dont add any package definitions to this repository, the idea is that
- # packages should not have to be defined in the repository once they are
- # installed
- mock_repo = MockPackageMultiRepo([])
- try:
- spack.repo = mock_repo
- spack.store.db.reindex(spack.store.layout)
- _check_db_sanity(install_db)
- finally:
- spack.repo = saved_repo
+ # packages should not have to be defined in the repository once they
+ # are installed
+ with spack.repo.swap(MockPackageMultiRepo([])):
+ spack.store.store.reindex()
+ _check_db_sanity(mutable_database)
def test_external_entries_in_db(database):
- install_db = database.mock.db
-
- rec = install_db.get_record('mpileaks ^zmpi')
+ rec = database.get_record('mpileaks ^zmpi')
assert rec.spec.external_path is None
assert rec.spec.external_module is None
- rec = install_db.get_record('externaltool')
+ rec = database.get_record('externaltool')
assert rec.spec.external_path == '/path/to/external_tool'
assert rec.spec.external_module is None
assert rec.explicit is False
rec.spec.package.do_install(fake=True, explicit=True)
- rec = install_db.get_record('externaltool')
+ rec = database.get_record('externaltool')
assert rec.spec.external_path == '/path/to/external_tool'
assert rec.spec.external_module is None
assert rec.explicit is True
+
+
+@pytest.mark.regression('8036')
+def test_regression_issue_8036(mutable_database, usr_folder_exists):
+ # The test ensures that the external package prefix is treated as
+ # existing. Even when the package prefix exists, the package should
+ # not be considered installed until it is added to the database with
+ # do_install.
+ s = spack.spec.Spec('externaltool@0.9')
+ s.concretize()
+ assert not s.package.installed
+
+ # Now install the external package and check again the `installed` property
+ s.package.do_install(fake=True)
+ assert s.package.installed
diff --git a/lib/spack/spack/test/directory_layout.py b/lib/spack/spack/test/directory_layout.py
index b166ea4eac..6584c3c636 100644
--- a/lib/spack/spack/test/directory_layout.py
+++ b/lib/spack/spack/test/directory_layout.py
@@ -1,39 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This test verifies that the Spack directory layout works properly.
"""
import os
import pytest
-from llnl.util.filesystem import join_path
-
-import spack
+import spack.paths
+import spack.repo
from spack.directory_layout import YamlDirectoryLayout
from spack.directory_layout import InvalidDirectoryLayoutParametersError
-from spack.repository import RepoPath
from spack.spec import Spec
# number of packages to test (to reduce test time)
@@ -74,13 +53,19 @@ def test_yaml_directory_layout_parameters(
# Test path_scheme
arch, compiler, package7 = path_7.split('/')
scheme_package7 = "${PACKAGE}-${VERSION}-${HASH:7}"
-
layout_package7 = YamlDirectoryLayout(str(tmpdir),
path_scheme=scheme_package7)
path_package7 = layout_package7.relative_path_for_spec(spec)
assert(package7 == path_package7)
+ # Test separation of architecture
+ arch_scheme_package = "${PLATFORM}/${TARGET}/${OS}/${PACKAGE}/${VERSION}/${HASH:7}" # NOQA: ignore=E501
+ layout_arch_package = YamlDirectoryLayout(str(tmpdir),
+ path_scheme=arch_scheme_package)
+ arch_path_package = layout_arch_package.relative_path_for_spec(spec)
+ assert(arch_path_package == spec.format(arch_scheme_package))
+
# Ensure conflicting parameters caught
with pytest.raises(InvalidDirectoryLayoutParametersError):
YamlDirectoryLayout(str(tmpdir),
@@ -89,7 +74,7 @@ def test_yaml_directory_layout_parameters(
def test_read_and_write_spec(
- layout_and_dir, config, builtin_mock
+ layout_and_dir, config, mock_packages
):
"""This goes through each package in spack and creates a directory for
it. It then ensures that the spec for the directory's
@@ -98,7 +83,7 @@ def test_read_and_write_spec(
layout.
"""
layout, tmpdir = layout_and_dir
- packages = list(spack.repo.all_packages())[:max_packages]
+ packages = list(spack.repo.path.all_packages())[:max_packages]
for pkg in packages:
if pkg.name.startswith('external'):
@@ -167,7 +152,7 @@ def test_read_and_write_spec(
def test_handle_unknown_package(
- layout_and_dir, config, builtin_mock
+ layout_and_dir, config, mock_packages
):
"""This test ensures that spack can at least do *some*
operations with packages that are installed but that it
@@ -180,7 +165,7 @@ def test_handle_unknown_package(
or query them again if the package goes away.
"""
layout, _ = layout_and_dir
- mock_db = RepoPath(spack.mock_packages_path)
+ mock_db = spack.repo.RepoPath(spack.paths.mock_packages_path)
not_in_mock = set.difference(
set(spack.repo.all_package_names()),
@@ -202,28 +187,25 @@ def test_handle_unknown_package(
layout.create_install_directory(spec)
installed_specs[spec] = layout.path_for_spec(spec)
- spack.repo.swap(mock_db)
-
- # Now check that even without the package files, we know
- # enough to read a spec from the spec file.
- for spec, path in installed_specs.items():
- spec_from_file = layout.read_spec(
- join_path(path, '.spack', 'spec.yaml')
- )
- # To satisfy these conditions, directory layouts need to
- # read in concrete specs from their install dirs somehow.
- assert path == layout.path_for_spec(spec_from_file)
- assert spec == spec_from_file
- assert spec.eq_dag(spec_from_file)
- assert spec.dag_hash() == spec_from_file.dag_hash()
+ with spack.repo.swap(mock_db):
+ # Now check that even without the package files, we know
+ # enough to read a spec from the spec file.
+ for spec, path in installed_specs.items():
+ spec_from_file = layout.read_spec(
+ os.path.join(path, '.spack', 'spec.yaml'))
- spack.repo.swap(mock_db)
+ # To satisfy these conditions, directory layouts need to
+ # read in concrete specs from their install dirs somehow.
+ assert path == layout.path_for_spec(spec_from_file)
+ assert spec == spec_from_file
+ assert spec.eq_dag(spec_from_file)
+ assert spec.dag_hash() == spec_from_file.dag_hash()
-def test_find(layout_and_dir, config, builtin_mock):
+def test_find(layout_and_dir, config, mock_packages):
"""Test that finding specs within an install layout works."""
layout, _ = layout_and_dir
- packages = list(spack.repo.all_packages())[:max_packages]
+ packages = list(spack.repo.path.all_packages())[:max_packages]
# Create install prefixes for all packages in the list
installed_specs = {}
diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment_modifications.py
index c11c050820..a7941a30cb 100644
--- a/lib/spack/spack/test/environment.py
+++ b/lib/spack/spack/test/environment_modifications.py
@@ -1,35 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack.environment as environment
-from spack import spack_root
-from spack.environment import EnvironmentModifications
-from spack.environment import RemovePath, PrependPath, AppendPath
-from spack.environment import SetEnv, UnsetEnv
+import spack.util.environment as environment
+from spack.paths import spack_root
+from spack.util.environment import EnvironmentModifications
+from spack.util.environment import RemovePath, PrependPath, AppendPath
+from spack.util.environment import SetEnv, UnsetEnv
from spack.util.environment import filter_system_paths, is_system_path
@@ -306,3 +287,22 @@ def test_source_files(files_to_be_sourced):
assert modifications['PATH_LIST'][1].value == '/path/fourth'
assert isinstance(modifications['PATH_LIST'][2], PrependPath)
assert modifications['PATH_LIST'][2].value == '/path/first'
+
+
+@pytest.mark.regression('8345')
+def test_preserve_environment(prepare_environment_for_tests):
+ # UNSET_ME is defined, and will be unset in the context manager,
+ # NOT_SET is not in the environment and will be set within the
+ # context manager, PATH_LIST is set and will be changed.
+ with environment.preserve_environment('UNSET_ME', 'NOT_SET', 'PATH_LIST'):
+ os.environ['NOT_SET'] = 'a'
+ assert os.environ['NOT_SET'] == 'a'
+
+ del os.environ['UNSET_ME']
+ assert 'UNSET_ME' not in os.environ
+
+ os.environ['PATH_LIST'] = 'changed'
+
+ assert 'NOT_SET' not in os.environ
+ assert os.environ['UNSET_ME'] == 'foo'
+ assert os.environ['PATH_LIST'] == '/path/second:/path/third'
diff --git a/lib/spack/spack/test/flag_handlers.py b/lib/spack/spack/test/flag_handlers.py
index 80dad9c35e..de84a19008 100644
--- a/lib/spack/spack/test/flag_handlers.py
+++ b/lib/spack/spack/test/flag_handlers.py
@@ -1,33 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import os
import spack.spec
+import spack.repo
import spack.build_environment
+from spack.pkgkit import inject_flags, env_flags, build_system_flags
+
@pytest.fixture()
def temp_env():
@@ -36,23 +20,23 @@ def temp_env():
os.environ = old_env
-def add_O3_to_build_system_cflags(pkg, name, flags):
+def add_o3_to_build_system_cflags(pkg, name, flags):
build_system_flags = []
if name == 'cflags':
build_system_flags.append('-O3')
return (flags, None, build_system_flags)
-@pytest.mark.usefixtures('config')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestFlagHandlers(object):
def test_no_build_system_flags(self, temp_env):
# Test that both autotools and cmake work getting no build_system flags
- s1 = spack.spec.Spec('callpath')
+ s1 = spack.spec.Spec('cmake-client')
s1.concretize()
pkg1 = spack.repo.get(s1)
spack.build_environment.setup_package(pkg1, False)
- s2 = spack.spec.Spec('libelf')
+ s2 = spack.spec.Spec('patchelf')
s2.concretize()
pkg2 = spack.repo.get(s2)
spack.build_environment.setup_package(pkg2, False)
@@ -69,7 +53,6 @@ class TestFlagHandlers(object):
pkg = spack.repo.get(s)
pkg.flag_handler = pkg.__class__.inject_flags
spack.build_environment.setup_package(pkg, False)
-
assert os.environ['SPACK_CPPFLAGS'] == '-g'
assert 'CPPFLAGS' not in os.environ
@@ -77,7 +60,7 @@ class TestFlagHandlers(object):
s = spack.spec.Spec('mpileaks cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.inject_flags
+ pkg.flag_handler = inject_flags
spack.build_environment.setup_package(pkg, False)
assert os.environ['SPACK_CPPFLAGS'] == '-g'
@@ -87,17 +70,17 @@ class TestFlagHandlers(object):
s = spack.spec.Spec('mpileaks cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.env_flags
+ pkg.flag_handler = env_flags
spack.build_environment.setup_package(pkg, False)
assert os.environ['CPPFLAGS'] == '-g'
assert 'SPACK_CPPFLAGS' not in os.environ
def test_build_system_flags_cmake(self, temp_env):
- s = spack.spec.Spec('callpath cppflags=-g')
+ s = spack.spec.Spec('cmake-client cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.build_system_flags
+ pkg.flag_handler = build_system_flags
spack.build_environment.setup_package(pkg, False)
assert 'SPACK_CPPFLAGS' not in os.environ
@@ -108,10 +91,10 @@ class TestFlagHandlers(object):
assert set(pkg.cmake_flag_args) == expected
def test_build_system_flags_autotools(self, temp_env):
- s = spack.spec.Spec('libelf cppflags=-g')
+ s = spack.spec.Spec('patchelf cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.build_system_flags
+ pkg.flag_handler = build_system_flags
spack.build_environment.setup_package(pkg, False)
assert 'SPACK_CPPFLAGS' not in os.environ
@@ -123,7 +106,7 @@ class TestFlagHandlers(object):
s = spack.spec.Spec('mpileaks cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.build_system_flags
+ pkg.flag_handler = build_system_flags
# Test the command line flags method raises a NotImplementedError
try:
@@ -133,10 +116,10 @@ class TestFlagHandlers(object):
assert True
def test_add_build_system_flags_autotools(self, temp_env):
- s = spack.spec.Spec('libelf cppflags=-g')
+ s = spack.spec.Spec('patchelf cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = add_O3_to_build_system_cflags
+ pkg.flag_handler = add_o3_to_build_system_cflags
spack.build_environment.setup_package(pkg, False)
assert '-g' in os.environ['SPACK_CPPFLAGS']
@@ -145,10 +128,10 @@ class TestFlagHandlers(object):
assert pkg.configure_flag_args == ['CFLAGS=-O3']
def test_add_build_system_flags_cmake(self, temp_env):
- s = spack.spec.Spec('callpath cppflags=-g')
+ s = spack.spec.Spec('cmake-client cppflags=-g')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = add_O3_to_build_system_cflags
+ pkg.flag_handler = add_o3_to_build_system_cflags
spack.build_environment.setup_package(pkg, False)
assert '-g' in os.environ['SPACK_CPPFLAGS']
@@ -157,10 +140,10 @@ class TestFlagHandlers(object):
assert pkg.cmake_flag_args == ['-DCMAKE_C_FLAGS=-O3']
def test_ld_flags_cmake(self, temp_env):
- s = spack.spec.Spec('callpath ldflags=-mthreads')
+ s = spack.spec.Spec('cmake-client ldflags=-mthreads')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.build_system_flags
+ pkg.flag_handler = build_system_flags
spack.build_environment.setup_package(pkg, False)
assert 'SPACK_LDFLAGS' not in os.environ
@@ -173,10 +156,10 @@ class TestFlagHandlers(object):
assert set(pkg.cmake_flag_args) == expected
def test_ld_libs_cmake(self, temp_env):
- s = spack.spec.Spec('callpath ldlibs=-lfoo')
+ s = spack.spec.Spec('cmake-client ldlibs=-lfoo')
s.concretize()
pkg = spack.repo.get(s)
- pkg.flag_handler = pkg.build_system_flags
+ pkg.flag_handler = build_system_flags
spack.build_environment.setup_package(pkg, False)
assert 'SPACK_LDLIBS' not in os.environ
diff --git a/lib/spack/spack/test/git_fetch.py b/lib/spack/spack/test/git_fetch.py
index b28c553753..8171538756 100644
--- a/lib/spack/spack/test/git_fetch.py
+++ b/lib/spack/spack/test/git_fetch.py
@@ -1,32 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack
-from llnl.util.filesystem import working_dir, join_path, touch
+
+from llnl.util.filesystem import working_dir, touch
+
+import spack.repo
+import spack.config
from spack.spec import Spec
from spack.version import ver
from spack.fetch_strategy import GitFetchStrategy
@@ -71,7 +55,7 @@ def test_fetch(type_of_test,
secure,
mock_git_repository,
config,
- refresh_builtin_mock,
+ mutable_mock_packages,
git_version):
"""Tries to:
@@ -89,21 +73,18 @@ def test_fetch(type_of_test,
# Construct the package under test
spec = Spec('git-test')
spec.concretize()
- pkg = spack.repo.get(spec, new=True)
+ pkg = spack.repo.get(spec)
pkg.versions[ver('git')] = t.args
# Enter the stage directory and check some properties
with pkg.stage:
- try:
- spack.insecure = secure
+ with spack.config.override('config:verify_ssl', secure):
pkg.do_stage()
- finally:
- spack.insecure = False
with working_dir(pkg.stage.source_path):
assert h('HEAD') == h(t.revision)
- file_path = join_path(pkg.stage.source_path, t.file)
+ file_path = os.path.join(pkg.stage.source_path, t.file)
assert os.path.isdir(pkg.stage.source_path)
assert os.path.isfile(file_path)
diff --git a/lib/spack/spack/test/graph.py b/lib/spack/spack/test/graph.py
index 7cd82c3a88..d1de8db8cb 100644
--- a/lib/spack/spack/test/graph.py
+++ b/lib/spack/spack/test/graph.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from six import StringIO
from spack.spec import Spec
from spack.graph import AsciiGraph, topological_sort, graph_dot
-def test_topo_sort(builtin_mock):
+def test_topo_sort(mock_packages):
"""Test topo sort gives correct order."""
s = Spec('mpileaks').normalized()
@@ -51,7 +32,7 @@ def test_topo_sort(builtin_mock):
assert topo.index('libdwarf') < topo.index('libelf')
-def test_static_graph_mpileaks(builtin_mock):
+def test_static_graph_mpileaks(mock_packages):
"""Test a static spack graph for a simple package."""
s = Spec('mpileaks').normalized()
@@ -75,7 +56,7 @@ def test_static_graph_mpileaks(builtin_mock):
assert ' "dyninst" -> "libelf"\n' in dot
-def test_dynamic_dot_graph_mpileaks(builtin_mock):
+def test_dynamic_dot_graph_mpileaks(mock_packages):
"""Test dynamically graphing the mpileaks package."""
s = Spec('mpileaks').normalized()
@@ -111,7 +92,7 @@ def test_dynamic_dot_graph_mpileaks(builtin_mock):
assert ' "%s" -> "%s"\n' % (dyninst_hash, libelf_hash) in dot
-def test_ascii_graph_mpileaks(builtin_mock):
+def test_ascii_graph_mpileaks(mock_packages):
"""Test dynamically graphing the mpileaks package."""
s = Spec('mpileaks').normalized()
diff --git a/lib/spack/spack/test/hg_fetch.py b/lib/spack/spack/test/hg_fetch.py
index 6a22502e86..b9fa6a1e6d 100644
--- a/lib/spack/spack/test/hg_fetch.py
+++ b/lib/spack/spack/test/hg_fetch.py
@@ -1,32 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack
-from llnl.util.filesystem import working_dir, join_path, touch
+
+from llnl.util.filesystem import working_dir, touch
+
+import spack.repo
+import spack.config
from spack.spec import Spec
from spack.version import ver
from spack.util.executable import which
@@ -43,7 +27,7 @@ def test_fetch(
secure,
mock_hg_repository,
config,
- refresh_builtin_mock
+ mutable_mock_packages
):
"""Tries to:
@@ -61,21 +45,18 @@ def test_fetch(
# Construct the package under test
spec = Spec('hg-test')
spec.concretize()
- pkg = spack.repo.get(spec, new=True)
+ pkg = spack.repo.get(spec)
pkg.versions[ver('hg')] = t.args
# Enter the stage directory and check some properties
with pkg.stage:
- try:
- spack.insecure = secure
+ with spack.config.override('config:verify_ssl', secure):
pkg.do_stage()
- finally:
- spack.insecure = False
with working_dir(pkg.stage.source_path):
assert h() == t.revision
- file_path = join_path(pkg.stage.source_path, t.file)
+ file_path = os.path.join(pkg.stage.source_path, t.file)
assert os.path.isdir(pkg.stage.source_path)
assert os.path.isfile(file_path)
diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py
index 86b95459f4..a63c149d3d 100644
--- a/lib/spack/spack/test/install.py
+++ b/lib/spack/spack/test/install.py
@@ -1,31 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack
+import spack.repo
import spack.store
from spack.spec import Spec
@@ -132,7 +113,7 @@ def test_dont_add_patches_to_installed_package(install_mockery, mock_fetch):
def test_installed_dependency_request_conflicts(
- install_mockery, mock_fetch, refresh_builtin_mock):
+ install_mockery, mock_fetch, mutable_mock_packages):
dependency = Spec('dependency-install')
dependency.concretize()
dependency.package.do_install()
diff --git a/lib/spack/spack/test/llnl/util/file_list.py b/lib/spack/spack/test/llnl/util/file_list.py
index f7d5dde4d3..e54e479e14 100644
--- a/lib/spack/spack/test/llnl/util/file_list.py
+++ b/lib/spack/spack/test/llnl/util/file_list.py
@@ -1,36 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import fnmatch
import os
+import fnmatch
-import pytest
import six
-import spack
+import pytest
+
from llnl.util.filesystem import LibraryList, HeaderList
-from llnl.util.filesystem import find_libraries, find_headers
+from llnl.util.filesystem import find_libraries, find_headers, find
+
+import spack.paths
@pytest.fixture()
@@ -211,40 +193,44 @@ class TestHeaderList(object):
#: Directory where the data for the test below is stored
-search_dir = os.path.join(spack.test_path, 'data', 'directory_search')
+search_dir = os.path.join(spack.paths.test_path, 'data', 'directory_search')
@pytest.mark.parametrize('search_fn,search_list,root,kwargs', [
- (find_libraries, 'liba', search_dir, {'recurse': True}),
- (find_libraries, ['liba'], search_dir, {'recurse': True}),
- (find_libraries, 'libb', search_dir, {'recurse': True}),
- (find_libraries, ['libc'], search_dir, {'recurse': True}),
- (find_libraries, ['libc', 'liba'], search_dir, {'recurse': True}),
- (find_libraries, ['liba', 'libc'], search_dir, {'recurse': True}),
- (find_libraries, ['libc', 'libb', 'liba'], search_dir, {'recurse': True}),
- (find_libraries, ['liba', 'libc'], search_dir, {'recurse': True}),
+ (find_libraries, 'liba', search_dir, {'recursive': True}),
+ (find_libraries, ['liba'], search_dir, {'recursive': True}),
+ (find_libraries, 'libb', search_dir, {'recursive': True}),
+ (find_libraries, ['libc'], search_dir, {'recursive': True}),
+ (find_libraries, ['libc', 'liba'], search_dir, {'recursive': True}),
+ (find_libraries, ['liba', 'libc'], search_dir, {'recursive': True}),
(find_libraries,
['libc', 'libb', 'liba'],
search_dir,
- {'recurse': True, 'shared': False}
+ {'recursive': True}
),
- (find_headers, 'a', search_dir, {'recurse': True}),
- (find_headers, ['a'], search_dir, {'recurse': True}),
- (find_headers, 'b', search_dir, {'recurse': True}),
- (find_headers, ['c'], search_dir, {'recurse': True}),
- (find_headers, ['c', 'a'], search_dir, {'recurse': True}),
- (find_headers, ['a', 'c'], search_dir, {'recurse': True}),
- (find_headers, ['c', 'b', 'a'], search_dir, {'recurse': True}),
- (find_headers, ['a', 'c'], search_dir, {'recurse': True}),
+ (find_libraries, ['liba', 'libc'], search_dir, {'recursive': True}),
+ (find_libraries,
+ ['libc', 'libb', 'liba'],
+ search_dir,
+ {'recursive': True, 'shared': False}
+ ),
+ (find_headers, 'a', search_dir, {'recursive': True}),
+ (find_headers, ['a'], search_dir, {'recursive': True}),
+ (find_headers, 'b', search_dir, {'recursive': True}),
+ (find_headers, ['c'], search_dir, {'recursive': True}),
+ (find_headers, ['c', 'a'], search_dir, {'recursive': True}),
+ (find_headers, ['a', 'c'], search_dir, {'recursive': True}),
+ (find_headers, ['c', 'b', 'a'], search_dir, {'recursive': True}),
+ (find_headers, ['a', 'c'], search_dir, {'recursive': True}),
(find_libraries,
['liba', 'libd'],
os.path.join(search_dir, 'b'),
- {'recurse': False}
+ {'recursive': False}
),
(find_headers,
['b', 'd'],
os.path.join(search_dir, 'b'),
- {'recurse': False}
+ {'recursive': False}
),
])
def test_searching_order(search_fn, search_list, root, kwargs):
@@ -258,7 +244,7 @@ def test_searching_order(search_fn, search_list, root, kwargs):
# Now reverse the result and start discarding things
# as soon as you have matches. In the end the list should
# be emptied.
- L = list(reversed(result))
+ rlist = list(reversed(result))
# At this point make sure the search list is a sequence
if isinstance(search_list, six.string_types):
@@ -267,11 +253,28 @@ def test_searching_order(search_fn, search_list, root, kwargs):
# Discard entries in the order they appear in search list
for x in search_list:
try:
- while fnmatch.fnmatch(L[-1], x) or x in L[-1]:
- L.pop()
+ while fnmatch.fnmatch(rlist[-1], x) or x in rlist[-1]:
+ rlist.pop()
except IndexError:
# List is empty
pass
# List should be empty here
- assert len(L) == 0
+ assert len(rlist) == 0
+
+
+@pytest.mark.parametrize('root,search_list,kwargs,expected', [
+ (search_dir, '*/*bar.tx?', {'recursive': False}, [
+ os.path.join(search_dir, 'a/foobar.txt'),
+ os.path.join(search_dir, 'b/bar.txp'),
+ os.path.join(search_dir, 'c/bar.txt'),
+ ]),
+ (search_dir, '*/*bar.tx?', {'recursive': True}, [
+ os.path.join(search_dir, 'a/foobar.txt'),
+ os.path.join(search_dir, 'b/bar.txp'),
+ os.path.join(search_dir, 'c/bar.txt'),
+ ])
+])
+def test_find_with_globbing(root, search_list, kwargs, expected):
+ matches = find(root, search_list, **kwargs)
+ assert sorted(matches) == sorted(expected)
diff --git a/lib/spack/spack/test/llnl/util/filesystem.py b/lib/spack/spack/test/llnl/util/filesystem.py
new file mode 100644
index 0000000000..33857854fe
--- /dev/null
+++ b/lib/spack/spack/test/llnl/util/filesystem.py
@@ -0,0 +1,217 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Tests for ``llnl/util/filesystem.py``"""
+
+import llnl.util.filesystem as fs
+import os
+import stat
+import pytest
+
+
+@pytest.fixture()
+def stage(tmpdir_factory):
+ """Creates a stage with the directory structure for the tests."""
+
+ s = tmpdir_factory.mktemp('filesystem_test')
+
+ with s.as_cwd():
+ # Create source file hierarchy
+ fs.touchp('source/1')
+ fs.touchp('source/a/b/2')
+ fs.touchp('source/a/b/3')
+ fs.touchp('source/c/4')
+ fs.touchp('source/c/d/5')
+ fs.touchp('source/c/d/6')
+ fs.touchp('source/c/d/e/7')
+
+ # Create symlinks
+ os.symlink(os.path.abspath('source/1'), 'source/2')
+ os.symlink('b/2', 'source/a/b2')
+ os.symlink('a/b', 'source/f')
+
+ # Create destination directory
+ fs.mkdirp('dest')
+
+ yield s
+
+
+class TestCopy:
+ """Tests for ``filesystem.copy``"""
+
+ def test_file_dest(self, stage):
+ """Test using a filename as the destination."""
+
+ with fs.working_dir(str(stage)):
+ fs.copy('source/1', 'dest/1')
+
+ assert os.path.exists('dest/1')
+
+ def test_dir_dest(self, stage):
+ """Test using a directory as the destination."""
+
+ with fs.working_dir(str(stage)):
+ fs.copy('source/1', 'dest')
+
+ assert os.path.exists('dest/1')
+
+
+def check_added_exe_permissions(src, dst):
+ src_mode = os.stat(src).st_mode
+ dst_mode = os.stat(dst).st_mode
+ for perm in [stat.S_IXUSR, stat.S_IXGRP, stat.S_IXOTH]:
+ if src_mode & perm:
+ assert dst_mode & perm
+
+
+class TestInstall:
+ """Tests for ``filesystem.install``"""
+
+ def test_file_dest(self, stage):
+ """Test using a filename as the destination."""
+
+ with fs.working_dir(str(stage)):
+ fs.install('source/1', 'dest/1')
+
+ assert os.path.exists('dest/1')
+ check_added_exe_permissions('source/1', 'dest/1')
+
+ def test_dir_dest(self, stage):
+ """Test using a directory as the destination."""
+
+ with fs.working_dir(str(stage)):
+ fs.install('source/1', 'dest')
+
+ assert os.path.exists('dest/1')
+ check_added_exe_permissions('source/1', 'dest/1')
+
+
+class TestCopyTree:
+ """Tests for ``filesystem.copy_tree``"""
+
+ def test_existing_dir(self, stage):
+ """Test copying to an existing directory."""
+
+ with fs.working_dir(str(stage)):
+ fs.copy_tree('source', 'dest')
+
+ assert os.path.exists('dest/a/b/2')
+
+ def test_non_existing_dir(self, stage):
+ """Test copying to a non-existing directory."""
+
+ with fs.working_dir(str(stage)):
+ fs.copy_tree('source', 'dest/sub/directory')
+
+ assert os.path.exists('dest/sub/directory/a/b/2')
+
+ def test_symlinks_true(self, stage):
+ """Test copying with symlink preservation."""
+
+ with fs.working_dir(str(stage)):
+ fs.copy_tree('source', 'dest', symlinks=True)
+
+ assert os.path.exists('dest/2')
+ assert os.path.islink('dest/2')
+
+ assert os.path.exists('dest/a/b2')
+ with fs.working_dir('dest/a'):
+ assert os.path.exists(os.readlink('b2'))
+
+ assert (os.path.realpath('dest/f/2') ==
+ os.path.abspath('dest/a/b/2'))
+ assert os.path.realpath('dest/2') == os.path.abspath('dest/1')
+
+ def test_symlinks_true_ignore(self, stage):
+ """Test copying when specifying relative paths that should be ignored
+ """
+ with fs.working_dir(str(stage)):
+ ignore = lambda p: p in ['c/d/e', 'a']
+ fs.copy_tree('source', 'dest', symlinks=True, ignore=ignore)
+ assert not os.path.exists('dest/a')
+ assert os.path.exists('dest/c/d')
+ assert not os.path.exists('dest/c/d/e')
+
+ def test_symlinks_false(self, stage):
+ """Test copying without symlink preservation."""
+
+ with fs.working_dir(str(stage)):
+ fs.copy_tree('source', 'dest', symlinks=False)
+
+ assert os.path.exists('dest/2')
+ assert not os.path.islink('dest/2')
+
+
+class TestInstallTree:
+ """Tests for ``filesystem.install_tree``"""
+
+ def test_existing_dir(self, stage):
+ """Test installing to an existing directory."""
+
+ with fs.working_dir(str(stage)):
+ fs.install_tree('source', 'dest')
+
+ assert os.path.exists('dest/a/b/2')
+
+ def test_non_existing_dir(self, stage):
+ """Test installing to a non-existing directory."""
+
+ with fs.working_dir(str(stage)):
+ fs.install_tree('source', 'dest/sub/directory')
+
+ assert os.path.exists('dest/sub/directory/a/b/2')
+
+ def test_symlinks_true(self, stage):
+ """Test installing with symlink preservation."""
+
+ with fs.working_dir(str(stage)):
+ fs.install_tree('source', 'dest', symlinks=True)
+
+ assert os.path.exists('dest/2')
+ assert os.path.islink('dest/2')
+
+ def test_symlinks_false(self, stage):
+ """Test installing without symlink preservation."""
+
+ with fs.working_dir(str(stage)):
+ fs.install_tree('source', 'dest', symlinks=False)
+
+ assert os.path.exists('dest/2')
+ assert not os.path.islink('dest/2')
+
+
+def test_move_transaction_commit(tmpdir):
+
+ fake_library = tmpdir.mkdir('lib').join('libfoo.so')
+ fake_library.write('Just some fake content.')
+
+ old_md5 = fs.hash_directory(str(tmpdir))
+
+ with fs.replace_directory_transaction(str(tmpdir.join('lib'))):
+ fake_library = tmpdir.mkdir('lib').join('libfoo.so')
+ fake_library.write('Other content.')
+ new_md5 = fs.hash_directory(str(tmpdir))
+
+ assert old_md5 != fs.hash_directory(str(tmpdir))
+ assert new_md5 == fs.hash_directory(str(tmpdir))
+
+
+def test_move_transaction_rollback(tmpdir):
+
+ fake_library = tmpdir.mkdir('lib').join('libfoo.so')
+ fake_library.write('Just some fake content.')
+
+ h = fs.hash_directory(str(tmpdir))
+
+ try:
+ with fs.replace_directory_transaction(str(tmpdir.join('lib'))):
+ assert h != fs.hash_directory(str(tmpdir))
+ fake_library = tmpdir.mkdir('lib').join('libfoo.so')
+ fake_library.write('Other content.')
+ raise RuntimeError('')
+ except RuntimeError:
+ pass
+
+ assert h == fs.hash_directory(str(tmpdir))
diff --git a/lib/spack/spack/test/llnl/util/lang.py b/lib/spack/spack/test/llnl/util/lang.py
index 37dc01ce53..eec75f036f 100644
--- a/lib/spack/spack/test/llnl/util/lang.py
+++ b/lib/spack/spack/test/llnl/util/lang.py
@@ -1,33 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
+
from datetime import datetime, timedelta
+import llnl.util.lang
from llnl.util.lang import pretty_date, match_predicate
+@pytest.fixture()
+def now():
+ return datetime.now()
+
+
def test_pretty_date():
"""Make sure pretty_date prints the right dates."""
now = datetime.now()
@@ -75,6 +63,32 @@ def test_pretty_date():
assert pretty_date(years, now) == "2 years ago"
+@pytest.mark.parametrize('delta,pretty_string', [
+ (timedelta(days=1), 'a day ago'),
+ (timedelta(days=1), 'yesterday'),
+ (timedelta(days=1), '1 day ago'),
+ (timedelta(weeks=1), '1 week ago'),
+ (timedelta(weeks=3), '3 weeks ago'),
+ (timedelta(days=30), '1 month ago'),
+ (timedelta(days=730), '2 years ago'),
+])
+def test_pretty_string_to_date_delta(now, delta, pretty_string):
+ t1 = now - delta
+ t2 = llnl.util.lang.pretty_string_to_date(pretty_string, now)
+ assert t1 == t2
+
+
+@pytest.mark.parametrize('format,pretty_string', [
+ ('%Y', '2018'),
+ ('%Y-%m', '2015-03'),
+ ('%Y-%m-%d', '2015-03-28'),
+])
+def test_pretty_string_to_date(format, pretty_string):
+ t1 = datetime.strptime(pretty_string, format)
+ t2 = llnl.util.lang.pretty_string_to_date(pretty_string, now)
+ assert t1 == t2
+
+
def test_match_predicate():
matcher = match_predicate(lambda x: True)
assert matcher('foo')
diff --git a/lib/spack/spack/test/llnl/util/link_tree.py b/lib/spack/spack/test/llnl/util/link_tree.py
index 59af3b8ad4..0c526512f9 100644
--- a/lib/spack/spack/test/llnl/util/link_tree.py
+++ b/lib/spack/spack/test/llnl/util/link_tree.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
diff --git a/lib/spack/spack/test/llnl/util/lock.py b/lib/spack/spack/test/llnl/util/lock.py
index 0574adff51..1991c9640b 100644
--- a/lib/spack/spack/test/llnl/util/lock.py
+++ b/lib/spack/spack/test/llnl/util/lock.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""These tests ensure that our lock works correctly.
This can be run in two ways.
@@ -62,19 +43,20 @@ actually on a shared filesystem.
"""
import os
+import socket
import shutil
import tempfile
import traceback
import glob
import getpass
from contextlib import contextmanager
-from multiprocessing import Process
+from multiprocessing import Process, Queue
import pytest
-from llnl.util.filesystem import join_path, touch
-from spack.util.multiproc import Barrier
-from llnl.util.lock import Lock, WriteTransaction, ReadTransaction, LockError
+import llnl.util.lock as lk
+import llnl.util.multiproc as mp
+from llnl.util.filesystem import touch
#
@@ -127,12 +109,27 @@ This may need to be higher for some filesystems."""
lock_fail_timeout = 0.1
+def make_readable(*paths):
+ for path in paths:
+ mode = 0o555 if os.path.isdir(path) else 0o444
+ os.chmod(path, mode)
+
+
+def make_writable(*paths):
+ for path in paths:
+ mode = 0o755 if os.path.isdir(path) else 0o744
+ os.chmod(path, mode)
+
+
@contextmanager
-def read_only(path):
- orginal_mode = os.stat(path).st_mode
- os.chmod(path, 0o444)
+def read_only(*paths):
+ modes = [os.stat(p).st_mode for p in paths]
+ make_readable(*paths)
+
yield
- os.chmod(path, orginal_mode)
+
+ for path, mode in zip(paths, modes):
+ os.chmod(path, mode)
@pytest.fixture(scope='session', params=locations)
@@ -171,6 +168,7 @@ def lock_dir(lock_test_directory):
comm.barrier()
if not mpi or comm.rank == 0:
+ make_writable(tempdir)
shutil.rmtree(tempdir)
@@ -180,30 +178,51 @@ def private_lock_path(lock_dir):
For other modes, it is the same as a shared lock.
"""
- lock_file = join_path(lock_dir, 'lockfile')
+ lock_file = os.path.join(lock_dir, 'lockfile')
if mpi:
lock_file += '.%s' % comm.rank
+
yield lock_file
+ if os.path.exists(lock_file):
+ make_writable(lock_dir, lock_file)
+ os.unlink(lock_file)
+
@pytest.fixture
def lock_path(lock_dir):
"""This lock is shared among all processes in a multiproc test."""
- lock_file = join_path(lock_dir, 'lockfile')
+ lock_file = os.path.join(lock_dir, 'lockfile')
+
yield lock_file
+ if os.path.exists(lock_file):
+ make_writable(lock_dir, lock_file)
+ os.unlink(lock_file)
+
+
+def test_poll_interval_generator():
+ interval_iter = iter(
+ lk.Lock._poll_interval_generator(_wait_times=[1, 2, 3]))
+ intervals = list(next(interval_iter) for i in range(100))
+ assert intervals == [1] * 20 + [2] * 40 + [3] * 40
-def local_multiproc_test(*functions):
+
+def local_multiproc_test(*functions, **kwargs):
"""Order some processes using simple barrier synchronization."""
- b = Barrier(len(functions), timeout=barrier_timeout)
- procs = [Process(target=f, args=(b,)) for f in functions]
+ b = mp.Barrier(len(functions), timeout=barrier_timeout)
+
+ args = (b,) + tuple(kwargs.get('extra_args', ()))
+ procs = [Process(target=f, args=args, name=f.__name__)
+ for f in functions]
for p in procs:
p.start()
for p in procs:
p.join()
- assert p.exitcode == 0
+
+ assert all(p.exitcode == 0 for p in procs)
def mpi_multiproc_test(*functions):
@@ -257,7 +276,7 @@ multiproc_test = mpi_multiproc_test if mpi else local_multiproc_test
#
def acquire_write(lock_path, start=0, length=0):
def fn(barrier):
- lock = Lock(lock_path, start, length)
+ lock = lk.Lock(lock_path, start, length)
lock.acquire_write() # grab exclusive lock
barrier.wait()
barrier.wait() # hold the lock until timeout in other procs.
@@ -266,7 +285,7 @@ def acquire_write(lock_path, start=0, length=0):
def acquire_read(lock_path, start=0, length=0):
def fn(barrier):
- lock = Lock(lock_path, start, length)
+ lock = lk.Lock(lock_path, start, length)
lock.acquire_read() # grab shared lock
barrier.wait()
barrier.wait() # hold the lock until timeout in other procs.
@@ -275,9 +294,9 @@ def acquire_read(lock_path, start=0, length=0):
def timeout_write(lock_path, start=0, length=0):
def fn(barrier):
- lock = Lock(lock_path, start, length)
+ lock = lk.Lock(lock_path, start, length)
barrier.wait() # wait for lock acquire in first process
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
barrier.wait()
return fn
@@ -285,9 +304,9 @@ def timeout_write(lock_path, start=0, length=0):
def timeout_read(lock_path, start=0, length=0):
def fn(barrier):
- lock = Lock(lock_path, start, length)
+ lock = lk.Lock(lock_path, start, length)
barrier.wait() # wait for lock acquire in first process
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait()
return fn
@@ -527,9 +546,47 @@ def test_write_lock_timeout_with_multiple_readers_3_2_ranges(lock_path):
timeout_write(lock_path, 5, 1))
-#
-# Test that read can be upgraded to write.
-#
+def test_read_lock_on_read_only_lockfile(lock_dir, lock_path):
+ """read-only directory, read-only lockfile."""
+ touch(lock_path)
+ with read_only(lock_path, lock_dir):
+ lock = lk.Lock(lock_path)
+
+ with lk.ReadTransaction(lock):
+ pass
+
+ with pytest.raises(lk.LockROFileError):
+ with lk.WriteTransaction(lock):
+ pass
+
+
+def test_read_lock_read_only_dir_writable_lockfile(lock_dir, lock_path):
+ """read-only directory, writable lockfile."""
+ touch(lock_path)
+ with read_only(lock_dir):
+ lock = lk.Lock(lock_path)
+
+ with lk.ReadTransaction(lock):
+ pass
+
+ with lk.WriteTransaction(lock):
+ pass
+
+
+def test_read_lock_no_lockfile(lock_dir, lock_path):
+ """read-only directory, no lockfile (so can't create)."""
+ with read_only(lock_dir):
+ lock = lk.Lock(lock_path)
+
+ with pytest.raises(lk.CantCreateLockError):
+ with lk.ReadTransaction(lock):
+ pass
+
+ with pytest.raises(lk.CantCreateLockError):
+ with lk.WriteTransaction(lock):
+ pass
+
+
def test_upgrade_read_to_write(private_lock_path):
"""Test that a read lock can be upgraded to a write lock.
@@ -542,7 +599,7 @@ def test_upgrade_read_to_write(private_lock_path):
# to begin wtih.
touch(private_lock_path)
- lock = Lock(private_lock_path)
+ lock = lk.Lock(private_lock_path)
assert lock._reads == 0
assert lock._writes == 0
@@ -567,16 +624,14 @@ def test_upgrade_read_to_write(private_lock_path):
assert lock._file is None
-#
-# Test that read-only file can be read-locked but not write-locked.
-#
def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
- # ensure lock file exists the first time, so we open it read-only
- # to begin wtih.
+ """Test that read-only file can be read-locked but not write-locked."""
+ # ensure lock file exists the first time
touch(private_lock_path)
+ # open it read-only to begin wtih.
with read_only(private_lock_path):
- lock = Lock(private_lock_path)
+ lock = lk.Lock(private_lock_path)
assert lock._reads == 0
assert lock._writes == 0
@@ -585,7 +640,8 @@ def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
assert lock._writes == 0
assert lock._file.mode == 'r'
- with pytest.raises(LockError):
+ # upgrade to writ here
+ with pytest.raises(lk.LockROFileError):
lock.acquire_write()
@@ -595,7 +651,7 @@ def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
#
def test_complex_acquire_and_release_chain(lock_path):
def p1(barrier):
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
lock.acquire_write()
barrier.wait() # ---------------------------------------- 1
@@ -603,7 +659,7 @@ def test_complex_acquire_and_release_chain(lock_path):
barrier.wait() # ---------------------------------------- 2
lock.release_write() # release and others acquire read
barrier.wait() # ---------------------------------------- 3
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
lock.acquire_read()
barrier.wait() # ---------------------------------------- 4
@@ -612,9 +668,9 @@ def test_complex_acquire_and_release_chain(lock_path):
# p2 upgrades read to write
barrier.wait() # ---------------------------------------- 6
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait() # ---------------------------------------- 7
# p2 releases write and read
@@ -624,9 +680,9 @@ def test_complex_acquire_and_release_chain(lock_path):
barrier.wait() # ---------------------------------------- 9
# p3 upgrades read to write
barrier.wait() # ---------------------------------------- 10
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait() # ---------------------------------------- 11
# p3 releases locks
@@ -636,13 +692,13 @@ def test_complex_acquire_and_release_chain(lock_path):
lock.release_read()
def p2(barrier):
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
# p1 acquires write
barrier.wait() # ---------------------------------------- 1
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait() # ---------------------------------------- 2
lock.acquire_read()
@@ -664,9 +720,9 @@ def test_complex_acquire_and_release_chain(lock_path):
barrier.wait() # ---------------------------------------- 9
# p3 upgrades read to write
barrier.wait() # ---------------------------------------- 10
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait() # ---------------------------------------- 11
# p3 releases locks
@@ -676,13 +732,13 @@ def test_complex_acquire_and_release_chain(lock_path):
lock.release_read()
def p3(barrier):
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
# p1 acquires write
barrier.wait() # ---------------------------------------- 1
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait() # ---------------------------------------- 2
lock.acquire_read()
@@ -694,9 +750,9 @@ def test_complex_acquire_and_release_chain(lock_path):
# p2 upgrades read to write
barrier.wait() # ---------------------------------------- 6
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_write(lock_fail_timeout)
- with pytest.raises(LockError):
+ with pytest.raises(lk.LockTimeoutError):
lock.acquire_read(lock_fail_timeout)
barrier.wait() # ---------------------------------------- 7
# p2 releases write & read
@@ -726,9 +782,9 @@ def test_transaction(lock_path):
vals['exited'] = True
vals['exception'] = (t or v or tb)
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
vals = {'entered': False, 'exited': False, 'exception': False}
- with ReadTransaction(lock, enter_fn, exit_fn):
+ with lk.ReadTransaction(lock, enter_fn, exit_fn):
pass
assert vals['entered']
@@ -736,7 +792,7 @@ def test_transaction(lock_path):
assert not vals['exception']
vals = {'entered': False, 'exited': False, 'exception': False}
- with WriteTransaction(lock, enter_fn, exit_fn):
+ with lk.WriteTransaction(lock, enter_fn, exit_fn):
pass
assert vals['entered']
@@ -752,14 +808,14 @@ def test_transaction_with_exception(lock_path):
vals['exited'] = True
vals['exception'] = (t or v or tb)
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
def do_read_with_exception():
- with ReadTransaction(lock, enter_fn, exit_fn):
+ with lk.ReadTransaction(lock, enter_fn, exit_fn):
raise Exception()
def do_write_with_exception():
- with WriteTransaction(lock, enter_fn, exit_fn):
+ with lk.WriteTransaction(lock, enter_fn, exit_fn):
raise Exception()
vals = {'entered': False, 'exited': False, 'exception': False}
@@ -791,11 +847,11 @@ def test_transaction_with_context_manager(lock_path):
vals['exited_fn'] = True
vals['exception_fn'] = (t or v or tb)
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
vals = {'entered': False, 'exited': False, 'exited_fn': False,
'exception': False, 'exception_fn': False}
- with ReadTransaction(lock, TestContextManager, exit_fn):
+ with lk.ReadTransaction(lock, TestContextManager, exit_fn):
pass
assert vals['entered']
@@ -806,7 +862,7 @@ def test_transaction_with_context_manager(lock_path):
vals = {'entered': False, 'exited': False, 'exited_fn': False,
'exception': False, 'exception_fn': False}
- with ReadTransaction(lock, TestContextManager):
+ with lk.ReadTransaction(lock, TestContextManager):
pass
assert vals['entered']
@@ -817,7 +873,7 @@ def test_transaction_with_context_manager(lock_path):
vals = {'entered': False, 'exited': False, 'exited_fn': False,
'exception': False, 'exception_fn': False}
- with WriteTransaction(lock, TestContextManager, exit_fn):
+ with lk.WriteTransaction(lock, TestContextManager, exit_fn):
pass
assert vals['entered']
@@ -828,7 +884,7 @@ def test_transaction_with_context_manager(lock_path):
vals = {'entered': False, 'exited': False, 'exited_fn': False,
'exception': False, 'exception_fn': False}
- with WriteTransaction(lock, TestContextManager):
+ with lk.WriteTransaction(lock, TestContextManager):
pass
assert vals['entered']
@@ -851,14 +907,14 @@ def test_transaction_with_context_manager_and_exception(lock_path):
vals['exited_fn'] = True
vals['exception_fn'] = (t or v or tb)
- lock = Lock(lock_path)
+ lock = lk.Lock(lock_path)
def do_read_with_exception(exit_fn):
- with ReadTransaction(lock, TestContextManager, exit_fn):
+ with lk.ReadTransaction(lock, TestContextManager, exit_fn):
raise Exception()
def do_write_with_exception(exit_fn):
- with WriteTransaction(lock, TestContextManager, exit_fn):
+ with lk.WriteTransaction(lock, TestContextManager, exit_fn):
raise Exception()
vals = {'entered': False, 'exited': False, 'exited_fn': False,
@@ -900,3 +956,102 @@ def test_transaction_with_context_manager_and_exception(lock_path):
assert vals['exception']
assert not vals['exited_fn']
assert not vals['exception_fn']
+
+
+def test_lock_debug_output(lock_path):
+ host = socket.getfqdn()
+
+ def p1(barrier, q1, q2):
+ # exchange pids
+ p1_pid = os.getpid()
+ q1.put(p1_pid)
+ p2_pid = q2.get()
+
+ # set up lock
+ lock = lk.Lock(lock_path, debug=True)
+
+ with lk.WriteTransaction(lock):
+ # p1 takes write lock and writes pid/host to file
+ barrier.wait() # ------------------------------------ 1
+
+ assert lock.pid == p1_pid
+ assert lock.host == host
+
+ # wait for p2 to verify contents of file
+ barrier.wait() # ---------------------------------------- 2
+
+ # wait for p2 to take a write lock
+ barrier.wait() # ---------------------------------------- 3
+
+ # verify pid/host info again
+ with lk.ReadTransaction(lock):
+ assert lock.old_pid == p1_pid
+ assert lock.old_host == host
+
+ assert lock.pid == p2_pid
+ assert lock.host == host
+
+ barrier.wait() # ---------------------------------------- 4
+
+ def p2(barrier, q1, q2):
+ # exchange pids
+ p2_pid = os.getpid()
+ p1_pid = q1.get()
+ q2.put(p2_pid)
+
+ # set up lock
+ lock = lk.Lock(lock_path, debug=True)
+
+ # p1 takes write lock and writes pid/host to file
+ barrier.wait() # ---------------------------------------- 1
+
+ # verify that p1 wrote information to lock file
+ with lk.ReadTransaction(lock):
+ assert lock.pid == p1_pid
+ assert lock.host == host
+
+ barrier.wait() # ---------------------------------------- 2
+
+ # take a write lock on the file and verify pid/host info
+ with lk.WriteTransaction(lock):
+ assert lock.old_pid == p1_pid
+ assert lock.old_host == host
+
+ assert lock.pid == p2_pid
+ assert lock.host == host
+
+ barrier.wait() # ------------------------------------ 3
+
+ # wait for p1 to verify pid/host info
+ barrier.wait() # ---------------------------------------- 4
+
+ q1, q2 = Queue(), Queue()
+ local_multiproc_test(p2, p1, extra_args=(q1, q2))
+
+
+def test_lock_with_no_parent_directory(tmpdir):
+ """Make sure locks work even when their parent directory does not exist."""
+ with tmpdir.as_cwd():
+ lock = lk.Lock('foo/bar/baz/lockfile')
+ with lk.WriteTransaction(lock):
+ pass
+
+
+def test_lock_in_current_directory(tmpdir):
+ """Make sure locks work even when their parent directory does not exist."""
+ with tmpdir.as_cwd():
+ # test we can create a lock in the current directory
+ lock = lk.Lock('lockfile')
+ for i in range(10):
+ with lk.ReadTransaction(lock):
+ pass
+ with lk.WriteTransaction(lock):
+ pass
+
+ # and that we can do the same thing after it's already there
+ lock = lk.Lock('lockfile')
+ for i in range(10):
+ with lk.ReadTransaction(lock):
+ pass
+ with lk.WriteTransaction(lock):
+ pass
diff --git a/lib/spack/spack/test/llnl/util/log.py b/lib/spack/spack/test/llnl/util/log.py
index 44f4f15131..530c4b8be6 100644
--- a/lib/spack/spack/test/llnl/util/log.py
+++ b/lib/spack/spack/test/llnl/util/log.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import pytest
diff --git a/lib/spack/spack/test/make_executable.py b/lib/spack/spack/test/make_executable.py
index dd50746ade..08dbe4edf7 100644
--- a/lib/spack/spack/test/make_executable.py
+++ b/lib/spack/spack/test/make_executable.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
Tests for Spack's built-in parallel make support.
@@ -32,7 +13,6 @@ import shutil
import tempfile
import unittest
-from llnl.util.filesystem import join_path
from spack.build_environment import MakeExecutable
from spack.util.environment import path_put_first
@@ -42,7 +22,7 @@ class MakeExecutableTest(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
- make_exe = join_path(self.tmpdir, 'make')
+ make_exe = os.path.join(self.tmpdir, 'make')
with open(make_exe, 'w') as f:
f.write('#!/bin/sh\n')
f.write('echo "$@"')
@@ -123,3 +103,10 @@ class MakeExecutableTest(unittest.TestCase):
output=str).strip(), '-j8 install')
del os.environ['SPACK_NO_PARALLEL_MAKE']
+
+ def test_make_jobs_env(self):
+ make = MakeExecutable('make', 8)
+ dump_env = {}
+ self.assertEqual(make(output=str, jobs_env='MAKE_PARALLELISM',
+ _dump_env=dump_env).strip(), '-j8')
+ self.assertEqual(dump_env['MAKE_PARALLELISM'], '8')
diff --git a/lib/spack/spack/test/mirror.py b/lib/spack/spack/test/mirror.py
index ec8a0d504c..d59f958481 100644
--- a/lib/spack/spack/test/mirror.py
+++ b/lib/spack/spack/test/mirror.py
@@ -1,40 +1,21 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import filecmp
import os
import pytest
-from llnl.util.filesystem import join_path
-
-import spack
+import spack.repo
import spack.mirror
import spack.util.executable
from spack.spec import Spec
from spack.stage import Stage
from spack.util.executable import which
+pytestmark = pytest.mark.usefixtures('config', 'mutable_mock_packages')
+
# paths in repos that shouldn't be in the mirror tarballs.
exclude = ['.hg', '.git', '.svn']
@@ -66,10 +47,10 @@ def set_up_package(name, repository, url_attr):
def check_mirror():
with Stage('spack-mirror-test') as stage:
- mirror_root = join_path(stage.path, 'test-mirror')
+ mirror_root = os.path.join(stage.path, 'test-mirror')
# register mirror with spack config
mirrors = {'spack-mirror-test': 'file://' + mirror_root}
- spack.config.update_config('mirrors', mirrors)
+ spack.config.set('mirrors', mirrors)
spack.mirror.create(mirror_root, repos, no_checksum=True)
# Stage directory exists
@@ -77,7 +58,7 @@ def check_mirror():
# check that there are subdirs for each package
for name in repos:
- subdir = join_path(mirror_root, name)
+ subdir = os.path.join(mirror_root, name)
assert os.path.isdir(subdir)
files = os.listdir(subdir)
@@ -88,72 +69,72 @@ def check_mirror():
spec = Spec(name).concretized()
pkg = spec.package
- saved_checksum_setting = spack.do_checksum
- with pkg.stage:
- # Stage the archive from the mirror and cd to it.
- spack.do_checksum = False
- pkg.do_stage(mirror_only=True)
-
- # Compare the original repo with the expanded archive
- original_path = mock_repo.path
- if 'svn' in name:
- # have to check out the svn repo to compare.
- original_path = join_path(
- mock_repo.path, 'checked_out')
-
- svn = which('svn', required=True)
- svn('checkout', mock_repo.url, original_path)
-
- dcmp = filecmp.dircmp(original_path, pkg.stage.source_path)
- # make sure there are no new files in the expanded
- # tarball
- assert not dcmp.right_only
- # and that all original files are present.
- assert all(l in exclude for l in dcmp.left_only)
- spack.do_checksum = saved_checksum_setting
-
-
-@pytest.mark.usefixtures('config', 'refresh_builtin_mock')
-class TestMirror(object):
- def test_url_mirror(self, mock_archive):
- set_up_package('trivial-install-test-package', mock_archive, 'url')
- check_mirror()
- repos.clear()
-
- @pytest.mark.skipif(
- not which('git'), reason='requires git to be installed')
- def test_git_mirror(self, mock_git_repository):
- set_up_package('git-test', mock_git_repository, 'git')
- check_mirror()
- repos.clear()
-
- @pytest.mark.skipif(
- not which('svn'), reason='requires subversion to be installed')
- def test_svn_mirror(self, mock_svn_repository):
- set_up_package('svn-test', mock_svn_repository, 'svn')
- check_mirror()
- repos.clear()
-
- @pytest.mark.skipif(
- not which('hg'), reason='requires mercurial to be installed')
- def test_hg_mirror(self, mock_hg_repository):
- set_up_package('hg-test', mock_hg_repository, 'hg')
- check_mirror()
- repos.clear()
-
- @pytest.mark.skipif(
- not all([which('svn'), which('hg'), which('git')]),
- reason='requires subversion, git, and mercurial to be installed')
- def test_all_mirror(
- self,
- mock_git_repository,
- mock_svn_repository,
- mock_hg_repository,
- mock_archive):
-
- set_up_package('git-test', mock_git_repository, 'git')
- set_up_package('svn-test', mock_svn_repository, 'svn')
- set_up_package('hg-test', mock_hg_repository, 'hg')
- set_up_package('trivial-install-test-package', mock_archive, 'url')
- check_mirror()
- repos.clear()
+ with spack.config.override('config:checksum', False):
+ with pkg.stage:
+ pkg.do_stage(mirror_only=True)
+
+ # Compare the original repo with the expanded archive
+ original_path = mock_repo.path
+ if 'svn' in name:
+ # have to check out the svn repo to compare.
+ original_path = os.path.join(
+ mock_repo.path, 'checked_out')
+
+ svn = which('svn', required=True)
+ svn('checkout', mock_repo.url, original_path)
+
+ dcmp = filecmp.dircmp(
+ original_path, pkg.stage.source_path)
+
+ # make sure there are no new files in the expanded
+ # tarball
+ assert not dcmp.right_only
+ # and that all original files are present.
+ assert all(l in exclude for l in dcmp.left_only)
+
+
+def test_url_mirror(mock_archive):
+ set_up_package('trivial-install-test-package', mock_archive, 'url')
+ check_mirror()
+ repos.clear()
+
+
+@pytest.mark.skipif(
+ not which('git'), reason='requires git to be installed')
+def test_git_mirror(mock_git_repository):
+ set_up_package('git-test', mock_git_repository, 'git')
+ check_mirror()
+ repos.clear()
+
+
+@pytest.mark.skipif(
+ not which('svn'), reason='requires subversion to be installed')
+def test_svn_mirror(mock_svn_repository):
+ set_up_package('svn-test', mock_svn_repository, 'svn')
+ check_mirror()
+ repos.clear()
+
+
+@pytest.mark.skipif(
+ not which('hg'), reason='requires mercurial to be installed')
+def test_hg_mirror(mock_hg_repository):
+ set_up_package('hg-test', mock_hg_repository, 'hg')
+ check_mirror()
+ repos.clear()
+
+
+@pytest.mark.skipif(
+ not all([which('svn'), which('hg'), which('git')]),
+ reason='requires subversion, git, and mercurial to be installed')
+def test_all_mirror(
+ mock_git_repository,
+ mock_svn_repository,
+ mock_hg_repository,
+ mock_archive):
+
+ set_up_package('git-test', mock_git_repository, 'git')
+ set_up_package('svn-test', mock_svn_repository, 'svn')
+ set_up_package('hg-test', mock_hg_repository, 'hg')
+ set_up_package('trivial-install-test-package', mock_archive, 'url')
+ check_mirror()
+ repos.clear()
diff --git a/lib/spack/spack/test/module_parsing.py b/lib/spack/spack/test/module_parsing.py
index 61e0ba1972..3ff7e764a9 100644
--- a/lib/spack/spack/test/module_parsing.py
+++ b/lib/spack/spack/test/module_parsing.py
@@ -1,34 +1,18 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import subprocess
import os
-from spack.util.module_cmd import get_path_from_module
-from spack.util.module_cmd import get_argument_from_module_line
-from spack.util.module_cmd import get_module_cmd_from_bash
-from spack.util.module_cmd import get_module_cmd, ModuleError
+from spack.util.module_cmd import (
+ get_path_from_module,
+ get_path_from_module_contents,
+ get_path_arg_from_module_line,
+ get_module_cmd_from_bash,
+ get_module_cmd,
+ ModuleError)
typeset_func = subprocess.Popen('module avail',
@@ -42,19 +26,20 @@ MODULE_NOT_DEFINED = b'not found' in typeset
@pytest.fixture
def save_env():
- old_PATH = os.environ.get('PATH', None)
+ old_path = os.environ.get('PATH', None)
old_bash_func = os.environ.get('BASH_FUNC_module()', None)
yield
- if old_PATH:
- os.environ['PATH'] = old_PATH
+ if old_path:
+ os.environ['PATH'] = old_path
if old_bash_func:
os.environ['BASH_FUNC_module()'] = old_bash_func
def test_get_path_from_module(save_env):
lines = ['prepend-path LD_LIBRARY_PATH /path/to/lib',
+ 'prepend-path CRAY_LD_LIBRARY_PATH /path/to/lib',
'setenv MOD_DIR /path/to',
'setenv LDFLAGS -Wl,-rpath/path/to/lib',
'setenv LDFLAGS -L/path/to/lib',
@@ -64,7 +49,6 @@ def test_get_path_from_module(save_env):
module_func = '() { eval `echo ' + line + ' bash filler`\n}'
os.environ['BASH_FUNC_module()'] = module_func
path = get_path_from_module('mod')
-
assert path == '/path/to'
os.environ['BASH_FUNC_module()'] = '() { eval $(echo fill bash $*)\n}'
@@ -73,6 +57,38 @@ def test_get_path_from_module(save_env):
assert path is None
+def test_get_path_from_module_contents():
+ # A line with "MODULEPATH" appears early on, and the test confirms that it
+ # is not extracted as the package's path
+ module_show_output = """
+os.environ["MODULEPATH"] = "/path/to/modules1:/path/to/modules2";
+----------------------------------------------------------------------------
+ /root/cmake/3.9.2.lua:
+----------------------------------------------------------------------------
+help([[CMake Version 3.9.2
+]])
+whatis("Name: CMake")
+whatis("Version: 3.9.2")
+whatis("Category: Tools")
+whatis("URL: https://cmake.org/")
+prepend_path("PATH","/path/to/cmake-3.9.2/bin")
+prepend_path("MANPATH","/path/to/cmake/cmake-3.9.2/share/man")
+"""
+ module_show_lines = module_show_output.split('\n')
+ assert (get_path_from_module_contents(module_show_lines, 'cmake-3.9.2') ==
+ '/path/to/cmake-3.9.2')
+
+
+def test_pkg_dir_from_module_name():
+ module_show_lines = ['setenv FOO_BAR_DIR /path/to/foo-bar']
+
+ assert (get_path_from_module_contents(module_show_lines, 'foo-bar') ==
+ '/path/to/foo-bar')
+
+ assert (get_path_from_module_contents(module_show_lines, 'foo-bar/1.0') ==
+ '/path/to/foo-bar')
+
+
def test_get_argument_from_module_line():
lines = ['prepend-path LD_LIBRARY_PATH /lib/path',
'prepend-path LD_LIBRARY_PATH /lib/path',
@@ -83,10 +99,10 @@ def test_get_argument_from_module_line():
bad_lines = ['prepend_path(PATH,/lib/path)',
'prepend-path (LD_LIBRARY_PATH) /lib/path']
- assert all(get_argument_from_module_line(l) == '/lib/path' for l in lines)
+ assert all(get_path_arg_from_module_line(l) == '/lib/path' for l in lines)
for bl in bad_lines:
with pytest.raises(ValueError):
- get_argument_from_module_line(bl)
+ get_path_arg_from_module_line(bl)
@pytest.mark.skipif(MODULE_NOT_DEFINED, reason='Depends on defined module fn')
diff --git a/lib/spack/spack/test/modules/common.py b/lib/spack/spack/test/modules/common.py
index 9c04dae649..63d3f562fd 100644
--- a/lib/spack/spack/test/modules/common.py
+++ b/lib/spack/spack/test/modules/common.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import spack.modules.common
diff --git a/lib/spack/spack/test/modules/conftest.py b/lib/spack/spack/test/modules/conftest.py
index 35b5a30856..5e5133ec9c 100644
--- a/lib/spack/spack/test/modules/conftest.py
+++ b/lib/spack/spack/test/modules/conftest.py
@@ -1,37 +1,19 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+import os.path
import collections
import contextlib
import inspect
-import os.path
-import yaml
-from six import StringIO
+import ruamel.yaml as yaml
import pytest
-import spack
+from six import StringIO
+
+import spack.paths
+import spack.spec
import spack.modules.common
import spack.util.path
@@ -90,14 +72,6 @@ def modulefile_content(filename_dict, request):
@pytest.fixture()
-def update_template_dirs(config, monkeypatch):
- """Mocks the template directories for tests"""
- dirs = spack.config.get_config('config')['template_dirs']
- dirs = [spack.util.path.canonicalize_path(x) for x in dirs]
- monkeypatch.setattr(spack, 'template_dirs', dirs)
-
-
-@pytest.fixture()
def patch_configuration(monkeypatch, request):
"""Reads a configuration file from the mock ones prepared for tests
and monkeypatches the right classes to hook it in.
@@ -110,7 +84,7 @@ def patch_configuration(monkeypatch, request):
writer_key = str(writer_mod.__name__).split('.')[-1]
# Root folder for configuration
root_for_conf = os.path.join(
- spack.test_path, 'data', 'modules', writer_key
+ spack.paths.test_path, 'data', 'modules', writer_key
)
def _impl(filename):
@@ -138,6 +112,14 @@ def patch_configuration(monkeypatch, request):
@pytest.fixture()
+def update_template_dirs(config, monkeypatch):
+ """Mocks the template directories for tests"""
+ dirs = spack.config.get_config('config')['template_dirs']
+ dirs = [spack.util.path.canonicalize_path(x) for x in dirs]
+ monkeypatch.setattr(spack, 'template_dirs', dirs)
+
+
+@pytest.fixture()
def factory(request):
"""Function that, given a spec string, returns an instance of the writer
and the corresponding spec.
diff --git a/lib/spack/spack/test/modules/dotkit.py b/lib/spack/spack/test/modules/dotkit.py
index b27a9eecf7..f97bc14216 100644
--- a/lib/spack/spack/test/modules/dotkit.py
+++ b/lib/spack/spack/test/modules/dotkit.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.modules.dotkit
@@ -30,39 +11,37 @@ import spack.modules.dotkit
writer_cls = spack.modules.dotkit.DotkitModulefileWriter
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestDotkit(object):
- def test_dotkit(self, modulefile_content, patch_configuration):
+ def test_dotkit(self, modulefile_content, module_configuration):
"""Tests the generation of a dotkit file that loads dependencies
automatically.
"""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content('mpileaks arch=x86-linux')
assert '#c spack' in content
assert '#d mpileaks @2.3' in content
assert len([x for x in content if 'dk_op' in x]) == 2
- @pytest.mark.usefixtures('update_template_dirs')
def test_override_template_in_package(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests overriding a template from and attribute in the package."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content('override-module-templates')
assert 'Override successful!' in content
- @pytest.mark.usefixtures('update_template_dirs')
def test_override_template_in_modules_yaml(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests overriding a template from `modules.yaml`"""
- patch_configuration('override_template')
+ module_configuration('override_template')
# Check that this takes precedence over an attribute in the package
content = modulefile_content('override-module-templates')
diff --git a/lib/spack/spack/test/modules/lmod.py b/lib/spack/spack/test/modules/lmod.py
index 494a78e829..fe97ae9910 100644
--- a/lib/spack/spack/test/modules/lmod.py
+++ b/lib/spack/spack/test/modules/lmod.py
@@ -1,28 +1,10 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import re
import pytest
import spack.modules.lmod
@@ -52,14 +34,14 @@ def provider(request):
return request.param
-@pytest.mark.usefixtures('config', 'builtin_mock',)
+@pytest.mark.usefixtures('config', 'mock_packages',)
class TestLmod(object):
def test_file_layout(
- self, compiler, provider, factory, patch_configuration
+ self, compiler, provider, factory, module_configuration
):
"""Tests the layout of files in the hierarchy is the one expected."""
- patch_configuration('complex_hierarchy')
+ module_configuration('complex_hierarchy')
spec_string, services = provider
module, spec = factory(spec_string + '%' + compiler)
@@ -91,10 +73,10 @@ class TestLmod(object):
else:
assert repetitions == 1
- def test_simple_case(self, modulefile_content, patch_configuration):
+ def test_simple_case(self, modulefile_content, module_configuration):
"""Tests the generation of a simple TCL module file."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content(mpich_spec_string)
assert '-- -*- lua -*-' in content
@@ -102,10 +84,10 @@ class TestLmod(object):
assert 'whatis([[Version : 3.0.4]])' in content
assert 'family("mpi")' in content
- def test_autoload_direct(self, modulefile_content, patch_configuration):
+ def test_autoload_direct(self, modulefile_content, module_configuration):
"""Tests the automatic loading of direct dependencies."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content(mpileaks_spec_string)
assert len([x for x in content if 'if not isloaded(' in x]) == 2
@@ -116,10 +98,10 @@ class TestLmod(object):
messages = [x for x in content if 'LmodMessage("Autoloading' in x]
assert len(messages) == 0
- def test_autoload_all(self, modulefile_content, patch_configuration):
+ def test_autoload_all(self, modulefile_content, module_configuration):
"""Tests the automatic loading of all dependencies."""
- patch_configuration('autoload_all')
+ module_configuration('autoload_all')
content = modulefile_content(mpileaks_spec_string)
assert len([x for x in content if 'if not isloaded(' in x]) == 5
@@ -129,10 +111,10 @@ class TestLmod(object):
messages = [x for x in content if 'LmodMessage("Autoloading' in x]
assert len(messages) == 5
- def test_alter_environment(self, modulefile_content, patch_configuration):
+ def test_alter_environment(self, modulefile_content, module_configuration):
"""Tests modifications to run-time environment."""
- patch_configuration('alter_environment')
+ module_configuration('alter_environment')
content = modulefile_content('mpileaks platform=test target=x86_64')
assert len(
@@ -151,31 +133,44 @@ class TestLmod(object):
assert len([x for x in content if 'setenv("FOO", "foo")' in x]) == 0
assert len([x for x in content if 'unsetenv("BAR")' in x]) == 0
- def test_blacklist(self, modulefile_content, patch_configuration):
+ def test_prepend_path_separator(self, modulefile_content,
+ module_configuration):
+ """Tests modifications to run-time environment."""
+
+ module_configuration('module_path_separator')
+ content = modulefile_content('module-path-separator')
+
+ for line in content:
+ if re.match(r'[a-z]+_path\("COLON"', line):
+ assert line.endswith('"foo", ":")')
+ elif re.match(r'[a-z]+_path\("SEMICOLON"', line):
+ assert line.endswith('"bar", ";")')
+
+ def test_blacklist(self, modulefile_content, module_configuration):
"""Tests blacklisting the generation of selected modules."""
- patch_configuration('blacklist')
+ module_configuration('blacklist')
content = modulefile_content(mpileaks_spec_string)
assert len([x for x in content if 'if not isloaded(' in x]) == 1
assert len([x for x in content if 'load(' in x]) == 1
- def test_no_hash(self, factory, patch_configuration):
+ def test_no_hash(self, factory, module_configuration):
"""Makes sure that virtual providers (in the hierarchy) always
include a hash. Make sure that the module file for the spec
does not include a hash if hash_length is 0.
"""
- patch_configuration('no_hash')
+ module_configuration('no_hash')
module, spec = factory(mpileaks_spec_string)
path = module.layout.filename
mpi_spec = spec['mpi']
- mpiElement = "{0}/{1}-{2}/".format(
+ mpi_element = "{0}/{1}-{2}/".format(
mpi_spec.name, mpi_spec.version, mpi_spec.dag_hash(length=7)
)
- assert mpiElement in path
+ assert mpi_element in path
mpileaks_spec = spec
mpileaks_element = "{0}/{1}.lua".format(
@@ -184,52 +179,50 @@ class TestLmod(object):
assert path.endswith(mpileaks_element)
- def test_no_core_compilers(self, factory, patch_configuration):
+ def test_no_core_compilers(self, factory, module_configuration):
"""Ensures that missing 'core_compilers' in the configuration file
raises the right exception.
"""
# In this case we miss the entry completely
- patch_configuration('missing_core_compilers')
+ module_configuration('missing_core_compilers')
module, spec = factory(mpileaks_spec_string)
with pytest.raises(spack.modules.lmod.CoreCompilersNotFoundError):
module.write()
# Here we have an empty list
- patch_configuration('core_compilers_empty')
+ module_configuration('core_compilers_empty')
module, spec = factory(mpileaks_spec_string)
with pytest.raises(spack.modules.lmod.CoreCompilersNotFoundError):
module.write()
- def test_non_virtual_in_hierarchy(self, factory, patch_configuration):
+ def test_non_virtual_in_hierarchy(self, factory, module_configuration):
"""Ensures that if a non-virtual is in hierarchy, an exception will
be raised.
"""
- patch_configuration('non_virtual_in_hierarchy')
+ module_configuration('non_virtual_in_hierarchy')
module, spec = factory(mpileaks_spec_string)
with pytest.raises(spack.modules.lmod.NonVirtualInHierarchyError):
module.write()
- @pytest.mark.usefixtures('update_template_dirs')
def test_override_template_in_package(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests overriding a template from and attribute in the package."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content('override-module-templates')
assert 'Override successful!' in content
- @pytest.mark.usefixtures('update_template_dirs')
def test_override_template_in_modules_yaml(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests overriding a template from `modules.yaml`"""
- patch_configuration('override_template')
+ module_configuration('override_template')
content = modulefile_content('override-module-templates')
assert 'Override even better!' in content
@@ -246,3 +239,26 @@ class TestLmod(object):
writer, spec = factory('externaltool')
assert 'unknown' in writer.context.configure_options
+
+ def test_guess_core_compilers(
+ self, factory, module_configuration, monkeypatch
+ ):
+ """Check that we can guess core compilers."""
+
+ # In this case we miss the entry completely
+ module_configuration('missing_core_compilers')
+
+ # Our mock paths must be detected as system paths
+ monkeypatch.setattr(
+ spack.util.environment, 'system_dirs', ['/path/to']
+ )
+
+ # We don't want to really write into user configuration
+ # when running tests
+ def no_op_set(*args, **kwargs):
+ pass
+ monkeypatch.setattr(spack.config, 'set', no_op_set)
+
+ # Assert we have core compilers now
+ writer, _ = factory(mpileaks_spec_string)
+ assert writer.conf.core_compilers
diff --git a/lib/spack/spack/test/modules/tcl.py b/lib/spack/spack/test/modules/tcl.py
index 0a8dd99c76..b7b6a023ce 100644
--- a/lib/spack/spack/test/modules/tcl.py
+++ b/lib/spack/spack/test/modules/tcl.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.modules.common
@@ -36,21 +17,21 @@ libdwarf_spec_string = 'libdwarf arch=x64-linux'
writer_cls = spack.modules.tcl.TclModulefileWriter
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestTcl(object):
- def test_simple_case(self, modulefile_content, patch_configuration):
+ def test_simple_case(self, modulefile_content, module_configuration):
"""Tests the generation of a simple TCL module file."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content(mpich_spec_string)
assert 'module-whatis "mpich @3.0.4"' in content
- def test_autoload_direct(self, modulefile_content, patch_configuration):
+ def test_autoload_direct(self, modulefile_content, module_configuration):
"""Tests the automatic loading of direct dependencies."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content(mpileaks_spec_string)
assert len([x for x in content if 'is-loaded' in x]) == 2
@@ -70,10 +51,10 @@ class TestTcl(object):
messages = [x for x in content if 'puts stderr "Autoloading' in x]
assert len(messages) == 0
- def test_autoload_all(self, modulefile_content, patch_configuration):
+ def test_autoload_all(self, modulefile_content, module_configuration):
"""Tests the automatic loading of all dependencies."""
- patch_configuration('autoload_all')
+ module_configuration('autoload_all')
content = modulefile_content(mpileaks_spec_string)
assert len([x for x in content if 'is-loaded' in x]) == 5
@@ -94,27 +75,27 @@ class TestTcl(object):
assert len(messages) == 2
def test_prerequisites_direct(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests asking direct dependencies as prerequisites."""
- patch_configuration('prerequisites_direct')
+ module_configuration('prerequisites_direct')
content = modulefile_content('mpileaks arch=x86-linux')
assert len([x for x in content if 'prereq' in x]) == 2
- def test_prerequisites_all(self, modulefile_content, patch_configuration):
+ def test_prerequisites_all(self, modulefile_content, module_configuration):
"""Tests asking all dependencies as prerequisites."""
- patch_configuration('prerequisites_all')
+ module_configuration('prerequisites_all')
content = modulefile_content('mpileaks arch=x86-linux')
assert len([x for x in content if 'prereq' in x]) == 5
- def test_alter_environment(self, modulefile_content, patch_configuration):
+ def test_alter_environment(self, modulefile_content, module_configuration):
"""Tests modifications to run-time environment."""
- patch_configuration('alter_environment')
+ module_configuration('alter_environment')
content = modulefile_content('mpileaks platform=test target=x86_64')
assert len([x for x in content
@@ -143,10 +124,10 @@ class TestTcl(object):
assert len([x for x in content if 'module load foo/bar' in x]) == 1
assert len([x for x in content if 'setenv LIBDWARF_ROOT' in x]) == 1
- def test_blacklist(self, modulefile_content, patch_configuration):
+ def test_blacklist(self, modulefile_content, module_configuration):
"""Tests blacklisting the generation of selected modules."""
- patch_configuration('blacklist')
+ module_configuration('blacklist')
content = modulefile_content('mpileaks ^zmpi')
assert len([x for x in content if 'is-loaded' in x]) == 1
@@ -161,12 +142,12 @@ class TestTcl(object):
assert len([x for x in content if 'is-loaded' in x]) == 1
assert len([x for x in content if 'module load ' in x]) == 1
- def test_naming_scheme(self, factory, patch_configuration):
+ def test_naming_scheme(self, factory, module_configuration):
"""Tests reading the correct naming scheme."""
# This configuration has no error, so check the conflicts directives
# are there
- patch_configuration('conflicts')
+ module_configuration('conflicts')
# Test we read the expected configuration for the naming scheme
writer, _ = factory('mpileaks')
@@ -174,10 +155,10 @@ class TestTcl(object):
assert writer.conf.naming_scheme == expected
- def test_invalid_naming_scheme(self, factory, patch_configuration):
+ def test_invalid_naming_scheme(self, factory, module_configuration):
"""Tests the evaluation of an invalid naming scheme."""
- patch_configuration('invalid_naming_scheme')
+ module_configuration('invalid_naming_scheme')
# Test that having invalid tokens in the naming scheme raises
# a RuntimeError
@@ -185,21 +166,21 @@ class TestTcl(object):
with pytest.raises(RuntimeError):
writer.layout.use_name
- def test_invalid_token_in_env_name(self, factory, patch_configuration):
+ def test_invalid_token_in_env_name(self, factory, module_configuration):
"""Tests setting environment variables with an invalid name."""
- patch_configuration('invalid_token_in_env_var_name')
+ module_configuration('invalid_token_in_env_var_name')
writer, _ = factory('mpileaks')
with pytest.raises(RuntimeError):
writer.write()
- def test_conflicts(self, modulefile_content, patch_configuration):
+ def test_conflicts(self, modulefile_content, module_configuration):
"""Tests adding conflicts to the module."""
# This configuration has no error, so check the conflicts directives
# are there
- patch_configuration('conflicts')
+ module_configuration('conflicts')
content = modulefile_content('mpileaks')
assert len([x for x in content if x.startswith('conflict')]) == 2
@@ -207,13 +188,13 @@ class TestTcl(object):
assert len([x for x in content if x == 'conflict intel/14.0.1']) == 1
# This configuration is inconsistent, check an error is raised
- patch_configuration('wrong_conflicts')
+ module_configuration('wrong_conflicts')
with pytest.raises(SystemExit):
modulefile_content('mpileaks')
- def test_suffixes(self, patch_configuration, factory):
+ def test_suffixes(self, module_configuration, factory):
"""Tests adding suffixes to module file name."""
- patch_configuration('suffix')
+ module_configuration('suffix')
writer, spec = factory('mpileaks+debug arch=x86-linux')
assert 'foo' in writer.layout.use_name
@@ -221,10 +202,10 @@ class TestTcl(object):
writer, spec = factory('mpileaks~debug arch=x86-linux')
assert 'bar' in writer.layout.use_name
- def test_setup_environment(self, modulefile_content, patch_configuration):
+ def test_setup_environment(self, modulefile_content, module_configuration):
"""Tests the internal set-up of run-time environment."""
- patch_configuration('suffix')
+ module_configuration('suffix')
content = modulefile_content('mpileaks')
assert len([x for x in content if 'setenv FOOBAR' in x]) == 1
@@ -241,23 +222,21 @@ class TestTcl(object):
[x for x in content if 'setenv FOOBAR "callpath"' in x]
) == 1
- @pytest.mark.usefixtures('update_template_dirs')
def test_override_template_in_package(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests overriding a template from and attribute in the package."""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content('override-module-templates')
assert 'Override successful!' in content
- @pytest.mark.usefixtures('update_template_dirs')
def test_override_template_in_modules_yaml(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests overriding a template from `modules.yaml`"""
- patch_configuration('override_template')
+ module_configuration('override_template')
content = modulefile_content('override-module-templates')
assert 'Override even better!' in content
@@ -265,15 +244,52 @@ class TestTcl(object):
content = modulefile_content('mpileaks arch=x86-linux')
assert 'Override even better!' in content
- @pytest.mark.usefixtures('update_template_dirs')
def test_extend_context(
- self, modulefile_content, patch_configuration
+ self, modulefile_content, module_configuration
):
"""Tests using a package defined context"""
- patch_configuration('autoload_direct')
+ module_configuration('autoload_direct')
content = modulefile_content('override-context-templates')
assert 'puts stderr "sentence from package"' in content
short_description = 'module-whatis "This package updates the context for TCL modulefiles."' # NOQA: ignore=E501
assert short_description in content
+
+ @pytest.mark.regression('4400')
+ @pytest.mark.db
+ def test_blacklist_implicits(
+ self, modulefile_content, module_configuration, database
+ ):
+ module_configuration('blacklist_implicits')
+
+ # mpileaks has been installed explicitly when setting up
+ # the tests database
+ mpileaks_specs = database.query('mpileaks')
+ for item in mpileaks_specs:
+ writer = writer_cls(item)
+ assert not writer.conf.blacklisted
+
+ # callpath is a dependency of mpileaks, and has been pulled
+ # in implicitly
+ callpath_specs = database.query('callpath')
+ for item in callpath_specs:
+ writer = writer_cls(item)
+ assert writer.conf.blacklisted
+
+ @pytest.mark.regression('9624')
+ @pytest.mark.db
+ def test_autoload_with_constraints(
+ self, modulefile_content, module_configuration, database
+ ):
+ """Tests the automatic loading of direct dependencies."""
+
+ module_configuration('autoload_with_constraints')
+
+ # Test the mpileaks that should have the autoloaded dependencies
+ content = modulefile_content('mpileaks ^mpich2')
+ assert len([x for x in content if 'is-loaded' in x]) == 2
+
+ # Test the mpileaks that should NOT have the autoloaded dependencies
+ content = modulefile_content('mpileaks ^mpich')
+ assert len([x for x in content if 'is-loaded' in x]) == 0
diff --git a/lib/spack/spack/test/multimethod.py b/lib/spack/spack/test/multimethod.py
index 40519cccb1..de694c1498 100644
--- a/lib/spack/spack/test/multimethod.py
+++ b/lib/spack/spack/test/multimethod.py
@@ -1,40 +1,22 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Test for multi_method dispatch."""
-import spack
import pytest
+
+import spack.repo
from spack.multimethod import NoSuchMethodError
-def test_no_version_match(builtin_mock):
+def test_no_version_match(mock_packages):
pkg = spack.repo.get('multimethod@2.0')
with pytest.raises(NoSuchMethodError):
pkg.no_version_2()
-def test_one_version_match(builtin_mock):
+def test_one_version_match(mock_packages):
pkg = spack.repo.get('multimethod@1.0')
assert pkg.no_version_2() == 1
@@ -45,7 +27,7 @@ def test_one_version_match(builtin_mock):
assert pkg.no_version_2() == 4
-def test_version_overlap(builtin_mock):
+def test_version_overlap(mock_packages):
pkg = spack.repo.get('multimethod@2.0')
assert pkg.version_overlap() == 1
@@ -53,7 +35,7 @@ def test_version_overlap(builtin_mock):
assert pkg.version_overlap() == 2
-def test_mpi_version(builtin_mock):
+def test_mpi_version(mock_packages):
pkg = spack.repo.get('multimethod^mpich@3.0.4')
assert pkg.mpi_version() == 3
@@ -64,7 +46,7 @@ def test_mpi_version(builtin_mock):
assert pkg.mpi_version() == 1
-def test_undefined_mpi_version(builtin_mock):
+def test_undefined_mpi_version(mock_packages):
pkg = spack.repo.get('multimethod^mpich@0.4')
assert pkg.mpi_version() == 1
@@ -72,7 +54,7 @@ def test_undefined_mpi_version(builtin_mock):
assert pkg.mpi_version() == 1
-def test_default_works(builtin_mock):
+def test_default_works(mock_packages):
pkg = spack.repo.get('multimethod%gcc')
assert pkg.has_a_default() == 'gcc'
@@ -83,7 +65,7 @@ def test_default_works(builtin_mock):
assert pkg.has_a_default() == 'default'
-def test_target_match(builtin_mock):
+def test_target_match(mock_packages):
platform = spack.architecture.platform()
targets = list(platform.targets.values())
for target in targets[:-1]:
@@ -98,7 +80,7 @@ def test_target_match(builtin_mock):
pkg.different_by_target()
-def test_dependency_match(builtin_mock):
+def test_dependency_match(mock_packages):
pkg = spack.repo.get('multimethod^zmpi')
assert pkg.different_by_dep() == 'zmpi'
@@ -111,7 +93,7 @@ def test_dependency_match(builtin_mock):
assert pkg.different_by_dep() == 'mpich'
-def test_virtual_dep_match(builtin_mock):
+def test_virtual_dep_match(mock_packages):
pkg = spack.repo.get('multimethod^mpich2')
assert pkg.different_by_virtual_dep() == 2
@@ -119,7 +101,7 @@ def test_virtual_dep_match(builtin_mock):
assert pkg.different_by_virtual_dep() == 1
-def test_multimethod_with_base_class(builtin_mock):
+def test_multimethod_with_base_class(mock_packages):
pkg = spack.repo.get('multimethod@3')
assert pkg.base_method() == "subclass_method"
diff --git a/lib/spack/spack/test/namespace_trie.py b/lib/spack/spack/test/namespace_trie.py
index fa38a76cc1..6c64c71f00 100644
--- a/lib/spack/spack/test/namespace_trie.py
+++ b/lib/spack/spack/test/namespace_trie.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.util.naming
diff --git a/lib/spack/spack/test/optional_deps.py b/lib/spack/spack/test/optional_deps.py
index 23702a3410..bac942618b 100644
--- a/lib/spack/spack/test/optional_deps.py
+++ b/lib/spack/spack/test/optional_deps.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
from spack.spec import Spec
@@ -107,14 +88,14 @@ def spec_and_expected(request):
return spec, Spec.from_literal(d)
-def test_normalize(spec_and_expected, config, builtin_mock):
+def test_normalize(spec_and_expected, config, mock_packages):
spec, expected = spec_and_expected
spec = Spec(spec)
spec.normalize()
assert spec.eq_dag(expected, deptypes=False)
-def test_default_variant(config, builtin_mock):
+def test_default_variant(config, mock_packages):
spec = Spec('optional-dep-test-3')
spec.concretize()
assert 'a' in spec
diff --git a/lib/spack/spack/test/package_hash.py b/lib/spack/spack/test/package_hash.py
new file mode 100644
index 0000000000..89fe8e9294
--- /dev/null
+++ b/lib/spack/spack/test/package_hash.py
@@ -0,0 +1,65 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.util.package_hash import package_hash, package_content
+from spack.spec import Spec
+
+
+def test_hash(tmpdir, mock_packages, config):
+ package_hash("hash-test1@1.2")
+
+
+def test_different_variants(tmpdir, mock_packages, config):
+ spec1 = Spec("hash-test1@1.2 +variantx")
+ spec2 = Spec("hash-test1@1.2 +varianty")
+ assert package_hash(spec1) == package_hash(spec2)
+
+
+def test_all_same_but_name(tmpdir, mock_packages, config):
+ spec1 = Spec("hash-test1@1.2")
+ spec2 = Spec("hash-test2@1.2")
+ compare_sans_name(True, spec1, spec2)
+
+ spec1 = Spec("hash-test1@1.2 +varianty")
+ spec2 = Spec("hash-test2@1.2 +varianty")
+ compare_sans_name(True, spec1, spec2)
+
+
+def test_all_same_but_archive_hash(tmpdir, mock_packages, config):
+ """
+ Archive hash is not intended to be reflected in Package hash.
+ """
+ spec1 = Spec("hash-test1@1.3")
+ spec2 = Spec("hash-test2@1.3")
+ compare_sans_name(True, spec1, spec2)
+
+
+def test_all_same_but_patch_contents(tmpdir, mock_packages, config):
+ spec1 = Spec("hash-test1@1.1")
+ spec2 = Spec("hash-test2@1.1")
+ compare_sans_name(True, spec1, spec2)
+
+
+def test_all_same_but_patches_to_apply(tmpdir, mock_packages, config):
+ spec1 = Spec("hash-test1@1.4")
+ spec2 = Spec("hash-test2@1.4")
+ compare_sans_name(True, spec1, spec2)
+
+
+def test_all_same_but_install(tmpdir, mock_packages, config):
+ spec1 = Spec("hash-test1@1.5")
+ spec2 = Spec("hash-test2@1.5")
+ compare_sans_name(False, spec1, spec2)
+
+
+def compare_sans_name(eq, spec1, spec2):
+ content1 = package_content(spec1)
+ content1 = content1.replace(spec1.package.__class__.__name__, '')
+ content2 = package_content(spec2)
+ content2 = content2.replace(spec2.package.__class__.__name__, '')
+ if eq:
+ assert content1 == content2
+ else:
+ assert content1 != content2
diff --git a/lib/spack/spack/test/package_sanity.py b/lib/spack/spack/test/package_sanity.py
index adc6867b72..a8c84bd70d 100644
--- a/lib/spack/spack/test/package_sanity.py
+++ b/lib/spack/spack/test/package_sanity.py
@@ -1,52 +1,35 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-"""This test does sanity checks on Spack's builtin package database."""
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+"""This test does sanity checks on Spack's builtin package database."""
import re
-import spack
-from spack.repository import RepoPath
+import pytest
+import spack.paths
+import spack.repo
+import spack.fetch_strategy
-def check_db():
- """Get all packages in a DB to make sure they work."""
+
+def check_repo():
+ """Get all packages in the builtin repo to make sure they work."""
for name in spack.repo.all_package_names():
spack.repo.get(name)
+@pytest.mark.maybeslow
def test_get_all_packages():
"""Get all packages once and make sure that works."""
- check_db()
+ check_repo()
def test_get_all_mock_packages():
"""Get the mock packages once each too."""
- db = RepoPath(spack.mock_packages_path)
- spack.repo.swap(db)
- check_db()
- spack.repo.swap(db)
+ db = spack.repo.RepoPath(spack.paths.mock_packages_path)
+ with spack.repo.swap(db):
+ check_repo()
def test_all_versions_are_lowercase():
@@ -57,3 +40,50 @@ def test_all_versions_are_lowercase():
errors.append(name)
assert len(errors) == 0
+
+
+def test_all_virtual_packages_have_default_providers():
+ """All virtual packages must have a default provider explicitly set."""
+ defaults = spack.config.get('packages', scope='defaults')
+ default_providers = defaults['all']['providers']
+ providers = spack.repo.path.provider_index.providers
+ default_providers_filename = \
+ spack.config.config.scopes['defaults'].get_section_filename('packages')
+ for provider in providers:
+ assert provider in default_providers, \
+ "all providers must have a default in %s" \
+ % default_providers_filename
+
+
+def test_package_version_consistency():
+ """Make sure all versions on builtin packages can produce a fetcher."""
+ for name in spack.repo.all_package_names():
+ pkg = spack.repo.get(name)
+ spack.fetch_strategy.check_pkg_attributes(pkg)
+ for version in pkg.versions:
+ assert spack.fetch_strategy.for_package_version(pkg, version)
+
+
+def test_no_fixme():
+ """Packages should not contain any boilerplate such as
+ FIXME or example.com."""
+ errors = []
+ fixme_regexes = [
+ r'remove this boilerplate',
+ r'FIXME: Put',
+ r'FIXME: Add',
+ r'example.com',
+ ]
+ for name in spack.repo.all_package_names():
+ repo = spack.repo.Repo(spack.paths.packages_path)
+ filename = repo.filename_for_package_name(name)
+ with open(filename, 'r') as package_file:
+ for i, line in enumerate(package_file):
+ pattern = next((r for r in fixme_regexes
+ if re.search(r, line)), None)
+ if pattern:
+ errors.append(
+ "%s:%d: boilerplate needs to be removed: %s" %
+ (filename, i, line.strip())
+ )
+ assert [] == errors
diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py
index 9533627b24..1206d274ce 100644
--- a/lib/spack/spack/test/packages.py
+++ b/lib/spack/spack/test/packages.py
@@ -1,37 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import spack
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os.path
import pytest
-from llnl.util.filesystem import join_path
-from spack.repository import Repo
+import spack.repo
+import spack.fetch_strategy
+from spack.paths import mock_packages_path
from spack.util.naming import mod_to_class
from spack.spec import Spec
+from spack.util.package_hash import package_content
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestPackage(object):
def test_load_package(self):
spack.repo.get('mpich')
@@ -41,20 +24,20 @@ class TestPackage(object):
assert pkg.name == 'mpich'
def test_package_filename(self):
- repo = Repo(spack.mock_packages_path)
+ repo = spack.repo.Repo(mock_packages_path)
filename = repo.filename_for_package_name('mpich')
- assert filename == join_path(
- spack.mock_packages_path,
+ assert filename == os.path.join(
+ mock_packages_path,
'packages',
'mpich',
'package.py'
)
def test_nonexisting_package_filename(self):
- repo = Repo(spack.mock_packages_path)
+ repo = spack.repo.Repo(mock_packages_path)
filename = repo.filename_for_package_name('some-nonexisting-package')
- assert filename == join_path(
- spack.mock_packages_path,
+ assert filename == os.path.join(
+ mock_packages_path,
'packages',
'some-nonexisting-package',
'package.py'
@@ -67,6 +50,42 @@ class TestPackage(object):
assert 'Pmgrcollective' == mod_to_class('PmgrCollective')
assert '_3db' == mod_to_class('3db')
+ def test_content_hash_all_same_but_patch_contents(self):
+ spec1 = Spec("hash-test1@1.1")
+ spec2 = Spec("hash-test2@1.1")
+ spec1.concretize()
+ spec2.concretize()
+ content1 = package_content(spec1)
+ content1 = content1.replace(spec1.package.__class__.__name__, '')
+ content2 = package_content(spec2)
+ content2 = content2.replace(spec2.package.__class__.__name__, '')
+ assert spec1.package.content_hash(content=content1) != \
+ spec2.package.content_hash(content=content2)
+
+ def test_content_hash_different_variants(self):
+ spec1 = Spec("hash-test1@1.2 +variantx")
+ spec2 = Spec("hash-test2@1.2 ~variantx")
+ spec1.concretize()
+ spec2.concretize()
+ content1 = package_content(spec1)
+ content1 = content1.replace(spec1.package.__class__.__name__, '')
+ content2 = package_content(spec2)
+ content2 = content2.replace(spec2.package.__class__.__name__, '')
+ assert spec1.package.content_hash(content=content1) == \
+ spec2.package.content_hash(content=content2)
+
+ def test_all_same_but_archive_hash(self):
+ spec1 = Spec("hash-test1@1.3")
+ spec2 = Spec("hash-test2@1.3")
+ spec1.concretize()
+ spec2.concretize()
+ content1 = package_content(spec1)
+ content1 = content1.replace(spec1.package.__class__.__name__, '')
+ content2 = package_content(spec2)
+ content2 = content2.replace(spec2.package.__class__.__name__, '')
+ assert spec1.package.content_hash(content=content1) != \
+ spec2.package.content_hash(content=content2)
+
# Below tests target direct imports of spack packages from the
# spack.pkg namespace
def test_import_package(self):
@@ -128,3 +147,209 @@ class TestPackage(object):
import spack.pkg.builtin.mock # noqa
import spack.pkg.builtin.mock as m # noqa
from spack.pkg.builtin import mock # noqa
+
+
+@pytest.mark.regression('2737')
+def test_urls_for_versions(mock_packages, config):
+ """Version directive without a 'url' argument should use default url."""
+ for spec_str in ('url_override@0.9.0', 'url_override@1.0.0'):
+ s = Spec(spec_str).concretized()
+ url = s.package.url_for_version('0.9.0')
+ assert url == 'http://www.anothersite.org/uo-0.9.0.tgz'
+
+ url = s.package.url_for_version('1.0.0')
+ assert url == 'http://www.doesnotexist.org/url_override-1.0.0.tar.gz'
+
+ url = s.package.url_for_version('0.8.1')
+ assert url == 'http://www.doesnotexist.org/url_override-0.8.1.tar.gz'
+
+
+def test_url_for_version_with_no_urls():
+ pkg = spack.repo.get('git-test')
+ with pytest.raises(spack.package.NoURLError):
+ pkg.url_for_version('1.0')
+
+ with pytest.raises(spack.package.NoURLError):
+ pkg.url_for_version('1.1')
+
+
+def test_url_for_version_with_only_overrides(mock_packages, config):
+ spec = Spec('url-only-override')
+ spec.concretize()
+
+ pkg = spack.repo.get(spec)
+
+ # these exist and should just take the URL provided in the package
+ assert pkg.url_for_version('1.0.0') == 'http://a.example.com/url_override-1.0.0.tar.gz'
+ assert pkg.url_for_version('0.9.0') == 'http://b.example.com/url_override-0.9.0.tar.gz'
+ assert pkg.url_for_version('0.8.1') == 'http://c.example.com/url_override-0.8.1.tar.gz'
+
+ # these don't exist but should still work, even if there are only overrides
+ assert pkg.url_for_version('1.0.5') == 'http://a.example.com/url_override-1.0.5.tar.gz'
+ assert pkg.url_for_version('0.9.5') == 'http://b.example.com/url_override-0.9.5.tar.gz'
+ assert pkg.url_for_version('0.8.5') == 'http://c.example.com/url_override-0.8.5.tar.gz'
+ assert pkg.url_for_version('0.7.0') == 'http://c.example.com/url_override-0.7.0.tar.gz'
+
+
+def test_url_for_version_with_only_overrides_with_gaps(mock_packages, config):
+ spec = Spec('url-only-override-with-gaps')
+ spec.concretize()
+
+ pkg = spack.repo.get(spec)
+
+ # same as for url-only-override -- these are specific
+ assert pkg.url_for_version('1.0.0') == 'http://a.example.com/url_override-1.0.0.tar.gz'
+ assert pkg.url_for_version('0.9.0') == 'http://b.example.com/url_override-0.9.0.tar.gz'
+ assert pkg.url_for_version('0.8.1') == 'http://c.example.com/url_override-0.8.1.tar.gz'
+
+ # these don't have specific URLs, but should still work by extrapolation
+ assert pkg.url_for_version('1.0.5') == 'http://a.example.com/url_override-1.0.5.tar.gz'
+ assert pkg.url_for_version('0.9.5') == 'http://b.example.com/url_override-0.9.5.tar.gz'
+ assert pkg.url_for_version('0.8.5') == 'http://c.example.com/url_override-0.8.5.tar.gz'
+ assert pkg.url_for_version('0.7.0') == 'http://c.example.com/url_override-0.7.0.tar.gz'
+
+
+def test_git_top_level(mock_packages, config):
+ """Ensure that top-level git attribute can be used as a default."""
+ pkg = spack.repo.get('git-top-level')
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+
+
+def test_svn_top_level(mock_packages, config):
+ """Ensure that top-level svn attribute can be used as a default."""
+ pkg = spack.repo.get('svn-top-level')
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
+ assert isinstance(fetcher, spack.fetch_strategy.SvnFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/svn/repo'
+
+
+def test_hg_top_level(mock_packages, config):
+ """Ensure that top-level hg attribute can be used as a default."""
+ pkg = spack.repo.get('hg-top-level')
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
+ assert isinstance(fetcher, spack.fetch_strategy.HgFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/hg/repo'
+
+
+def test_no_extrapolate_without_url(mock_packages, config):
+ """Verify that we can't extrapolate versions for non-URL packages."""
+ pkg = spack.repo.get('git-top-level')
+
+ with pytest.raises(spack.fetch_strategy.ExtrapolationError):
+ spack.fetch_strategy.for_package_version(pkg, '1.1')
+
+
+def test_two_vcs_fetchers_top_level(mock_packages, config):
+ """Verify conflict when two VCS strategies are specified together."""
+
+ pkg = spack.repo.get('git-url-svn-top-level')
+ with pytest.raises(spack.fetch_strategy.FetcherConflict):
+ spack.fetch_strategy.for_package_version(pkg, '1.0')
+
+ pkg = spack.repo.get('git-svn-top-level')
+ with pytest.raises(spack.fetch_strategy.FetcherConflict):
+ spack.fetch_strategy.for_package_version(pkg, '1.0')
+
+
+def test_git_url_top_level_url_versions(mock_packages, config):
+ """Test URL fetch strategy inference when url is specified with git."""
+
+ pkg = spack.repo.get('git-url-top-level')
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '2.0')
+ assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/tarball-2.0.tar.gz'
+ assert fetcher.digest == 'abc20'
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '2.1')
+ assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/tarball-2.1.tar.gz'
+ assert fetcher.digest == 'abc21'
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '2.2')
+ assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
+ assert fetcher.url == 'https://www.example.com/foo2.2.tar.gz'
+ assert fetcher.digest == 'abc22'
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '2.3')
+ assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
+ assert fetcher.url == 'https://www.example.com/foo2.3.tar.gz'
+ assert fetcher.digest == 'abc23'
+
+
+def test_git_url_top_level_git_versions(mock_packages, config):
+ """Test git fetch strategy inference when url is specified with git."""
+
+ pkg = spack.repo.get('git-url-top-level')
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '3.0')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag == 'v3.0'
+ assert fetcher.commit is None
+ assert fetcher.branch is None
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '3.1')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag == 'v3.1'
+ assert fetcher.commit == 'abc31'
+ assert fetcher.branch is None
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '3.2')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag is None
+ assert fetcher.commit is None
+ assert fetcher.branch == 'releases/v3.2'
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '3.3')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag is None
+ assert fetcher.commit == 'abc33'
+ assert fetcher.branch == 'releases/v3.3'
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, '3.4')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag is None
+ assert fetcher.commit == 'abc34'
+ assert fetcher.branch is None
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, 'submodules')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag is None
+ assert fetcher.commit is None
+ assert fetcher.branch is None
+
+ fetcher = spack.fetch_strategy.for_package_version(pkg, 'develop')
+ assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
+ assert fetcher.url == 'https://example.com/some/git/repo'
+ assert fetcher.tag is None
+ assert fetcher.commit is None
+ assert fetcher.branch == 'develop'
+
+
+def test_git_url_top_level_conflicts(mock_packages, config):
+ """Test git fetch strategy inference when url is specified with git."""
+
+ pkg = spack.repo.get('git-url-top-level')
+
+ with pytest.raises(spack.fetch_strategy.FetcherConflict):
+ spack.fetch_strategy.for_package_version(pkg, '1.0')
+
+ with pytest.raises(spack.fetch_strategy.FetcherConflict):
+ spack.fetch_strategy.for_package_version(pkg, '1.1')
+
+ with pytest.raises(spack.fetch_strategy.FetcherConflict):
+ spack.fetch_strategy.for_package_version(pkg, '1.2')
+
+ with pytest.raises(spack.fetch_strategy.FetcherConflict):
+ spack.fetch_strategy.for_package_version(pkg, '1.3')
diff --git a/lib/spack/spack/test/packaging.py b/lib/spack/spack/test/packaging.py
index 49e5138c89..ae7d7678ae 100644
--- a/lib/spack/spack/test/packaging.py
+++ b/lib/spack/spack/test/packaging.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This test checks the binary packaging infrastructure
"""
@@ -34,14 +15,16 @@ import argparse
from llnl.util.filesystem import mkdirp
-import spack
+import spack.repo
import spack.store
import spack.binary_distribution as bindist
import spack.cmd.buildcache as buildcache
from spack.spec import Spec
+from spack.paths import mock_gpg_keys_path
from spack.fetch_strategy import URLFetchStrategy, FetchStrategyComposite
from spack.util.executable import ProcessError
from spack.relocate import needs_binary_relocation, needs_text_relocation
+from spack.relocate import strings_contains_installroot
from spack.relocate import get_patchelf, relocate_text
from spack.relocate import substitute_rpath, get_relative_rpaths
from spack.relocate import macho_replace_paths, macho_make_paths_relative
@@ -72,7 +55,7 @@ def fake_fetchify(url, pkg):
@pytest.mark.usefixtures('install_mockery', 'testing_gpg_directory')
-def test_packaging(mock_archive, tmpdir):
+def test_buildcache(mock_archive, tmpdir):
# tweak patchelf to only do a download
spec = Spec("patchelf")
spec.concretize()
@@ -92,7 +75,7 @@ echo $PATH"""
spec = Spec('trivial-install-test-package')
spec.concretize()
assert spec.concrete
- pkg = spack.repo.get(spec)
+ pkg = spec.package
fake_fetchify(mock_archive.url, pkg)
pkg.do_install()
pkghash = '/' + spec.dag_hash(7)
@@ -106,14 +89,13 @@ echo $PATH"""
# put it directly into the mirror
mirror_path = os.path.join(str(tmpdir), 'test-mirror')
- specs = [spec]
spack.mirror.create(
- mirror_path, specs, no_checksum=True
+ mirror_path, specs=[], no_checksum=True
)
# register mirror with spack config
mirrors = {'spack-mirror-test': 'file://' + mirror_path}
- spack.config.update_config('mirrors', mirrors)
+ spack.config.set('mirrors', mirrors)
stage = spack.stage.Stage(
mirrors['spack-mirror-test'], name="build_cache", keep=True)
@@ -157,34 +139,34 @@ echo $PATH"""
else:
# create build cache without signing
args = parser.parse_args(
- ['create', '-d', mirror_path, '-y', str(spec)])
+ ['create', '-d', mirror_path, '-u', str(spec)])
buildcache.buildcache(parser, args)
# Uninstall the package
pkg.do_uninstall(force=True)
# install build cache without verification
- args = parser.parse_args(['install', '-y', str(spec)])
+ args = parser.parse_args(['install', '-u', str(spec)])
buildcache.install_tarball(spec, args)
# test overwrite install without verification
- args = parser.parse_args(['install', '-f', '-y', str(pkghash)])
+ args = parser.parse_args(['install', '-f', '-u', str(pkghash)])
buildcache.buildcache(parser, args)
# create build cache with relative path
args = parser.parse_args(
- ['create', '-d', mirror_path, '-f', '-r', '-y', str(pkghash)])
+ ['create', '-d', mirror_path, '-f', '-r', '-u', str(pkghash)])
buildcache.buildcache(parser, args)
# Uninstall the package
pkg.do_uninstall(force=True)
# install build cache
- args = parser.parse_args(['install', '-y', str(spec)])
+ args = parser.parse_args(['install', '-u', str(spec)])
buildcache.install_tarball(spec, args)
# test overwrite install
- args = parser.parse_args(['install', '-f', '-y', str(pkghash)])
+ args = parser.parse_args(['install', '-f', '-u', str(pkghash)])
buildcache.buildcache(parser, args)
# Validate the relocation information
@@ -201,7 +183,7 @@ echo $PATH"""
buildcache.buildcache(parser, args)
# Copy a key to the mirror to have something to download
- shutil.copyfile(spack.mock_gpg_keys_path + '/external.key',
+ shutil.copyfile(mock_gpg_keys_path + '/external.key',
mirror_path + '/external.key')
args = parser.parse_args(['keys'])
@@ -212,26 +194,29 @@ echo $PATH"""
# unregister mirror with spack config
mirrors = {}
- spack.config.update_config('mirrors', mirrors)
+ spack.config.set('mirrors', mirrors)
shutil.rmtree(mirror_path)
stage.destroy()
+ # Remove cached binary specs since we deleted the mirror
+ bindist._cached_specs = None
-def test_relocate_text():
- # Validate the text path replacement
- old_dir = '/home/spack/opt/spack'
- filename = 'dummy.txt'
- with open(filename, "w") as script:
- script.write(old_dir)
- script.close()
-
- filenames = [filename]
- new_dir = '/opt/rh/devtoolset/'
- relocate_text(filenames, old_dir, new_dir)
- with open(filename, "r")as script:
- for line in script:
- assert(new_dir in line)
+def test_relocate_text(tmpdir):
+ with tmpdir.as_cwd():
+ # Validate the text path replacement
+ old_dir = '/home/spack/opt/spack'
+ filename = 'dummy.txt'
+ with open(filename, "w") as script:
+ script.write(old_dir)
+ script.close()
+ filenames = [filename]
+ new_dir = '/opt/rh/devtoolset/'
+ relocate_text(filenames, old_dir, new_dir)
+ with open(filename, "r")as script:
+ for line in script:
+ assert(new_dir in line)
+ assert(strings_contains_installroot(filename, old_dir) is False)
def test_needs_relocation():
diff --git a/lib/spack/spack/test/patch.py b/lib/spack/spack/test/patch.py
index 6afb50bba0..e606c9113a 100644
--- a/lib/spack/spack/test/patch.py
+++ b/lib/spack/spack/test/patch.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import sys
import filecmp
@@ -29,8 +10,9 @@ import pytest
from llnl.util.filesystem import working_dir, mkdirp
-import spack
+import spack.paths
import spack.util.compression
+from spack.util.executable import Executable
from spack.stage import Stage
from spack.spec import Spec
@@ -39,11 +21,11 @@ from spack.spec import Spec
def mock_stage(tmpdir, monkeypatch):
# don't disrupt the spack install directory with tests.
mock_path = str(tmpdir)
- monkeypatch.setattr(spack, 'stage_path', mock_path)
+ monkeypatch.setattr(spack.paths, 'stage_path', mock_path)
return mock_path
-data_path = os.path.join(spack.test_path, 'data', 'patch')
+data_path = os.path.join(spack.paths.test_path, 'data', 'patch')
@pytest.mark.parametrize('filename, sha256, archive_sha256', [
@@ -93,7 +75,7 @@ third line
assert filecmp.cmp('foo.txt', 'foo-expected.txt')
-def test_patch_in_spec(builtin_mock, config):
+def test_patch_in_spec(mock_packages, config):
"""Test whether patches in a package appear in the spec."""
spec = Spec('patch')
spec.concretize()
@@ -108,18 +90,34 @@ def test_patch_in_spec(builtin_mock, config):
spec.variants['patches'].value)
-def test_patched_dependency(builtin_mock, config):
+def test_patched_dependency(
+ mock_packages, config, install_mockery, mock_fetch):
"""Test whether patched dependencies work."""
spec = Spec('patch-a-dependency')
spec.concretize()
assert 'patches' in list(spec['libelf'].variants.keys())
- # foo
- assert (('b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c',) ==
+ # make sure the patch makes it into the dependency spec
+ assert (('c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8',) ==
spec['libelf'].variants['patches'].value)
+ # make sure the patch in the dependent's directory is applied to the
+ # dependency
+ libelf = spec['libelf']
+ pkg = libelf.package
+ pkg.do_patch()
+ with pkg.stage:
+ with working_dir(pkg.stage.source_path):
+ # output a Makefile with 'echo Patched!' as the default target
+ configure = Executable('./configure')
+ configure()
+
+ # Make sure the Makefile contains the patched text
+ with open('Makefile') as mf:
+ assert 'Patched!' in mf.read()
+
-def test_multiple_patched_dependencies(builtin_mock, config):
+def test_multiple_patched_dependencies(mock_packages, config):
"""Test whether multiple patched dependencies work."""
spec = Spec('patch-several-dependencies')
spec.concretize()
@@ -138,7 +136,7 @@ def test_multiple_patched_dependencies(builtin_mock, config):
spec['fake'].variants['patches'].value)
-def test_conditional_patched_dependencies(builtin_mock, config):
+def test_conditional_patched_dependencies(mock_packages, config):
"""Test whether conditional patched dependencies work."""
spec = Spec('patch-several-dependencies @1.0')
spec.concretize()
@@ -166,7 +164,7 @@ def test_conditional_patched_dependencies(builtin_mock, config):
spec['fake'].variants['patches'].value)
-def test_conditional_patched_deps_with_conditions(builtin_mock, config):
+def test_conditional_patched_deps_with_conditions(mock_packages, config):
"""Test whether conditional patched dependencies with conditions work."""
spec = Spec('patch-several-dependencies @1.0 ^libdwarf@20111030')
spec.concretize()
diff --git a/lib/spack/spack/test/pattern.py b/lib/spack/spack/test/pattern.py
index 72cabbbfd7..fc2c85735d 100644
--- a/lib/spack/spack/test/pattern.py
+++ b/lib/spack/spack/test/pattern.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.util.pattern as pattern
diff --git a/lib/spack/spack/test/provider_index.py b/lib/spack/spack/test/provider_index.py
index 985a1ae3f3..dfa9ef37fc 100644
--- a/lib/spack/spack/test/provider_index.py
+++ b/lib/spack/spack/test/provider_index.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Tests for provider index cache files.
Tests assume that mock packages provide this::
@@ -39,12 +20,12 @@ Tests assume that mock packages provide this::
"""
from six import StringIO
-import spack
+import spack.repo
from spack.provider_index import ProviderIndex
from spack.spec import Spec
-def test_yaml_round_trip(builtin_mock):
+def test_yaml_round_trip(mock_packages):
p = ProviderIndex(spack.repo.all_package_names())
ostream = StringIO()
@@ -56,7 +37,7 @@ def test_yaml_round_trip(builtin_mock):
assert p == q
-def test_providers_for_simple(builtin_mock):
+def test_providers_for_simple(mock_packages):
p = ProviderIndex(spack.repo.all_package_names())
blas_providers = p.providers_for('blas')
@@ -69,7 +50,7 @@ def test_providers_for_simple(builtin_mock):
assert Spec('openblas-with-lapack') in lapack_providers
-def test_mpi_providers(builtin_mock):
+def test_mpi_providers(mock_packages):
p = ProviderIndex(spack.repo.all_package_names())
mpi_2_providers = p.providers_for('mpi@2')
@@ -82,13 +63,13 @@ def test_mpi_providers(builtin_mock):
assert Spec('zmpi') in mpi_3_providers
-def test_equal(builtin_mock):
+def test_equal(mock_packages):
p = ProviderIndex(spack.repo.all_package_names())
q = ProviderIndex(spack.repo.all_package_names())
assert p == q
-def test_copy(builtin_mock):
+def test_copy(mock_packages):
p = ProviderIndex(spack.repo.all_package_names())
q = p.copy()
assert p == q
diff --git a/lib/spack/spack/test/pytest.ini b/lib/spack/spack/test/pytest.ini
new file mode 100644
index 0000000000..ccad5f86cc
--- /dev/null
+++ b/lib/spack/spack/test/pytest.ini
@@ -0,0 +1,9 @@
+# content of pytest.ini
+[pytest]
+addopts = --durations=20 -ra
+testpaths = .
+python_files = *.py
+markers =
+ db: tests that require creating a DB
+ network: tests that require access to the network
+ maybeslow: tests that may be slow (e.g. access a lot the filesystem, etc.)
diff --git a/lib/spack/spack/test/python_version.py b/lib/spack/spack/test/python_version.py
index b9bb18bfd2..4e2a4b41f1 100644
--- a/lib/spack/spack/test/python_version.py
+++ b/lib/spack/spack/test/python_version.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Check that Spack complies with minimum supported python versions.
We ensure that all Spack files work with Python2 >= 2.6 and Python3 >= 3.0.
@@ -37,8 +18,13 @@ import os
import sys
import re
+import pytest
+
import llnl.util.tty as tty
-import spack
+
+import spack.paths
+from spack.paths import lib_path as spack_lib_path
+
#
# This test uses pyqver, by Greg Hewgill, which is a dual-source module.
@@ -53,10 +39,10 @@ if sys.version_info[0] < 3:
exclude_paths = [
# Jinja 2 has some 'async def' functions that are not treated correctly
# by pyqver.py
- os.path.join(spack.lib_path, 'external', 'jinja2', 'asyncfilters.py'),
- os.path.join(spack.lib_path, 'external', 'jinja2', 'asyncsupport.py'),
- os.path.join(spack.lib_path, 'external', 'yaml', 'lib3'),
- os.path.join(spack.lib_path, 'external', 'pyqver3.py')]
+ os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncfilters.py'),
+ os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncsupport.py'),
+ os.path.join(spack_lib_path, 'external', 'yaml', 'lib3'),
+ os.path.join(spack_lib_path, 'external', 'pyqver3.py')]
else:
import pyqver3 as pyqver
@@ -66,10 +52,10 @@ else:
exclude_paths = [
# Jinja 2 has some 'async def' functions that are not treated correctly
# by pyqver.py
- os.path.join(spack.lib_path, 'external', 'jinja2', 'asyncfilters.py'),
- os.path.join(spack.lib_path, 'external', 'jinja2', 'asyncsupport.py'),
- os.path.join(spack.lib_path, 'external', 'yaml', 'lib'),
- os.path.join(spack.lib_path, 'external', 'pyqver2.py')]
+ os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncfilters.py'),
+ os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncsupport.py'),
+ os.path.join(spack_lib_path, 'external', 'yaml', 'lib'),
+ os.path.join(spack_lib_path, 'external', 'pyqver2.py')]
def pyfiles(search_paths, exclude=()):
@@ -83,7 +69,7 @@ def pyfiles(search_paths, exclude=()):
python files in the search path.
"""
# first file is the spack script.
- yield spack.spack_file
+ yield spack.paths.spack_script
# Iterate through the whole spack source tree.
for path in search_paths:
@@ -133,8 +119,8 @@ def check_python_versions(files):
messages = []
for path in sorted(all_issues[v].keys()):
short_path = path
- if path.startswith(spack.prefix):
- short_path = path[len(spack.prefix):]
+ if path.startswith(spack.paths.prefix):
+ short_path = path[len(spack.paths.prefix):]
reasons = [r for r in set(all_issues[v][path]) if r]
for lineno, cause in reasons:
@@ -154,11 +140,14 @@ def check_python_versions(files):
assert not all_issues
+@pytest.mark.maybeslow
def test_core_module_compatibility():
"""Test that all core spack modules work with supported Python versions."""
- check_python_versions(pyfiles([spack.lib_path], exclude=exclude_paths))
+ check_python_versions(
+ pyfiles([spack_lib_path], exclude=exclude_paths))
+@pytest.mark.maybeslow
def test_package_module_compatibility():
"""Test that all spack packages work with supported Python versions."""
- check_python_versions(pyfiles([spack.packages_path]))
+ check_python_versions(pyfiles([spack.paths.packages_path]))
diff --git a/lib/spack/spack/test/repo.py b/lib/spack/spack/test/repo.py
index 7bf1291ec0..3dcb9eaf9f 100644
--- a/lib/spack/spack/test/repo.py
+++ b/lib/spack/spack/test/repo.py
@@ -1,38 +1,20 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-import spack
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import pytest
+import spack.repo
+import spack.paths
+
# Unlike the repo_path fixture defined in conftest, this has a test-level
# scope rather than a session level scope, since we want to edit the
# given RepoPath
@pytest.fixture()
def repo_for_test():
- return spack.repository.RepoPath(spack.mock_packages_path)
+ return spack.repo.RepoPath(spack.paths.mock_packages_path)
@pytest.fixture()
@@ -41,12 +23,12 @@ def extra_repo(tmpdir_factory):
repo_dir = tmpdir_factory.mktemp(repo_namespace)
repo_dir.ensure('packages', dir=True)
- with open(str(repo_dir.join('repo.yaml')), 'w') as F:
- F.write("""
+ with open(str(repo_dir.join('repo.yaml')), 'w') as f:
+ f.write("""
repo:
namespace: extra_test_repo
""")
- return spack.repository.Repo(str(repo_dir))
+ return spack.repo.Repo(str(repo_dir))
def test_repo_getpkg(repo_for_test):
@@ -67,10 +49,10 @@ def test_repo_multi_getpkgclass(repo_for_test, extra_repo):
def test_repo_pkg_with_unknown_namespace(repo_for_test):
- with pytest.raises(spack.repository.UnknownNamespaceError):
+ with pytest.raises(spack.repo.UnknownNamespaceError):
repo_for_test.get('unknown.a')
def test_repo_unknown_pkg(repo_for_test):
- with pytest.raises(spack.repository.UnknownPackageError):
+ with pytest.raises(spack.repo.UnknownPackageError):
repo_for_test.get('builtin.mock.nonexistentpackage')
diff --git a/lib/spack/spack/test/sbang.py b/lib/spack/spack/test/sbang.py
index 6b583b187f..6e22483608 100644
--- a/lib/spack/spack/test/sbang.py
+++ b/lib/spack/spack/test/sbang.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""\
Test that Spack's shebang filtering works correctly.
"""
@@ -34,7 +15,7 @@ import filecmp
from llnl.util.filesystem import mkdirp
-import spack
+import spack.paths
from spack.hooks.sbang import shebang_too_long, filter_shebangs_in_directory
from spack.util.executable import which
@@ -47,7 +28,7 @@ lua_line_patched = "--!/this/" + ('x' * 200) + "/is/lua\n"
node_line = "#!/this/" + ('x' * 200) + "/is/node\n"
node_in_text = ("line\n") * 100 + "lua\n" + ("line\n" * 100)
node_line_patched = "//!/this/" + ('x' * 200) + "/is/node\n"
-sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.spack_root
+sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.paths.prefix
last_line = "last!\n"
diff --git a/lib/spack/spack/test/spack_yaml.py b/lib/spack/spack/test/spack_yaml.py
index 2bcb2b4ce9..b05aacf4b2 100644
--- a/lib/spack/spack/test/spack_yaml.py
+++ b/lib/spack/spack/test/spack_yaml.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Test Spack's custom YAML format."""
import pytest
@@ -68,10 +49,10 @@ def test_parse(data):
def test_dict_order(data):
expected_order = ['x86_64', 'some_list', 'another_list', 'some_key']
- assert data['config_file'].keys() == expected_order
+ assert list(data['config_file'].keys()) == expected_order
expected_order = ['foo', 'bar', 'baz']
- assert data['config_file']['x86_64'].keys() == expected_order
+ assert list(data['config_file']['x86_64'].keys()) == expected_order
def test_line_numbers(data):
diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py
index 0f359d8291..7d29e5da34 100644
--- a/lib/spack/spack/test/spec_dag.py
+++ b/lib/spack/spack/test/spec_dag.py
@@ -1,32 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
These tests check Spec DAG operations using dummy packages.
"""
import pytest
-import spack
import spack.architecture
import spack.package
@@ -86,8 +66,6 @@ packages in the following spec DAG::
w->y deptypes are (link, build), w->x and y->z deptypes are (test)
"""
- saved_repo = spack.repo
-
default = ('build', 'link')
test_only = ('test',)
@@ -97,20 +75,53 @@ w->y deptypes are (link, build), w->x and y->z deptypes are (test)
w = MockPackage('w', [x, y], [test_only, default])
mock_repo = MockPackageMultiRepo([w, x, y, z])
- try:
- spack.package_testing.test(w.name)
- spack.repo = mock_repo
+ with spack.repo.swap(mock_repo):
spec = Spec('w')
- spec.concretize()
+ spec.concretize(tests=(w.name,))
assert ('x' in spec)
assert ('z' not in spec)
- finally:
- spack.repo = saved_repo
- spack.package_testing.clear()
-@pytest.mark.usefixtures('refresh_builtin_mock')
+@pytest.mark.usefixtures('config')
+def test_conditional_dep_with_user_constraints():
+ """This sets up packages X->Y such that X depends on Y conditionally. It
+ then constructs a Spec with X but with no constraints on X, so that the
+ initial normalization pass cannot determine whether the constraints are
+ met to add the dependency; this checks whether a user-specified constraint
+ on Y is applied properly.
+ """
+ default = ('build', 'link')
+
+ y = MockPackage('y', [], [])
+ x_on_y_conditions = {
+ y.name: {
+ 'x@2:': 'y'
+ }
+ }
+ x = MockPackage('x', [y], [default], conditions=x_on_y_conditions)
+
+ mock_repo = MockPackageMultiRepo([x, y])
+ with spack.repo.swap(mock_repo):
+ spec = Spec('x ^y@2')
+ spec.concretize()
+
+ assert ('y@2' in spec)
+
+ with spack.repo.swap(mock_repo):
+ spec = Spec('x@1')
+ spec.concretize()
+
+ assert ('y' not in spec)
+
+ with spack.repo.swap(mock_repo):
+ spec = Spec('x')
+ spec.concretize()
+
+ assert ('y@3' in spec)
+
+
+@pytest.mark.usefixtures('mutable_mock_packages')
class TestSpecDag(object):
def test_conflicting_package_constraints(self, set_dependency):
@@ -308,18 +319,19 @@ class TestSpecDag(object):
with pytest.raises(spack.spec.UnsatisfiableArchitectureSpecError):
spec.normalize()
+ @pytest.mark.usefixtures('config')
def test_invalid_dep(self):
spec = Spec('libelf ^mpich')
with pytest.raises(spack.spec.InvalidDependencyError):
- spec.normalize()
+ spec.concretize()
spec = Spec('libelf ^libdwarf')
with pytest.raises(spack.spec.InvalidDependencyError):
- spec.normalize()
+ spec.concretize()
spec = Spec('mpich ^dyninst ^libelf')
with pytest.raises(spack.spec.InvalidDependencyError):
- spec.normalize()
+ spec.concretize()
def test_equal(self):
# Different spec structures to test for equality
diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py
index 03f77992c5..d24c38fafc 100644
--- a/lib/spack/spack/test/spec_semantics.py
+++ b/lib/spack/spack/test/spec_semantics.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import spack.architecture
import pytest
@@ -101,7 +82,7 @@ def check_invalid_constraint(spec, constraint):
spec.constrain(constraint)
-@pytest.mark.usefixtures('config', 'builtin_mock')
+@pytest.mark.usefixtures('config', 'mock_packages')
class TestSpecSematics(object):
"""This tests satisfies(), constrain() and other semantic operations
on specs.
@@ -720,3 +701,45 @@ class TestSpecSematics(object):
with pytest.raises(ValueError):
Spec('libelf foo')
+
+ def test_spec_formatting(self):
+ spec = Spec("libelf cflags=-O2")
+ spec.concretize()
+
+ # Since the default is the full spec see if the string rep of
+ # spec is the same as the output of spec.format()
+ # ignoring whitespace (though should we?)
+ assert str(spec) == spec.format().strip()
+
+ # Testing named strings ie ${STRING} and whether we get
+ # the correct component
+ package_segments = [("${PACKAGE}", "name"),
+ ("${VERSION}", "versions"),
+ ("${COMPILER}", "compiler"),
+ ("${COMPILERFLAGS}", "compiler_flags"),
+ ("${OPTIONS}", "variants"),
+ ("${ARCHITECTURE}", "architecture")]
+
+ compiler_segments = [("${COMPILERNAME}", "name"),
+ ("${COMPILERVER}", "versions")]
+
+ architecture_segments = [("${PLATFORM}", "platform"),
+ ("${OS}", "platform_os"),
+ ("${TARGET}", "target")]
+
+ for named_str, prop in package_segments:
+ expected = getattr(spec, prop, "")
+ actual = spec.format(named_str)
+ assert str(expected) == actual
+
+ compiler = spec.compiler
+ for named_str, prop in compiler_segments:
+ expected = getattr(compiler, prop, "")
+ actual = spec.format(named_str)
+ assert str(expected) == actual
+
+ arch = spec.architecture
+ for named_str, prop in architecture_segments:
+ expected = getattr(arch, prop, "")
+ actual = spec.format(named_str)
+ assert str(expected) == actual
diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py
index 009cb5c129..fc8cec097a 100644
--- a/lib/spack/spack/test/spec_syntax.py
+++ b/lib/spack/spack/test/spec_syntax.py
@@ -1,31 +1,12 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import shlex
-import spack
+import spack.store
import spack.spec as sp
from spack.parse import Token
from spack.spec import Spec, parse, parse_anonymous_spec
@@ -94,7 +75,7 @@ class TestSpecSyntax(object):
# Parse checks
# ========================================================================
- def check_parse(self, expected, spec=None, remove_arch=True):
+ def check_parse(self, expected, spec=None):
"""Assert that the provided spec is able to be parsed.
If this is called with one argument, it assumes that the
@@ -152,14 +133,18 @@ class TestSpecSyntax(object):
self.check_parse('@4.2: languages=go')
def test_simple_dependence(self):
- self.check_parse("openmpi^hwloc")
- self.check_parse("openmpi^hwloc^libunwind")
+ self.check_parse("openmpi ^hwloc")
+ self.check_parse("openmpi ^hwloc", "openmpi^hwloc")
+
+ self.check_parse("openmpi ^hwloc ^libunwind")
+ self.check_parse("openmpi ^hwloc ^libunwind",
+ "openmpi^hwloc^libunwind")
def test_dependencies_with_versions(self):
- self.check_parse("openmpi^hwloc@1.2e6")
- self.check_parse("openmpi^hwloc@1.2e6:")
- self.check_parse("openmpi^hwloc@:1.4b7-rc3")
- self.check_parse("openmpi^hwloc@1.2e6:1.4b7-rc3")
+ self.check_parse("openmpi ^hwloc@1.2e6")
+ self.check_parse("openmpi ^hwloc@1.2e6:")
+ self.check_parse("openmpi ^hwloc@:1.4b7-rc3")
+ self.check_parse("openmpi ^hwloc@1.2e6:1.4b7-rc3")
def test_multiple_specs(self):
self.check_parse("mvapich emacs")
@@ -172,31 +157,33 @@ class TestSpecSyntax(object):
def test_multiple_specs_long_second(self):
self.check_parse('mvapich emacs@1.1.1%intel cflags="-O3"',
'mvapich emacs @1.1.1 %intel cflags=-O3')
- self.check_parse('mvapich cflags="-O3 -fPIC" emacs^ncurses%intel')
+ self.check_parse('mvapich cflags="-O3 -fPIC" emacs ^ncurses%intel')
+ self.check_parse('mvapich cflags="-O3 -fPIC" emacs ^ncurses%intel',
+ 'mvapich cflags="-O3 -fPIC" emacs^ncurses%intel')
def test_full_specs(self):
self.check_parse(
"mvapich_foo"
- "^_openmpi@1.2:1.4,1.6%intel@12.1+debug~qt_4"
- "^stackwalker@8.1_1e")
+ " ^_openmpi@1.2:1.4,1.6%intel@12.1+debug~qt_4"
+ " ^stackwalker@8.1_1e")
self.check_parse(
"mvapich_foo"
- "^_openmpi@1.2:1.4,1.6%intel@12.1 debug=2 ~qt_4"
- "^stackwalker@8.1_1e")
+ " ^_openmpi@1.2:1.4,1.6%intel@12.1 debug=2 ~qt_4"
+ " ^stackwalker@8.1_1e")
self.check_parse(
'mvapich_foo'
- '^_openmpi@1.2:1.4,1.6%intel@12.1 cppflags="-O3" +debug~qt_4'
- '^stackwalker@8.1_1e')
+ ' ^_openmpi@1.2:1.4,1.6%intel@12.1 cppflags="-O3" +debug~qt_4'
+ ' ^stackwalker@8.1_1e')
self.check_parse(
"mvapich_foo"
- "^_openmpi@1.2:1.4,1.6%intel@12.1 debug=2 ~qt_4"
- "^stackwalker@8.1_1e arch=test-redhat6-x86_32")
+ " ^_openmpi@1.2:1.4,1.6%intel@12.1 debug=2 ~qt_4"
+ " ^stackwalker@8.1_1e arch=test-redhat6-x86_32")
def test_canonicalize(self):
self.check_parse(
"mvapich_foo"
- "^_openmpi@1.2:1.4,1.6%intel@12.1:12.6+debug~qt_4"
- "^stackwalker@8.1_1e",
+ " ^_openmpi@1.2:1.4,1.6%intel@12.1:12.6+debug~qt_4"
+ " ^stackwalker@8.1_1e",
"mvapich_foo "
"^_openmpi@1.6,1.2:1.4%intel@12.1:12.6+debug~qt_4 "
@@ -204,21 +191,21 @@ class TestSpecSyntax(object):
self.check_parse(
"mvapich_foo"
- "^_openmpi@1.2:1.4,1.6%intel@12.1:12.6+debug~qt_4"
- "^stackwalker@8.1_1e",
+ " ^_openmpi@1.2:1.4,1.6%intel@12.1:12.6+debug~qt_4"
+ " ^stackwalker@8.1_1e",
"mvapich_foo "
"^stackwalker@8.1_1e "
"^_openmpi@1.6,1.2:1.4%intel@12.1:12.6~qt_4+debug")
self.check_parse(
- "x^y@1,2:3,4%intel@1,2,3,4+a~b+c~d+e~f",
+ "x ^y@1,2:3,4%intel@1,2,3,4+a~b+c~d+e~f",
"x ^y~f+e~d+c~b+a@4,2:3,1%intel@4,3,2,1")
self.check_parse(
"x arch=test-redhat6-None "
- "^y arch=test-None-x86_64 "
- "^z arch=linux-None-None",
+ " ^y arch=test-None-x86_64 "
+ " ^z arch=linux-None-None",
"x os=fe "
"^y target=be "
@@ -226,12 +213,12 @@ class TestSpecSyntax(object):
self.check_parse(
"x arch=test-debian6-x86_64 "
- "^y arch=test-debian6-x86_64",
+ " ^y arch=test-debian6-x86_64",
"x os=default_os target=default_target "
"^y os=default_os target=default_target")
- self.check_parse("x^y", "x@: ^y@:")
+ self.check_parse("x ^y", "x@: ^y@:")
def test_parse_errors(self):
errors = ['x@@1.2', 'x ^y@@1.2', 'x@1.2::', 'x::']
@@ -253,17 +240,19 @@ class TestSpecSyntax(object):
str(spec), spec.name + '@' + str(spec.version) +
' /' + spec.dag_hash()[:6])
+ @pytest.mark.db
def test_spec_by_hash(self, database):
- specs = database.mock.db.query()
+ specs = database.query()
assert len(specs) # make sure something's in the DB
for spec in specs:
self._check_hash_parse(spec)
+ @pytest.mark.db
def test_dep_spec_by_hash(self, database):
- mpileaks_zmpi = database.mock.db.query_one('mpileaks ^zmpi')
- zmpi = database.mock.db.query_one('zmpi')
- fake = database.mock.db.query_one('fake')
+ mpileaks_zmpi = database.query_one('mpileaks ^zmpi')
+ zmpi = database.query_one('zmpi')
+ fake = database.query_one('fake')
assert 'fake' in mpileaks_zmpi
assert 'zmpi' in mpileaks_zmpi
@@ -287,9 +276,10 @@ class TestSpecSyntax(object):
assert 'fake' in mpileaks_hash_fake_and_zmpi
assert mpileaks_hash_fake_and_zmpi['fake'] == fake
+ @pytest.mark.db
def test_multiple_specs_with_hash(self, database):
- mpileaks_zmpi = database.mock.db.query_one('mpileaks ^zmpi')
- callpath_mpich2 = database.mock.db.query_one('callpath ^mpich2')
+ mpileaks_zmpi = database.query_one('mpileaks ^zmpi')
+ callpath_mpich2 = database.query_one('callpath ^mpich2')
# name + hash + separate hash
specs = sp.parse('mpileaks /' + mpileaks_zmpi.dag_hash() +
@@ -319,6 +309,7 @@ class TestSpecSyntax(object):
' / ' + callpath_mpich2.dag_hash())
assert len(specs) == 2
+ @pytest.mark.db
def test_ambiguous_hash(self, database):
x1 = Spec('a')
x1._hash = 'xy'
@@ -326,8 +317,8 @@ class TestSpecSyntax(object):
x2 = Spec('a')
x2._hash = 'xx'
x2._concrete = True
- database.mock.db.add(x1, spack.store.layout)
- database.mock.db.add(x2, spack.store.layout)
+ database.add(x1, spack.store.layout)
+ database.add(x2, spack.store.layout)
# ambiguity in first hash character
self._check_raises(AmbiguousHashError, ['/x'])
@@ -335,12 +326,13 @@ class TestSpecSyntax(object):
# ambiguity in first hash character AND spec name
self._check_raises(AmbiguousHashError, ['a/x'])
+ @pytest.mark.db
def test_invalid_hash(self, database):
- mpileaks_zmpi = database.mock.db.query_one('mpileaks ^zmpi')
- zmpi = database.mock.db.query_one('zmpi')
+ mpileaks_zmpi = database.query_one('mpileaks ^zmpi')
+ zmpi = database.query_one('zmpi')
- mpileaks_mpich = database.mock.db.query_one('mpileaks ^mpich')
- mpich = database.mock.db.query_one('mpich')
+ mpileaks_mpich = database.query_one('mpileaks ^mpich')
+ mpich = database.query_one('mpich')
# name + incompatible hash
self._check_raises(InvalidHashError, [
@@ -352,9 +344,10 @@ class TestSpecSyntax(object):
'mpileaks ^mpich /' + mpileaks_zmpi.dag_hash(),
'mpileaks ^zmpi /' + mpileaks_mpich.dag_hash()])
+ @pytest.mark.db
def test_nonexistent_hash(self, database):
"""Ensure we get errors for nonexistant hashes."""
- specs = database.mock.db.query()
+ specs = database.query()
# This hash shouldn't be in the test DB. What are the odds :)
no_such_hash = 'aaaaaaaaaaaaaaa'
@@ -365,6 +358,7 @@ class TestSpecSyntax(object):
'/' + no_such_hash,
'mpileaks /' + no_such_hash])
+ @pytest.mark.db
def test_redundant_spec(self, database):
"""Check that redundant spec constraints raise errors.
@@ -372,11 +366,11 @@ class TestSpecSyntax(object):
specs only raise errors if constraints cause a contradiction?
"""
- mpileaks_zmpi = database.mock.db.query_one('mpileaks ^zmpi')
- callpath_zmpi = database.mock.db.query_one('callpath ^zmpi')
- dyninst = database.mock.db.query_one('dyninst')
+ mpileaks_zmpi = database.query_one('mpileaks ^zmpi')
+ callpath_zmpi = database.query_one('callpath ^zmpi')
+ dyninst = database.query_one('dyninst')
- mpileaks_mpich2 = database.mock.db.query_one('mpileaks ^mpich2')
+ mpileaks_mpich2 = database.query_one('mpileaks ^mpich2')
redundant_specs = [
# redudant compiler
diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py
index cefb737cfb..5e5ac37904 100644
--- a/lib/spack/spack/test/spec_yaml.py
+++ b/lib/spack/spack/test/spec_yaml.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Test YAML serialization for specs.
YAML format preserves DAG information in the spec.
@@ -46,13 +27,13 @@ def test_simple_spec():
check_yaml_round_trip(spec)
-def test_normal_spec(builtin_mock):
+def test_normal_spec(mock_packages):
spec = Spec('mpileaks+debug~opt')
spec.normalize()
check_yaml_round_trip(spec)
-def test_external_spec(config, builtin_mock):
+def test_external_spec(config, mock_packages):
spec = Spec('externaltool')
spec.concretize()
check_yaml_round_trip(spec)
@@ -62,13 +43,13 @@ def test_external_spec(config, builtin_mock):
check_yaml_round_trip(spec)
-def test_ambiguous_version_spec(builtin_mock):
+def test_ambiguous_version_spec(mock_packages):
spec = Spec('mpileaks@1.0:5.0,6.1,7.3+debug~opt')
spec.normalize()
check_yaml_round_trip(spec)
-def test_concrete_spec(config, builtin_mock):
+def test_concrete_spec(config, mock_packages):
spec = Spec('mpileaks+debug~opt')
spec.concretize()
check_yaml_round_trip(spec)
@@ -80,7 +61,7 @@ def test_yaml_multivalue():
check_yaml_round_trip(spec)
-def test_yaml_subdag(config, builtin_mock):
+def test_yaml_subdag(config, mock_packages):
spec = Spec('mpileaks^mpich+debug')
spec.concretize()
yaml_spec = Spec.from_yaml(spec.to_yaml())
@@ -89,7 +70,7 @@ def test_yaml_subdag(config, builtin_mock):
assert spec[dep].eq_dag(yaml_spec[dep])
-def test_using_ordered_dict(builtin_mock):
+def test_using_ordered_dict(mock_packages):
""" Checks that dicts are ordered
Necessary to make sure that dag_hash is stable across python
@@ -122,7 +103,7 @@ def test_using_ordered_dict(builtin_mock):
def test_ordered_read_not_required_for_consistent_dag_hash(
- config, builtin_mock
+ config, mock_packages
):
"""Make sure ordered serialization isn't required to preserve hashes.
@@ -195,6 +176,16 @@ def test_ordered_read_not_required_for_consistent_dag_hash(
assert spec.dag_hash() == round_trip_json_spec.dag_hash()
assert spec.dag_hash() == round_trip_reversed_yaml_spec.dag_hash()
assert spec.dag_hash() == round_trip_reversed_json_spec.dag_hash()
+ # full_hashes are equal
+ spec.concretize()
+ round_trip_yaml_spec.concretize()
+ round_trip_json_spec.concretize()
+ round_trip_reversed_yaml_spec.concretize()
+ round_trip_reversed_json_spec.concretize()
+ assert spec.full_hash() == round_trip_yaml_spec.full_hash()
+ assert spec.full_hash() == round_trip_json_spec.full_hash()
+ assert spec.full_hash() == round_trip_reversed_yaml_spec.full_hash()
+ assert spec.full_hash() == round_trip_reversed_json_spec.full_hash()
def reverse_all_dicts(data):
diff --git a/lib/spack/spack/test/stage.py b/lib/spack/spack/test/stage.py
index 2117ef5462..971033472a 100644
--- a/lib/spack/spack/test/stage.py
+++ b/lib/spack/spack/test/stage.py
@@ -1,35 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Test that the Stage class works correctly."""
-import collections
import os
-
-from llnl.util.filesystem import join_path, working_dir
+import collections
import pytest
-import spack
+
+from llnl.util.filesystem import working_dir
+
+import spack.paths
import spack.stage
import spack.util.executable
from spack.stage import Stage
@@ -42,9 +24,9 @@ def check_expand_archive(stage, stage_name, mock_archive):
assert archive_name in os.listdir(stage_path)
assert archive_dir in os.listdir(stage_path)
- assert join_path(stage_path, archive_dir) == stage.source_path
+ assert os.path.join(stage_path, archive_dir) == stage.source_path
- readme = join_path(stage_path, archive_dir, 'README.txt')
+ readme = os.path.join(stage_path, archive_dir, 'README.txt')
assert os.path.isfile(readme)
with open(readme) as file:
'hello world!\n' == file.read()
@@ -54,7 +36,7 @@ def check_fetch(stage, stage_name):
archive_name = 'test-files.tar.gz'
stage_path = get_stage_path(stage, stage_name)
assert archive_name in os.listdir(stage_path)
- assert join_path(stage_path, archive_name) == stage.fetcher.archive_file
+ assert os.path.join(stage_path, archive_name) == stage.fetcher.archive_file
def check_destroy(stage, stage_name):
@@ -101,31 +83,28 @@ def get_stage_path(stage, stage_name):
"""
if stage_name is not None:
# If it is a named stage, we know where the stage should be
- return join_path(spack.stage_path, stage_name)
+ return os.path.join(spack.paths.stage_path, stage_name)
else:
# If it's unnamed, ensure that we ran mkdtemp in the right spot.
assert stage.path is not None
- assert stage.path.startswith(spack.stage_path)
+ assert stage.path.startswith(spack.paths.stage_path)
return stage.path
@pytest.fixture()
-def tmpdir_for_stage(mock_archive):
+def tmpdir_for_stage(mock_archive, mutable_config):
"""Uses a temporary directory for staging"""
- current = spack.stage_path
- spack.config.update_config(
+ current = spack.paths.stage_path
+ spack.config.set(
'config',
{'build_stage': [str(mock_archive.test_tmp_dir)]},
- scope='user'
- )
+ scope='user')
yield
- spack.config.update_config(
- 'config', {'build_stage': [current]}, scope='user'
- )
+ spack.config.set('config', {'build_stage': [current]}, scope='user')
@pytest.fixture()
-def mock_archive(tmpdir, monkeypatch):
+def mock_archive(tmpdir, monkeypatch, mutable_config):
"""Creates a mock archive with the structure expected by the tests"""
# Mock up a stage area that looks like this:
#
@@ -137,9 +116,8 @@ def mock_archive(tmpdir, monkeypatch):
#
test_tmp_path = tmpdir.join('tmp')
# set _test_tmp_path as the default test directory to use for stages.
- spack.config.update_config(
- 'config', {'build_stage': [str(test_tmp_path)]}, scope='user'
- )
+ spack.config.set(
+ 'config', {'build_stage': [str(test_tmp_path)]}, scope='user')
archive_dir = tmpdir.join('test-files')
archive_name = 'test-files.tar.gz'
@@ -202,7 +180,7 @@ def search_fn():
return _Mock()
-@pytest.mark.usefixtures('builtin_mock')
+@pytest.mark.usefixtures('mock_packages')
class TestStage(object):
stage_name = 'spack-test-stage'
diff --git a/lib/spack/spack/test/svn_fetch.py b/lib/spack/spack/test/svn_fetch.py
index f00b0b8259..129c38587a 100644
--- a/lib/spack/spack/test/svn_fetch.py
+++ b/lib/spack/spack/test/svn_fetch.py
@@ -1,32 +1,16 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
-import spack
-from llnl.util.filesystem import join_path, touch, working_dir
+
+from llnl.util.filesystem import touch, working_dir
+
+import spack.repo
+import spack.config
from spack.spec import Spec
from spack.version import ver
from spack.util.executable import which
@@ -43,7 +27,7 @@ def test_fetch(
secure,
mock_svn_repository,
config,
- refresh_builtin_mock
+ mutable_mock_packages
):
"""Tries to:
@@ -61,21 +45,18 @@ def test_fetch(
# Construct the package under test
spec = Spec('svn-test')
spec.concretize()
- pkg = spack.repo.get(spec, new=True)
+ pkg = spack.repo.get(spec)
pkg.versions[ver('svn')] = t.args
# Enter the stage directory and check some properties
with pkg.stage:
- try:
- spack.insecure = secure
+ with spack.config.override('config:verify_ssl', secure):
pkg.do_stage()
- finally:
- spack.insecure = False
with working_dir(pkg.stage.source_path):
assert h() == t.revision
- file_path = join_path(pkg.stage.source_path, t.file)
+ file_path = os.path.join(pkg.stage.source_path, t.file)
assert os.path.isdir(pkg.stage.source_path)
assert os.path.isfile(file_path)
diff --git a/lib/spack/spack/test/tengine.py b/lib/spack/spack/test/tengine.py
index 35979879e1..c9cfbc59d0 100644
--- a/lib/spack/spack/test/tengine.py
+++ b/lib/spack/spack/test/tengine.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import spack.tengine as tengine
@@ -91,7 +72,7 @@ class TestTengineEnvironment(object):
def test_template_retrieval(self):
"""Tests the template retrieval mechanism hooked into config files"""
# Check the directories are correct
- template_dirs = spack.config.get_config('config')['template_dirs']
+ template_dirs = spack.config.get('config:template_dirs')
template_dirs = [canonicalize_path(x) for x in template_dirs]
assert len(template_dirs) == 3
diff --git a/lib/spack/spack/test/test_activations.py b/lib/spack/spack/test/test_activations.py
index ec3562aaa6..35f1d0c87d 100644
--- a/lib/spack/spack/test/test_activations.py
+++ b/lib/spack/spack/test/test_activations.py
@@ -1,41 +1,29 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-import spack
-from llnl.util.filesystem import join_path
+import os
+import pytest
+import sys
+
+import spack.spec
+import spack.package
+from llnl.util.link_tree import MergeConflictError
+from spack.build_systems.python import PythonPackage
from spack.directory_layout import YamlDirectoryLayout
from spack.filesystem_view import YamlFilesystemView
+from spack.util.prefix import Prefix
-import os
-import pytest
+"""This includes tests for customized activation logic for specific packages
+ (e.g. python and perl).
+"""
-class FakeExtensionPackage(object):
+class FakeExtensionPackage(spack.package.PackageViewMixin):
def __init__(self, name, prefix):
self.name = name
- self.prefix = prefix
+ self.prefix = Prefix(prefix)
self.spec = FakeSpec(self)
@@ -44,10 +32,43 @@ class FakeSpec(object):
self.name = package.name
self.prefix = package.prefix
self.hash = self.name
+ self.package = package
+ self.concrete = True
def dag_hash(self):
return self.hash
+ def __lt__(self, other):
+ return self.name < other.name
+
+
+class FakePythonExtensionPackage(FakeExtensionPackage):
+ def __init__(self, name, prefix, py_namespace, python_spec):
+ self.py_namespace = py_namespace
+ self.extendee_spec = python_spec
+ super(FakePythonExtensionPackage, self).__init__(name, prefix)
+
+ def add_files_to_view(self, view, merge_map):
+ if sys.version_info >= (3, 0):
+ add_fn = PythonPackage.add_files_to_view
+ else:
+ add_fn = PythonPackage.add_files_to_view.im_func
+ return add_fn(self, view, merge_map)
+
+ def view_file_conflicts(self, view, merge_map):
+ if sys.version_info >= (3, 0):
+ conflicts_fn = PythonPackage.view_file_conflicts
+ else:
+ conflicts_fn = PythonPackage.view_file_conflicts.im_func
+ return conflicts_fn(self, view, merge_map)
+
+ def remove_files_from_view(self, view, merge_map):
+ if sys.version_info >= (3, 0):
+ remove_fn = PythonPackage.remove_files_from_view
+ else:
+ remove_fn = PythonPackage.remove_files_from_view.im_func
+ return remove_fn(self, view, merge_map)
+
def create_dir_structure(tmpdir, dir_structure):
for fname, children in dir_structure.items():
@@ -75,7 +96,7 @@ def python_and_extension_dirs(tmpdir):
python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True
- python_spec.package.spec._set_test_prefix(str(python_prefix))
+ python_spec.package.spec.prefix = str(python_prefix)
ext_dirs = {
'bin/': {
@@ -97,32 +118,56 @@ def python_and_extension_dirs(tmpdir):
create_dir_structure(ext_prefix, ext_dirs)
easy_install_location = 'lib/python2.7/site-packages/easy-install.pth'
- with open(join_path(ext_prefix, easy_install_location), 'w') as F:
- F.write("""path/to/ext1.egg
+ with open(str(ext_prefix.join(easy_install_location)), 'w') as f:
+ f.write("""path/to/ext1.egg
path/to/setuptools.egg""")
return str(python_prefix), str(ext_prefix)
-def test_python_activation(tmpdir):
- # Note the lib directory is based partly on the python version
- python_spec = spack.spec.Spec('python@2.7.12')
- python_spec._concrete = True
+@pytest.fixture()
+def namespace_extensions(tmpdir):
+ ext1_dirs = {
+ 'bin/': {
+ 'py-ext-tool1': None
+ },
+ 'lib/': {
+ 'python2.7/': {
+ 'site-packages/': {
+ 'examplenamespace/': {
+ '__init__.py': None,
+ 'ext1_sample.py': None
+ }
+ }
+ }
+ }
+ }
- python_name = 'python'
- tmpdir.ensure(python_name, dir=True)
+ ext2_dirs = {
+ 'bin/': {
+ 'py-ext-tool2': None
+ },
+ 'lib/': {
+ 'python2.7/': {
+ 'site-packages/': {
+ 'examplenamespace/': {
+ '__init__.py': None,
+ 'ext2_sample.py': None
+ }
+ }
+ }
+ }
+ }
- python_prefix = str(tmpdir.join(python_name))
- # Set the prefix on the package's spec reference because that is a copy of
- # the original spec
- python_spec.package.spec._set_test_prefix(python_prefix)
+ ext1_name = 'py-extension1'
+ ext1_prefix = tmpdir.join(ext1_name)
+ create_dir_structure(ext1_prefix, ext1_dirs)
- ext_name = 'py-extension'
- tmpdir.ensure(ext_name, dir=True)
- ext_pkg = FakeExtensionPackage(ext_name, str(tmpdir.join(ext_name)))
+ ext2_name = 'py-extension2'
+ ext2_prefix = tmpdir.join(ext2_name)
+ create_dir_structure(ext2_prefix, ext2_dirs)
- python_pkg = python_spec.package
- python_pkg.activate(ext_pkg)
+ return str(ext1_prefix), str(ext2_prefix), 'examplenamespace'
def test_python_activation_with_files(tmpdir, python_and_extension_dirs):
@@ -130,18 +175,18 @@ def test_python_activation_with_files(tmpdir, python_and_extension_dirs):
python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True
- python_spec.package.spec._set_test_prefix(python_prefix)
+ python_spec.package.spec.prefix = python_prefix
ext_pkg = FakeExtensionPackage('py-extension', ext_prefix)
python_pkg = python_spec.package
- python_pkg.activate(ext_pkg)
+ python_pkg.activate(ext_pkg, python_pkg.view())
- assert os.path.exists(join_path(python_prefix, 'bin/py-ext-tool'))
+ assert os.path.exists(os.path.join(python_prefix, 'bin/py-ext-tool'))
easy_install_location = 'lib/python2.7/site-packages/easy-install.pth'
- with open(join_path(python_prefix, easy_install_location), 'r') as F:
- easy_install_contents = F.read()
+ with open(os.path.join(python_prefix, easy_install_location), 'r') as f:
+ easy_install_contents = f.read()
assert 'ext1.egg' in easy_install_contents
assert 'setuptools.egg' not in easy_install_contents
@@ -152,7 +197,7 @@ def test_python_activation_view(tmpdir, python_and_extension_dirs):
python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True
- python_spec.package.spec._set_test_prefix(python_prefix)
+ python_spec.package.spec.prefix = python_prefix
ext_pkg = FakeExtensionPackage('py-extension', ext_prefix)
@@ -161,11 +206,112 @@ def test_python_activation_view(tmpdir, python_and_extension_dirs):
view = YamlFilesystemView(view_dir, layout)
python_pkg = python_spec.package
- python_pkg.activate(ext_pkg, extensions_layout=view.extensions_layout)
+ python_pkg.activate(ext_pkg, view)
+
+ assert not os.path.exists(os.path.join(python_prefix, 'bin/py-ext-tool'))
+
+ assert os.path.exists(os.path.join(view_dir, 'bin/py-ext-tool'))
+
+
+def test_python_ignore_namespace_init_conflict(tmpdir, namespace_extensions):
+ """Test the view update logic in PythonPackage ignores conflicting
+ instances of __init__ for packages which are in the same namespace.
+ """
+ ext1_prefix, ext2_prefix, py_namespace = namespace_extensions
+
+ python_spec = spack.spec.Spec('python@2.7.12')
+ python_spec._concrete = True
+
+ ext1_pkg = FakePythonExtensionPackage(
+ 'py-extension1', ext1_prefix, py_namespace, python_spec)
+ ext2_pkg = FakePythonExtensionPackage(
+ 'py-extension2', ext2_prefix, py_namespace, python_spec)
+
+ view_dir = str(tmpdir.join('view'))
+ layout = YamlDirectoryLayout(view_dir)
+ view = YamlFilesystemView(view_dir, layout)
+
+ python_pkg = python_spec.package
+ python_pkg.activate(ext1_pkg, view)
+ # Normally handled by Package.do_activate, but here we activate directly
+ view.extensions_layout.add_extension(python_spec, ext1_pkg.spec)
+ python_pkg.activate(ext2_pkg, view)
+
+ f1 = 'lib/python2.7/site-packages/examplenamespace/ext1_sample.py'
+ f2 = 'lib/python2.7/site-packages/examplenamespace/ext2_sample.py'
+ init_file = 'lib/python2.7/site-packages/examplenamespace/__init__.py'
+
+ assert os.path.exists(os.path.join(view_dir, f1))
+ assert os.path.exists(os.path.join(view_dir, f2))
+ assert os.path.exists(os.path.join(view_dir, init_file))
+
+
+def test_python_keep_namespace_init(tmpdir, namespace_extensions):
+ """Test the view update logic in PythonPackage keeps the namespace
+ __init__ file as long as one package in the namespace still
+ exists.
+ """
+ ext1_prefix, ext2_prefix, py_namespace = namespace_extensions
+
+ python_spec = spack.spec.Spec('python@2.7.12')
+ python_spec._concrete = True
+
+ ext1_pkg = FakePythonExtensionPackage(
+ 'py-extension1', ext1_prefix, py_namespace, python_spec)
+ ext2_pkg = FakePythonExtensionPackage(
+ 'py-extension2', ext2_prefix, py_namespace, python_spec)
+
+ view_dir = str(tmpdir.join('view'))
+ layout = YamlDirectoryLayout(view_dir)
+ view = YamlFilesystemView(view_dir, layout)
+
+ python_pkg = python_spec.package
+ python_pkg.activate(ext1_pkg, view)
+ # Normally handled by Package.do_activate, but here we activate directly
+ view.extensions_layout.add_extension(python_spec, ext1_pkg.spec)
+ python_pkg.activate(ext2_pkg, view)
+ view.extensions_layout.add_extension(python_spec, ext2_pkg.spec)
+
+ f1 = 'lib/python2.7/site-packages/examplenamespace/ext1_sample.py'
+ init_file = 'lib/python2.7/site-packages/examplenamespace/__init__.py'
+
+ python_pkg.deactivate(ext1_pkg, view)
+ view.extensions_layout.remove_extension(python_spec, ext1_pkg.spec)
+
+ assert not os.path.exists(os.path.join(view_dir, f1))
+ assert os.path.exists(os.path.join(view_dir, init_file))
+
+ python_pkg.deactivate(ext2_pkg, view)
+ view.extensions_layout.remove_extension(python_spec, ext2_pkg.spec)
- assert not os.path.exists(join_path(python_prefix, 'bin/py-ext-tool'))
+ assert not os.path.exists(os.path.join(view_dir, init_file))
- assert os.path.exists(join_path(view_dir, 'bin/py-ext-tool'))
+
+def test_python_namespace_conflict(tmpdir, namespace_extensions):
+ """Test the view update logic in PythonPackage reports an error when two
+ python extensions with different namespaces have a conflicting __init__
+ file.
+ """
+ ext1_prefix, ext2_prefix, py_namespace = namespace_extensions
+ other_namespace = py_namespace + 'other'
+
+ python_spec = spack.spec.Spec('python@2.7.12')
+ python_spec._concrete = True
+
+ ext1_pkg = FakePythonExtensionPackage(
+ 'py-extension1', ext1_prefix, py_namespace, python_spec)
+ ext2_pkg = FakePythonExtensionPackage(
+ 'py-extension2', ext2_prefix, other_namespace, python_spec)
+
+ view_dir = str(tmpdir.join('view'))
+ layout = YamlDirectoryLayout(view_dir)
+ view = YamlFilesystemView(view_dir, layout)
+
+ python_pkg = python_spec.package
+ python_pkg.activate(ext1_pkg, view)
+ view.extensions_layout.add_extension(python_spec, ext1_pkg.spec)
+ with pytest.raises(MergeConflictError):
+ python_pkg.activate(ext2_pkg, view)
@pytest.fixture()
@@ -189,7 +335,7 @@ def perl_and_extension_dirs(tmpdir):
perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True
- perl_spec.package.spec._set_test_prefix(str(perl_prefix))
+ perl_spec.package.spec.prefix = str(perl_prefix)
ext_dirs = {
'bin/': {
@@ -225,14 +371,14 @@ def test_perl_activation(tmpdir):
perl_prefix = str(tmpdir.join(perl_name))
# Set the prefix on the package's spec reference because that is a copy of
# the original spec
- perl_spec.package.spec._set_test_prefix(perl_prefix)
+ perl_spec.package.spec.prefix = perl_prefix
ext_name = 'perl-extension'
tmpdir.ensure(ext_name, dir=True)
ext_pkg = FakeExtensionPackage(ext_name, str(tmpdir.join(ext_name)))
perl_pkg = perl_spec.package
- perl_pkg.activate(ext_pkg)
+ perl_pkg.activate(ext_pkg, perl_pkg.view())
def test_perl_activation_with_files(tmpdir, perl_and_extension_dirs):
@@ -240,14 +386,14 @@ def test_perl_activation_with_files(tmpdir, perl_and_extension_dirs):
perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True
- perl_spec.package.spec._set_test_prefix(perl_prefix)
+ perl_spec.package.spec.prefix = perl_prefix
ext_pkg = FakeExtensionPackage('perl-extension', ext_prefix)
perl_pkg = perl_spec.package
- perl_pkg.activate(ext_pkg)
+ perl_pkg.activate(ext_pkg, perl_pkg.view())
- assert os.path.exists(join_path(perl_prefix, 'bin/perl-ext-tool'))
+ assert os.path.exists(os.path.join(perl_prefix, 'bin/perl-ext-tool'))
def test_perl_activation_view(tmpdir, perl_and_extension_dirs):
@@ -255,7 +401,7 @@ def test_perl_activation_view(tmpdir, perl_and_extension_dirs):
perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True
- perl_spec.package.spec._set_test_prefix(perl_prefix)
+ perl_spec.package.spec.prefix = perl_prefix
ext_pkg = FakeExtensionPackage('perl-extension', ext_prefix)
@@ -264,8 +410,8 @@ def test_perl_activation_view(tmpdir, perl_and_extension_dirs):
view = YamlFilesystemView(view_dir, layout)
perl_pkg = perl_spec.package
- perl_pkg.activate(ext_pkg, extensions_layout=view.extensions_layout)
+ perl_pkg.activate(ext_pkg, view)
- assert not os.path.exists(join_path(perl_prefix, 'bin/perl-ext-tool'))
+ assert not os.path.exists(os.path.join(perl_prefix, 'bin/perl-ext-tool'))
- assert os.path.exists(join_path(view_dir, 'bin/perl-ext-tool'))
+ assert os.path.exists(os.path.join(view_dir, 'bin/perl-ext-tool'))
diff --git a/lib/spack/spack/test/url_fetch.py b/lib/spack/spack/test/url_fetch.py
index 168bda5f64..f81521c2b0 100644
--- a/lib/spack/spack/test/url_fetch.py
+++ b/lib/spack/spack/test/url_fetch.py
@@ -1,33 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import pytest
from llnl.util.filesystem import working_dir, is_exe
-import spack
+import spack.repo
+import spack.config
from spack.fetch_strategy import from_list_url, URLFetchStrategy
from spack.spec import Spec
from spack.version import ver
@@ -45,13 +27,13 @@ def test_fetch(
secure,
checksum_type,
config,
- refresh_builtin_mock
+ mutable_mock_packages
):
"""Fetch an archive and make sure we can checksum it."""
mock_archive.url
mock_archive.path
- algo = crypto.hashes[checksum_type]()
+ algo = crypto.hash_fun_for_algo(checksum_type)()
with open(mock_archive.archive_file, 'rb') as f:
algo.update(f.read())
checksum = algo.hexdigest()
@@ -60,18 +42,15 @@ def test_fetch(
spec = Spec('url-test')
spec.concretize()
- pkg = spack.repo.get('url-test', new=True)
+ pkg = spack.repo.get('url-test')
pkg.url = mock_archive.url
pkg.versions[ver('test')] = {checksum_type: checksum, 'url': pkg.url}
pkg.spec = spec
# Enter the stage directory and check some properties
with pkg.stage:
- try:
- spack.insecure = secure
+ with spack.config.override('config:verify_ssl', secure):
pkg.do_stage()
- finally:
- spack.insecure = False
with working_dir(pkg.stage.source_path):
assert os.path.exists('configure')
@@ -83,22 +62,71 @@ def test_fetch(
assert 'echo Building...' in contents
-def test_from_list_url(builtin_mock, config):
- pkg = spack.repo.get('url-list-test', new=True)
- for ver_str in ['0.0.0', '1.0.0', '2.0.0',
- '3.0', '4.5', '2.0.0b2',
- '3.0a1', '4.5-rc5']:
- spec = Spec('url-list-test@%s' % ver_str)
- spec.concretize()
- pkg.spec = spec
- fetch_strategy = from_list_url(pkg)
- assert isinstance(fetch_strategy, URLFetchStrategy)
- assert (os.path.basename(fetch_strategy.url) ==
- ('foo-' + ver_str + '.tar.gz'))
+def test_from_list_url(mock_packages, config):
+ pkg = spack.repo.get('url-list-test')
+
+ # These URLs are all in the url-list-test package and should have
+ # checksums taken from the package.
+ spec = Spec('url-list-test @0.0.0').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-0.0.0.tar.gz'
+ assert fetch_strategy.digest == 'abc000'
+
+ spec = Spec('url-list-test @1.0.0').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-1.0.0.tar.gz'
+ assert fetch_strategy.digest == 'abc100'
+
+ spec = Spec('url-list-test @3.0').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-3.0.tar.gz'
+ assert fetch_strategy.digest == 'abc30'
+
+ spec = Spec('url-list-test @4.5').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-4.5.tar.gz'
+ assert fetch_strategy.digest == 'abc45'
+
+ spec = Spec('url-list-test @2.0.0b2').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-2.0.0b2.tar.gz'
+ assert fetch_strategy.digest == 'abc200b2'
+
+ spec = Spec('url-list-test @3.0a1').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-3.0a1.tar.gz'
+ assert fetch_strategy.digest == 'abc30a1'
+
+ spec = Spec('url-list-test @4.5-rc5').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-4.5-rc5.tar.gz'
+ assert fetch_strategy.digest == 'abc45rc5'
+
+ # this one is not in the url-list-test package.
+ spec = Spec('url-list-test @2.0.0').concretized()
+ pkg = spack.repo.get(spec)
+ fetch_strategy = from_list_url(pkg)
+ assert isinstance(fetch_strategy, URLFetchStrategy)
+ assert os.path.basename(fetch_strategy.url) == 'foo-2.0.0.tar.gz'
+ assert fetch_strategy.digest is None
def test_hash_detection(checksum_type):
- algo = crypto.hashes[checksum_type]()
+ algo = crypto.hash_fun_for_algo(checksum_type)()
h = 'f' * (algo.digest_size * 2) # hex -> bytes
checker = crypto.Checker(h)
assert checker.hash_name == checksum_type
diff --git a/lib/spack/spack/test/url_parse.py b/lib/spack/spack/test/url_parse.py
index 7a22205076..7dcdb36424 100644
--- a/lib/spack/spack/test/url_parse.py
+++ b/lib/spack/spack/test/url_parse.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Tests Spack's ability to parse the name and version of a package
based on its URL.
"""
@@ -43,6 +24,8 @@ from spack.version import Version
('jpegsrc.v9b', 'jpegsrc.v9b'),
('turbolinux702', 'turbolinux702'),
('converge_install_2.3.16', 'converge_install_2.3.16'),
+ # Download type - code, source
+ ('cistem-1.0.0-beta-source-code', 'cistem-1.0.0-beta'),
# Download type - src
('apache-ant-1.9.7-src', 'apache-ant-1.9.7'),
('go1.7.4.src', 'go1.7.4'),
@@ -75,6 +58,8 @@ from spack.version import Version
('ncbi-blast-2.6.0+-src', 'ncbi-blast-2.6.0'),
# License
('cppad-20170114.gpl', 'cppad-20170114'),
+ # Arch
+ ('pcraster-4.1.0_x86-64', 'pcraster-4.1.0'),
# OS - linux
('astyle_2.04_linux', 'astyle_2.04'),
# OS - unix
@@ -167,6 +152,7 @@ def test_url_strip_name_suffixes(url, version, expected):
('libxc', 58, '2.2.2', 64, 'http://www.tddft.org/programs/octopus/down.php?file=libxc/libxc-2.2.2.tar.gz'),
# Version in suffix
('swiftsim', 36, '0.3.0', 76, 'http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0'),
+ ('swiftsim', 55, '0.3.0', 95, 'https://gitlab.cosma.dur.ac.uk/api/v4/projects/swift%2Fswiftsim/repository/archive.tar.gz?sha=v0.3.0'),
('sionlib', 30, '1.7.1', 59, 'http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1'),
# Regex in name
('voro++', 40, '0.4.6', 47, 'http://math.lbl.gov/voro++/download/dir/voro++-0.4.6.tar.gz'),
@@ -207,14 +193,21 @@ def test_url_parse_offset(name, noffset, ver, voffset, path):
('git', '2.7.1', 'https://github.com/git/git/tarball/v2.7.1'),
# name/zipball/vver.ver
('git', '2.7.1', 'https://github.com/git/git/zipball/v2.7.1'),
+
# Common Repositories - gitlab downloads
# name/repository/archive.ext?ref=vver.ver
('swiftsim', '0.3.0',
'http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0'),
+ # /api/v4/projects/NAMESPACE%2Fname/repository/archive.ext?sha=vver.ver
+ ('swiftsim', '0.3.0',
+ 'https://gitlab.cosma.dur.ac.uk/api/v4/projects/swift%2Fswiftsim/repository/archive.tar.gz?sha=v0.3.0'),
# name/repository/archive.ext?ref=name-ver.ver
('icet', '1.2.3',
'https://gitlab.kitware.com/icet/icet/repository/archive.tar.gz?ref=IceT-1.2.3'),
+ # /api/v4/projects/NAMESPACE%2Fname/repository/archive.ext?sha=name-ver.ver
+ ('icet', '1.2.3',
+ 'https://gitlab.kitware.com/api/v4/projects/icet%2Ficet/repository/archive.tar.bz2?sha=IceT-1.2.3'),
# Common Repositories - bitbucket downloads
@@ -370,6 +363,7 @@ def test_url_parse_offset(name, noffset, ver, voffset, path):
('nextflow', '0.20.1', 'https://github.com/nextflow-io/nextflow/releases/download/v0.20.1/nextflow'),
# suffix queries
('swiftsim', '0.3.0', 'http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0'),
+ ('swiftsim', '0.3.0', 'https://gitlab.cosma.dur.ac.uk/api/v4/projects/swift%2Fswiftsim/repository/archive.tar.gz?sha=v0.3.0'),
('sionlib', '1.7.1', 'http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1'),
# stem queries
('slepc', '3.6.2', 'http://slepc.upv.es/download/download.php?filename=slepc-3.6.2.tar.gz'),
diff --git a/lib/spack/spack/test/url_substitution.py b/lib/spack/spack/test/url_substitution.py
index dcd26aad0d..a07a9bf6f0 100644
--- a/lib/spack/spack/test/url_substitution.py
+++ b/lib/spack/spack/test/url_substitution.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Tests Spack's ability to substitute a different version into a URL."""
import os
diff --git a/lib/spack/spack/test/file_cache.py b/lib/spack/spack/test/util/file_cache.py
index 7098b9673e..fc1391c8e6 100644
--- a/lib/spack/spack/test/file_cache.py
+++ b/lib/spack/spack/test/util/file_cache.py
@@ -1,32 +1,13 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Test Spack's FileCache."""
import os
import pytest
-from spack.file_cache import FileCache
+from spack.util.file_cache import FileCache
@pytest.fixture()
diff --git a/lib/spack/spack/test/util/filesystem.py b/lib/spack/spack/test/util/filesystem.py
deleted file mode 100644
index 86c243a97e..0000000000
--- a/lib/spack/spack/test/util/filesystem.py
+++ /dev/null
@@ -1,61 +0,0 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
-#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
-
-import llnl.util.filesystem as fs
-
-
-def test_move_transaction_commit(tmpdir):
-
- fake_library = tmpdir.mkdir('lib').join('libfoo.so')
- fake_library.write('Just some fake content.')
-
- old_md5 = fs.hash_directory(str(tmpdir))
-
- with fs.replace_directory_transaction(str(tmpdir.join('lib'))):
- fake_library = tmpdir.mkdir('lib').join('libfoo.so')
- fake_library.write('Other content.')
- new_md5 = fs.hash_directory(str(tmpdir))
-
- assert old_md5 != fs.hash_directory(str(tmpdir))
- assert new_md5 == fs.hash_directory(str(tmpdir))
-
-
-def test_move_transaction_rollback(tmpdir):
-
- fake_library = tmpdir.mkdir('lib').join('libfoo.so')
- fake_library.write('Just some fake content.')
-
- h = fs.hash_directory(str(tmpdir))
-
- try:
- with fs.replace_directory_transaction(str(tmpdir.join('lib'))):
- assert h != fs.hash_directory(str(tmpdir))
- fake_library = tmpdir.mkdir('lib').join('libfoo.so')
- fake_library.write('Other content.')
- raise RuntimeError('')
- except RuntimeError:
- pass
-
- assert h == fs.hash_directory(str(tmpdir))
diff --git a/lib/spack/spack/test/util/log_parser.py b/lib/spack/spack/test/util/log_parser.py
index 37642f7f1f..976b720fa8 100644
--- a/lib/spack/spack/test/util/log_parser.py
+++ b/lib/spack/spack/test/util/log_parser.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from ctest_log_parser import CTestLogParser
diff --git a/lib/spack/spack/test/util/prefix.py b/lib/spack/spack/test/util/prefix.py
index e1cda1f1e4..f312afbc29 100644
--- a/lib/spack/spack/test/util/prefix.py
+++ b/lib/spack/spack/test/util/prefix.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Tests various features of :py:class:`spack.util.prefix.Prefix`"""
from spack.util.prefix import Prefix
@@ -36,6 +17,35 @@ def test_prefix_attributes():
assert prefix.include == '/usr/include'
+def test_prefix_join():
+ """Test prefix join ``prefix.join(...)``"""
+ prefix = Prefix('/usr')
+
+ a1 = prefix.join('a_{0}'.format(1)).lib64
+ a2 = prefix.join('a-{0}'.format(1)).lib64
+ a3 = prefix.join('a.{0}'.format(1)).lib64
+
+ assert a1 == '/usr/a_1/lib64'
+ assert a2 == '/usr/a-1/lib64'
+ assert a3 == '/usr/a.1/lib64'
+
+ assert isinstance(a1, Prefix)
+ assert isinstance(a2, Prefix)
+ assert isinstance(a3, Prefix)
+
+ p1 = prefix.bin.join('executable.sh')
+ p2 = prefix.share.join('pkg-config').join('foo.pc')
+ p3 = prefix.join('dashed-directory').foo
+
+ assert p1 == '/usr/bin/executable.sh'
+ assert p2 == '/usr/share/pkg-config/foo.pc'
+ assert p3 == '/usr/dashed-directory/foo'
+
+ assert isinstance(p1, Prefix)
+ assert isinstance(p2, Prefix)
+ assert isinstance(p3, Prefix)
+
+
def test_multilevel_attributes():
"""Test attributes of attributes, like ``prefix.share.man``"""
prefix = Prefix('/usr/')
diff --git a/lib/spack/spack/test/util/spack_lock_wrapper.py b/lib/spack/spack/test/util/spack_lock_wrapper.py
new file mode 100644
index 0000000000..fd06d6b386
--- /dev/null
+++ b/lib/spack/spack/test/util/spack_lock_wrapper.py
@@ -0,0 +1,104 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Tests for Spack's wrapper module around llnl.util.lock."""
+import os
+
+import pytest
+
+from llnl.util.filesystem import group_ids
+
+import spack.config
+import spack.util.lock as lk
+
+
+def test_disable_locking(tmpdir):
+ """Ensure that locks do no real locking when disabled."""
+ lock_path = str(tmpdir.join('lockfile'))
+
+ old_value = spack.config.get('config:locks')
+
+ with spack.config.override('config:locks', False):
+ lock = lk.Lock(lock_path)
+
+ lock.acquire_read()
+ assert not os.path.exists(lock_path)
+
+ lock.acquire_write()
+ assert not os.path.exists(lock_path)
+
+ lock.release_write()
+ assert not os.path.exists(lock_path)
+
+ lock.release_read()
+ assert not os.path.exists(lock_path)
+
+ assert old_value == spack.config.get('config:locks')
+
+
+def test_lock_checks_user(tmpdir):
+ """Ensure lock checks work with a self-owned, self-group repo."""
+ uid = os.getuid()
+ if uid not in group_ids():
+ pytest.skip("user has no group with gid == uid")
+
+ # self-owned, own group
+ tmpdir.chown(uid, uid)
+
+ # safe
+ path = str(tmpdir)
+ tmpdir.chmod(0o744)
+ lk.check_lock_safety(path)
+
+ # safe
+ tmpdir.chmod(0o774)
+ lk.check_lock_safety(path)
+
+ # unsafe
+ tmpdir.chmod(0o777)
+ with pytest.raises(spack.error.SpackError):
+ lk.check_lock_safety(path)
+
+ # safe
+ tmpdir.chmod(0o474)
+ lk.check_lock_safety(path)
+
+ # safe
+ tmpdir.chmod(0o477)
+ lk.check_lock_safety(path)
+
+
+def test_lock_checks_group(tmpdir):
+ """Ensure lock checks work with a self-owned, non-self-group repo."""
+ uid = os.getuid()
+ gid = next((g for g in group_ids() if g != uid), None)
+ if not gid:
+ pytest.skip("user has no group with gid != uid")
+
+ # self-owned, another group
+ tmpdir.chown(uid, gid)
+
+ # safe
+ path = str(tmpdir)
+ tmpdir.chmod(0o744)
+ lk.check_lock_safety(path)
+
+ # unsafe
+ tmpdir.chmod(0o774)
+ with pytest.raises(spack.error.SpackError):
+ lk.check_lock_safety(path)
+
+ # unsafe
+ tmpdir.chmod(0o777)
+ with pytest.raises(spack.error.SpackError):
+ lk.check_lock_safety(path)
+
+ # safe
+ tmpdir.chmod(0o474)
+ lk.check_lock_safety(path)
+
+ # safe
+ tmpdir.chmod(0o477)
+ lk.check_lock_safety(path)
diff --git a/lib/spack/spack/test/util/spack_yaml.py b/lib/spack/spack/test/util/spack_yaml.py
new file mode 100644
index 0000000000..d14e2de3a1
--- /dev/null
+++ b/lib/spack/spack/test/util/spack_yaml.py
@@ -0,0 +1,67 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import re
+
+import spack.config
+from spack.main import SpackCommand
+
+config_cmd = SpackCommand('config')
+
+
+def get_config_line(pattern, lines):
+ """Get a configuration line that matches a particular pattern."""
+ line = next((l for l in lines if re.search(pattern, l)), None)
+ assert line is not None, 'no such line!'
+ return line
+
+
+def check_blame(element, file_name, line=None):
+ """Check that `config blame config` gets right file/line for an element.
+
+ This runs `spack config blame config` and scrapes the output for a
+ particular YAML key. It thne checks that the requested file/line info
+ is also on that line.
+
+ Line is optional; if it is ``None`` we just check for the
+ ``file_name``, which may just be a name for a special config scope
+ like ``_builtin`` or ``command_line``.
+ """
+ output = config_cmd('blame', 'config')
+
+ blame_lines = output.rstrip().split('\n')
+ element_line = get_config_line(element + ':', blame_lines)
+
+ annotation = file_name
+ if line is not None:
+ annotation += ':%d' % line
+
+ assert file_name in element_line
+
+
+def test_config_blame(config):
+ """check blame info for elements in mock configuration."""
+ config_file = config.get_config_filename('site', 'config')
+
+ check_blame('install_tree', config_file, 2)
+ check_blame('source_cache', config_file, 11)
+ check_blame('misc_cache', config_file, 12)
+ check_blame('verify_ssl', config_file, 13)
+ check_blame('checksum', config_file, 14)
+ check_blame('dirty', config_file, 15)
+
+
+def test_config_blame_with_override(config):
+ """check blame for an element from an override scope"""
+ config_file = config.get_config_filename('site', 'config')
+
+ with spack.config.override('config:install_tree', 'foobar'):
+ check_blame('install_tree', 'overrides')
+
+ check_blame('source_cache', config_file, 11)
+ check_blame('misc_cache', config_file, 12)
+ check_blame('verify_ssl', config_file, 13)
+ check_blame('checksum', config_file, 14)
+ check_blame('dirty', config_file, 15)
diff --git a/lib/spack/spack/test/util/util_string.py b/lib/spack/spack/test/util/util_string.py
new file mode 100644
index 0000000000..205fd1105f
--- /dev/null
+++ b/lib/spack/spack/test/util/util_string.py
@@ -0,0 +1,14 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.util.string import plural
+
+
+def test_plural():
+ assert plural(0, 'thing') == '0 things'
+ assert plural(1, 'thing') == '1 thing'
+ assert plural(2, 'thing') == '2 things'
+ assert plural(1, 'thing', 'wombats') == '1 thing'
+ assert plural(2, 'thing', 'wombats') == '2 wombats'
diff --git a/lib/spack/spack/test/variant.py b/lib/spack/spack/test/variant.py
index 6bb7dc78e4..0bbab46efa 100644
--- a/lib/spack/spack/test/variant.py
+++ b/lib/spack/spack/test/variant.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import pytest
import numbers
diff --git a/lib/spack/spack/test/versions.py b/lib/spack/spack/test/versions.py
index c0136c41dc..1a56b921b3 100644
--- a/lib/spack/spack/test/versions.py
+++ b/lib/spack/spack/test/versions.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""These version tests were taken from the RPM source code.
We try to maintain compatibility with RPM's version semantics
where it makes sense.
@@ -488,6 +469,14 @@ def test_repr_and_str():
check_repr_and_str('R2016a.2-3_4')
+def test_len():
+ a = Version('1.2.3.4')
+ assert len(a) == len(a.version)
+ assert(len(a) == 4)
+ b = Version('2018.0')
+ assert(len(b) == 2)
+
+
def test_get_item():
a = Version('0.1_2-3')
assert isinstance(a[1], int)
diff --git a/lib/spack/spack/test/views.py b/lib/spack/spack/test/views.py
new file mode 100644
index 0000000000..827c9f0a3f
--- /dev/null
+++ b/lib/spack/spack/test/views.py
@@ -0,0 +1,29 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+
+from spack.spec import Spec
+
+
+def test_global_activation(install_mockery, mock_fetch):
+ """This test ensures that views which are maintained inside of an extendee
+ package's prefix are maintained as expected and are compatible with
+ global activations prior to #7152.
+ """
+ spec = Spec('extension1').concretized()
+ pkg = spec.package
+ pkg.do_install()
+ pkg.do_activate()
+
+ extendee_spec = spec['extendee']
+ extendee_pkg = spec['extendee'].package
+ view = extendee_pkg.view()
+ assert pkg.is_activated(view)
+
+ expected_path = os.path.join(
+ extendee_spec.prefix, '.spack', 'extensions.yaml')
+ assert (view.extensions_layout.extension_file_path(extendee_spec) ==
+ expected_path)
diff --git a/lib/spack/spack/test/web.py b/lib/spack/spack/test/web.py
index 82ca61f410..07e1f656fa 100644
--- a/lib/spack/spack/test/web.py
+++ b/lib/spack/spack/test/web.py
@@ -1,36 +1,17 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Tests for web.py."""
import os
-import spack
+import spack.paths
from spack.util.web import spider, find_versions_of_archive
from spack.version import ver
-web_data_path = os.path.join(spack.test_path, 'data', 'web')
+web_data_path = os.path.join(spack.paths.test_path, 'data', 'web')
root = 'file://' + web_data_path + '/index.html'
root_tarball = 'file://' + web_data_path + '/foo-0.0.0.tar.gz'
diff --git a/lib/spack/spack/url.py b/lib/spack/spack/url.py
index 5276b3165f..644ff53bbf 100644
--- a/lib/spack/spack/url.py
+++ b/lib/spack/spack/url.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This module has methods for parsing names and versions of packages from URLs.
The idea is to allow package creators to supply nothing more than the
@@ -90,9 +71,14 @@ def find_list_url(url):
(r'(.*github\.com/[^/]+/[^/]+)',
lambda m: m.group(1) + '/releases'),
- # GitLab
+ # GitLab API endpoint
+ # e.g. https://gitlab.dkrz.de/api/v4/projects/k202009%2Flibaec/repository/archive.tar.gz?sha=v1.0.2
+ (r'(.*gitlab[^/]+)/api/v4/projects/([^/]+)%2F([^/]+)',
+ lambda m: m.group(1) + '/' + m.group(2) + '/' + m.group(3) + '/tags'),
+
+ # GitLab non-API endpoint
# e.g. https://gitlab.dkrz.de/k202009/libaec/uploads/631e85bcf877c2dcaca9b2e6d6526339/libaec-1.0.0.tar.gz
- (r'(.*gitlab[^/]+/[^/]+/[^/]+)',
+ (r'(.*gitlab[^/]+/(?!api/v4/projects)[^/]+/[^/]+)',
lambda m: m.group(1) + '/tags'),
# BitBucket
@@ -164,6 +150,7 @@ def strip_version_suffixes(path):
# Download type
'[Ii]nstall',
'all',
+ 'code',
'src(_0)?',
'[Ss]ources?',
'file',
@@ -201,7 +188,7 @@ def strip_version_suffixes(path):
'intel',
'amd64',
'x64',
- 'x86_64',
+ 'x86[_-]64',
'x86',
'i[36]86',
'ppc64(le)?',
@@ -226,7 +213,7 @@ def strip_version_suffixes(path):
'intel',
'amd64',
'x64',
- 'x86_64',
+ 'x86[_-]64',
'x86',
'i[36]86',
'ppc64(le)?',
@@ -529,6 +516,9 @@ def parse_version_offset(path):
# 9th Pass: Query strings
+ # e.g. https://gitlab.cosma.dur.ac.uk/api/v4/projects/swift%2Fswiftsim/repository/archive.tar.gz?sha=v0.3.0
+ (r'\?sha=[a-zA-Z+._-]*v?(\d[\da-zA-Z._-]*)$', suffix),
+
# e.g. http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0
(r'\?ref=[a-zA-Z+._-]*v?(\d[\da-zA-Z._-]*)$', suffix),
@@ -640,9 +630,13 @@ def parse_name_offset(path, v=None):
# e.g. https://github.com/nco/nco/archive/4.6.2.tar.gz
(r'github\.com/[^/]+/([^/]+)', path),
- # GitLab: gitlab.*/repo/name/
+ # GitLab API endpoint: gitlab.*/api/v4/projects/NAMESPACE%2Fname/
+ # e.g. https://gitlab.cosma.dur.ac.uk/api/v4/projects/swift%2Fswiftsim/repository/archive.tar.gz?sha=v0.3.0
+ (r'gitlab[^/]+/api/v4/projects/[^/]+%2F([^/]+)', path),
+
+ # GitLab non-API endpoint: gitlab.*/repo/name/
# e.g. http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0
- (r'gitlab[^/]+/[^/]+/([^/]+)', path),
+ (r'gitlab[^/]+/(?!api/v4/projects)[^/]+/([^/]+)', path),
# Bitbucket: bitbucket.org/repo/name/
# e.g. https://bitbucket.org/glotzer/hoomd-blue/get/v1.3.3.tar.bz2
diff --git a/lib/spack/spack/util/__init__.py b/lib/spack/spack/util/__init__.py
index 8922701e9f..4f442db458 100644
--- a/lib/spack/spack/util/__init__.py
+++ b/lib/spack/spack/util/__init__.py
@@ -1,24 +1,4 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
diff --git a/lib/spack/spack/util/compression.py b/lib/spack/spack/util/compression.py
index 3b747e08c6..93c91dc49c 100644
--- a/lib/spack/spack/util/compression.py
+++ b/lib/spack/spack/util/compression.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import re
import os
from itertools import product
from spack.util.executable import which
# Supported archive extensions.
-PRE_EXTS = ["tar"]
+PRE_EXTS = ["tar", "TAR"]
EXTS = ["gz", "bz2", "xz", "Z", "zip", "tgz"]
# Add PRE_EXTS and EXTS last so that .tar.gz is matched *before* .tar or .gz
diff --git a/lib/spack/spack/util/crypto.py b/lib/spack/spack/util/crypto.py
index 13262be551..34e62e218a 100644
--- a/lib/spack/spack/util/crypto.py
+++ b/lib/spack/spack/util/crypto.py
@@ -1,41 +1,90 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import sys
import hashlib
-"""Set of acceptable hashes that Spack will use."""
-hashes = dict((h, getattr(hashlib, h)) for h in [
- 'md5',
- 'sha1',
- 'sha224',
- 'sha256',
- 'sha384',
- 'sha512'])
+import llnl.util.tty as tty
+
+
+#: Set of hash algorithms that Spack can use, mapped to digest size in bytes
+hashes = {
+ 'md5': 16,
+ 'sha1': 20,
+ 'sha224': 28,
+ 'sha256': 32,
+ 'sha384': 48,
+ 'sha512': 64
+}
+
+
+#: size of hash digests in bytes, mapped to algoritm names
+_size_to_hash = dict((v, k) for k, v in hashes.items())
+
+
+#: List of deprecated hash functions. On some systems, these cannot be
+#: used without special options to hashlib.
+_deprecated_hash_algorithms = ['md5']
+
+
+#: cache of hash functions generated
+_hash_functions = {}
-"""Index for looking up hasher for a digest."""
-_size_to_hash = dict((h().digest_size, h) for h in hashes.values())
+
+class DeprecatedHash(object):
+ def __init__(self, hash_alg, alert_fn, disable_security_check):
+ self.hash_alg = hash_alg
+ self.alert_fn = alert_fn
+ self.disable_security_check = disable_security_check
+
+ def __call__(self, disable_alert=False):
+ if not disable_alert:
+ self.alert_fn("Deprecation warning: {0} checksums will not be"
+ " supported in future Spack releases."
+ .format(self.hash_alg))
+ if self.disable_security_check:
+ return hashlib.new(self.hash_alg, usedforsecurity=False)
+ else:
+ return hashlib.new(self.hash_alg)
+
+
+def hash_fun_for_algo(algo):
+ """Get a function that can perform the specified hash algorithm."""
+ hash_gen = _hash_functions.get(algo)
+ if hash_gen is None:
+ if algo in _deprecated_hash_algorithms:
+ try:
+ hash_gen = DeprecatedHash(
+ algo, tty.debug, disable_security_check=False)
+
+ # call once to get a ValueError if usedforsecurity is needed
+ hash_gen(disable_alert=True)
+ except ValueError:
+ # Some systems may support the 'usedforsecurity' option
+ # so try with that (but display a warning when it is used)
+ hash_gen = DeprecatedHash(
+ algo, tty.warn, disable_security_check=True)
+ else:
+ hash_gen = getattr(hashlib, algo)
+ _hash_functions[algo] = hash_gen
+
+ return hash_gen
+
+
+def hash_algo_for_digest(hexdigest):
+ """Gets name of the hash algorithm for a hex digest."""
+ bytes = len(hexdigest) / 2
+ if bytes not in _size_to_hash:
+ raise ValueError(
+ 'Spack knows no hash algorithm for this digest: %s' % hexdigest)
+ return _size_to_hash[bytes]
+
+
+def hash_fun_for_digest(hexdigest):
+ """Gets a hash function corresponding to a hex digest."""
+ return hash_fun_for_algo(hash_algo_for_digest(hexdigest))
def checksum(hashlib_algo, filename, **kwargs):
@@ -78,15 +127,8 @@ class Checker(object):
def __init__(self, hexdigest, **kwargs):
self.block_size = kwargs.get('block_size', 2**20)
self.hexdigest = hexdigest
- self.sum = None
-
- bytes = len(hexdigest) / 2
- if bytes not in _size_to_hash:
- raise ValueError(
- 'Spack knows no hash algorithm for this digest: %s'
- % hexdigest)
-
- self.hash_fun = _size_to_hash[bytes]
+ self.sum = None
+ self.hash_fun = hash_fun_for_digest(hexdigest)
@property
def hash_name(self):
diff --git a/lib/spack/spack/util/debug.py b/lib/spack/spack/util/debug.py
index 25f0600935..99c9770aa2 100644
--- a/lib/spack/spack/util/debug.py
+++ b/lib/spack/spack/util/debug.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Debug signal handler: prints a stack trace and enters interpreter.
``register_interrupt_handler()`` enables a ctrl-C handler that prints
diff --git a/lib/spack/spack/util/editor.py b/lib/spack/spack/util/editor.py
new file mode 100644
index 0000000000..730eb9fa3a
--- /dev/null
+++ b/lib/spack/spack/util/editor.py
@@ -0,0 +1,35 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Module for finding the user's preferred text editor.
+
+Defines one variable: ``editor``, which is a
+``spack.util.executable.Executable`` object that can be called to invoke
+the editor.
+
+If no ``editor`` is found, an ``EnvironmentError`` is raised when
+``editor`` is invoked.
+"""
+import os
+
+from spack.util.executable import Executable, which
+
+# Set up the user's editor
+# $EDITOR environment variable has the highest precedence
+editor = os.environ.get('EDITOR')
+
+# if editor is not set, use some sensible defaults
+if editor is not None:
+ editor = Executable(editor)
+else:
+ editor = which('vim', 'vi', 'emacs', 'nano')
+
+# If there is no editor, only raise an error if we actually try to use it.
+if not editor:
+ def editor_not_found(*args, **kwargs):
+ raise EnvironmentError(
+ 'No text editor found! Please set the EDITOR environment variable '
+ 'to your preferred text editor.')
+ editor = editor_not_found
diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py
index 51f7f586ec..fc6d416e7e 100644
--- a/lib/spack/spack/util/environment.py
+++ b/lib/spack/spack/util/environment.py
@@ -1,28 +1,23 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Utilities for setting and modifying environment variables."""
+import collections
+import contextlib
+import inspect
+import json
import os
+import re
+import sys
+import os.path
+import subprocess
+
+import llnl.util.tty as tty
+
+from llnl.util.lang import dedupe
+
system_paths = ['/', '/usr', '/usr/local']
suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64']
@@ -86,3 +81,635 @@ def dump_environment(path):
with open(path, 'w') as env_file:
for key, val in sorted(os.environ.items()):
env_file.write('export %s="%s"\n' % (key, val))
+
+
+@contextlib.contextmanager
+def set_env(**kwargs):
+ """Temporarily sets and restores environment variables.
+
+ Variables can be set as keyword arguments to this function.
+ """
+ saved = {}
+ for var, value in kwargs.items():
+ if var in os.environ:
+ saved[var] = os.environ[var]
+
+ if value is None:
+ if var in os.environ:
+ del os.environ[var]
+ else:
+ os.environ[var] = value
+
+ yield
+
+ for var, value in kwargs.items():
+ if var in saved:
+ os.environ[var] = saved[var]
+ else:
+ if var in os.environ:
+ del os.environ[var]
+
+
+class NameModifier(object):
+
+ def __init__(self, name, **kwargs):
+ self.name = name
+ self.args = {'name': name}
+ self.args.update(kwargs)
+
+ def update_args(self, **kwargs):
+ self.__dict__.update(kwargs)
+ self.args.update(kwargs)
+
+
+class NameValueModifier(object):
+
+ def __init__(self, name, value, **kwargs):
+ self.name = name
+ self.value = value
+ self.separator = kwargs.get('separator', ':')
+ self.args = {'name': name, 'value': value, 'separator': self.separator}
+ self.args.update(kwargs)
+
+ def update_args(self, **kwargs):
+ self.__dict__.update(kwargs)
+ self.args.update(kwargs)
+
+
+class SetEnv(NameValueModifier):
+
+ def execute(self):
+ os.environ[self.name] = str(self.value)
+
+
+class AppendFlagsEnv(NameValueModifier):
+
+ def execute(self):
+ if self.name in os.environ and os.environ[self.name]:
+ os.environ[self.name] += self.separator + str(self.value)
+ else:
+ os.environ[self.name] = str(self.value)
+
+
+class UnsetEnv(NameModifier):
+
+ def execute(self):
+ # Avoid throwing if the variable was not set
+ os.environ.pop(self.name, None)
+
+
+class SetPath(NameValueModifier):
+
+ def execute(self):
+ string_path = concatenate_paths(self.value, separator=self.separator)
+ os.environ[self.name] = string_path
+
+
+class AppendPath(NameValueModifier):
+
+ def execute(self):
+ environment_value = os.environ.get(self.name, '')
+ directories = environment_value.split(
+ self.separator) if environment_value else []
+ directories.append(os.path.normpath(self.value))
+ os.environ[self.name] = self.separator.join(directories)
+
+
+class PrependPath(NameValueModifier):
+
+ def execute(self):
+ environment_value = os.environ.get(self.name, '')
+ directories = environment_value.split(
+ self.separator) if environment_value else []
+ directories = [os.path.normpath(self.value)] + directories
+ os.environ[self.name] = self.separator.join(directories)
+
+
+class RemovePath(NameValueModifier):
+
+ def execute(self):
+ environment_value = os.environ.get(self.name, '')
+ directories = environment_value.split(
+ self.separator) if environment_value else []
+ directories = [os.path.normpath(x) for x in directories
+ if x != os.path.normpath(self.value)]
+ os.environ[self.name] = self.separator.join(directories)
+
+
+class EnvironmentModifications(object):
+ """Keeps track of requests to modify the current environment.
+
+ Each call to a method to modify the environment stores the extra
+ information on the caller in the request:
+
+ * 'filename' : filename of the module where the caller is defined
+ * 'lineno': line number where the request occurred
+ * 'context' : line of code that issued the request that failed
+ """
+
+ def __init__(self, other=None):
+ """Initializes a new instance, copying commands from 'other'
+ if it is not None.
+
+ Args:
+ other (EnvironmentModifications): list of environment modifications
+ to be extended (optional)
+ """
+ self.env_modifications = []
+ if other is not None:
+ self.extend(other)
+
+ def __iter__(self):
+ return iter(self.env_modifications)
+
+ def __len__(self):
+ return len(self.env_modifications)
+
+ def extend(self, other):
+ self._check_other(other)
+ self.env_modifications.extend(other.env_modifications)
+
+ @staticmethod
+ def _check_other(other):
+ if not isinstance(other, EnvironmentModifications):
+ raise TypeError(
+ 'other must be an instance of EnvironmentModifications')
+
+ def _get_outside_caller_attributes(self):
+ stack = inspect.stack()
+ try:
+ _, filename, lineno, _, context, index = stack[2]
+ context = context[index].strip()
+ except Exception:
+ filename = 'unknown file'
+ lineno = 'unknown line'
+ context = 'unknown context'
+ args = {'filename': filename, 'lineno': lineno, 'context': context}
+ return args
+
+ def set(self, name, value, **kwargs):
+ """Stores a request to set an environment variable.
+
+ Args:
+ name: name of the environment variable to be set
+ value: value of the environment variable
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ item = SetEnv(name, value, **kwargs)
+ self.env_modifications.append(item)
+
+ def append_flags(self, name, value, sep=' ', **kwargs):
+ """
+ Stores in the current object a request to append to an env variable
+
+ Args:
+ name: name of the environment variable to be appended to
+ value: value to append to the environment variable
+ Appends with spaces separating different additions to the variable
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ kwargs.update({'separator': sep})
+ item = AppendFlagsEnv(name, value, **kwargs)
+ self.env_modifications.append(item)
+
+ def unset(self, name, **kwargs):
+ """Stores a request to unset an environment variable.
+
+ Args:
+ name: name of the environment variable to be set
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ item = UnsetEnv(name, **kwargs)
+ self.env_modifications.append(item)
+
+ def set_path(self, name, elements, **kwargs):
+ """Stores a request to set a path generated from a list.
+
+ Args:
+ name: name o the environment variable to be set.
+ elements: elements of the path to set.
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ item = SetPath(name, elements, **kwargs)
+ self.env_modifications.append(item)
+
+ def append_path(self, name, path, **kwargs):
+ """Stores a request to append a path to a path list.
+
+ Args:
+ name: name of the path list in the environment
+ path: path to be appended
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ item = AppendPath(name, path, **kwargs)
+ self.env_modifications.append(item)
+
+ def prepend_path(self, name, path, **kwargs):
+ """Same as `append_path`, but the path is pre-pended.
+
+ Args:
+ name: name of the path list in the environment
+ path: path to be pre-pended
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ item = PrependPath(name, path, **kwargs)
+ self.env_modifications.append(item)
+
+ def remove_path(self, name, path, **kwargs):
+ """Stores a request to remove a path from a path list.
+
+ Args:
+ name: name of the path list in the environment
+ path: path to be removed
+ """
+ kwargs.update(self._get_outside_caller_attributes())
+ item = RemovePath(name, path, **kwargs)
+ self.env_modifications.append(item)
+
+ def group_by_name(self):
+ """Returns a dict of the modifications grouped by variable name.
+
+ Returns:
+ dict mapping the environment variable name to the modifications to
+ be done on it
+ """
+ modifications = collections.defaultdict(list)
+ for item in self:
+ modifications[item.name].append(item)
+ return modifications
+
+ def clear(self):
+ """
+ Clears the current list of modifications
+ """
+ self.env_modifications.clear()
+
+ def apply_modifications(self):
+ """Applies the modifications and clears the list."""
+ modifications = self.group_by_name()
+ # Apply modifications one variable at a time
+ for name, actions in sorted(modifications.items()):
+ for x in actions:
+ x.execute()
+
+ @staticmethod
+ def from_sourcing_file(filename, *args, **kwargs):
+ """Returns modifications that would be made by sourcing a file.
+
+ Parameters:
+ filename (str): The file to source
+ *args (list of str): Arguments to pass on the command line
+
+ Keyword Arguments:
+ shell (str): The shell to use (default: ``bash``)
+ shell_options (str): Options passed to the shell (default: ``-c``)
+ source_command (str): The command to run (default: ``source``)
+ suppress_output (str): Redirect used to suppress output of command
+ (default: ``&> /dev/null``)
+ concatenate_on_success (str): Operator used to execute a command
+ only when the previous command succeeds (default: ``&&``)
+ blacklist ([str or re]): Ignore any modifications of these
+ variables (default: [])
+ whitelist ([str or re]): Always respect modifications of these
+ variables (default: []). Has precedence over blacklist.
+ clean (bool): In addition to removing empty entries,
+ also remove duplicate entries (default: False).
+
+ Returns:
+ EnvironmentModifications: an object that, if executed, has
+ the same effect on the environment as sourcing the file
+ """
+ # Check if the file actually exists
+ if not os.path.isfile(filename):
+ msg = 'Trying to source non-existing file: {0}'.format(filename)
+ raise RuntimeError(msg)
+
+ # Kwargs parsing and default values
+ shell = kwargs.get('shell', '/bin/bash')
+ shell_options = kwargs.get('shell_options', '-c')
+ source_command = kwargs.get('source_command', 'source')
+ suppress_output = kwargs.get('suppress_output', '&> /dev/null')
+ concatenate_on_success = kwargs.get('concatenate_on_success', '&&')
+ blacklist = kwargs.get('blacklist', [])
+ whitelist = kwargs.get('whitelist', [])
+ clean = kwargs.get('clean', False)
+
+ source_file = [source_command, filename]
+ source_file.extend(args)
+ source_file = ' '.join(source_file)
+
+ dump_cmd = 'import os, json; print(json.dumps(dict(os.environ)))'
+ dump_environment = 'python -c "{0}"'.format(dump_cmd)
+
+ # Construct the command that will be executed
+ command = [
+ shell,
+ shell_options,
+ ' '.join([
+ source_file, suppress_output,
+ concatenate_on_success, dump_environment,
+ ]),
+ ]
+
+ # Try to source the file
+ proc = subprocess.Popen(
+ command, stdout=subprocess.PIPE, env=os.environ)
+ proc.wait()
+
+ if proc.returncode != 0:
+ msg = 'Sourcing file {0} returned a non-zero exit code'.format(
+ filename)
+ raise RuntimeError(msg)
+
+ output = ''.join([line.decode('utf-8') for line in proc.stdout])
+
+ # Construct dictionaries of the environment before and after
+ # sourcing the file, so that we can diff them.
+ env_before = dict(os.environ)
+ env_after = json.loads(output)
+
+ # If we're in python2, convert to str objects instead of unicode
+ # like json gives us. We can't put unicode in os.environ anyway.
+ if sys.version_info[0] < 3:
+ env_after = dict((k.encode('utf-8'), v.encode('utf-8'))
+ for k, v in env_after.items())
+
+ # Other variables unrelated to sourcing a file
+ blacklist.extend(['SHLVL', '_', 'PWD', 'OLDPWD', 'PS2'])
+
+ def set_intersection(fullset, *args):
+ # A set intersection using string literals and regexs
+ meta = '[' + re.escape('[$()*?[]^{|}') + ']'
+ subset = fullset & set(args) # As literal
+ for name in args:
+ if re.search(meta, name):
+ pattern = re.compile(name)
+ for k in fullset:
+ if re.match(pattern, k):
+ subset.add(k)
+ return subset
+
+ for d in env_after, env_before:
+ # Retain (whitelist) has priority over prune (blacklist)
+ prune = set_intersection(set(d), *blacklist)
+ prune -= set_intersection(prune, *whitelist)
+ for k in prune:
+ d.pop(k, None)
+
+ # Fill the EnvironmentModifications instance
+ env = EnvironmentModifications()
+
+ # New variables
+ new_variables = list(set(env_after) - set(env_before))
+ # Variables that have been unset
+ unset_variables = list(set(env_before) - set(env_after))
+ # Variables that have been modified
+ common_variables = set(env_before).intersection(set(env_after))
+
+ modified_variables = [x for x in common_variables
+ if env_before[x] != env_after[x]]
+
+ # Consistent output order - looks nicer, easier comparison...
+ new_variables.sort()
+ unset_variables.sort()
+ modified_variables.sort()
+
+ def return_separator_if_any(*args):
+ separators = ':', ';'
+ for separator in separators:
+ for arg in args:
+ if separator in arg:
+ return separator
+ return None
+
+ # Add variables to env.
+ # Assume that variables with 'PATH' in the name or that contain
+ # separators like ':' or ';' are more likely to be paths
+ for x in new_variables:
+ sep = return_separator_if_any(env_after[x])
+ if sep:
+ env.prepend_path(x, env_after[x], separator=sep)
+ elif 'PATH' in x:
+ env.prepend_path(x, env_after[x])
+ else:
+ # We just need to set the variable to the new value
+ env.set(x, env_after[x])
+
+ for x in unset_variables:
+ env.unset(x)
+
+ for x in modified_variables:
+ before = env_before[x]
+ after = env_after[x]
+ sep = return_separator_if_any(before, after)
+ if sep:
+ before_list = before.split(sep)
+ after_list = after.split(sep)
+
+ # Filter out empty strings
+ before_list = list(filter(None, before_list))
+ after_list = list(filter(None, after_list))
+
+ # Remove duplicate entries (worse matching, bloats env)
+ if clean:
+ before_list = list(dedupe(before_list))
+ after_list = list(dedupe(after_list))
+ # The reassembled cleaned entries
+ before = sep.join(before_list)
+ after = sep.join(after_list)
+
+ # Paths that have been removed
+ remove_list = [
+ ii for ii in before_list if ii not in after_list]
+ # Check that nothing has been added in the middle of
+ # before_list
+ remaining_list = [
+ ii for ii in before_list if ii in after_list]
+ try:
+ start = after_list.index(remaining_list[0])
+ end = after_list.index(remaining_list[-1])
+ search = sep.join(after_list[start:end + 1])
+ except IndexError:
+ env.prepend_path(x, after)
+
+ if search not in before:
+ # We just need to set the variable to the new value
+ env.prepend_path(x, after)
+ else:
+ try:
+ prepend_list = after_list[:start]
+ prepend_list.reverse() # Preserve order after prepend
+ except KeyError:
+ prepend_list = []
+ try:
+ append_list = after_list[end + 1:]
+ except KeyError:
+ append_list = []
+
+ for item in remove_list:
+ env.remove_path(x, item)
+ for item in append_list:
+ env.append_path(x, item)
+ for item in prepend_list:
+ env.prepend_path(x, item)
+ else:
+ # We just need to set the variable to the new value
+ env.set(x, after)
+
+ return env
+
+
+def concatenate_paths(paths, separator=':'):
+ """Concatenates an iterable of paths into a string of paths separated by
+ separator, defaulting to colon.
+
+ Args:
+ paths: iterable of paths
+ separator: the separator to use, default ':'
+
+ Returns:
+ string
+ """
+ return separator.join(str(item) for item in paths)
+
+
+def set_or_unset_not_first(variable, changes, errstream):
+ """Check if we are going to set or unset something after other
+ modifications have already been requested.
+ """
+ indexes = [ii for ii, item in enumerate(changes)
+ if ii != 0 and
+ not item.args.get('force', False) and
+ type(item) in [SetEnv, UnsetEnv]]
+ if indexes:
+ good = '\t \t{context} at {filename}:{lineno}'
+ nogood = '\t--->\t{context} at {filename}:{lineno}'
+ message = "Suspicious requests to set or unset '{var}' found"
+ errstream(message.format(var=variable))
+ for ii, item in enumerate(changes):
+ print_format = nogood if ii in indexes else good
+ errstream(print_format.format(**item.args))
+
+
+def validate(env, errstream):
+ """Validates the environment modifications to check for the presence of
+ suspicious patterns. Prompts a warning for everything that was found.
+
+ Current checks:
+ - set or unset variables after other changes on the same variable
+
+ Args:
+ env: list of environment modifications
+ """
+ modifications = env.group_by_name()
+ for variable, list_of_changes in sorted(modifications.items()):
+ set_or_unset_not_first(variable, list_of_changes, errstream)
+
+
+def filter_environment_blacklist(env, variables):
+ """Generator that filters out any change to environment variables present in
+ the input list.
+
+ Args:
+ env: list of environment modifications
+ variables: list of variable names to be filtered
+
+ Returns:
+ items in env if they are not in variables
+ """
+ for item in env:
+ if item.name not in variables:
+ yield item
+
+
+def inspect_path(root, inspections, exclude=None):
+ """Inspects ``root`` to search for the subdirectories in ``inspections``.
+ Adds every path found to a list of prepend-path commands and returns it.
+
+ Args:
+ root (str): absolute path where to search for subdirectories
+
+ inspections (dict): maps relative paths to a list of environment
+ variables that will be modified if the path exists. The
+ modifications are not performed immediately, but stored in a
+ command object that is returned to client
+
+ exclude (callable): optional callable. If present it must accept an
+ absolute path and return True if it should be excluded from the
+ inspection
+
+ Examples:
+
+ The following lines execute an inspection in ``/usr`` to search for
+ ``/usr/include`` and ``/usr/lib64``. If found we want to prepend
+ ``/usr/include`` to ``CPATH`` and ``/usr/lib64`` to ``MY_LIB64_PATH``.
+
+ .. code-block:: python
+
+ # Set up the dictionary containing the inspection
+ inspections = {
+ 'include': ['CPATH'],
+ 'lib64': ['MY_LIB64_PATH']
+ }
+
+ # Get back the list of command needed to modify the environment
+ env = inspect_path('/usr', inspections)
+
+ # Eventually execute the commands
+ env.apply_modifications()
+
+ Returns:
+ instance of EnvironmentModifications containing the requested
+ modifications
+ """
+ if exclude is None:
+ exclude = lambda x: False
+
+ env = EnvironmentModifications()
+ # Inspect the prefix to check for the existence of common directories
+ for relative_path, variables in inspections.items():
+ expected = os.path.join(root, relative_path)
+
+ if os.path.isdir(expected) and not exclude(expected):
+ for variable in variables:
+ env.prepend_path(variable, expected)
+
+ return env
+
+
+@contextlib.contextmanager
+def preserve_environment(*variables):
+ """Ensures that the value of the environment variables passed as
+ arguments is the same before entering to the context manager and after
+ exiting it.
+
+ Variables that are unset before entering the context manager will be
+ explicitly unset on exit.
+
+ Args:
+ variables (list of str): list of environment variables to be preserved
+ """
+ cache = {}
+ for var in variables:
+ # The environment variable to be preserved might not be there.
+ # In that case store None as a placeholder.
+ cache[var] = os.environ.get(var, None)
+
+ yield
+
+ for var in variables:
+ value = cache[var]
+ msg = '[PRESERVE_ENVIRONMENT]'
+ if value is not None:
+ # Print a debug statement if the value changed
+ if var not in os.environ:
+ msg += ' {0} was unset, will be reset to "{1}"'
+ tty.debug(msg.format(var, value))
+ elif os.environ[var] != value:
+ msg += ' {0} was set to "{1}", will be reset to "{2}"'
+ tty.debug(msg.format(var, os.environ[var], value))
+ os.environ[var] = value
+ elif var in os.environ:
+ msg += ' {0} was set to "{1}", will be unset'
+ tty.debug(msg.format(var, os.environ[var]))
+ del os.environ[var]
diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py
index af516dc607..e1d7b49016 100644
--- a/lib/spack/spack/util/executable.py
+++ b/lib/spack/spack/util/executable.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import re
import subprocess
@@ -29,7 +10,7 @@ from six import string_types
import sys
import llnl.util.tty as tty
-import spack
+
import spack.error
__all__ = ['Executable', 'which', 'ProcessError']
@@ -93,7 +74,11 @@ class Executable(object):
*args (str): Command-line arguments to the executable to run
Keyword Arguments:
+ _dump_env (dict): Dict to be set to the environment actually
+ used (envisaged for testing purposes only)
env (dict): The environment to run the executable with
+ extra_env (dict): Extra items to add to the environment
+ (neither requires nor precludes env)
fail_on_error (bool): Raise an exception if the subprocess returns
an error. Default is True. The return code is available as
``exe.returncode``
@@ -115,6 +100,7 @@ class Executable(object):
for ``input``
By default, the subprocess inherits the parent's file descriptors.
+
"""
# Environment
env_arg = kwargs.get('env', None)
@@ -124,6 +110,10 @@ class Executable(object):
else:
env = self.default_env.copy()
env.update(env_arg)
+ env.update(kwargs.get('extra_env', {}))
+ if '_dump_env' in kwargs:
+ kwargs['_dump_env'].clear()
+ kwargs['_dump_env'].update(env)
fail_on_error = kwargs.pop('fail_on_error', True)
ignore_errors = kwargs.pop('ignore_errors', ())
@@ -177,18 +167,28 @@ class Executable(object):
env=env)
out, err = proc.communicate()
- rc = self.returncode = proc.returncode
- if fail_on_error and rc != 0 and (rc not in ignore_errors):
- raise ProcessError('Command exited with status %d:' %
- proc.returncode, cmd_line)
-
+ result = None
if output is str or error is str:
result = ''
if output is str:
result += to_str(out)
if error is str:
result += to_str(err)
- return result
+
+ rc = self.returncode = proc.returncode
+ if fail_on_error and rc != 0 and (rc not in ignore_errors):
+ long_msg = cmd_line
+ if result:
+ # If the output is not captured in the result, it will have
+ # been stored either in the specified files (e.g. if
+ # 'output' specifies a file) or written to the parent's
+ # stdout/stderr (e.g. if 'output' is not specified)
+ long_msg += '\n' + result
+
+ raise ProcessError('Command exited with status %d:' %
+ proc.returncode, long_msg)
+
+ return result
except OSError as e:
raise ProcessError(
diff --git a/lib/spack/spack/file_cache.py b/lib/spack/spack/util/file_cache.py
index 688f32a4ad..6e6ef3037f 100644
--- a/lib/spack/spack/file_cache.py
+++ b/lib/spack/spack/util/file_cache.py
@@ -1,34 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import os
import shutil
-from llnl.util.filesystem import mkdirp, join_path
-from llnl.util.lock import Lock, ReadTransaction, WriteTransaction
+from llnl.util.filesystem import mkdirp
from spack.error import SpackError
+from spack.util.lock import Lock, ReadTransaction, WriteTransaction
class FileCache(object):
@@ -42,22 +23,29 @@ class FileCache(object):
"""
- def __init__(self, root):
+ def __init__(self, root, timeout=120):
"""Create a file cache object.
This will create the cache directory if it does not exist yet.
+ Args:
+ root: specifies the root directory where the cache stores files
+
+ timeout: when there is contention among multiple Spack processes
+ for cache files, this specifies how long Spack should wait
+ before assuming that there is a deadlock.
"""
self.root = root.rstrip(os.path.sep)
if not os.path.exists(self.root):
mkdirp(self.root)
self._locks = {}
+ self.lock_timeout = timeout
def destroy(self):
"""Remove all files under the cache root."""
for f in os.listdir(self.root):
- path = join_path(self.root, f)
+ path = os.path.join(self.root, f)
if os.path.isdir(path):
shutil.rmtree(path, True)
else:
@@ -65,19 +53,20 @@ class FileCache(object):
def cache_path(self, key):
"""Path to the file in the cache for a particular key."""
- return join_path(self.root, key)
+ return os.path.join(self.root, key)
def _lock_path(self, key):
"""Path to the file in the cache for a particular key."""
keyfile = os.path.basename(key)
keydir = os.path.dirname(key)
- return join_path(self.root, keydir, '.' + keyfile + '.lock')
+ return os.path.join(self.root, keydir, '.' + keyfile + '.lock')
def _get_lock(self, key):
"""Create a lock for a key, if necessary, and return a lock object."""
if key not in self._locks:
- self._locks[key] = Lock(self._lock_path(key))
+ self._locks[key] = Lock(self._lock_path(key),
+ default_timeout=self.lock_timeout)
return self._locks[key]
def init_entry(self, key):
@@ -130,7 +119,7 @@ class FileCache(object):
"""
class WriteContextManager(object):
- def __enter__(cm):
+ def __enter__(cm): # noqa
cm.orig_filename = self.cache_path(key)
cm.orig_file = None
if os.path.exists(cm.orig_filename):
@@ -141,7 +130,7 @@ class FileCache(object):
return cm.orig_file, cm.tmp_file
- def __exit__(cm, type, value, traceback):
+ def __exit__(cm, type, value, traceback): # noqa
if cm.orig_file:
cm.orig_file.close()
cm.tmp_file.close()
diff --git a/lib/spack/spack/util/gpg.py b/lib/spack/spack/util/gpg.py
index 4af849fb3c..77979047b0 100644
--- a/lib/spack/spack/util/gpg.py
+++ b/lib/spack/spack/util/gpg.py
@@ -1,35 +1,15 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
-import spack
+import spack.paths
from spack.util.executable import Executable
-GNUPGHOME = spack.gpg_path
+GNUPGHOME = spack.paths.gpg_path
class Gpg(object):
diff --git a/lib/spack/spack/util/imp/__init__.py b/lib/spack/spack/util/imp/__init__.py
new file mode 100644
index 0000000000..4d6ef756ca
--- /dev/null
+++ b/lib/spack/spack/util/imp/__init__.py
@@ -0,0 +1,22 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Consolidated module for all imports done by Spack.
+
+Many parts of Spack have to import Python code. This utility package
+wraps Spack's interface with Python's import system.
+
+We do this because Python's import system is confusing and changes from
+Python version to Python version, and we should be able to adapt our
+approach to the underlying implementation.
+
+Currently, this uses ``importlib.machinery`` where available and ``imp``
+when ``importlib`` is not completely usable.
+"""
+
+try:
+ from .importlib_importer import load_source # noqa
+except ImportError:
+ from .imp_importer import load_source # noqa
diff --git a/lib/spack/spack/util/imp/imp_importer.py b/lib/spack/spack/util/imp/imp_importer.py
new file mode 100644
index 0000000000..2949ef3b3e
--- /dev/null
+++ b/lib/spack/spack/util/imp/imp_importer.py
@@ -0,0 +1,67 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Implementation of Spack imports that uses imp underneath.
+
+``imp`` is deprecated in newer versions of Python, but is the only option
+in Python 2.6.
+"""
+import imp
+import tempfile
+from contextlib import contextmanager
+
+
+@contextmanager
+def import_lock():
+ imp.acquire_lock()
+ yield
+ imp.release_lock()
+
+
+def load_source(full_name, path, prepend=None):
+ """Import a Python module from source.
+
+ Load the source file and add it to ``sys.modules``.
+
+ Args:
+ full_name (str): full name of the module to be loaded
+ path (str): path to the file that should be loaded
+ prepend (str, optional): some optional code to prepend to the
+ loaded module; e.g., can be used to inject import statements
+
+ Returns:
+ (ModuleType): the loaded module
+ """
+ with import_lock():
+ if prepend is None:
+ return imp.load_source(full_name, path)
+ else:
+ with prepend_open(path, text=prepend) as f:
+ return imp.load_source(full_name, path, f)
+
+
+@contextmanager
+def prepend_open(f, *args, **kwargs):
+ """Open a file for reading, but prepend with some text prepended
+
+ Arguments are same as for ``open()``, with one keyword argument,
+ ``text``, specifying the text to prepend.
+
+ We have to write and read a tempfile for the ``imp``-based importer,
+ as the ``file`` argument to ``imp.load_source()`` requires a
+ low-level file handle.
+
+ See the ``importlib``-based importer for a faster way to do this in
+ later versions of python.
+ """
+ text = kwargs.get('text', None)
+
+ with open(f, *args) as f:
+ with tempfile.NamedTemporaryFile(mode='w+') as tf:
+ if text:
+ tf.write(text + '\n')
+ tf.write(f.read())
+ tf.seek(0)
+ yield tf.file
diff --git a/lib/spack/spack/util/imp/importlib_importer.py b/lib/spack/spack/util/imp/importlib_importer.py
new file mode 100644
index 0000000000..a36d13e67b
--- /dev/null
+++ b/lib/spack/spack/util/imp/importlib_importer.py
@@ -0,0 +1,42 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Implementation of Spack imports that uses importlib underneath.
+
+``importlib`` is only fully implemented in Python 3.
+"""
+from importlib.machinery import SourceFileLoader
+
+
+class PrependFileLoader(SourceFileLoader):
+ def __init__(self, full_name, path, prepend=None):
+ super(PrependFileLoader, self).__init__(full_name, path)
+ self.prepend = prepend
+
+ def get_data(self, path):
+ data = super(PrependFileLoader, self).get_data(path)
+ if path != self.path or self.prepend is None:
+ return data
+ else:
+ return self.prepend.encode() + b"\n" + data
+
+
+def load_source(full_name, path, prepend=None):
+ """Import a Python module from source.
+
+ Load the source file and add it to ``sys.modules``.
+
+ Args:
+ full_name (str): full name of the module to be loaded
+ path (str): path to the file that should be loaded
+ prepend (str, optional): some optional code to prepend to the
+ loaded module; e.g., can be used to inject import statements
+
+ Returns:
+ (ModuleType): the loaded module
+ """
+ # use our custom loader
+ loader = PrependFileLoader(full_name, path, prepend)
+ return loader.load_module()
diff --git a/lib/spack/spack/util/lock.py b/lib/spack/spack/util/lock.py
new file mode 100644
index 0000000000..05efe14d8d
--- /dev/null
+++ b/lib/spack/spack/util/lock.py
@@ -0,0 +1,74 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Wrapper for ``llnl.util.lock`` allows locking to be enabled/disabled."""
+import os
+import stat
+
+import llnl.util.lock
+from llnl.util.lock import * # noqa
+
+import spack.config
+import spack.error
+import spack.paths
+
+
+class Lock(llnl.util.lock.Lock):
+ """Lock that can be disabled.
+
+ This overrides the ``_lock()`` and ``_unlock()`` methods from
+ ``llnl.util.lock`` so that all the lock API calls will succeed, but
+ the actual locking mechanism can be disabled via ``_enable_locks``.
+ """
+ def __init__(self, *args, **kwargs):
+ super(Lock, self).__init__(*args, **kwargs)
+ self._enable = spack.config.get('config:locks', True)
+
+ def _lock(self, op, timeout=0):
+ if self._enable:
+ return super(Lock, self)._lock(op, timeout)
+ else:
+ return 0, 0
+
+ def _unlock(self):
+ """Unlock call that always succeeds."""
+ if self._enable:
+ super(Lock, self)._unlock()
+
+ def _debug(self, *args):
+ if self._enable:
+ super(Lock, self)._debug(*args)
+
+
+def check_lock_safety(path):
+ """Do some extra checks to ensure disabling locks is safe.
+
+ This will raise an error if ``path`` can is group- or world-writable
+ AND the current user can write to the directory (i.e., if this user
+ AND others could write to the path).
+
+ This is intended to run on the Spack prefix, but can be run on any
+ path for testing.
+ """
+ if os.access(path, os.W_OK):
+ stat_result = os.stat(path)
+ uid, gid = stat_result.st_uid, stat_result.st_gid
+ mode = stat_result[stat.ST_MODE]
+
+ writable = None
+ if (mode & stat.S_IWGRP) and (uid != gid):
+ # spack is group-writeable and the group is not the owner
+ writable = 'group'
+ elif (mode & stat.S_IWOTH):
+ # spack is world-writeable
+ writable = 'world'
+
+ if writable:
+ msg = "Refusing to disable locks: spack is {0}-writable.".format(
+ writable)
+ long_msg = (
+ "Running a shared spack without locks is unsafe. You must "
+ "restrict permissions on {0} or enable locks.").format(path)
+ raise spack.error.SpackError(msg, long_msg)
diff --git a/lib/spack/spack/util/log_parse.py b/lib/spack/spack/util/log_parse.py
index 1d5ad465fa..36b3312ec8 100644
--- a/lib/spack/spack/util/log_parse.py
+++ b/lib/spack/spack/util/log_parse.py
@@ -1,41 +1,29 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
+import sys
from six import StringIO
-from ctest_log_parser import CTestLogParser
-from llnl.util.tty.color import colorize
+from ctest_log_parser import CTestLogParser, BuildError, BuildWarning
+
+import llnl.util.tty as tty
+from llnl.util.tty.color import cescape, colorize
+__all__ = ['parse_log_events', 'make_log_context']
-def parse_log_events(stream, context=6):
+
+def parse_log_events(stream, context=6, jobs=None, profile=False):
"""Extract interesting events from a log file as a list of LogEvent.
Args:
stream (str or fileobject): build log name or file object
context (int): lines of context to extract around each log event
+ jobs (int): number of jobs to parse with; default ncpus
+ profile (bool): print out profile information for parsing
Returns:
(tuple): two lists containig ``BuildError`` and
@@ -46,47 +34,87 @@ def parse_log_events(stream, context=6):
that all the regex compilation is only done once.
"""
if parse_log_events.ctest_parser is None:
- parse_log_events.ctest_parser = CTestLogParser()
+ parse_log_events.ctest_parser = CTestLogParser(profile=profile)
- return parse_log_events.ctest_parser.parse(stream, context)
+ result = parse_log_events.ctest_parser.parse(stream, context, jobs)
+ if profile:
+ parse_log_events.ctest_parser.print_timings()
+ return result
#: lazily constructed CTest log parser
parse_log_events.ctest_parser = None
-def make_log_context(log_events):
+def _wrap(text, width):
+ """Break text into lines of specific width."""
+ lines = []
+ pos = 0
+ while pos < len(text):
+ lines.append(text[pos:pos + width])
+ pos += width
+ return lines
+
+
+def make_log_context(log_events, width=None):
"""Get error context from a log file.
Args:
log_events (list of LogEvent): list of events created by
``ctest_log_parser.parse()``
-
+ width (int or None): wrap width; ``0`` for no limit; ``None`` to
+ auto-size for terminal
Returns:
str: context from the build log with errors highlighted
Parses the log file for lines containing errors, and prints them out
with line numbers and context. Errors are highlighted with '>>' and
with red highlighting (if color is enabled).
+
+ Events are sorted by line number before they are displayed.
"""
error_lines = set(e.line_no for e in log_events)
+ log_events = sorted(log_events, key=lambda e: e.line_no)
+
+ num_width = len(str(max(error_lines))) + 4
+ line_fmt = '%%-%dd%%s' % num_width
+ indent = ' ' * (5 + num_width)
+
+ if width is None:
+ _, width = tty.terminal_size()
+ if width <= 0:
+ width = sys.maxsize
+ wrap_width = width - num_width - 6
out = StringIO()
next_line = 1
for event in log_events:
start = event.start
- if start > next_line:
- out.write(' [ ... ]\n')
+ if isinstance(event, BuildError):
+ color = 'R'
+ elif isinstance(event, BuildWarning):
+ color = 'Y'
+ else:
+ color = 'W'
+
+ if next_line != 1 and start > next_line:
+ out.write('\n ...\n\n')
if start < next_line:
start = next_line
for i in range(start, event.end):
+ # wrap to width
+ lines = _wrap(event[i], wrap_width)
+ lines[1:] = [indent + l for l in lines[1:]]
+ wrapped_line = line_fmt % (i, '\n'.join(lines))
+
if i in error_lines:
- out.write(colorize(' @R{>> %-6d%s}\n' % (i, event[i])))
+ out.write(colorize(
+ ' @%s{>> %s}\n' % (color, cescape(wrapped_line))))
else:
- out.write(' %-6d%s\n' % (i, event[i]))
+ out.write(' %s\n' % wrapped_line)
next_line = event.end
diff --git a/lib/spack/spack/util/module_cmd.py b/lib/spack/spack/util/module_cmd.py
index 00fc4ddc65..d195e0db9c 100644
--- a/lib/spack/spack/util/module_cmd.py
+++ b/lib/spack/spack/util/module_cmd.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This module contains routines related to the module command for accessing and
parsing environment modules.
@@ -115,6 +96,14 @@ def get_module_cmd_from_bash(bashopts=''):
return module_cmd
+def unload_module(mod):
+ """Takes a module name and unloads the module from the environment. It does
+ not check whether conflicts arise from the unloaded module"""
+ modulecmd = get_module_cmd()
+ exec(compile(modulecmd('unload', mod, output=str, error=str), '<string>',
+ 'exec'))
+
+
def load_module(mod):
"""Takes a module name and removes modules until it is possible to
load that module. It then loads the provided module. Depends on the
@@ -130,14 +119,17 @@ def load_module(mod):
text = modulecmd('show', mod, output=str, error=str).split()
for i, word in enumerate(text):
if word == 'conflict':
- exec(compile(modulecmd('unload', text[i + 1], output=str,
- error=str), '<string>', 'exec'))
+ unload_module(text[i + 1])
+
# Load the module now that there are no conflicts
- load = modulecmd('load', mod, output=str, error=str)
+ # Some module systems use stdout and some use stderr
+ load = modulecmd('load', mod, output=str, error='/dev/null')
+ if not load:
+ load = modulecmd('load', mod, error=str)
exec(compile(load, '<string>', 'exec'))
-def get_argument_from_module_line(line):
+def get_path_arg_from_module_line(line):
if '(' in line and ')' in line:
# Determine which lua quote symbol is being used for the argument
comma_index = line.index(',')
@@ -149,9 +141,10 @@ def get_argument_from_module_line(line):
# Change error text to describe what is going on.
raise ValueError("No lua quote symbol found in lmod module line.")
words_and_symbols = line.split(lua_quote)
- return words_and_symbols[-2]
+ path_arg = words_and_symbols[-2]
else:
- return line.split()[2]
+ path_arg = line.split()[2]
+ return path_arg
def get_path_from_module(mod):
@@ -164,16 +157,35 @@ def get_path_from_module(mod):
# Read the module
text = modulecmd('show', mod, output=str, error=str).split('\n')
+ p = get_path_from_module_contents(text, mod)
+ if p and not os.path.exists(p):
+ tty.warn("Extracted path from module does not exist:"
+ "\n\tExtracted path: " + p)
+ return p
+
+
+def get_path_from_module_contents(text, module_name):
+ tty.debug("Module name: " + module_name)
+ pkg_var_prefix = module_name.replace('-', '_').upper()
+ components = pkg_var_prefix.split('/')
+ # For modules with multiple components like foo/1.0.1, retrieve the package
+ # name "foo" from the module name
+ if len(components) > 1:
+ pkg_var_prefix = components[-2]
+ tty.debug("Package directory variable prefix: " + pkg_var_prefix)
+
# If it sets the LD_LIBRARY_PATH or CRAY_LD_LIBRARY_PATH, use that
for line in text:
- if line.find('LD_LIBRARY_PATH') >= 0:
- path = get_argument_from_module_line(line)
+ pattern = r'\W(CRAY_)?LD_LIBRARY_PATH'
+ if re.search(pattern, line):
+ path = get_path_arg_from_module_line(line)
return path[:path.find('/lib')]
# If it lists its package directory, return that
for line in text:
- if line.find(mod.upper() + '_DIR') >= 0:
- return get_argument_from_module_line(line)
+ pattern = r'\W{0}_DIR'.format(pkg_var_prefix)
+ if re.search(pattern, line):
+ return get_path_arg_from_module_line(line)
# If it lists a -rpath instruction, use that
for line in text:
@@ -183,14 +195,15 @@ def get_path_from_module(mod):
# If it lists a -L instruction, use that
for line in text:
- L = line.find('-L/')
- if L >= 0:
- return line[L + 2:line.find('/lib')]
+ lib_paths = line.find('-L/')
+ if lib_paths >= 0:
+ return line[lib_paths + 2:line.find('/lib')]
# If it sets the PATH, use it
for line in text:
- if line.find('PATH') >= 0:
- path = get_argument_from_module_line(line)
+ pattern = r'\WPATH'
+ if re.search(pattern, line):
+ path = get_path_arg_from_module_line(line)
return path[:path.find('/bin')]
# Unable to find module path
diff --git a/lib/spack/spack/util/naming.py b/lib/spack/spack/util/naming.py
index 78e368f06c..949189a3ca 100644
--- a/lib/spack/spack/util/naming.py
+++ b/lib/spack/spack/util/naming.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
# Need this because of spack.util.string
from __future__ import absolute_import
import string
@@ -29,7 +10,7 @@ import itertools
import re
from six import StringIO
-import spack
+import spack.error
__all__ = [
'mod_to_class',
diff --git a/lib/spack/spack/util/package_hash.py b/lib/spack/spack/util/package_hash.py
new file mode 100644
index 0000000000..c7354e97cf
--- /dev/null
+++ b/lib/spack/spack/util/package_hash.py
@@ -0,0 +1,133 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import ast
+import hashlib
+
+import spack.repo
+import spack.package
+import spack.directives
+import spack.error
+import spack.spec
+import spack.util.naming
+
+
+class RemoveDocstrings(ast.NodeTransformer):
+ """Transformer that removes docstrings from a Python AST."""
+ def remove_docstring(self, node):
+ if node.body:
+ if isinstance(node.body[0], ast.Expr) and \
+ isinstance(node.body[0].value, ast.Str):
+ node.body.pop(0)
+
+ self.generic_visit(node)
+ return node
+
+ def visit_FunctionDef(self, node): # noqa
+ return self.remove_docstring(node)
+
+ def visit_ClassDef(self, node): # noqa
+ return self.remove_docstring(node)
+
+ def visit_Module(self, node): # noqa
+ return self.remove_docstring(node)
+
+
+class RemoveDirectives(ast.NodeTransformer):
+ """Remove Spack directives from a package AST."""
+ def __init__(self, spec):
+ self.spec = spec
+
+ def is_directive(self, node):
+ return (isinstance(node, ast.Expr) and
+ node.value and isinstance(node.value, ast.Call) and
+ node.value.func.id in spack.directives.__all__)
+
+ def is_spack_attr(self, node):
+ return (isinstance(node, ast.Assign) and
+ node.targets and isinstance(node.targets[0], ast.Name) and
+ node.targets[0].id in spack.package.Package.metadata_attrs)
+
+ def visit_ClassDef(self, node): # noqa
+ if node.name == spack.util.naming.mod_to_class(self.spec.name):
+ node.body = [
+ c for c in node.body
+ if (not self.is_directive(c) and not self.is_spack_attr(c))]
+ return node
+
+
+class TagMultiMethods(ast.NodeVisitor):
+ """Tag @when-decorated methods in a spec."""
+ def __init__(self, spec):
+ self.spec = spec
+ self.methods = {}
+
+ def visit_FunctionDef(self, node): # noqa
+ nodes = self.methods.setdefault(node.name, [])
+ if node.decorator_list:
+ dec = node.decorator_list[0]
+ if isinstance(dec, ast.Call) and dec.func.id == 'when':
+ cond = dec.args[0].s
+ nodes.append((node, self.spec.satisfies(cond, strict=True)))
+ else:
+ nodes.append((node, None))
+
+
+class ResolveMultiMethods(ast.NodeTransformer):
+ """Remove methods which do not exist if their @when is not satisfied."""
+ def __init__(self, methods):
+ self.methods = methods
+
+ def resolve(self, node):
+ if node.name not in self.methods:
+ raise PackageHashError(
+ "Future traversal visited new node: %s" % node.name)
+
+ result = None
+ for n, cond in self.methods[node.name]:
+ if cond:
+ return n
+ if cond is None:
+ result = n
+ return result
+
+ def visit_FunctionDef(self, node): # noqa
+ if self.resolve(node) is node:
+ node.decorator_list = []
+ return node
+ return None
+
+
+def package_content(spec):
+ return ast.dump(package_ast(spec))
+
+
+def package_hash(spec, content=None):
+ if content is None:
+ content = package_content(spec)
+ return hashlib.sha256(content.encode('utf-8')).digest().lower()
+
+
+def package_ast(spec):
+ spec = spack.spec.Spec(spec)
+
+ filename = spack.repo.path.filename_for_package_name(spec.name)
+ with open(filename) as f:
+ text = f.read()
+ root = ast.parse(text)
+
+ root = RemoveDocstrings().visit(root)
+
+ RemoveDirectives(spec).visit(root)
+
+ fmm = TagMultiMethods(spec)
+ fmm.visit(root)
+
+ root = ResolveMultiMethods(fmm.methods).visit(root)
+ return root
+
+
+class PackageHashError(spack.error.SpackError):
+ """Raised for all errors encountered during package hashing."""
diff --git a/lib/spack/spack/util/path.py b/lib/spack/spack/util/path.py
index 9ce6c9306c..dc866984d6 100644
--- a/lib/spack/spack/util/path.py
+++ b/lib/spack/spack/util/path.py
@@ -1,42 +1,27 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Utilities for managing paths in Spack.
+
+TODO: this is really part of spack.config. Consolidate it.
"""
import os
import re
-import spack
import getpass
import tempfile
+import spack.paths
+
+
__all__ = [
'substitute_config_variables',
'canonicalize_path']
# Substitutions to perform
replacements = {
- 'spack': spack.prefix,
+ 'spack': spack.paths.prefix,
'user': getpass.getuser(),
'tempdir': tempfile.gettempdir(),
}
diff --git a/lib/spack/spack/util/pattern.py b/lib/spack/spack/util/pattern.py
index 3a85336bdc..32ee342135 100644
--- a/lib/spack/spack/util/pattern.py
+++ b/lib/spack/spack/util/pattern.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
import inspect
import collections
import functools
diff --git a/lib/spack/spack/util/prefix.py b/lib/spack/spack/util/prefix.py
index d96b1c2449..60f8408b5a 100644
--- a/lib/spack/spack/util/prefix.py
+++ b/lib/spack/spack/util/prefix.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This file contains utilities for managing the installation prefix of a package.
"""
@@ -44,6 +25,8 @@ class Prefix(str):
/usr/share/man
>>> prefix.foo.bar.baz
/usr/foo/bar/baz
+ >>> prefix.join('dashed-directory').bin64
+ /usr/dashed-directory/bin64
Prefix objects behave identically to strings. In fact, they
subclass ``str``. So operators like ``+`` are legal::
@@ -55,3 +38,14 @@ class Prefix(str):
"""
def __getattr__(self, attr):
return Prefix(os.path.join(self, attr))
+
+ def join(self, string):
+ """Concatenates a string to a prefix.
+
+ Parameters:
+ string (str): the string to append to the prefix
+
+ Returns:
+ Prefix: the newly created installation prefix
+ """
+ return Prefix(os.path.join(self, string))
diff --git a/lib/spack/spack/util/spack_json.py b/lib/spack/spack/util/spack_json.py
index fbc514c14b..a56b6283d3 100644
--- a/lib/spack/spack/util/spack_json.py
+++ b/lib/spack/spack/util/spack_json.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Simple wrapper around JSON to guarantee consistent use of load/dump. """
import sys
import json
@@ -59,7 +40,7 @@ def dump(data, stream=None):
def _strify(data, ignore_dicts=False):
# if this is a unicode string in python 2, return its string representation
if sys.version_info[0] < 3:
- if isinstance(data, unicode):
+ if isinstance(data, string_types):
return data.encode('utf-8')
# if this is a list of values, return list of byteified values
diff --git a/lib/spack/spack/util/spack_yaml.py b/lib/spack/spack/util/spack_yaml.py
index 476ed464f5..a1966664d9 100644
--- a/lib/spack/spack/util/spack_yaml.py
+++ b/lib/spack/spack/util/spack_yaml.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""Enhanced YAML parsing for Spack.
- ``load()`` preserves YAML Marks on returned objects -- this allows
@@ -31,11 +12,15 @@
default unorderd dict.
"""
-import yaml
-from yaml import Loader, Dumper
-from yaml.nodes import MappingNode, SequenceNode, ScalarNode
-from yaml.constructor import ConstructorError
from ordereddict_backport import OrderedDict
+from six import string_types, StringIO
+
+import ruamel.yaml as yaml
+from ruamel.yaml import Loader, Dumper
+from ruamel.yaml.nodes import MappingNode, SequenceNode, ScalarNode
+from ruamel.yaml.constructor import ConstructorError
+
+from llnl.util.tty.color import colorize, clen, cextra
import spack.error
@@ -60,10 +45,56 @@ class syaml_str(str):
__repr__ = str.__repr__
+class syaml_int(int):
+ __repr__ = str.__repr__
+
+
+#: mapping from syaml type -> primitive type
+syaml_types = {
+ syaml_str: string_types,
+ syaml_int: int,
+ syaml_dict: dict,
+ syaml_list: list,
+}
+
+
+def syaml_type(obj):
+ """Get the corresponding syaml wrapper type for a primitive type.
+
+ Return:
+ (object): syaml-typed copy of object, or the obj if no wrapper
+ """
+ for syaml_t, t in syaml_types.items():
+ if type(obj) is not bool and isinstance(obj, t):
+ return syaml_t(obj) if type(obj) != syaml_t else obj
+ return obj
+
+
+def markable(obj):
+ """Whether an object can be marked."""
+ return type(obj) in syaml_types
+
+
def mark(obj, node):
"""Add start and end markers to an object."""
- obj._start_mark = node.start_mark
- obj._end_mark = node.end_mark
+ if not markable(obj):
+ return
+
+ if hasattr(node, 'start_mark'):
+ obj._start_mark = node.start_mark
+ elif hasattr(node, '_start_mark'):
+ obj._start_mark = node._start_mark
+
+ if hasattr(node, 'end_mark'):
+ obj._end_mark = node.end_mark
+ elif hasattr(node, '_end_mark'):
+ obj._end_mark = node._end_mark
+
+
+def marked(obj):
+ """Whether an object has been marked by spack_yaml."""
+ return (hasattr(obj, '_start_mark') and obj._start_mark or
+ hasattr(obj, '_end_mark') and obj._end_mark)
class OrderedLineLoader(Loader):
@@ -193,6 +224,7 @@ class OrderedLineDumper(Dumper):
node.flow_style = self.default_flow_style
else:
node.flow_style = best_style
+
return node
def ignore_aliases(self, _data):
@@ -204,6 +236,87 @@ class OrderedLineDumper(Dumper):
OrderedLineDumper.add_representer(syaml_dict, OrderedLineDumper.represent_dict)
OrderedLineDumper.add_representer(syaml_list, OrderedLineDumper.represent_list)
OrderedLineDumper.add_representer(syaml_str, OrderedLineDumper.represent_str)
+OrderedLineDumper.add_representer(syaml_int, OrderedLineDumper.represent_int)
+
+
+def file_line(mark):
+ """Format a mark as <file>:<line> information."""
+ result = mark.name
+ if mark.line:
+ result += ':' + str(mark.line)
+ return result
+
+
+#: Global for interactions between LineAnnotationDumper and dump_annotated().
+#: This is nasty but YAML doesn't give us many ways to pass arguments --
+#: yaml.dump() takes a class (not an instance) and instantiates the dumper
+#: itself, so we can't just pass an instance
+_annotations = []
+
+
+class LineAnnotationDumper(OrderedLineDumper):
+ """Dumper that generates per-line annotations.
+
+ Annotations are stored in the ``_annotations`` global. After one
+ dump pass, the strings in ``_annotations`` will correspond one-to-one
+ with the lines output by the dumper.
+
+ LineAnnotationDumper records blame information after each line is
+ generated. As each line is parsed, it saves file/line info for each
+ object printed. At the end of each line, it creates an annotation
+ based on the saved mark and stores it in ``_annotations``.
+
+ For an example of how to use this, see ``dump_annotated()``, which
+ writes to a ``StringIO`` then joins the lines from that with
+ annotations.
+ """
+ saved = None
+
+ def __init__(self, *args, **kwargs):
+ super(LineAnnotationDumper, self).__init__(*args, **kwargs)
+ del _annotations[:]
+ self.colors = 'KgrbmcyGRBMCY'
+ self.filename_colors = {}
+
+ def process_scalar(self):
+ super(LineAnnotationDumper, self).process_scalar()
+ if marked(self.event.value):
+ self.saved = self.event.value
+
+ def represent_data(self, data):
+ """Force syaml_str to be passed through with marks."""
+ result = super(LineAnnotationDumper, self).represent_data(data)
+ if isinstance(result.value, string_types):
+ result.value = syaml_str(data)
+ mark(result.value, data)
+ return result
+
+ def write_stream_start(self):
+ super(LineAnnotationDumper, self).write_stream_start()
+ _annotations.append(colorize('@K{---}'))
+
+ def write_line_break(self):
+ super(LineAnnotationDumper, self).write_line_break()
+ if not self.saved:
+ return
+
+ # append annotations at the end of each line
+ if self.saved:
+ mark = self.saved._start_mark
+
+ color = self.filename_colors.get(mark.name)
+ if not color:
+ ncolors = len(self.colors)
+ color = self.colors[len(self.filename_colors) % ncolors]
+ self.filename_colors[mark.name] = color
+
+ fmt = '@%s{%%s}' % color
+ ann = fmt % mark.name
+ if mark.line is not None:
+ ann += ':@c{%s}' % (mark.line + 1)
+ _annotations.append(colorize(ann))
+ else:
+ _annotations.append('')
def load(*args, **kwargs):
@@ -214,8 +327,36 @@ def load(*args, **kwargs):
def dump(*args, **kwargs):
- kwargs['Dumper'] = OrderedLineDumper
- return yaml.dump(*args, **kwargs)
+ blame = kwargs.pop('blame', False)
+
+ if blame:
+ return dump_annotated(*args, **kwargs)
+ else:
+ kwargs['Dumper'] = OrderedLineDumper
+ return yaml.dump(*args, **kwargs)
+
+
+def dump_annotated(data, stream=None, *args, **kwargs):
+ kwargs['Dumper'] = LineAnnotationDumper
+
+ sio = StringIO()
+ yaml.dump(data, sio, *args, **kwargs)
+ lines = sio.getvalue().rstrip().split('\n')
+
+ getvalue = None
+ if stream is None:
+ stream = StringIO()
+ getvalue = stream.getvalue
+
+ # write out annotations and linees, accounting for color
+ width = max(clen(a) for a in _annotations)
+ formats = ['%%-%ds %%s\n' % (width + cextra(a)) for a in _annotations]
+
+ for f, a, l in zip(formats, _annotations, lines):
+ stream.write(f % (a, l))
+
+ if getvalue:
+ return getvalue()
class SpackYAMLError(spack.error.SpackError):
diff --git a/lib/spack/spack/util/string.py b/lib/spack/spack/util/string.py
index feb05a31a8..a85d50f50f 100644
--- a/lib/spack/spack/util/string.py
+++ b/lib/spack/spack/util/string.py
@@ -1,27 +1,7 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
def comma_list(sequence, article=''):
@@ -49,3 +29,29 @@ def comma_or(sequence):
def comma_and(sequence):
return comma_list(sequence, 'and')
+
+
+def quote(sequence, q="'"):
+ return ['%s%s%s' % (q, e, q) for e in sequence]
+
+
+def plural(n, singular, plural=None, show_n=True):
+ """Pluralize <singular> word by adding an s if n != 1.
+
+ Arguments:
+ n (int): number of things there are
+ singular (str): singular form of word
+ plural (str, optional): optional plural form, for when it's not just
+ singular + 's'
+ show_n (bool): whether to include n in the result string (default True)
+
+ Returns:
+ (str): "1 thing" if n == 1 or "n things" if n != 1
+ """
+ number = '%s ' % n if show_n else ''
+ if n == 1:
+ return "%s%s" % (number, singular)
+ elif plural is not None:
+ return "%s%s" % (number, plural)
+ else:
+ return "%s%ss" % (number, singular)
diff --git a/lib/spack/spack/util/web.py b/lib/spack/spack/util/web.py
index eadfc66ee0..b403e44d18 100644
--- a/lib/spack/spack/util/web.py
+++ b/lib/spack/spack/util/web.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import re
@@ -49,8 +30,12 @@ except ImportError:
import llnl.util.tty as tty
-import spack
+import spack.config
+import spack.cmd
+import spack.url
+import spack.stage
import spack.error
+import spack.util.crypto
from spack.util.compression import ALLOWED_ARCHIVE_TYPES
@@ -75,18 +60,30 @@ class LinkParser(HTMLParser):
class NonDaemonProcess(multiprocessing.Process):
"""Process tha allows sub-processes, so pools can have sub-pools."""
- def _get_daemon(self):
+ @property
+ def daemon(self):
return False
- def _set_daemon(self, value):
+ @daemon.setter
+ def daemon(self, value):
pass
- daemon = property(_get_daemon, _set_daemon)
+if sys.version_info[0] < 3:
+ class NonDaemonPool(multiprocessing.pool.Pool):
+ """Pool that uses non-daemon processes"""
+ Process = NonDaemonProcess
+else:
+
+ class NonDaemonContext(type(multiprocessing.get_context())):
+ Process = NonDaemonProcess
-class NonDaemonPool(multiprocessing.pool.Pool):
- """Pool that uses non-daemon processes"""
- Process = NonDaemonProcess
+ class NonDaemonPool(multiprocessing.pool.Pool):
+ """Pool that uses non-daemon processes"""
+
+ def __init__(self, *args, **kwargs):
+ kwargs['context'] = NonDaemonContext()
+ super(NonDaemonPool, self).__init__(*args, **kwargs)
def _spider(url, visited, root, depth, max_depth, raise_on_error):
@@ -111,18 +108,19 @@ def _spider(url, visited, root, depth, max_depth, raise_on_error):
try:
context = None
- if sys.version_info < (2, 7, 9) or \
- ((3,) < sys.version_info < (3, 4, 3)):
- if not spack.insecure:
+ verify_ssl = spack.config.get('config:verify_ssl')
+ pyver = sys.version_info
+ if (pyver < (2, 7, 9) or (3,) < pyver < (3, 4, 3)):
+ if verify_ssl:
tty.warn("Spack will not check SSL certificates. You need to "
"update your Python to enable certificate "
"verification.")
- else:
+ elif verify_ssl:
# We explicitly create default context to avoid error described in
# https://blog.sucuri.net/2016/03/beware-unverified-tls-certificates-php-python.html
- context = ssl._create_unverified_context() \
- if spack.insecure \
- else ssl.create_default_context()
+ context = ssl.create_default_context()
+ else:
+ context = ssl._create_unverified_context()
# Make a HEAD request first to check the content type. This lets
# us ignore tarballs and gigantic files.
@@ -196,7 +194,7 @@ def _spider(url, visited, root, depth, max_depth, raise_on_error):
except URLError as e:
tty.debug(e)
- if isinstance(e.reason, ssl.SSLError):
+ if hasattr(e, 'reason') and isinstance(e.reason, ssl.SSLError):
tty.warn("Spack was unable to fetch url list due to a certificate "
"verification problem. You can try running spack -k, "
"which will not check SSL certificates. Use this at your "
@@ -281,6 +279,13 @@ def find_versions_of_archive(archive_urls, list_url=None, list_depth=0):
for aurl in archive_urls:
list_urls.add(spack.url.find_list_url(aurl))
+ # Add '/' to the end of the URL. Some web servers require this.
+ additional_list_urls = set()
+ for lurl in list_urls:
+ if not lurl.endswith('/'):
+ additional_list_urls.add(lurl + '/')
+ list_urls.update(additional_list_urls)
+
# Grab some web pages to scrape.
pages = {}
links = set()
@@ -317,7 +322,7 @@ def find_versions_of_archive(archive_urls, list_url=None, list_depth=0):
# .sha256
# .sig
# However, SourceForge downloads still need to end in '/download'.
- url_regex += '(\/download)?$'
+ url_regex += r'(\/download)?$'
regexes.append(url_regex)
@@ -392,7 +397,7 @@ def get_checksums_for_versions(
# Checksum the archive and add it to the list
version_hashes.append((version, spack.util.crypto.checksum(
- hashlib.md5, stage.archive_file)))
+ hashlib.sha256, stage.archive_file)))
i += 1
except spack.stage.FailedDownloadError:
tty.msg("Failed to fetch {0}".format(url))
@@ -408,7 +413,7 @@ def get_checksums_for_versions(
# Generate the version directives to put in a package.py
version_lines = "\n".join([
- " version('{0}', {1}'{2}')".format(
+ " version('{0}', {1}sha256='{2}')".format(
v, ' ' * (max_len - len(str(v))), h) for v, h in version_hashes
])
diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py
index 43a1ab4ae6..8f154139c5 100644
--- a/lib/spack/spack/variant.py
+++ b/lib/spack/spack/variant.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""The variant module contains data structures that are needed to manage
variants both in packages and in specs.
"""
@@ -29,11 +10,12 @@ variants both in packages and in specs.
import functools
import inspect
import re
+from six import StringIO
import llnl.util.lang as lang
-import spack
+
+import spack.directives
import spack.error as error
-from six import StringIO
class Variant(object):
diff --git a/lib/spack/spack/version.py b/lib/spack/spack/version.py
index cef58d43f4..82d3927b64 100644
--- a/lib/spack/spack/version.py
+++ b/lib/spack/spack/version.py
@@ -1,27 +1,8 @@
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
-#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, February 1999.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
-# conditions of the GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
"""
This module implements Version and version-ish objects. These are:
@@ -51,6 +32,7 @@ from six import string_types
from spack.util.spack_yaml import syaml_dict
+
__all__ = ['Version', 'VersionRange', 'VersionList', 'ver']
# Valid version characters
@@ -253,6 +235,9 @@ class Version(object):
def __iter__(self):
return iter(self.version)
+ def __len__(self):
+ return len(self.version)
+
def __getitem__(self, idx):
cls = type(self)