railmux 0.4.0.dev27__tar.gz → 0.4.0.dev28__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.
- {railmux-0.4.0.dev27/src/railmux.egg-info → railmux-0.4.0.dev28}/PKG-INFO +1 -1
- railmux-0.4.0.dev28/src/railmux/__init__.py +1 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_install_log.py +12 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_msys2.py +155 -23
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28/src/railmux.egg-info}/PKG-INFO +1 -1
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_install_log.py +16 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_msys2.py +110 -1
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tools/windows_archive_smoke.py +18 -0
- railmux-0.4.0.dev27/src/railmux/__init__.py +0 -1
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/LICENSE +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/MANIFEST.in +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/README.md +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/pyproject.toml +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/setup.cfg +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/__main__.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/atomic_file.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/background_index.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/cli.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/codex_index.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/config.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/config_cli.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/diagnostics.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/discovery.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/display_transport.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/entrypoint.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/fast_display_client.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/fast_display_history.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/fast_display_input.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/fast_display_protocol.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/fast_display_server.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/favorites.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/fuzzy.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/help_workspace.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/launcher.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/legacy_sessions.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/local_clipboard.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/local_open.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/models.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/modes.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/mouse_manager.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/orphan_marker.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/pane_surface.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/path_codec.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/provider_paths.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/remote_config.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/renames.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/restart_state.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/runtime_config.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/scroll_agent.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/scroll_manager.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/selection_isolation.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/self_update.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/session_cache.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/session_index.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/session_lease.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/setting_contracts.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/settings.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ssh_args.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ssh_compat.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ssh_display_diagnostics.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ssh_doctor.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/system_deps.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/terminal_status.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/tmux_binding_manager.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/tmux_ctl.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/tmux_health.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/tmux_server.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/tool_panes.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/transcript.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/__init__.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/_widgets.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/app.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/keymap.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/modals.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/projects_pane.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/running_pane.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/sessions_pane.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/sidebar.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/statusbar.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/ui/workspace.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_attach_relay.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_bootstrap.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_pacman.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_tmux_lifecycle.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux/windows_ui_transition.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux.egg-info/SOURCES.txt +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux.egg-info/dependency_links.txt +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux.egg-info/entry_points.txt +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux.egg-info/requires.txt +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/src/railmux.egg-info/top_level.txt +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_agent_workspace.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_atomic_file.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_background_index.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_cli.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_codex_delete.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_codex_index.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_codex_lineage.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_codex_transcript.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_config.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_config_cli.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_denested_transport_benchmark.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_diagnostics.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_discovery.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_display_transport.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_fast_full_window.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_focus_highlight.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_fullscreen_binding.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_fuzzy.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_help_agent.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_help_workspace.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_history_cleanup.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_keymap.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_launcher.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_layout_profile.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_legacy_sessions.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_local_clipboard.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_local_open.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_modals.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_mode_selection.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_modes.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_mouse_manager.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_new_project.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_options.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_orphan_recovery.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_pane_surface.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_path_codec.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_projects_pane.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_provider_paths.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_release_notes.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_release_workflow.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_remote_config.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_renames.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_restart_state.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_running_pane.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_running_sort.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_runtime_config.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_scroll_agent.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_scroll_manager.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_selection_isolation.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_self_update.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_session_cache.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_session_index.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_session_lease.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_sessions_pane.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_setting_contracts.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_settings.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_sidebar.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_soft_quit.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_ssh_args.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_ssh_compat.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_ssh_display_benchmark.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_ssh_display_diagnostics.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_ssh_doctor.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_status.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_statusbar.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_system_deps.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_terminal_size.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_terminal_status.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_termux_local_touch.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tmux_binding_manager.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tmux_ctl.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tmux_health.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tmux_integration.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tmux_server.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tmux_status.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_tool_panes.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_transcript.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_utf8_state.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_web_demo_recorder.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_wheel_smoke.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_widgets.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_attach_relay.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_bootstrap.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_pacman.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_tmux_lifecycle.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_ui_transition.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_windows_wrapper_contract.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tests/test_yolo_prompt.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tools/denested_transport_benchmark.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tools/release_notes.py +0 -0
- {railmux-0.4.0.dev27 → railmux-0.4.0.dev28}/tools/wheel_smoke.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.0.dev28"
|
|
@@ -56,6 +56,10 @@ _PIP_NETWORK_ERROR_MARKERS = (
|
|
|
56
56
|
"connection aborted",
|
|
57
57
|
"temporary failure in name resolution",
|
|
58
58
|
)
|
|
59
|
+
_MSYS2_RESTART_MARKER = (
|
|
60
|
+
"to complete this update all msys2 processes including this terminal "
|
|
61
|
+
"will be closed"
|
|
62
|
+
)
|
|
59
63
|
_EXTRACTION_PERCENT_RE = re.compile(r"(?:^|\s)([0-9]{1,3})%\s")
|
|
60
64
|
_PACKAGE_COUNT_RE = re.compile(r"^Packages \(([0-9]+)\)")
|
|
61
65
|
_PACKAGE_DOWNLOAD_RE = re.compile(r"^\s*([^ ]+) downloading\.\.\.\s*$")
|
|
@@ -142,6 +146,7 @@ class InstallReporter:
|
|
|
142
146
|
self._network_failure = False
|
|
143
147
|
self._pip_network_failure = False
|
|
144
148
|
self._hard_failed_hosts: set[str] = set()
|
|
149
|
+
self._msys2_restart_requested = False
|
|
145
150
|
|
|
146
151
|
def __enter__(self) -> InstallReporter:
|
|
147
152
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -209,6 +214,7 @@ class InstallReporter:
|
|
|
209
214
|
self._network_failure = False
|
|
210
215
|
self._pip_network_failure = False
|
|
211
216
|
self._hard_failed_hosts.clear()
|
|
217
|
+
self._msys2_restart_requested = False
|
|
212
218
|
self._write_log(f"\n--- {label} ---\n")
|
|
213
219
|
|
|
214
220
|
def command_output(self, output: bytes | str | None) -> None:
|
|
@@ -259,6 +265,8 @@ class InstallReporter:
|
|
|
259
265
|
if line.strip():
|
|
260
266
|
self._tail.append(line)
|
|
261
267
|
lowered = line.lower()
|
|
268
|
+
if _MSYS2_RESTART_MARKER in lowered:
|
|
269
|
+
self._msys2_restart_requested = True
|
|
262
270
|
if any(marker in lowered for marker in _NETWORK_ERROR_MARKERS):
|
|
263
271
|
self._network_failure = True
|
|
264
272
|
if any(marker in lowered for marker in _PIP_NETWORK_ERROR_MARKERS):
|
|
@@ -364,6 +372,10 @@ class InstallReporter:
|
|
|
364
372
|
def hard_failed_mirror_hosts(self) -> frozenset[str]:
|
|
365
373
|
return frozenset(self._hard_failed_hosts)
|
|
366
374
|
|
|
375
|
+
@property
|
|
376
|
+
def command_requested_msys2_restart(self) -> bool:
|
|
377
|
+
return self._msys2_restart_requested
|
|
378
|
+
|
|
367
379
|
def heartbeat(self) -> None:
|
|
368
380
|
now = self._clock()
|
|
369
381
|
if now - self._last_heartbeat < _HEARTBEAT_SECONDS:
|
|
@@ -119,6 +119,10 @@ _PACKAGE_URL_COMMAND = (
|
|
|
119
119
|
_PACKAGE_INVENTORY_COMMAND = "set -o pipefail; pacman -Q | LC_ALL=C sort"
|
|
120
120
|
_PACKAGE_INVENTORY_LIMIT = 1024 * 1024
|
|
121
121
|
_CORE_RUNTIME_PACKAGES = ("tmux", "python", "python-pip")
|
|
122
|
+
_MAX_BASE_UPDATE_PASSES = 3
|
|
123
|
+
_PRIVATE_GPG_SHUTDOWN_COMMAND = (
|
|
124
|
+
"gpgconf --homedir /etc/pacman.d/gnupg --kill all"
|
|
125
|
+
)
|
|
122
126
|
_IN_USE_APPS_COMMAND = (
|
|
123
127
|
"for f in /proc/[0-9]*/cmdline; do "
|
|
124
128
|
"[ -r \"$f\" ] || continue; tr '\\0' '\\n' <\"$f\"; done"
|
|
@@ -1624,18 +1628,23 @@ def _run_checked(
|
|
|
1624
1628
|
if returncode:
|
|
1625
1629
|
if allow_failure:
|
|
1626
1630
|
return returncode
|
|
1627
|
-
|
|
1628
|
-
reporter.note(
|
|
1629
|
-
"Windows reported STATUS_DLL_NOT_FOUND. Check whether security "
|
|
1630
|
-
"software quarantined a file in the private MSYS2 staging tree.",
|
|
1631
|
-
level="error",
|
|
1632
|
-
)
|
|
1631
|
+
_explain_windows_status(returncode, reporter)
|
|
1633
1632
|
reporter.command_failed(label, returncode)
|
|
1634
1633
|
raise RuntimeInstallError(f"{label} failed with exit code {returncode}")
|
|
1635
1634
|
reporter.command_succeeded()
|
|
1636
1635
|
return 0
|
|
1637
1636
|
|
|
1638
1637
|
|
|
1638
|
+
def _explain_windows_status(returncode: int, reporter: InstallReporter) -> None:
|
|
1639
|
+
if _NATIVE_WINDOWS and returncode & 0xFFFFFFFF == 0xC0000135:
|
|
1640
|
+
reporter.note(
|
|
1641
|
+
"Windows reported STATUS_DLL_NOT_FOUND outside a confirmed MSYS2 "
|
|
1642
|
+
"core-update restart. Check whether security software quarantined "
|
|
1643
|
+
"a file in the private MSYS2 staging tree.",
|
|
1644
|
+
level="error",
|
|
1645
|
+
)
|
|
1646
|
+
|
|
1647
|
+
|
|
1639
1648
|
def _pacman_command(*, packages: bool, relaxed: bool) -> str:
|
|
1640
1649
|
timeout = " --disable-download-timeout" if relaxed else ""
|
|
1641
1650
|
needed = f" --needed {_PACMAN_PACKAGES}" if packages else ""
|
|
@@ -1644,10 +1653,11 @@ def _pacman_command(*, packages: bool, relaxed: bool) -> str:
|
|
|
1644
1653
|
if not packages
|
|
1645
1654
|
else ""
|
|
1646
1655
|
)
|
|
1656
|
+
operation = "-Syu" if packages else "-Syuu"
|
|
1647
1657
|
return (
|
|
1648
1658
|
'cache=$(cygpath -u "$1") && mkdir -p "$cache" && '
|
|
1649
1659
|
f"{keyring}pacman --config {_PACMAN_CONFIG} --cachedir \"$cache\" "
|
|
1650
|
-
f"
|
|
1660
|
+
f"{operation} --noconfirm{timeout}{needed}"
|
|
1651
1661
|
)
|
|
1652
1662
|
|
|
1653
1663
|
|
|
@@ -1693,7 +1703,8 @@ def _run_pacman_with_recovery(
|
|
|
1693
1703
|
runner: Runner | None,
|
|
1694
1704
|
label: str,
|
|
1695
1705
|
mirror_optimizer: MirrorOptimizer,
|
|
1696
|
-
|
|
1706
|
+
allow_core_restart: bool = False,
|
|
1707
|
+
) -> bool:
|
|
1697
1708
|
argv = _bash_command(root, _pacman_command(packages=packages, relaxed=False), str(cache))
|
|
1698
1709
|
returncode = _run_checked(
|
|
1699
1710
|
argv,
|
|
@@ -1704,11 +1715,20 @@ def _run_pacman_with_recovery(
|
|
|
1704
1715
|
progress="pacman",
|
|
1705
1716
|
allow_failure=True,
|
|
1706
1717
|
)
|
|
1718
|
+
restart_requested = reporter.command_requested_msys2_restart
|
|
1707
1719
|
if returncode == 0:
|
|
1708
|
-
return
|
|
1720
|
+
return restart_requested
|
|
1721
|
+
if allow_core_restart and not packages and restart_requested:
|
|
1722
|
+
reporter.note(
|
|
1723
|
+
"MSYS2 replaced core runtime files and closed its own process as "
|
|
1724
|
+
"expected; continuing from a fresh Windows-launched shell.",
|
|
1725
|
+
level="warning",
|
|
1726
|
+
)
|
|
1727
|
+
return True
|
|
1709
1728
|
network_failure = reporter.command_had_network_failure
|
|
1710
1729
|
hard_failed_hosts = reporter.hard_failed_mirror_hosts
|
|
1711
1730
|
if not network_failure:
|
|
1731
|
+
_explain_windows_status(returncode, reporter)
|
|
1712
1732
|
reporter.command_failed(label, returncode)
|
|
1713
1733
|
raise RuntimeInstallError(f"{label} failed with exit code {returncode}")
|
|
1714
1734
|
reporter.note(
|
|
@@ -1739,13 +1759,112 @@ def _run_pacman_with_recovery(
|
|
|
1739
1759
|
_pacman_command(packages=packages, relaxed=True),
|
|
1740
1760
|
str(cache),
|
|
1741
1761
|
)
|
|
1742
|
-
_run_checked(
|
|
1762
|
+
retry_returncode = _run_checked(
|
|
1743
1763
|
retry_argv,
|
|
1744
1764
|
env=env,
|
|
1745
1765
|
reporter=reporter,
|
|
1746
1766
|
runner=runner,
|
|
1747
1767
|
label=f"{label} resilient retry",
|
|
1748
1768
|
progress="pacman",
|
|
1769
|
+
allow_failure=True,
|
|
1770
|
+
)
|
|
1771
|
+
restart_requested = reporter.command_requested_msys2_restart
|
|
1772
|
+
if retry_returncode == 0:
|
|
1773
|
+
return restart_requested
|
|
1774
|
+
if allow_core_restart and not packages and restart_requested:
|
|
1775
|
+
reporter.note(
|
|
1776
|
+
"MSYS2 replaced core runtime files and closed its own process as "
|
|
1777
|
+
"expected; continuing from a fresh Windows-launched shell.",
|
|
1778
|
+
level="warning",
|
|
1779
|
+
)
|
|
1780
|
+
return True
|
|
1781
|
+
_explain_windows_status(retry_returncode, reporter)
|
|
1782
|
+
reporter.command_failed(f"{label} resilient retry", retry_returncode)
|
|
1783
|
+
raise RuntimeInstallError(
|
|
1784
|
+
f"{label} resilient retry failed with exit code {retry_returncode}"
|
|
1785
|
+
)
|
|
1786
|
+
|
|
1787
|
+
|
|
1788
|
+
def _run_base_update_with_restarts(
|
|
1789
|
+
root: Path,
|
|
1790
|
+
*,
|
|
1791
|
+
cache: Path,
|
|
1792
|
+
env: Mapping[str, str],
|
|
1793
|
+
reporter: InstallReporter,
|
|
1794
|
+
runner: Runner | None,
|
|
1795
|
+
mirror_optimizer: MirrorOptimizer,
|
|
1796
|
+
) -> None:
|
|
1797
|
+
"""Run MSYS2's full upgrade in fresh processes until restart-safe."""
|
|
1798
|
+
try:
|
|
1799
|
+
for pass_number in range(1, _MAX_BASE_UPDATE_PASSES + 1):
|
|
1800
|
+
restart_requested = _run_pacman_with_recovery(
|
|
1801
|
+
root,
|
|
1802
|
+
packages=False,
|
|
1803
|
+
cache=cache,
|
|
1804
|
+
env=env,
|
|
1805
|
+
reporter=reporter,
|
|
1806
|
+
runner=runner,
|
|
1807
|
+
label=f"MSYS2 base update pass {pass_number}",
|
|
1808
|
+
mirror_optimizer=mirror_optimizer,
|
|
1809
|
+
allow_core_restart=pass_number < _MAX_BASE_UPDATE_PASSES,
|
|
1810
|
+
)
|
|
1811
|
+
if restart_requested:
|
|
1812
|
+
reporter.note(
|
|
1813
|
+
"Starting a new MSYS2 process for the remaining update…"
|
|
1814
|
+
)
|
|
1815
|
+
continue
|
|
1816
|
+
if pass_number == 1:
|
|
1817
|
+
# MSYS2's supported unattended update procedure invokes Syuu
|
|
1818
|
+
# twice, even when the first pass did not request a restart.
|
|
1819
|
+
reporter.note(
|
|
1820
|
+
"Starting the required second MSYS2 update pass in a new "
|
|
1821
|
+
"process…"
|
|
1822
|
+
)
|
|
1823
|
+
continue
|
|
1824
|
+
return
|
|
1825
|
+
raise RuntimeInstallError(
|
|
1826
|
+
"MSYS2 repeatedly requested a core-runtime restart; the temporary "
|
|
1827
|
+
"base was not published"
|
|
1828
|
+
)
|
|
1829
|
+
finally:
|
|
1830
|
+
_stop_private_gpg_agents(
|
|
1831
|
+
root,
|
|
1832
|
+
env=env,
|
|
1833
|
+
reporter=reporter,
|
|
1834
|
+
runner=runner,
|
|
1835
|
+
strict=sys.exc_info()[0] is None,
|
|
1836
|
+
)
|
|
1837
|
+
|
|
1838
|
+
|
|
1839
|
+
def _stop_private_gpg_agents(
|
|
1840
|
+
root: Path,
|
|
1841
|
+
*,
|
|
1842
|
+
env: Mapping[str, str],
|
|
1843
|
+
reporter: InstallReporter,
|
|
1844
|
+
runner: Runner | None,
|
|
1845
|
+
strict: bool,
|
|
1846
|
+
) -> None:
|
|
1847
|
+
returncode = _run_checked(
|
|
1848
|
+
_bash_command(root, _PRIVATE_GPG_SHUTDOWN_COMMAND),
|
|
1849
|
+
env=env,
|
|
1850
|
+
reporter=reporter,
|
|
1851
|
+
runner=runner,
|
|
1852
|
+
label="Stopping private MSYS2 keyring agents",
|
|
1853
|
+
allow_failure=True,
|
|
1854
|
+
)
|
|
1855
|
+
if returncode == 0:
|
|
1856
|
+
return
|
|
1857
|
+
if not strict:
|
|
1858
|
+
reporter.note(
|
|
1859
|
+
"Could not stop a private MSYS2 keyring agent while recovering "
|
|
1860
|
+
"from another installation failure.",
|
|
1861
|
+
level="warning",
|
|
1862
|
+
)
|
|
1863
|
+
return
|
|
1864
|
+
reporter.command_failed("Stopping private MSYS2 keyring agents", returncode)
|
|
1865
|
+
raise RuntimeInstallError(
|
|
1866
|
+
"stopping private MSYS2 keyring agents failed with exit code "
|
|
1867
|
+
f"{returncode}"
|
|
1749
1868
|
)
|
|
1750
1869
|
|
|
1751
1870
|
|
|
@@ -2399,16 +2518,20 @@ def install_managed_runtime(
|
|
|
2399
2518
|
"pacman is noninteractive; displayed [Y/n] prompts do "
|
|
2400
2519
|
"not require input."
|
|
2401
2520
|
)
|
|
2521
|
+
reporter.note(
|
|
2522
|
+
"Core updates may close the first MSYS2 process; "
|
|
2523
|
+
"Railmux will start the required fresh process "
|
|
2524
|
+
"automatically.",
|
|
2525
|
+
level="muted",
|
|
2526
|
+
)
|
|
2402
2527
|
package_cache = cache_base / f"pacman-{MSYS2_RUNTIME_ID}"
|
|
2403
2528
|
package_cache.mkdir(parents=True, exist_ok=True)
|
|
2404
|
-
|
|
2529
|
+
_run_base_update_with_restarts(
|
|
2405
2530
|
root,
|
|
2406
|
-
packages=False,
|
|
2407
2531
|
cache=package_cache,
|
|
2408
2532
|
env=child_env,
|
|
2409
2533
|
reporter=reporter,
|
|
2410
2534
|
runner=runner,
|
|
2411
|
-
label="MSYS2 base update",
|
|
2412
2535
|
mirror_optimizer=mirror_optimizer,
|
|
2413
2536
|
)
|
|
2414
2537
|
reporter.done()
|
|
@@ -2445,16 +2568,25 @@ def install_managed_runtime(
|
|
|
2445
2568
|
reporter=reporter,
|
|
2446
2569
|
runner=runner,
|
|
2447
2570
|
)
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2571
|
+
try:
|
|
2572
|
+
_run_pacman_with_recovery(
|
|
2573
|
+
root,
|
|
2574
|
+
packages=True,
|
|
2575
|
+
cache=package_cache,
|
|
2576
|
+
env=child_env,
|
|
2577
|
+
reporter=reporter,
|
|
2578
|
+
runner=runner,
|
|
2579
|
+
label="MSYS2 package installation",
|
|
2580
|
+
mirror_optimizer=mirror_optimizer,
|
|
2581
|
+
)
|
|
2582
|
+
finally:
|
|
2583
|
+
_stop_private_gpg_agents(
|
|
2584
|
+
root,
|
|
2585
|
+
env=child_env,
|
|
2586
|
+
reporter=reporter,
|
|
2587
|
+
runner=runner,
|
|
2588
|
+
strict=sys.exc_info()[0] is None,
|
|
2589
|
+
)
|
|
2458
2590
|
reporter.done()
|
|
2459
2591
|
|
|
2460
2592
|
identity = _ensure_base_content_identity(
|
|
@@ -64,6 +64,22 @@ def test_verbose_reporter_streams_the_same_sanitized_output(tmp_path):
|
|
|
64
64
|
assert "package 中文\nprogress\n" in path.read_text(encoding="utf-8")
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def test_reporter_recognizes_only_the_explicit_msys2_core_restart(tmp_path):
|
|
68
|
+
path = tmp_path / "install.log"
|
|
69
|
+
with InstallReporter(path, verbose=False, stream=io.StringIO()) as reporter:
|
|
70
|
+
reporter.command_started("first update")
|
|
71
|
+
reporter.command_output(
|
|
72
|
+
":: To complete this update all MSYS2 processes including this "
|
|
73
|
+
"terminal will be closed. Confirm to proceed [Y/n]"
|
|
74
|
+
)
|
|
75
|
+
reporter.command_output_finished()
|
|
76
|
+
assert reporter.command_requested_msys2_restart
|
|
77
|
+
|
|
78
|
+
reporter.command_started("second update")
|
|
79
|
+
reporter.command_output("warning: terminate other MSYS2 programs\n")
|
|
80
|
+
assert not reporter.command_requested_msys2_restart
|
|
81
|
+
|
|
82
|
+
|
|
67
83
|
def test_verbose_reporter_never_fails_on_a_legacy_windows_console_codec(tmp_path):
|
|
68
84
|
stream = Cp1252Stream()
|
|
69
85
|
path = tmp_path / "install-0.4.0.dev7-20260803T000000Z-5.log"
|
|
@@ -797,6 +797,8 @@ def test_install_is_staged_and_activated_only_after_exact_probe(tmp_path):
|
|
|
797
797
|
).read_text(encoding="utf-8")
|
|
798
798
|
)["railmux"] == VERSION
|
|
799
799
|
joined = [" ".join(command) for command in commands]
|
|
800
|
+
base_updates = [command for command in joined if "-Syuu --noconfirm" in command]
|
|
801
|
+
assert len(base_updates) == 2
|
|
800
802
|
assert any("-Syu --noconfirm" in command for command in joined)
|
|
801
803
|
assert any("--needed tmux python python-pip" in command for command in joined)
|
|
802
804
|
assert any('python -m venv "$1/venv"' in command for command in joined)
|
|
@@ -806,7 +808,8 @@ def test_install_is_staged_and_activated_only_after_exact_probe(tmp_path):
|
|
|
806
808
|
assert len(logs) == 1
|
|
807
809
|
log = logs[0].read_text(encoding="utf-8")
|
|
808
810
|
assert "[1/7] Preparing verified MSYS2" in log
|
|
809
|
-
assert "--- MSYS2 base update ---" in log
|
|
811
|
+
assert "--- MSYS2 base update pass 1 ---" in log
|
|
812
|
+
assert "--- MSYS2 base update pass 2 ---" in log
|
|
810
813
|
assert "Installation completed successfully" in log
|
|
811
814
|
config = runtime.root / "etc" / "railmux-pacman.conf"
|
|
812
815
|
assert "[msys]" in config.read_text(encoding="utf-8")
|
|
@@ -1472,6 +1475,112 @@ def test_pacman_network_failure_retries_with_cache_and_relaxed_timeout(tmp_path)
|
|
|
1472
1475
|
assert f"Server = {repo}" in rendered
|
|
1473
1476
|
|
|
1474
1477
|
|
|
1478
|
+
def test_base_update_restarts_after_confirmed_core_shutdown(tmp_path):
|
|
1479
|
+
attempts = []
|
|
1480
|
+
restart = (
|
|
1481
|
+
b"upgrading msys2-runtime...\n"
|
|
1482
|
+
b":: To complete this update all MSYS2 processes including this "
|
|
1483
|
+
b"terminal will be closed. Confirm to proceed [Y/n]\n"
|
|
1484
|
+
)
|
|
1485
|
+
|
|
1486
|
+
def runner(argv, *, env, check):
|
|
1487
|
+
attempts.append(argv)
|
|
1488
|
+
update_attempts = [item for item in attempts if "-Syuu" in item[4]]
|
|
1489
|
+
if len(update_attempts) == 1 and "-Syuu" in argv[4]:
|
|
1490
|
+
return completed(argv, returncode=0xC0000135, stdout=restart)
|
|
1491
|
+
return completed(argv, stdout=b"there is nothing to do\n")
|
|
1492
|
+
|
|
1493
|
+
stream = io.StringIO()
|
|
1494
|
+
with InstallReporter(
|
|
1495
|
+
tmp_path / "install.log", verbose=False, stream=stream
|
|
1496
|
+
) as reporter:
|
|
1497
|
+
windows_msys2._run_base_update_with_restarts(
|
|
1498
|
+
tmp_path / "msys64",
|
|
1499
|
+
cache=tmp_path / "cache",
|
|
1500
|
+
env={},
|
|
1501
|
+
reporter=reporter,
|
|
1502
|
+
runner=runner,
|
|
1503
|
+
mirror_optimizer=lambda _root: PacmanMirrorDecision(
|
|
1504
|
+
None, None, False, (), ()
|
|
1505
|
+
),
|
|
1506
|
+
)
|
|
1507
|
+
|
|
1508
|
+
updates = [argv for argv in attempts if "-Syuu --noconfirm" in argv[4]]
|
|
1509
|
+
assert len(updates) == 2
|
|
1510
|
+
assert updates[0][0] == updates[1][0]
|
|
1511
|
+
assert windows_msys2._PRIVATE_GPG_SHUTDOWN_COMMAND in attempts[-1][4]
|
|
1512
|
+
rendered = stream.getvalue()
|
|
1513
|
+
assert "closed its own process as expected" in rendered
|
|
1514
|
+
assert "failed with exit code" not in rendered
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
def test_base_update_does_not_mask_unconfirmed_missing_dll(tmp_path, monkeypatch):
|
|
1518
|
+
monkeypatch.setattr(windows_msys2, "_NATIVE_WINDOWS", True)
|
|
1519
|
+
attempts = []
|
|
1520
|
+
|
|
1521
|
+
def runner(argv, *, env, check):
|
|
1522
|
+
attempts.append(argv)
|
|
1523
|
+
if windows_msys2._PRIVATE_GPG_SHUTDOWN_COMMAND in argv[4]:
|
|
1524
|
+
return completed(argv)
|
|
1525
|
+
return completed(
|
|
1526
|
+
argv,
|
|
1527
|
+
returncode=0xC0000135,
|
|
1528
|
+
stdout=b"upgrading msys2-runtime...\n",
|
|
1529
|
+
)
|
|
1530
|
+
|
|
1531
|
+
stream = io.StringIO()
|
|
1532
|
+
with InstallReporter(
|
|
1533
|
+
tmp_path / "install.log", verbose=False, stream=stream
|
|
1534
|
+
) as reporter:
|
|
1535
|
+
with pytest.raises(RuntimeInstallError, match="3221225781"):
|
|
1536
|
+
windows_msys2._run_base_update_with_restarts(
|
|
1537
|
+
tmp_path / "msys64",
|
|
1538
|
+
cache=tmp_path / "cache",
|
|
1539
|
+
env={},
|
|
1540
|
+
reporter=reporter,
|
|
1541
|
+
runner=runner,
|
|
1542
|
+
mirror_optimizer=lambda _root: PacmanMirrorDecision(
|
|
1543
|
+
None, None, False, (), ()
|
|
1544
|
+
),
|
|
1545
|
+
)
|
|
1546
|
+
|
|
1547
|
+
updates = [argv for argv in attempts if "-Syuu --noconfirm" in argv[4]]
|
|
1548
|
+
assert len(updates) == 1
|
|
1549
|
+
assert "outside a confirmed MSYS2 core-update restart" in stream.getvalue()
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
def test_base_update_restart_loop_is_bounded(tmp_path):
|
|
1553
|
+
attempts = []
|
|
1554
|
+
restart = (
|
|
1555
|
+
b":: To complete this update all MSYS2 processes including this "
|
|
1556
|
+
b"terminal will be closed. Confirm to proceed [Y/n]\n"
|
|
1557
|
+
)
|
|
1558
|
+
|
|
1559
|
+
def runner(argv, *, env, check):
|
|
1560
|
+
attempts.append(argv)
|
|
1561
|
+
if windows_msys2._PRIVATE_GPG_SHUTDOWN_COMMAND in argv[4]:
|
|
1562
|
+
return completed(argv)
|
|
1563
|
+
return completed(argv, stdout=restart)
|
|
1564
|
+
|
|
1565
|
+
with InstallReporter(
|
|
1566
|
+
tmp_path / "install.log", verbose=False, stream=io.StringIO()
|
|
1567
|
+
) as reporter:
|
|
1568
|
+
with pytest.raises(RuntimeInstallError, match="repeatedly requested"):
|
|
1569
|
+
windows_msys2._run_base_update_with_restarts(
|
|
1570
|
+
tmp_path / "msys64",
|
|
1571
|
+
cache=tmp_path / "cache",
|
|
1572
|
+
env={},
|
|
1573
|
+
reporter=reporter,
|
|
1574
|
+
runner=runner,
|
|
1575
|
+
mirror_optimizer=lambda _root: PacmanMirrorDecision(
|
|
1576
|
+
None, None, False, (), ()
|
|
1577
|
+
),
|
|
1578
|
+
)
|
|
1579
|
+
|
|
1580
|
+
updates = [argv for argv in attempts if "-Syuu --noconfirm" in argv[4]]
|
|
1581
|
+
assert len(updates) == windows_msys2._MAX_BASE_UPDATE_PASSES
|
|
1582
|
+
|
|
1583
|
+
|
|
1475
1584
|
def test_completed_package_cache_count_ignores_signatures_partials_and_links(tmp_path):
|
|
1476
1585
|
(tmp_path / "python.pkg.tar.zst").write_bytes(b"package")
|
|
1477
1586
|
(tmp_path / "python.pkg.tar.zst.sig").write_bytes(b"signature")
|
|
@@ -5,6 +5,7 @@ import io
|
|
|
5
5
|
import os
|
|
6
6
|
import stat
|
|
7
7
|
import subprocess
|
|
8
|
+
import sys
|
|
8
9
|
import tempfile
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
|
|
@@ -13,8 +14,13 @@ from railmux.windows_msys2 import (
|
|
|
13
14
|
MSYS2_ARCHIVE_SHA256,
|
|
14
15
|
Msys2Runtime,
|
|
15
16
|
_extract_msys2_archive,
|
|
17
|
+
_run_base_update_with_restarts,
|
|
16
18
|
download_from_sources,
|
|
17
19
|
)
|
|
20
|
+
from railmux.windows_pacman import (
|
|
21
|
+
optimize_pacman_mirror,
|
|
22
|
+
write_msys_only_pacman_config,
|
|
23
|
+
)
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
def main() -> int:
|
|
@@ -39,6 +45,18 @@ def main() -> int:
|
|
|
39
45
|
first = stream.read(1)
|
|
40
46
|
stream.seek(0)
|
|
41
47
|
stream.write(first)
|
|
48
|
+
write_msys_only_pacman_config(runtime.root)
|
|
49
|
+
with InstallReporter(
|
|
50
|
+
stage / "update.log", verbose=True, stream=sys.stdout
|
|
51
|
+
) as reporter:
|
|
52
|
+
_run_base_update_with_restarts(
|
|
53
|
+
runtime.root,
|
|
54
|
+
cache=stage / "pacman-cache",
|
|
55
|
+
env=runtime.environment(os.environ),
|
|
56
|
+
reporter=reporter,
|
|
57
|
+
runner=None,
|
|
58
|
+
mirror_optimizer=optimize_pacman_mirror,
|
|
59
|
+
)
|
|
42
60
|
result = subprocess.run(
|
|
43
61
|
[
|
|
44
62
|
str(runtime.bash),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.0.dev27"
|
|
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
|