zrb 1.0.0a14__tar.gz → 1.0.0a16__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.
- {zrb-1.0.0a14 → zrb-1.0.0a16}/PKG-INFO +1 -1
- {zrb-1.0.0a14 → zrb-1.0.0a16}/pyproject.toml +1 -1
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/git.py +28 -26
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/git_subtree.py +15 -11
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/cmd_task.py +17 -50
- zrb-1.0.0a16/src/zrb/util/cmd/command.py +93 -0
- zrb-1.0.0a16/src/zrb/util/git.py +156 -0
- zrb-1.0.0a16/src/zrb/util/git_subtree.py +113 -0
- zrb-1.0.0a14/src/zrb/util/cmd/command.py +0 -33
- zrb-1.0.0a14/src/zrb/util/git.py +0 -174
- zrb-1.0.0a14/src/zrb/util/git_subtree.py +0 -95
- {zrb-1.0.0a14 → zrb-1.0.0a16}/README.md +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/__main__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/attr/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/attr/type.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/base64.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/group.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/llm/llm_chat.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/llm/tool/cli.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/llm/tool/rag.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/llm/tool/web.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/md5.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/.gitignore +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/README.md +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/column/create_column_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/config.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/entity/create_entity_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/my_entity_usecase.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/factory.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/my_entity_db_repository.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/my_entity_repository.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/entity/schema.template.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/group.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/helper.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/main.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/create_module_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/alembic.ini +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/any_client.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/api_client.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/direct_client.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/factory.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/README +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/env.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/script.py.mako +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/versions/3093c7336477_add_user_table.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration_metadata.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/route.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/service/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/module/run_module.template.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/_zrb/venv_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/app.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/base_db_repository.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/base_usecase.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/db_engine.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/error.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/common/schema.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/config.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/main.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/migrate.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/alembic.ini +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/client/any_client.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/migration/README +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/migration/env.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/migration/script.py.mako +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/migration_metadata.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/route.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/user/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/user_db_repository.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/user_repository.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/auth/service/user/user_usecase.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/alembic.ini +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/migration/README +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/migration/env.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/migration/script.py.mako +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/migration/versions/.gitkeep +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/migration_metadata.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/module/gateway/route.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/requirements.txt +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/schema/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/schema/permission.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/schema/role.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/schema/user.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/add/fastapp_template/template.env +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/create/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/create/create.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/create/project-template/README.md +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/project/create/project-template/zrb_init.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/python.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/asdf/asdf.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/asdf/asdf_helper.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/common_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/latex/ubuntu.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/tmux/tmux.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/tmux/tmux_config.sh +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/tmux/tmux_helper.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/setup/ubuntu.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/shell/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/shell/autocomplete/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/shell/autocomplete/bash.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/shell/autocomplete/subcmd.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/shell/autocomplete/zsh.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/builtin/todo.py +7 -7
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/callback/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/callback/any_callback.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/callback/callback.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/cmd/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/cmd/cmd_result.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/cmd/cmd_val.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/config.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/content_transformer/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/content_transformer/any_content_transformer.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/content_transformer/content_transformer.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/context/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/context/any_context.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/context/any_shared_context.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/context/context.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/context/shared_context.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/dot_dict/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/dot_dict/dot_dict.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/env/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/env/any_env.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/env/env.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/env/env_file.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/env/env_map.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/group/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/group/any_group.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/group/group.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/any_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/base_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/bool_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/float_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/int_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/option_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/password_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/str_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/input/text_input.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/cli.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_app.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/controller.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/partial/group_info.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/partial/group_li.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/partial/task_info.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/partial/task_li.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/group_info_ui/view.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/controller.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/partial/group_info.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/partial/group_li.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/partial/task_info.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/partial/task_li.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/home_page/view.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/static/favicon-32x32.png +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/static/pico.min.css +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/controller.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/partial/common-util.js +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/partial/input.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/partial/main.js +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/partial/show-existing-session.js +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/partial/visualize-history.js +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_controller/task_ui/view.html +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/runner/web_util.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session/any_session.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session/session.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session_state_log/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session_state_log/session_state_log.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session_state_logger/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session_state_logger/any_session_state_logger.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session_state_logger/default_session_state_logger.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/session_state_logger/file_session_state_logger.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/any_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/base_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/base_trigger.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/http_check.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/llm_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/make_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/rsync_task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/scaffolder.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/scheduler.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/task.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task/tcp_check.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task_status/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/task_status/task_status.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/attr.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/cli/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/cli/style.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/cli/subcommand.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/cmd/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/cmd/remote.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_code_to_class.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_code_to_function.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_code_to_method.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_code_to_module.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_key_to_dict.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_param_to_function_call.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_parent_to_class.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/codemod/add_property_to_class.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/cron.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/group.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/llm/tool.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/load.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/run.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/string/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/string/conversion.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/string/format.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/string/name.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/util/todo.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/xcom/__init__.py +0 -0
- {zrb-1.0.0a14 → zrb-1.0.0a16}/src/zrb/xcom/xcom.py +0 -0
@@ -3,7 +3,7 @@ from zrb.context.any_context import AnyContext
|
|
3
3
|
from zrb.input.bool_input import BoolInput
|
4
4
|
from zrb.input.str_input import StrInput
|
5
5
|
from zrb.task.make_task import make_task
|
6
|
-
from zrb.util.cli.style import stylize_green, stylize_red, stylize_yellow
|
6
|
+
from zrb.util.cli.style import stylize_faint, stylize_green, stylize_red, stylize_yellow
|
7
7
|
from zrb.util.git import (
|
8
8
|
add,
|
9
9
|
commit,
|
@@ -55,9 +55,11 @@ from zrb.util.git import (
|
|
55
55
|
group=git_group,
|
56
56
|
alias="diff",
|
57
57
|
)
|
58
|
-
def get_git_diff(ctx: AnyContext):
|
59
|
-
repo_dir = get_repo_dir()
|
60
|
-
diff = get_diff(
|
58
|
+
async def get_git_diff(ctx: AnyContext):
|
59
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
60
|
+
diff = await get_diff(
|
61
|
+
repo_dir, ctx.input.source, ctx.input.current, log_method=ctx.print
|
62
|
+
)
|
61
63
|
result = []
|
62
64
|
decorated = []
|
63
65
|
if ctx.input.created and diff.created:
|
@@ -83,16 +85,16 @@ def get_git_diff(ctx: AnyContext):
|
|
83
85
|
group=git_branch_group,
|
84
86
|
alias="prune",
|
85
87
|
)
|
86
|
-
def prune_local_branches(ctx: AnyContext):
|
87
|
-
repo_dir = get_repo_dir()
|
88
|
-
branches = get_branches(repo_dir)
|
89
|
-
current_branch = get_current_branch(repo_dir)
|
88
|
+
async def prune_local_branches(ctx: AnyContext):
|
89
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
90
|
+
branches = await get_branches(repo_dir, log_method=ctx.print)
|
91
|
+
current_branch = await get_current_branch(repo_dir, log_method=ctx.print)
|
90
92
|
for branch in branches:
|
91
93
|
if branch == current_branch or branch == "main" or branch == "master":
|
92
94
|
continue
|
93
|
-
ctx.print(
|
95
|
+
ctx.print(stylize_faint(f"Removing local branch: {branch}"))
|
94
96
|
try:
|
95
|
-
delete_branch(repo_dir, branch)
|
97
|
+
await delete_branch(repo_dir, branch, log_method=ctx.print)
|
96
98
|
except Exception as e:
|
97
99
|
ctx.log_error(e)
|
98
100
|
|
@@ -109,12 +111,12 @@ def prune_local_branches(ctx: AnyContext):
|
|
109
111
|
group=git_group,
|
110
112
|
alias="commit",
|
111
113
|
)
|
112
|
-
def git_commit(ctx: AnyContext):
|
113
|
-
repo_dir = get_repo_dir()
|
114
|
-
ctx.print("Add changes to staging")
|
115
|
-
add(repo_dir)
|
116
|
-
ctx.print("Commit changes")
|
117
|
-
commit(repo_dir, ctx.input.message)
|
114
|
+
async def git_commit(ctx: AnyContext):
|
115
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
116
|
+
ctx.print(stylize_faint("Add changes to staging"))
|
117
|
+
await add(repo_dir, log_method=ctx.print)
|
118
|
+
ctx.print(stylize_faint("Commit changes"))
|
119
|
+
await commit(repo_dir, ctx.input.message, log_method=ctx.print)
|
118
120
|
|
119
121
|
|
120
122
|
@make_task(
|
@@ -130,12 +132,12 @@ def git_commit(ctx: AnyContext):
|
|
130
132
|
group=git_group,
|
131
133
|
alias="pull",
|
132
134
|
)
|
133
|
-
def git_pull(ctx: AnyContext):
|
134
|
-
repo_dir = get_repo_dir()
|
135
|
+
async def git_pull(ctx: AnyContext):
|
136
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
135
137
|
remote = ctx.input.remote
|
136
|
-
current_branch = get_current_branch(repo_dir)
|
137
|
-
ctx.print(f"Pulling from {remote}/{current_branch}")
|
138
|
-
pull(repo_dir, remote, current_branch)
|
138
|
+
current_branch = await get_current_branch(repo_dir, log_method=ctx.print)
|
139
|
+
ctx.print(stylize_faint(f"Pulling from {remote}/{current_branch}"))
|
140
|
+
await pull(repo_dir, remote, current_branch, log_method=ctx.print)
|
139
141
|
|
140
142
|
|
141
143
|
@make_task(
|
@@ -151,9 +153,9 @@ def git_pull(ctx: AnyContext):
|
|
151
153
|
group=git_group,
|
152
154
|
alias="push",
|
153
155
|
)
|
154
|
-
def git_push(ctx: AnyContext):
|
155
|
-
repo_dir = get_repo_dir()
|
156
|
+
async def git_push(ctx: AnyContext):
|
157
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
156
158
|
remote = ctx.input.remote
|
157
|
-
current_branch = get_current_branch(repo_dir)
|
158
|
-
ctx.print(f"Pushing to {remote}/{current_branch}")
|
159
|
-
push(repo_dir, remote, current_branch)
|
159
|
+
current_branch = await get_current_branch(repo_dir, log_method=ctx.print)
|
160
|
+
ctx.print(stylize_faint(f"Pushing to {remote}/{current_branch}"))
|
161
|
+
await push(repo_dir, remote, current_branch, log_method=ctx.print)
|
@@ -3,6 +3,7 @@ from zrb.builtin.group import git_subtree_group
|
|
3
3
|
from zrb.context.any_context import AnyContext
|
4
4
|
from zrb.input.str_input import StrInput
|
5
5
|
from zrb.task.make_task import make_task
|
6
|
+
from zrb.util.cli.style import stylize_faint
|
6
7
|
from zrb.util.git import get_repo_dir
|
7
8
|
from zrb.util.git_subtree import add_subtree, load_config, pull_subtree, push_subtree
|
8
9
|
|
@@ -32,14 +33,15 @@ from zrb.util.git_subtree import add_subtree, load_config, pull_subtree, push_su
|
|
32
33
|
group=git_subtree_group,
|
33
34
|
alias="add",
|
34
35
|
)
|
35
|
-
def git_add_subtree(ctx: AnyContext):
|
36
|
-
repo_dir = get_repo_dir()
|
37
|
-
add_subtree(
|
36
|
+
async def git_add_subtree(ctx: AnyContext):
|
37
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
38
|
+
await add_subtree(
|
38
39
|
repo_dir=repo_dir,
|
39
40
|
name=ctx.input.name,
|
40
41
|
repo_url=ctx.input["repo-url"],
|
41
42
|
branch=ctx.input["repo-branch"],
|
42
43
|
prefix=ctx.input["repo-prefix"],
|
44
|
+
log_method=ctx.print,
|
43
45
|
)
|
44
46
|
|
45
47
|
|
@@ -50,20 +52,21 @@ def git_add_subtree(ctx: AnyContext):
|
|
50
52
|
group=git_subtree_group,
|
51
53
|
alias="pull",
|
52
54
|
)
|
53
|
-
def git_pull_subtree(ctx: AnyContext):
|
54
|
-
repo_dir = get_repo_dir()
|
55
|
+
async def git_pull_subtree(ctx: AnyContext):
|
56
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
55
57
|
config = load_config(repo_dir)
|
56
58
|
if not config.data:
|
57
59
|
raise ValueError("No subtree config found")
|
58
60
|
first_err: Exception | None = None
|
59
61
|
for name, detail in config.data.items():
|
60
62
|
try:
|
61
|
-
ctx.print(f"Pull from subtree {name}")
|
62
|
-
pull_subtree(
|
63
|
+
ctx.print(stylize_faint(f"Pull from subtree {name}"))
|
64
|
+
await pull_subtree(
|
63
65
|
repo_dir=repo_dir,
|
64
66
|
prefix=detail.prefix,
|
65
67
|
repo_url=detail.repo_url,
|
66
68
|
branch=detail.branch,
|
69
|
+
log_method=ctx.print,
|
67
70
|
)
|
68
71
|
except Exception as e:
|
69
72
|
if first_err is None:
|
@@ -80,20 +83,21 @@ def git_pull_subtree(ctx: AnyContext):
|
|
80
83
|
group=git_subtree_group,
|
81
84
|
alias="push",
|
82
85
|
)
|
83
|
-
def git_push_subtree(ctx: AnyContext):
|
84
|
-
repo_dir = get_repo_dir()
|
86
|
+
async def git_push_subtree(ctx: AnyContext):
|
87
|
+
repo_dir = await get_repo_dir(log_method=ctx.print)
|
85
88
|
config = load_config(repo_dir)
|
86
89
|
if not config.data:
|
87
90
|
raise ValueError("No subtree config found")
|
88
91
|
first_err: Exception | None = None
|
89
92
|
for name, detail in config.data.items():
|
90
93
|
try:
|
91
|
-
ctx.print(f"Push to subtree {name}")
|
92
|
-
push_subtree(
|
94
|
+
ctx.print(stylize_faint(f"Push to subtree {name}"))
|
95
|
+
await push_subtree(
|
93
96
|
repo_dir=repo_dir,
|
94
97
|
prefix=detail.prefix,
|
95
98
|
repo_url=detail.repo_url,
|
96
99
|
branch=detail.branch,
|
100
|
+
log_method=ctx.print,
|
97
101
|
)
|
98
102
|
except Exception as e:
|
99
103
|
if first_err is None:
|
@@ -1,6 +1,4 @@
|
|
1
|
-
import asyncio
|
2
1
|
import os
|
3
|
-
import sys
|
4
2
|
|
5
3
|
from zrb.attr.type import BoolAttr, IntAttr, StrAttr
|
6
4
|
from zrb.cmd.cmd_result import CmdResult
|
@@ -12,7 +10,7 @@ from zrb.input.any_input import AnyInput
|
|
12
10
|
from zrb.task.any_task import AnyTask
|
13
11
|
from zrb.task.base_task import BaseTask
|
14
12
|
from zrb.util.attr import get_int_attr, get_str_attr
|
15
|
-
from zrb.util.cmd.command import check_unrecommended_commands
|
13
|
+
from zrb.util.cmd.command import check_unrecommended_commands, run_command
|
16
14
|
from zrb.util.cmd.remote import get_remote_cmd_script
|
17
15
|
|
18
16
|
|
@@ -119,43 +117,25 @@ class CmdTask(BaseTask):
|
|
119
117
|
ctx.log_debug(f"Working directory: {cwd}")
|
120
118
|
env_map = self.__get_env_map(ctx)
|
121
119
|
ctx.log_debug(f"Environment map: {env_map}")
|
122
|
-
cmd_process = None
|
123
120
|
if self._get_should_warn_unrecommended_commands():
|
124
121
|
self._check_unrecommended_commands(ctx, shell, cmd_script)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
self.__read_stream(cmd_process.stdout, ctx.print, self._max_output_line)
|
140
|
-
)
|
141
|
-
stderr_task = asyncio.create_task(
|
142
|
-
self.__read_stream(cmd_process.stderr, ctx.print, self._max_error_line)
|
122
|
+
ctx.log_info("Running script")
|
123
|
+
cmd_result, return_code = await run_command(
|
124
|
+
cmd=[shell, shell_flag, cmd_script],
|
125
|
+
cwd=cwd,
|
126
|
+
env_map=env_map,
|
127
|
+
log_method=ctx.print,
|
128
|
+
max_output_line=self._max_output_line,
|
129
|
+
max_error_line=self._max_error_line,
|
130
|
+
)
|
131
|
+
# Check for errors
|
132
|
+
if return_code != 0:
|
133
|
+
ctx.log_error(f"Exit status: {return_code}")
|
134
|
+
raise Exception(
|
135
|
+
f"Process {self._name} exited ({return_code}): {cmd_result.stderr}"
|
143
136
|
)
|
144
|
-
|
145
|
-
|
146
|
-
stdout = await stdout_task
|
147
|
-
stderr = await stderr_task
|
148
|
-
# Check for errors
|
149
|
-
if return_code != 0:
|
150
|
-
ctx.log_error(f"Exit status: {return_code}")
|
151
|
-
raise Exception(
|
152
|
-
f"Process {self._name} exited ({return_code}): {stderr}"
|
153
|
-
)
|
154
|
-
ctx.log_info(f"Exit status: {return_code}")
|
155
|
-
return CmdResult(stdout, stderr)
|
156
|
-
finally:
|
157
|
-
if cmd_process is not None and cmd_process.returncode is None:
|
158
|
-
cmd_process.terminate()
|
137
|
+
ctx.log_info(f"Exit status: {return_code}")
|
138
|
+
return cmd_result
|
159
139
|
|
160
140
|
def _get_should_warn_unrecommended_commands(self):
|
161
141
|
if self._should_warn_unrecommended_command is None:
|
@@ -178,19 +158,6 @@ class CmdTask(BaseTask):
|
|
178
158
|
envs["PYTHONBUFFERED"] = "1"
|
179
159
|
return envs
|
180
160
|
|
181
|
-
async def __read_stream(self, stream, log_method, max_lines):
|
182
|
-
lines = []
|
183
|
-
while True:
|
184
|
-
line = await stream.readline()
|
185
|
-
if not line:
|
186
|
-
break
|
187
|
-
line = line.decode("utf-8").rstrip()
|
188
|
-
lines.append(line)
|
189
|
-
if len(lines) > max_lines:
|
190
|
-
lines.pop(0) # Keep only the last max_lines
|
191
|
-
log_method(line)
|
192
|
-
return "\n".join(lines)
|
193
|
-
|
194
161
|
def _get_shell(self, ctx: AnyContext) -> str:
|
195
162
|
return get_str_attr(
|
196
163
|
ctx, self._shell, DEFAULT_SHELL, auto_render=self._render_shell
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import asyncio
|
2
|
+
import os
|
3
|
+
import re
|
4
|
+
import sys
|
5
|
+
from collections.abc import Callable
|
6
|
+
|
7
|
+
from zrb.cmd.cmd_result import CmdResult
|
8
|
+
|
9
|
+
|
10
|
+
def check_unrecommended_commands(cmd_script: str) -> dict[str, str]:
|
11
|
+
banned_commands = {
|
12
|
+
"<(": "Process substitution isn't POSIX compliant and causes trouble",
|
13
|
+
"column": "Command isn't included in Ubuntu packages and is not POSIX compliant",
|
14
|
+
"echo": "echo isn't consistent across OS; use printf instead",
|
15
|
+
"eval": "Avoid eval as it can accidentally execute arbitrary strings",
|
16
|
+
"realpath": "Not available by default on OSX",
|
17
|
+
"source": "Not POSIX compliant; use '.' instead",
|
18
|
+
" test": "Use '[' instead for consistency",
|
19
|
+
"which": "Command in not POSIX compliant, use command -v",
|
20
|
+
}
|
21
|
+
banned_commands_regex = {
|
22
|
+
r"grep.* -y": "grep -y does not work on Alpine; use grep -i",
|
23
|
+
r"grep.* -P": "grep -P is not valid on OSX",
|
24
|
+
r"grep[^|]+--\w{2,}": "grep long commands do not work on Alpine",
|
25
|
+
r'readlink.+-.*f.+["$]': "readlink -f behaves differently on OSX",
|
26
|
+
r"sort.*-V": "sort -V is not supported everywhere",
|
27
|
+
r"sort.*--sort-versions": "sort --sort-version is not supported everywhere",
|
28
|
+
r"\bls ": "Avoid using ls; use shell globs or find instead",
|
29
|
+
}
|
30
|
+
violations = {}
|
31
|
+
# Check banned commands
|
32
|
+
for cmd, reason in banned_commands.items():
|
33
|
+
if cmd in cmd_script:
|
34
|
+
violations[cmd] = reason
|
35
|
+
# Check banned regex patterns
|
36
|
+
for pattern, reason in banned_commands_regex.items():
|
37
|
+
if re.search(pattern, cmd_script):
|
38
|
+
violations[pattern] = reason
|
39
|
+
return violations
|
40
|
+
|
41
|
+
|
42
|
+
async def run_command(
|
43
|
+
cmd: list[str],
|
44
|
+
cwd: str | None = None,
|
45
|
+
env_map: dict[str, str] | None = None,
|
46
|
+
log_method: Callable[..., None] = print,
|
47
|
+
max_output_line: int = 1000,
|
48
|
+
max_error_line: int = 1000,
|
49
|
+
) -> tuple[CmdResult, int]:
|
50
|
+
|
51
|
+
async def __read_stream(
|
52
|
+
stream, log_method: Callable[..., None], max_lines: int
|
53
|
+
) -> str:
|
54
|
+
lines = []
|
55
|
+
while True:
|
56
|
+
line = await stream.readline()
|
57
|
+
if not line:
|
58
|
+
break
|
59
|
+
line = line.decode("utf-8").rstrip()
|
60
|
+
lines.append(line)
|
61
|
+
if len(lines) > max_lines:
|
62
|
+
lines.pop(0) # Keep only the last max_lines
|
63
|
+
log_method(line)
|
64
|
+
return "\n".join(lines)
|
65
|
+
|
66
|
+
try:
|
67
|
+
if cwd is None:
|
68
|
+
cwd = os.getcwd()
|
69
|
+
if env_map is None:
|
70
|
+
env_map = os.environ
|
71
|
+
cmd_process = await asyncio.create_subprocess_exec(
|
72
|
+
*cmd,
|
73
|
+
cwd=cwd,
|
74
|
+
stdin=sys.stdin if sys.stdin.isatty() else None,
|
75
|
+
stdout=asyncio.subprocess.PIPE,
|
76
|
+
stderr=asyncio.subprocess.PIPE,
|
77
|
+
env=env_map,
|
78
|
+
bufsize=0,
|
79
|
+
)
|
80
|
+
stdout_task = asyncio.create_task(
|
81
|
+
__read_stream(cmd_process.stdout, log_method, max_output_line)
|
82
|
+
)
|
83
|
+
stderr_task = asyncio.create_task(
|
84
|
+
__read_stream(cmd_process.stderr, log_method, max_error_line)
|
85
|
+
)
|
86
|
+
# Wait for process to complete and gather stdout/stderr
|
87
|
+
return_code = await cmd_process.wait()
|
88
|
+
stdout = await stdout_task
|
89
|
+
stderr = await stderr_task
|
90
|
+
return CmdResult(stdout, stderr), return_code
|
91
|
+
finally:
|
92
|
+
if cmd_process is not None and cmd_process.returncode is None:
|
93
|
+
cmd_process.terminate()
|
@@ -0,0 +1,156 @@
|
|
1
|
+
import os
|
2
|
+
from collections.abc import Callable
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from pydantic import BaseModel
|
6
|
+
|
7
|
+
from zrb.util.cmd.command import run_command
|
8
|
+
|
9
|
+
|
10
|
+
class DiffResult(BaseModel):
|
11
|
+
created: list[str]
|
12
|
+
removed: list[str]
|
13
|
+
updated: list[str]
|
14
|
+
|
15
|
+
|
16
|
+
async def get_diff(
|
17
|
+
repo_dir: str,
|
18
|
+
source_commit: str,
|
19
|
+
current_commit: str,
|
20
|
+
log_method: Callable[..., Any] = print,
|
21
|
+
) -> DiffResult:
|
22
|
+
cmd_result, exit_code = await run_command(
|
23
|
+
cmd=["git", "diff", source_commit, current_commit],
|
24
|
+
cwd=repo_dir,
|
25
|
+
log_method=log_method,
|
26
|
+
)
|
27
|
+
if exit_code != 0:
|
28
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
29
|
+
lines = cmd_result.output.strip().split("\n")
|
30
|
+
diff: dict[str, dict[str, bool]] = {}
|
31
|
+
for line in lines:
|
32
|
+
if not line.startswith("---") and not line.startswith("+++"):
|
33
|
+
continue
|
34
|
+
if line[4:6] != "a/" and line[4:6] != "b/":
|
35
|
+
continue
|
36
|
+
# line should contains something like `--- a/some-file.txt`
|
37
|
+
file = line[6:]
|
38
|
+
if file not in diff:
|
39
|
+
diff[file] = {"plus": False, "minus": False}
|
40
|
+
if line.startswith("---"):
|
41
|
+
diff[file]["minus"] = True
|
42
|
+
if line.startswith("+++"):
|
43
|
+
diff[file]["plus"] = True
|
44
|
+
return DiffResult(
|
45
|
+
created=[
|
46
|
+
file for file, state in diff.items() if state["plus"] and not state["minus"]
|
47
|
+
],
|
48
|
+
removed=[
|
49
|
+
file for file, state in diff.items() if not state["plus"] and state["minus"]
|
50
|
+
],
|
51
|
+
updated=[
|
52
|
+
file for file, state in diff.items() if state["plus"] and state["minus"]
|
53
|
+
],
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
async def get_repo_dir(log_method: Callable[..., Any] = print) -> str:
|
58
|
+
cmd_result, exit_code = await run_command(
|
59
|
+
cmd=["git", "rev-parse", "--show-toplevel"],
|
60
|
+
log_method=log_method,
|
61
|
+
)
|
62
|
+
if exit_code != 0:
|
63
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
64
|
+
return os.path.abspath(cmd_result.output.strip())
|
65
|
+
|
66
|
+
|
67
|
+
async def get_current_branch(
|
68
|
+
repo_dir: str, log_method: Callable[..., Any] = print
|
69
|
+
) -> str:
|
70
|
+
cmd_result, exit_code = await run_command(
|
71
|
+
cmd=["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
72
|
+
cwd=repo_dir,
|
73
|
+
log_method=log_method,
|
74
|
+
)
|
75
|
+
if exit_code != 0:
|
76
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
77
|
+
return cmd_result.output.strip()
|
78
|
+
|
79
|
+
|
80
|
+
async def get_branches(
|
81
|
+
repo_dir: str, log_method: Callable[..., Any] = print
|
82
|
+
) -> list[str]:
|
83
|
+
cmd_result, exit_code = await run_command(
|
84
|
+
cmd=["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
85
|
+
cwd=repo_dir,
|
86
|
+
log_method=log_method,
|
87
|
+
)
|
88
|
+
if exit_code != 0:
|
89
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
90
|
+
return [
|
91
|
+
branch.lstrip("*").strip() for branch in cmd_result.output.strip().split("\n")
|
92
|
+
]
|
93
|
+
|
94
|
+
|
95
|
+
async def delete_branch(
|
96
|
+
repo_dir: str, branch_name: str, log_method: Callable[..., Any] = print
|
97
|
+
) -> str:
|
98
|
+
cmd_result, exit_code = await run_command(
|
99
|
+
cmd=["git", "branch", "-D", branch_name],
|
100
|
+
cwd=repo_dir,
|
101
|
+
log_method=log_method,
|
102
|
+
)
|
103
|
+
if exit_code != 0:
|
104
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
105
|
+
return cmd_result.output.strip()
|
106
|
+
|
107
|
+
|
108
|
+
async def add(repo_dir: str, log_method: Callable[..., Any] = print):
|
109
|
+
_, exit_code = await run_command(
|
110
|
+
cmd=["git", "add", ".", "-A"],
|
111
|
+
cwd=repo_dir,
|
112
|
+
log_method=log_method,
|
113
|
+
)
|
114
|
+
if exit_code != 0:
|
115
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
116
|
+
|
117
|
+
|
118
|
+
async def commit(
|
119
|
+
repo_dir: str, message: str, log_method: Callable[..., Any] = print
|
120
|
+
) -> str:
|
121
|
+
cmd_result, exit_code = await run_command(
|
122
|
+
cmd=["git", "commit", "-m", message],
|
123
|
+
cwd=repo_dir,
|
124
|
+
log_method=log_method,
|
125
|
+
)
|
126
|
+
if exit_code != 0:
|
127
|
+
ignored_error_message = "nothing to commit, working tree clean"
|
128
|
+
if (
|
129
|
+
ignored_error_message not in cmd_result.error
|
130
|
+
and ignored_error_message not in cmd_result.output
|
131
|
+
):
|
132
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
133
|
+
|
134
|
+
|
135
|
+
async def pull(
|
136
|
+
repo_dir: str, remote: str, branch: str, log_method: Callable[..., Any] = print
|
137
|
+
) -> str:
|
138
|
+
_, exit_code = await run_command(
|
139
|
+
cmd=["git", "pull", remote, branch],
|
140
|
+
cwd=repo_dir,
|
141
|
+
log_method=log_method,
|
142
|
+
)
|
143
|
+
if exit_code != 0:
|
144
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
145
|
+
|
146
|
+
|
147
|
+
async def push(
|
148
|
+
repo_dir: str, remote: str, branch: str, log_method: Callable[..., Any] = print
|
149
|
+
) -> str:
|
150
|
+
_, exit_code = await run_command(
|
151
|
+
cmd=["git", "push", "-u", remote, branch],
|
152
|
+
cwd=repo_dir,
|
153
|
+
log_method=log_method,
|
154
|
+
)
|
155
|
+
if exit_code != 0:
|
156
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import os
|
2
|
+
from collections.abc import Callable
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from pydantic import BaseModel
|
6
|
+
|
7
|
+
from zrb.util.cmd.command import run_command
|
8
|
+
|
9
|
+
|
10
|
+
class SingleSubTreeConfig(BaseModel):
|
11
|
+
repo_url: str
|
12
|
+
branch: str
|
13
|
+
prefix: str
|
14
|
+
|
15
|
+
|
16
|
+
class SubTreeConfig(BaseModel):
|
17
|
+
data: dict[str, SingleSubTreeConfig]
|
18
|
+
|
19
|
+
|
20
|
+
def load_config(repo_dir: str) -> SubTreeConfig:
|
21
|
+
file_path = os.path.join(repo_dir, "subtrees.json")
|
22
|
+
if not os.path.exists(file_path):
|
23
|
+
return SubTreeConfig(data={})
|
24
|
+
with open(file_path, "r") as f:
|
25
|
+
return SubTreeConfig.model_validate_json(f.read())
|
26
|
+
|
27
|
+
|
28
|
+
def save_config(repo_dir: str, config: SubTreeConfig):
|
29
|
+
file_path = os.path.join(repo_dir, "subtrees.json")
|
30
|
+
with open(file_path, "w") as f:
|
31
|
+
f.write(config.model_dump_json(indent=2))
|
32
|
+
|
33
|
+
|
34
|
+
async def add_subtree(
|
35
|
+
repo_dir: str,
|
36
|
+
name: str,
|
37
|
+
repo_url: str,
|
38
|
+
branch: str,
|
39
|
+
prefix: str,
|
40
|
+
log_method: Callable[..., Any] = print,
|
41
|
+
):
|
42
|
+
config = load_config()
|
43
|
+
if os.path.isdir(prefix):
|
44
|
+
raise ValueError(f"Directory exists: {prefix}")
|
45
|
+
if name in config.data:
|
46
|
+
raise ValueError(f"Subtree config already exists: {name}")
|
47
|
+
_, exit_code = await run_command(
|
48
|
+
cmd=[
|
49
|
+
"git",
|
50
|
+
"subtree",
|
51
|
+
"add",
|
52
|
+
"--prefix",
|
53
|
+
prefix,
|
54
|
+
repo_url,
|
55
|
+
branch,
|
56
|
+
],
|
57
|
+
cwd=repo_dir,
|
58
|
+
log_method=log_method,
|
59
|
+
)
|
60
|
+
if exit_code != 0:
|
61
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
62
|
+
config.data[name] = SingleSubTreeConfig(
|
63
|
+
repo_url=repo_url, branch=branch, prefix=prefix
|
64
|
+
)
|
65
|
+
save_config(repo_dir, config)
|
66
|
+
|
67
|
+
|
68
|
+
async def pull_subtree(
|
69
|
+
repo_dir: str,
|
70
|
+
prefix: str,
|
71
|
+
repo_url: str,
|
72
|
+
branch: str,
|
73
|
+
log_method: Callable[..., Any] = print,
|
74
|
+
):
|
75
|
+
_, exit_code = await run_command(
|
76
|
+
cmd=[
|
77
|
+
"git",
|
78
|
+
"subtree",
|
79
|
+
"pull",
|
80
|
+
"--prefix",
|
81
|
+
prefix,
|
82
|
+
repo_url,
|
83
|
+
branch,
|
84
|
+
],
|
85
|
+
cwd=repo_dir,
|
86
|
+
log_method=log_method,
|
87
|
+
)
|
88
|
+
if exit_code != 0:
|
89
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
90
|
+
|
91
|
+
|
92
|
+
async def push_subtree(
|
93
|
+
repo_dir: str,
|
94
|
+
prefix: str,
|
95
|
+
repo_url: str,
|
96
|
+
branch: str,
|
97
|
+
log_method: Callable[..., Any] = print,
|
98
|
+
):
|
99
|
+
_, exit_code = await run_command(
|
100
|
+
cmd=[
|
101
|
+
"git",
|
102
|
+
"subtree",
|
103
|
+
"push",
|
104
|
+
"--prefix",
|
105
|
+
prefix,
|
106
|
+
repo_url,
|
107
|
+
branch,
|
108
|
+
],
|
109
|
+
cwd=repo_dir,
|
110
|
+
log_method=log_method,
|
111
|
+
)
|
112
|
+
if exit_code != 0:
|
113
|
+
raise Exception(f"Non zero exit code: {exit_code}")
|
@@ -1,33 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
|
3
|
-
|
4
|
-
def check_unrecommended_commands(cmd_script: str) -> dict[str, str]:
|
5
|
-
banned_commands = {
|
6
|
-
"<(": "Process substitution isn't POSIX compliant and causes trouble",
|
7
|
-
"column": "Command isn't included in Ubuntu packages and is not POSIX compliant",
|
8
|
-
"echo": "echo isn't consistent across OS; use printf instead",
|
9
|
-
"eval": "Avoid eval as it can accidentally execute arbitrary strings",
|
10
|
-
"realpath": "Not available by default on OSX",
|
11
|
-
"source": "Not POSIX compliant; use '.' instead",
|
12
|
-
" test": "Use '[' instead for consistency",
|
13
|
-
"which": "Command in not POSIX compliant, use command -v",
|
14
|
-
}
|
15
|
-
banned_commands_regex = {
|
16
|
-
r"grep.* -y": "grep -y does not work on Alpine; use grep -i",
|
17
|
-
r"grep.* -P": "grep -P is not valid on OSX",
|
18
|
-
r"grep[^|]+--\w{2,}": "grep long commands do not work on Alpine",
|
19
|
-
r'readlink.+-.*f.+["$]': "readlink -f behaves differently on OSX",
|
20
|
-
r"sort.*-V": "sort -V is not supported everywhere",
|
21
|
-
r"sort.*--sort-versions": "sort --sort-version is not supported everywhere",
|
22
|
-
r"\bls ": "Avoid using ls; use shell globs or find instead",
|
23
|
-
}
|
24
|
-
violations = {}
|
25
|
-
# Check banned commands
|
26
|
-
for cmd, reason in banned_commands.items():
|
27
|
-
if cmd in cmd_script:
|
28
|
-
violations[cmd] = reason
|
29
|
-
# Check banned regex patterns
|
30
|
-
for pattern, reason in banned_commands_regex.items():
|
31
|
-
if re.search(pattern, cmd_script):
|
32
|
-
violations[pattern] = reason
|
33
|
-
return violations
|