fcmd 0.3.2__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fcmd-0.3.2 → fcmd-0.3.3}/.bumpversion.toml +1 -1
- {fcmd-0.3.2 → fcmd-0.3.3}/PKG-INFO +1 -1
- {fcmd-0.3.2 → fcmd-0.3.3}/pyproject.toml +1 -1
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/__init__.py +1 -1
- fcmd-0.3.3/src/fcmd/apis/__init__.py +127 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/dag.py +3 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/pymake.py +2 -1
- fcmd-0.3.3/src/fcmd/engine/__init__.py +52 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/engine/dependency_runner.py +6 -2
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_lscalc.py +6 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_pymake.py +0 -5
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_perf_baseline.py +1 -1
- {fcmd-0.3.2 → fcmd-0.3.3}/uv.lock +1 -1
- fcmd-0.3.2/src/fcmd/apis/__init__.py +0 -87
- fcmd-0.3.2/src/fcmd/engine/__init__.py +0 -28
- {fcmd-0.3.2 → fcmd-0.3.3}/.copier-answers.yml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.coveragerc +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.gitattributes +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.github/workflows/ci.yml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.github/workflows/release.yml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.gitignore +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.pre-commit-config.yaml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.readthedocs.yaml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/.vscode/settings.json +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/LICENSE +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/Makefile +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/README.md +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/docs/_static/.gitkeep +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/docs/api.rst +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/docs/changelog.rst +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/docs/conf.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/docs/index.rst +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/pyrefly.toml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/pytest.ini +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/ruff.toml +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/__main__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/_tool_args.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/_tool_exec.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/context.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/errors.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/profiling.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/report.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/task.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/apis/toolkit.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/completion_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/doctor_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/env_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/graph_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/info_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/profiler_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_builtins/yaml_cmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_common.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_completion_scripts.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_discovery.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_doctor_helpers.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_env_helpers.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_env_persist.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/_profiler_helpers.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/archive/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/archive/archivex.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/archive/folderzip.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/archive/zipencrypt.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/calcdate.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/lscalc.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/mathtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/randtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/stattool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/calc/timetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/conv/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/conv/casetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/conv/codetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/conv/colortool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/conv/convtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/conv/urltool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/crypto/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/crypto/cryptool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/crypto/hashfile.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/crypto/hashtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/crypto/idtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/csvtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/inifile.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/jsontool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/tomltool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/xmltool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/data/yamtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/autofmt.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/bumpversion.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/dockercmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/envdev.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/gittool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/packtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/dev/piptool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/filedate.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/filelevel.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/filerename.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/filesearch.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/folderback.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/pathtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/fileops/writefile.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/main.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/media/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/media/imagetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/media/pdftool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/media/screenshot.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/net/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/net/iptool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/net/nettool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/net/portcheck.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/net/sshcopyid.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/clr.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/reseticoncache.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/setenv.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/sysinfo.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/taskkill.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/system/which.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/text/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/text/asciitool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/text/padtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/text/regextool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/text/textdiff.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/cli/text/txttool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/console.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/engine/executors.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/engine/layer_runner.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/engine/task_command.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/engine/task_runner.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/models/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/models/command.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/models/filefilter.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/models/pdf.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/models/version.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/orchestration/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/orchestration/conditions.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/orchestration/yaml_loader.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/src/fcmd/py.typed +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/__init__.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_archivex.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_asciitool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_autofmt.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_bumpversion.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_calcdate.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_casetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_clr.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_codetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_colortool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_convtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_cryptool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_csvtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_dockercmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_envdev.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_filedate.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_filelevel.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_filerename.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_filesearch.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_folderback.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_folderzip.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_gittool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_hashfile.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_hashtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_idtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_imagetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_inifile.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_iptool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_jsontool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_mathtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_nettool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_packtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_padtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_pathtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_pdftool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_piptool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_portcheck.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_profiler.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_randtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_regextool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_reseticoncache.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_screenshot.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_setenv.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_sshcopyid.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_stattool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_sysinfo.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_taskkill.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_textdiff.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_timetool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_tomltool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_txttool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_urltool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_which.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_writefile.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_xmltool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_yamtool.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_cli_zipencrypt.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_console.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_context.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_engine_executors.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_engine_task_command.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_env_persist.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_fcmd.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_graph.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_init.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_models.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_models_pdf.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_orchestration_conditions.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_orchestration_yaml_loader.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_profiling.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_report.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_task.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tests/test_toolkit.py +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/tox.ini +0 -0
- {fcmd-0.3.2 → fcmd-0.3.3}/uv.toml +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""fcmd.apis —— 框架级公共 API 聚合。
|
|
2
|
+
|
|
3
|
+
包含 7 个子模块:
|
|
4
|
+
- task: 任务数据结构(TaskSpec、RetryPolicy、RunConfig)
|
|
5
|
+
- dag: 图编排(Graph、GraphDefaults、graph 快捷构造)
|
|
6
|
+
- errors: 异常类型
|
|
7
|
+
- report: 执行报告(RunReport、TaskResult)
|
|
8
|
+
- context: 依赖注入工具
|
|
9
|
+
- profiling: 性能分析(ProfileReport、TaskProfile)
|
|
10
|
+
- toolkit: @fx.tool 装饰器框架(ToolSpec、build_tool_graph 等)
|
|
11
|
+
|
|
12
|
+
执行引擎(run/executors)位于 :mod:`fcmd.engine`,YAML 编排位于
|
|
13
|
+
:mod:`fcmd.orchestration`,经顶层 ``fcmd.__init__`` 懒加载暴露。
|
|
14
|
+
|
|
15
|
+
本包自身也通过 ``__getattr__`` 懒加载所有子模块,使首次访问
|
|
16
|
+
``fcmd.apis.toolkit`` / ``fcmd.apis.run_tool`` 等不会在父包加载时
|
|
17
|
+
触发整条导入链(toolkit → _tool_exec → engine → asyncio)。
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"Context",
|
|
26
|
+
"CycleError",
|
|
27
|
+
"DuplicateTaskError",
|
|
28
|
+
"FcmdError",
|
|
29
|
+
"Graph",
|
|
30
|
+
"GraphDefaults",
|
|
31
|
+
"InjectionError",
|
|
32
|
+
"MissingDependencyError",
|
|
33
|
+
"ProfileReport",
|
|
34
|
+
"RetryPolicy",
|
|
35
|
+
"RunConfig",
|
|
36
|
+
"RunReport",
|
|
37
|
+
"TaskCmd",
|
|
38
|
+
"TaskFailedError",
|
|
39
|
+
"TaskProfile",
|
|
40
|
+
"TaskResult",
|
|
41
|
+
"TaskSpec",
|
|
42
|
+
"TaskStatus",
|
|
43
|
+
"TaskTimeoutError",
|
|
44
|
+
"ToolExitCode",
|
|
45
|
+
"ToolSpec",
|
|
46
|
+
"_tool_exec",
|
|
47
|
+
"build_call_args",
|
|
48
|
+
"build_tool_graph",
|
|
49
|
+
"clear_tool_registry",
|
|
50
|
+
"cmd",
|
|
51
|
+
"describe_injection",
|
|
52
|
+
"get_tool",
|
|
53
|
+
"graph",
|
|
54
|
+
"list_subcommands",
|
|
55
|
+
"list_tools",
|
|
56
|
+
"run_tool",
|
|
57
|
+
"task",
|
|
58
|
+
"tool",
|
|
59
|
+
"toolkit",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
# 懒加载映射:公共符号 / 子模块名 -> (模块路径, 符号名 或 None 表示模块自身)
|
|
63
|
+
_LAZY_ATTRS: dict[str, tuple[str, str | None]] = {
|
|
64
|
+
# ---- 公共符号 ----
|
|
65
|
+
"Context": ("fcmd.apis.context", "Context"),
|
|
66
|
+
"build_call_args": ("fcmd.apis.context", "build_call_args"),
|
|
67
|
+
"describe_injection": ("fcmd.apis.context", "describe_injection"),
|
|
68
|
+
"Graph": ("fcmd.apis.dag", "Graph"),
|
|
69
|
+
"GraphDefaults": ("fcmd.apis.dag", "GraphDefaults"),
|
|
70
|
+
"graph": ("fcmd.apis.dag", "graph"),
|
|
71
|
+
"CycleError": ("fcmd.apis.errors", "CycleError"),
|
|
72
|
+
"DuplicateTaskError": ("fcmd.apis.errors", "DuplicateTaskError"),
|
|
73
|
+
"FcmdError": ("fcmd.apis.errors", "FcmdError"),
|
|
74
|
+
"InjectionError": ("fcmd.apis.errors", "InjectionError"),
|
|
75
|
+
"MissingDependencyError": ("fcmd.apis.errors", "MissingDependencyError"),
|
|
76
|
+
"TaskFailedError": ("fcmd.apis.errors", "TaskFailedError"),
|
|
77
|
+
"TaskTimeoutError": ("fcmd.apis.errors", "TaskTimeoutError"),
|
|
78
|
+
"ProfileReport": ("fcmd.apis.profiling", "ProfileReport"),
|
|
79
|
+
"TaskProfile": ("fcmd.apis.profiling", "TaskProfile"),
|
|
80
|
+
"RunReport": ("fcmd.apis.report", "RunReport"),
|
|
81
|
+
"RetryPolicy": ("fcmd.apis.task", "RetryPolicy"),
|
|
82
|
+
"RunConfig": ("fcmd.apis.task", "RunConfig"),
|
|
83
|
+
"TaskCmd": ("fcmd.apis.task", "TaskCmd"),
|
|
84
|
+
"TaskResult": ("fcmd.apis.task", "TaskResult"),
|
|
85
|
+
"TaskSpec": ("fcmd.apis.task", "TaskSpec"),
|
|
86
|
+
"TaskStatus": ("fcmd.apis.task", "TaskStatus"),
|
|
87
|
+
"cmd": ("fcmd.apis.task", "cmd"),
|
|
88
|
+
"task": ("fcmd.apis.task", "task"),
|
|
89
|
+
"ToolExitCode": ("fcmd.apis.toolkit", "ToolExitCode"),
|
|
90
|
+
"ToolSpec": ("fcmd.apis.toolkit", "ToolSpec"),
|
|
91
|
+
"build_tool_graph": ("fcmd.apis.toolkit", "build_tool_graph"),
|
|
92
|
+
"clear_tool_registry": ("fcmd.apis.toolkit", "clear_tool_registry"),
|
|
93
|
+
"get_tool": ("fcmd.apis.toolkit", "get_tool"),
|
|
94
|
+
"list_subcommands": ("fcmd.apis.toolkit", "list_subcommands"),
|
|
95
|
+
"list_tools": ("fcmd.apis.toolkit", "list_tools"),
|
|
96
|
+
"run_tool": ("fcmd.apis.toolkit", "run_tool"),
|
|
97
|
+
"tool": ("fcmd.apis.toolkit", "tool"),
|
|
98
|
+
# ---- 子模块名(供测试 from fcmd.apis import toolkit / _tool_exec)----
|
|
99
|
+
"toolkit": ("fcmd.apis.toolkit", None),
|
|
100
|
+
"_tool_exec": ("fcmd.apis._tool_exec", None),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def __getattr__(name: str) -> Any:
|
|
105
|
+
"""懒加载公共 API 符号与子模块。
|
|
106
|
+
|
|
107
|
+
首次访问时从对应模块导入并缓存到 ``globals()``,后续直接命中。
|
|
108
|
+
"""
|
|
109
|
+
mapping = _LAZY_ATTRS.get(name)
|
|
110
|
+
if mapping is None:
|
|
111
|
+
raise AttributeError(f"module 'fcmd.apis' has no attribute {name!r}")
|
|
112
|
+
module_path, attr_name = mapping
|
|
113
|
+
import importlib
|
|
114
|
+
|
|
115
|
+
module = importlib.import_module(module_path)
|
|
116
|
+
if attr_name is None:
|
|
117
|
+
# 请求子模块自身(如 ``from fcmd.apis import toolkit``)
|
|
118
|
+
value = module
|
|
119
|
+
else:
|
|
120
|
+
value = getattr(module, attr_name)
|
|
121
|
+
globals()[name] = value # 缓存到全局,后续直接命中
|
|
122
|
+
return value
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def __dir__() -> list[str]:
|
|
126
|
+
"""补全建议。"""
|
|
127
|
+
return sorted(set(globals()) | set(__all__))
|
|
@@ -160,6 +160,9 @@ class Graph:
|
|
|
160
160
|
raise DuplicateTaskError(spec.name)
|
|
161
161
|
self.specs[spec.name] = spec
|
|
162
162
|
self.deps[spec.name] = spec.depends_on
|
|
163
|
+
# 失效缓存:specs 变更后,旧的 resolved_spec / layers 不再可靠。
|
|
164
|
+
self._resolved_cache.clear()
|
|
165
|
+
self._layers_cache = None
|
|
163
166
|
self._validate_references()
|
|
164
167
|
return self
|
|
165
168
|
|
|
@@ -213,12 +213,13 @@ def test_n_cpu(cwd: Path = Path()) -> None:
|
|
|
213
213
|
"pytest",
|
|
214
214
|
"-m",
|
|
215
215
|
"not slow",
|
|
216
|
+
"-n",
|
|
217
|
+
"auto",
|
|
216
218
|
"--cov=fcmd",
|
|
217
219
|
f"--cov-fail-under={_COVERAGE_THRESHOLD}",
|
|
218
220
|
"--color=yes",
|
|
219
221
|
"--durations=10",
|
|
220
222
|
],
|
|
221
|
-
needs=["c"],
|
|
222
223
|
)
|
|
223
224
|
def test_coverage(cwd: Path = Path()) -> None:
|
|
224
225
|
"""测试并生成覆盖率(内部 job)。"""
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""fcmd.engine —— DAG 执行引擎层。
|
|
2
|
+
|
|
3
|
+
承载 ``run()`` 调用链中全部**执行侧**关注点("动词":调度与执行):
|
|
4
|
+
|
|
5
|
+
- ``executors``:公共 :func:`run` 入口与策略派发(``sequential`` /
|
|
6
|
+
``thread`` / ``async`` / ``dependency`` 四种策略)
|
|
7
|
+
- ``task_runner``:任务级执行内核(执行上下文、线程池复用、跳过/
|
|
8
|
+
重试/失败处理、同步/异步任务执行器)
|
|
9
|
+
- ``layer_runner``:层屏障模型调度(同层并发、整层完成后进入下一层)
|
|
10
|
+
- ``dependency_runner``:依赖驱动调度(无层屏障,任务就绪即启动)
|
|
11
|
+
- ``task_command``:TaskSpec ``cmd`` 字段执行器(list / shell 字符串 /
|
|
12
|
+
可调用对象)
|
|
13
|
+
|
|
14
|
+
与 :mod:`fcmd.apis`(API 定义层,"名词":数据结构与类型)相对。
|
|
15
|
+
本包通过 ``__getattr__`` 懒加载,避免父包加载时 eager import 整个
|
|
16
|
+
``executors`` 模块(它依赖 ``fcmd.apis.toolkit → asyncio`` 整条链)。
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"Strategy",
|
|
25
|
+
"run",
|
|
26
|
+
"run_command",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
_LAZY_ATTRS: dict[str, tuple[str, str]] = {
|
|
30
|
+
"Strategy": ("fcmd.engine.executors", "Strategy"),
|
|
31
|
+
"run": ("fcmd.engine.executors", "run"),
|
|
32
|
+
"run_command": ("fcmd.engine.task_command", "run_command"),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def __getattr__(name: str) -> Any:
|
|
37
|
+
"""懒加载执行引擎公共 API。"""
|
|
38
|
+
mapping = _LAZY_ATTRS.get(name)
|
|
39
|
+
if mapping is None:
|
|
40
|
+
raise AttributeError(f"module 'fcmd.engine' has no attribute {name!r}")
|
|
41
|
+
module_path, attr_name = mapping
|
|
42
|
+
import importlib
|
|
43
|
+
|
|
44
|
+
module = importlib.import_module(module_path)
|
|
45
|
+
value = getattr(module, attr_name)
|
|
46
|
+
globals()[name] = value # 缓存到全局,后续直接命中
|
|
47
|
+
return value
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def __dir__() -> list[str]:
|
|
51
|
+
"""补全建议。"""
|
|
52
|
+
return sorted(set(globals()) | set(__all__))
|
|
@@ -51,6 +51,8 @@ async def _run_dependency(
|
|
|
51
51
|
sorter.prepare()
|
|
52
52
|
|
|
53
53
|
in_flight: dict[str, asyncio.Task[TaskResult[Any]]] = {}
|
|
54
|
+
# 反向映射:task -> 任务名,O(1) 完成任务查找(替代 O(N) next() 扫描)。
|
|
55
|
+
_task_to_name: dict[asyncio.Task[TaskResult[Any]], str] = {}
|
|
54
56
|
loop = asyncio.get_running_loop()
|
|
55
57
|
|
|
56
58
|
async def _run_one(name: str) -> TaskResult[Any]:
|
|
@@ -67,7 +69,9 @@ async def _run_dependency(
|
|
|
67
69
|
# fail-fast:首个异常即取消剩余任务并抛出(匹配 gather 语义)。
|
|
68
70
|
while ready or in_flight:
|
|
69
71
|
for name in ready:
|
|
70
|
-
|
|
72
|
+
task = loop.create_task(_run_one(name))
|
|
73
|
+
in_flight[name] = task
|
|
74
|
+
_task_to_name[task] = name
|
|
71
75
|
ready = []
|
|
72
76
|
|
|
73
77
|
if not in_flight: # pragma: no cover - 图已校验无环,防御性处理
|
|
@@ -75,7 +79,7 @@ async def _run_dependency(
|
|
|
75
79
|
|
|
76
80
|
done, _ = await asyncio.wait(in_flight.values(), return_when=asyncio.FIRST_COMPLETED)
|
|
77
81
|
for task in done:
|
|
78
|
-
done_name =
|
|
82
|
+
done_name = _task_to_name.pop(task)
|
|
79
83
|
del in_flight[done_name]
|
|
80
84
|
exc = task.exception()
|
|
81
85
|
if exc is not None:
|
|
@@ -279,6 +279,10 @@ class TestGetLsDynaCommand:
|
|
|
279
279
|
def test_mpp_sp_intel_mpi_windows(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
280
280
|
"""MPP 单精度 + Intel MPI(Windows)。"""
|
|
281
281
|
monkeypatch.setattr(sys, "platform", "win32")
|
|
282
|
+
# shutil.which 在模块导入时根据真实 sys.platform 设置 _winapi,
|
|
283
|
+
# 不能只 patch sys.platform 就让它走 Windows 分支——需要
|
|
284
|
+
# 同时 mock 掉 which 返回 None 让 solver 发现走回退路径。
|
|
285
|
+
monkeypatch.setattr("shutil.which", lambda _n: None)
|
|
282
286
|
config = LsDynaConfig(
|
|
283
287
|
input_file="test.k",
|
|
284
288
|
parallel="mpp",
|
|
@@ -296,6 +300,8 @@ class TestGetLsDynaCommand:
|
|
|
296
300
|
def test_mpp_dp_intel_mpi_linux(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
297
301
|
"""MPP 双精度 + Intel MPI(Linux)。"""
|
|
298
302
|
monkeypatch.setattr(sys, "platform", "linux")
|
|
303
|
+
# 同上——mock shutil.which 避免真实探测
|
|
304
|
+
monkeypatch.setattr("shutil.which", lambda _n: None)
|
|
299
305
|
config = LsDynaConfig(
|
|
300
306
|
input_file="test.k",
|
|
301
307
|
parallel="mpp",
|
|
@@ -229,11 +229,6 @@ class TestPymakeHybridTasks:
|
|
|
229
229
|
assert "--cov-fail-under=95" in spec.cmd
|
|
230
230
|
assert spec.hidden is False
|
|
231
231
|
|
|
232
|
-
def test_cov_needs_c(self) -> None:
|
|
233
|
-
"""cov 应依赖 c(先清理)。"""
|
|
234
|
-
spec = get_tool("pymake", "cov")
|
|
235
|
-
assert "c" in spec.needs
|
|
236
|
-
|
|
237
232
|
def test_bump_cmd_uses_patch(self) -> None:
|
|
238
233
|
"""bump 应使用 patch。"""
|
|
239
234
|
spec = get_tool("pymake", "bump")
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
"""fcmd.apis —— 框架级公共 API 聚合。
|
|
2
|
-
|
|
3
|
-
包含 7 个子模块:
|
|
4
|
-
- task: 任务数据结构(TaskSpec、RetryPolicy、RunConfig)
|
|
5
|
-
- dag: 图编排(Graph、GraphDefaults、graph 快捷构造)
|
|
6
|
-
- errors: 异常类型
|
|
7
|
-
- report: 执行报告(RunReport、TaskResult)
|
|
8
|
-
- context: 依赖注入工具
|
|
9
|
-
- profiling: 性能分析(ProfileReport、TaskProfile)
|
|
10
|
-
- toolkit: @fx.tool 装饰器框架(ToolSpec、build_tool_graph 等)
|
|
11
|
-
|
|
12
|
-
执行引擎(run/executors)位于 :mod:`fcmd.engine`,YAML 编排位于
|
|
13
|
-
:mod:`fcmd.orchestration`,经顶层 ``fcmd.__init__`` 懒加载暴露。
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
from __future__ import annotations
|
|
17
|
-
|
|
18
|
-
from fcmd.apis.context import Context, build_call_args, describe_injection
|
|
19
|
-
from fcmd.apis.dag import Graph, GraphDefaults, graph
|
|
20
|
-
from fcmd.apis.errors import (
|
|
21
|
-
CycleError,
|
|
22
|
-
DuplicateTaskError,
|
|
23
|
-
FcmdError,
|
|
24
|
-
InjectionError,
|
|
25
|
-
MissingDependencyError,
|
|
26
|
-
TaskFailedError,
|
|
27
|
-
TaskTimeoutError,
|
|
28
|
-
)
|
|
29
|
-
from fcmd.apis.profiling import ProfileReport, TaskProfile
|
|
30
|
-
from fcmd.apis.report import RunReport
|
|
31
|
-
from fcmd.apis.task import (
|
|
32
|
-
RetryPolicy,
|
|
33
|
-
RunConfig,
|
|
34
|
-
TaskCmd,
|
|
35
|
-
TaskResult,
|
|
36
|
-
TaskSpec,
|
|
37
|
-
TaskStatus,
|
|
38
|
-
cmd,
|
|
39
|
-
task,
|
|
40
|
-
)
|
|
41
|
-
from fcmd.apis.toolkit import (
|
|
42
|
-
ToolExitCode,
|
|
43
|
-
ToolSpec,
|
|
44
|
-
build_tool_graph,
|
|
45
|
-
clear_tool_registry,
|
|
46
|
-
get_tool,
|
|
47
|
-
list_subcommands,
|
|
48
|
-
list_tools,
|
|
49
|
-
run_tool,
|
|
50
|
-
tool,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
__all__ = [
|
|
54
|
-
"Context",
|
|
55
|
-
"CycleError",
|
|
56
|
-
"DuplicateTaskError",
|
|
57
|
-
"FcmdError",
|
|
58
|
-
"Graph",
|
|
59
|
-
"GraphDefaults",
|
|
60
|
-
"InjectionError",
|
|
61
|
-
"MissingDependencyError",
|
|
62
|
-
"ProfileReport",
|
|
63
|
-
"RetryPolicy",
|
|
64
|
-
"RunConfig",
|
|
65
|
-
"RunReport",
|
|
66
|
-
"TaskCmd",
|
|
67
|
-
"TaskFailedError",
|
|
68
|
-
"TaskProfile",
|
|
69
|
-
"TaskResult",
|
|
70
|
-
"TaskSpec",
|
|
71
|
-
"TaskStatus",
|
|
72
|
-
"TaskTimeoutError",
|
|
73
|
-
"ToolExitCode",
|
|
74
|
-
"ToolSpec",
|
|
75
|
-
"build_call_args",
|
|
76
|
-
"build_tool_graph",
|
|
77
|
-
"clear_tool_registry",
|
|
78
|
-
"cmd",
|
|
79
|
-
"describe_injection",
|
|
80
|
-
"get_tool",
|
|
81
|
-
"graph",
|
|
82
|
-
"list_subcommands",
|
|
83
|
-
"list_tools",
|
|
84
|
-
"run_tool",
|
|
85
|
-
"task",
|
|
86
|
-
"tool",
|
|
87
|
-
]
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""fcmd.engine —— DAG 执行引擎层。
|
|
2
|
-
|
|
3
|
-
承载 ``run()`` 调用链中全部**执行侧**关注点("动词":调度与执行):
|
|
4
|
-
|
|
5
|
-
- ``executors``:公共 :func:`run` 入口与策略派发(``sequential`` /
|
|
6
|
-
``thread`` / ``async`` / ``dependency`` 四种策略)
|
|
7
|
-
- ``task_runner``:任务级执行内核(执行上下文、线程池复用、跳过/
|
|
8
|
-
重试/失败处理、同步/异步任务执行器)
|
|
9
|
-
- ``layer_runner``:层屏障模型调度(同层并发、整层完成后进入下一层)
|
|
10
|
-
- ``dependency_runner``:依赖驱动调度(无层屏障,任务就绪即启动)
|
|
11
|
-
- ``task_command``:TaskSpec ``cmd`` 字段执行器(list / shell 字符串 /
|
|
12
|
-
可调用对象)
|
|
13
|
-
|
|
14
|
-
与 :mod:`fcmd.apis`(API 定义层,"名词":数据结构与类型)相对。
|
|
15
|
-
本包顶层模块仅供人读与兼容引用;内部代码应使用深路径
|
|
16
|
-
(如 ``fcmd.engine.executors``)以避免不必要的导入开销。
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
from fcmd.engine.executors import Strategy, run
|
|
22
|
-
from fcmd.engine.task_command import run_command
|
|
23
|
-
|
|
24
|
-
__all__ = [
|
|
25
|
-
"Strategy",
|
|
26
|
-
"run",
|
|
27
|
-
"run_command",
|
|
28
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|