lager-cli 0.28.3__tar.gz → 0.28.4__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.
- {lager_cli-0.28.3/lager_cli.egg-info → lager_cli-0.28.4}/PKG-INFO +1 -1
- {lager_cli-0.28.3 → lager_cli-0.28.4}/__init__.py +1 -1
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/update.py +215 -115
- {lager_cli-0.28.3 → lager_cli-0.28.4/lager_cli.egg-info}/PKG-INFO +1 -1
- {lager_cli-0.28.3 → lager_cli-0.28.4}/LICENSE +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/MANIFEST.in +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/README.md +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/__main__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/address_utils.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/battery/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/battery/battery_tui.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/battery/websocket_client.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/box_storage.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/_host_ops.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/_mount_prep.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/_pip_validation.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/_shim_verbs.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/_ssh.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/authorize.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/box_group.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/boxes.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/config.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/diagnose.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/dut.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/hello.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/instruments.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/labjack_pins.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/lock.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/net_tui.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/nets.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/box/ssh.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/ble.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/blufi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/i2c.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/router.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/spi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/uart.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/usb.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/websocket_client.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/communication/wifi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/arm.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/commands.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/gdb.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/net_cache.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/service_client.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/service_helper.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/debug/tunnel.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/devenv.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/development/python.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/adc.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/dac.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/energy.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/gpi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/gpo.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/logic.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/scope.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/thermocouple.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/measurement/watt.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/power/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/power/battery.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/power/eload.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/power/solar.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/power/supply.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/binaries.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/defaults.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/exec_.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/install.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/install_wheel.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/logs.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/uninstall.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/commands/utility/webcam.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/config.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/context/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/context/ci_detection.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/context/constants.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/context/core.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/context/error_handlers.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/context/session.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/group_usage.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/matchers.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/net_group.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/net_helpers.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/net_storage.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/param_types.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/ssh_utils.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/utils.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/version_skew.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/core/ws_diagnose.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/scripts/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/scripts/convert_to_sparse_checkout.sh +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/scripts/setup_and_deploy_box.sh +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/scripts/setup_ssh_key.sh +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/security/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/deployment/security/secure_box_firewall.sh +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/common/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/common/construct_utils.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/common/exceptions.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/common/py3compat.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/common/utils.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/construct/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/construct/adapters.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/construct/core.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/construct/debug.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/construct/macros.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/abbrevtable.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/aranges.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/callframe.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/compileunit.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/constants.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/descriptions.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/die.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/dwarf_expr.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/dwarfinfo.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/enums.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/lineprogram.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/locationlists.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/namelut.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/ranges.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/dwarf/structs.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/ehabi/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/ehabi/constants.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/ehabi/decoder.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/ehabi/ehabiinfo.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/ehabi/structs.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/constants.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/descriptions.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/dynamic.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/elffile.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/enums.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/gnuversions.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/hash.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/notes.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/relocation.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/sections.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/segments.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/elftools/elf/structs.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/errors.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/exceptions.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/box_config.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/ble.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/blufi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/i2c.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/router.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/spi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/uart.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/communication/wifi.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/custom_devices.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/device/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/device/arm.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/device/hello.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/device/usb.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/device/webcam.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/adc.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/dac.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/energy.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/gpio.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/scope.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/scope_stream.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/thermocouple.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/measurement/watt.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/net.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/power/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/power/battery.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/power/eload.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/power/enable_disable.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/power/solar.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/power/supply.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/impl/query_instruments.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/lager_cli.egg-info/SOURCES.txt +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/lager_cli.egg-info/dependency_links.txt +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/lager_cli.egg-info/entry_points.txt +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/lager_cli.egg-info/requires.txt +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/lager_cli.egg-info/top_level.txt +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/main.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/pyproject.toml +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/safe_unpickle.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/setup.cfg +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/setup.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/simple_hdlc.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/sort_utils.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/status.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/supply/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/supply/supply_tui.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/supply/websocket_client.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/core/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/core/executor.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/main.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/ui/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/ui/completer.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/ui/display.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/ui/logo.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/ui/repl.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/terminal/ui/themes.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/tests/test_box_lager_imports.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/tests/test_box_storage.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/tests/test_io_imports.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/update_check.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/CRC16.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/CRC16DNP.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/CRC16Kermit.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/CRC16SICK.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/CRC32.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/CRCCCITT.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/PyCRC/__init__.py +0 -0
- {lager_cli-0.28.3 → lager_cli-0.28.4}/vendor/__init__.py +0 -0
|
@@ -16,6 +16,7 @@ import subprocess
|
|
|
16
16
|
import threading
|
|
17
17
|
import time
|
|
18
18
|
import sys
|
|
19
|
+
import uuid
|
|
19
20
|
from ...box_storage import (
|
|
20
21
|
auto_lock_acquire_for_command,
|
|
21
22
|
get_box_user,
|
|
@@ -698,6 +699,40 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
698
699
|
time.sleep(5)
|
|
699
700
|
return False
|
|
700
701
|
|
|
702
|
+
def store_build_hash(hash_value):
|
|
703
|
+
"""Persist the docker-build-inputs hash to /etc/lager/build-hash.
|
|
704
|
+
|
|
705
|
+
Returns True on success, False on failure (caller decides whether to
|
|
706
|
+
warn). Retries up to 3 times with backoff, like write_box_version_file.
|
|
707
|
+
|
|
708
|
+
The file is bind-mounted from the host into the container and can end up
|
|
709
|
+
owned by www-data (the container's runtime user); the SSH user
|
|
710
|
+
(lagerdata) is not in that group, so a plain `echo > /etc/lager/build-hash`
|
|
711
|
+
fails with EACCES and — when the write was unchecked — left a stale hash
|
|
712
|
+
that made every subsequent `lager update` rebuild needlessly. Step 10 has
|
|
713
|
+
already `chmod 777`'d /etc/lager, so we write a temp file in that dir and
|
|
714
|
+
`mv -f` it over the target: unlinking the old file needs only
|
|
715
|
+
directory-write (granted by 777), and the replacement is owned by
|
|
716
|
+
lagerdata, so future runs can overwrite it directly. Same-filesystem mv
|
|
717
|
+
is an atomic rename. The mktemp template's trailing X's must stay at the
|
|
718
|
+
end of the name.
|
|
719
|
+
"""
|
|
720
|
+
if not hash_value:
|
|
721
|
+
return True
|
|
722
|
+
write_cmd = (
|
|
723
|
+
'tmp=$(mktemp /etc/lager/.build-hash.XXXXXX) && '
|
|
724
|
+
f'printf "%s\\n" "{hash_value}" > "$tmp" && '
|
|
725
|
+
'chmod 644 "$tmp" && '
|
|
726
|
+
'mv -f "$tmp" /etc/lager/build-hash'
|
|
727
|
+
)
|
|
728
|
+
for attempt in range(3):
|
|
729
|
+
result = run_ssh_command_with_output(write_cmd, timeout_secs=30)
|
|
730
|
+
if result.returncode == 0:
|
|
731
|
+
return True
|
|
732
|
+
if attempt < 2:
|
|
733
|
+
time.sleep(5)
|
|
734
|
+
return False
|
|
735
|
+
|
|
701
736
|
# Step 2: Inspect box state — one SSH round-trip gathers every read-only
|
|
702
737
|
# fact the rest of the flow needs (git-repo check, remote URL, layout,
|
|
703
738
|
# current commit, docker-build cache inputs, udev/sudoers state, on-box
|
|
@@ -1143,6 +1178,25 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1143
1178
|
# or half-installed toolchain behind on the retry.
|
|
1144
1179
|
must_wipe_image = hash_mismatch or force
|
|
1145
1180
|
|
|
1181
|
+
# Privileged box-state operations (udev rules, modprobe blacklist,
|
|
1182
|
+
# sudoers-owner fix, box-config sudoers bootstrap) are COLLECTED here and
|
|
1183
|
+
# applied together in a single interactive `ssh -t` session further down.
|
|
1184
|
+
# Each is a no-op on a correctly-provisioned box (the probe already told us
|
|
1185
|
+
# what's in sync); when one IS needed and the box lacks the passwordless
|
|
1186
|
+
# sudoers grant, batching them means the sudo password is requested at most
|
|
1187
|
+
# once per run instead of once per step (each used to open its own `ssh -t`
|
|
1188
|
+
# session, and sudo's per-tty credential cache doesn't carry across them).
|
|
1189
|
+
# A run that needs no privileged work never opens the session -> 0 prompts.
|
|
1190
|
+
# Per-run unique results path: a static /tmp name could be left behind by a
|
|
1191
|
+
# crashed run (or another user) and, since /tmp is sticky, our `rm -f` then
|
|
1192
|
+
# fails and the append is denied — making every job misreport as FAILED. A
|
|
1193
|
+
# uuid suffix also avoids the predictable-path risk on a shared box.
|
|
1194
|
+
_priv_results_path = f'/tmp/lager_priv_results_{uuid.uuid4().hex}'
|
|
1195
|
+
priv_jobs = [] # each: {'name': str, 'snippet': shell str, 'render': fn(ok)}
|
|
1196
|
+
|
|
1197
|
+
def enqueue_priv(name, snippet, render):
|
|
1198
|
+
priv_jobs.append({'name': name, 'snippet': snippet, 'render': render})
|
|
1199
|
+
|
|
1146
1200
|
# Step 5: udev rules. The probe already located the source dir and diffed
|
|
1147
1201
|
# its 99-instrument.rules against the installed copy, so we only touch the
|
|
1148
1202
|
# box when an install/update is actually needed.
|
|
@@ -1170,6 +1224,12 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1170
1224
|
# to (GROUP="lager"); the getent guard keeps the groupadd off the
|
|
1171
1225
|
# common path so provisioned boxes stay within the passwordless
|
|
1172
1226
|
# sudoers grant and see no password prompt.
|
|
1227
|
+
# The `&&` chain means a non-zero exit already implies one of the
|
|
1228
|
+
# sudo steps failed, so no separate post-install verify is needed.
|
|
1229
|
+
# The "lager" group is what the instrument rules grant device access
|
|
1230
|
+
# to (GROUP="lager"); the getent guard keeps the groupadd off the
|
|
1231
|
+
# common path so provisioned boxes stay within the passwordless
|
|
1232
|
+
# sudoers grant. Queued for the single privileged session below.
|
|
1173
1233
|
install_cmd = (
|
|
1174
1234
|
f'cp {udev_src_path}/99-instrument.rules /tmp/ && '
|
|
1175
1235
|
'{ getent group lager >/dev/null || sudo /usr/sbin/groupadd lager; } && '
|
|
@@ -1180,32 +1240,20 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1180
1240
|
'sudo /bin/rm -f /tmp/99-instrument.rules'
|
|
1181
1241
|
)
|
|
1182
1242
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
elif verbose:
|
|
1196
|
-
click.echo()
|
|
1243
|
+
def _render_udev(ok, _src=udev_src_path):
|
|
1244
|
+
log('Installing udev rules...', nl=False)
|
|
1245
|
+
if ok:
|
|
1246
|
+
log_status('OK', 'green')
|
|
1247
|
+
else:
|
|
1248
|
+
log_status('FAILED', 'red')
|
|
1249
|
+
if verbose:
|
|
1250
|
+
click.echo(' Could not install udev rules — likely a sudoers permission issue.', err=True)
|
|
1251
|
+
click.echo(f' Manual fix: ssh {ssh_host}, then:', err=True)
|
|
1252
|
+
click.echo(' sudo groupadd -f lager', err=True)
|
|
1253
|
+
click.echo(f' sudo cp {_src}/99-instrument.rules /etc/udev/rules.d/', err=True)
|
|
1254
|
+
click.echo(' sudo udevadm control --reload-rules && sudo udevadm trigger', err=True)
|
|
1197
1255
|
|
|
1198
|
-
|
|
1199
|
-
if result.returncode == 0:
|
|
1200
|
-
log_status('OK', 'green')
|
|
1201
|
-
else:
|
|
1202
|
-
log_status('FAILED', 'red')
|
|
1203
|
-
if verbose:
|
|
1204
|
-
click.echo(' Could not install udev rules — likely a sudoers permission issue.', err=True)
|
|
1205
|
-
click.echo(f' Manual fix: ssh {ssh_host}, then:', err=True)
|
|
1206
|
-
click.echo(' sudo groupadd -f lager', err=True)
|
|
1207
|
-
click.echo(f' sudo cp {udev_src_path}/99-instrument.rules /etc/udev/rules.d/', err=True)
|
|
1208
|
-
click.echo(' sudo udevadm control --reload-rules && sudo udevadm trigger', err=True)
|
|
1256
|
+
enqueue_priv('udev', install_cmd, _render_udev)
|
|
1209
1257
|
|
|
1210
1258
|
# Step 5b: modprobe.d blacklists (0.20.0+: usbtmc blacklist for USB-TMC
|
|
1211
1259
|
# instrument drivers). Same shape as the udev step above — probe diffed
|
|
@@ -1260,48 +1308,31 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1260
1308
|
else:
|
|
1261
1309
|
log_status('update needed', 'yellow')
|
|
1262
1310
|
|
|
1311
|
+
# Install, then best-effort unload so the blacklist takes effect
|
|
1312
|
+
# without a reboot (EBUSY if a USB-TMC instrument is in use — tolerated
|
|
1313
|
+
# via `|| true`, so the job's success reflects the cp/chmod, not the
|
|
1314
|
+
# unload). Queued for the single privileged session below.
|
|
1263
1315
|
install_cmd = (
|
|
1264
1316
|
f'cp {mp_src_path}/blacklist-usbtmc.conf /tmp/ && '
|
|
1265
1317
|
'sudo /bin/cp /tmp/blacklist-usbtmc.conf /etc/modprobe.d/ && '
|
|
1266
1318
|
'sudo /bin/chmod 644 /etc/modprobe.d/blacklist-usbtmc.conf && '
|
|
1267
|
-
'sudo /bin/rm -f /tmp/blacklist-usbtmc.conf
|
|
1268
|
-
|
|
1269
|
-
# reboot. Fails with EBUSY if a USB-TMC instrument is in use; we
|
|
1270
|
-
# tolerate that and note a reboot is needed.
|
|
1271
|
-
'if lsmod | grep -q "^usbtmc"; then '
|
|
1272
|
-
' sudo /sbin/modprobe -r usbtmc 2>/dev/null && '
|
|
1273
|
-
' echo "LAGER_MP_UNLOAD=OK" || echo "LAGER_MP_UNLOAD=BUSY"; '
|
|
1274
|
-
'else echo "LAGER_MP_UNLOAD=NOT_LOADED"; fi'
|
|
1319
|
+
'sudo /bin/rm -f /tmp/blacklist-usbtmc.conf && '
|
|
1320
|
+
'{ ! lsmod | grep -q "^usbtmc" || sudo /sbin/modprobe -r usbtmc 2>/dev/null || true; }'
|
|
1275
1321
|
)
|
|
1276
1322
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
click.echo()
|
|
1323
|
+
def _render_modprobe(ok, _src=mp_src_path):
|
|
1324
|
+
log('Installing modprobe.d blacklists...', nl=False)
|
|
1325
|
+
if ok:
|
|
1326
|
+
log_status('OK', 'green')
|
|
1327
|
+
else:
|
|
1328
|
+
log_status('FAILED', 'red')
|
|
1329
|
+
if verbose:
|
|
1330
|
+
click.echo(' Could not install modprobe.d blacklist — likely a sudoers permission issue.', err=True)
|
|
1331
|
+
click.echo(f' Manual fix: ssh {ssh_host}, then:', err=True)
|
|
1332
|
+
click.echo(f' sudo cp {_src}/blacklist-usbtmc.conf /etc/modprobe.d/', err=True)
|
|
1333
|
+
click.echo(' sudo modprobe -r usbtmc # optional: takes effect immediately', err=True)
|
|
1289
1334
|
|
|
1290
|
-
|
|
1291
|
-
if result.returncode == 0:
|
|
1292
|
-
log_status('OK', 'green')
|
|
1293
|
-
if verbose:
|
|
1294
|
-
if 'LAGER_MP_UNLOAD=BUSY' in (result.stdout or ''):
|
|
1295
|
-
click.echo(' Note: usbtmc still loaded (instrument in use); reboot the box to fully apply.', err=True)
|
|
1296
|
-
elif 'LAGER_MP_UNLOAD=OK' in (result.stdout or ''):
|
|
1297
|
-
click.echo(' usbtmc kernel module unloaded; blacklist now in effect.')
|
|
1298
|
-
else:
|
|
1299
|
-
log_status('FAILED', 'red')
|
|
1300
|
-
if verbose:
|
|
1301
|
-
click.echo(' Could not install modprobe.d blacklist — likely a sudoers permission issue.', err=True)
|
|
1302
|
-
click.echo(f' Manual fix: ssh {ssh_host}, then:', err=True)
|
|
1303
|
-
click.echo(f' sudo cp {mp_src_path}/blacklist-usbtmc.conf /etc/modprobe.d/', err=True)
|
|
1304
|
-
click.echo(' sudo modprobe -r usbtmc # optional: takes effect immediately', err=True)
|
|
1335
|
+
enqueue_priv('modprobe', install_cmd, _render_modprobe)
|
|
1305
1336
|
|
|
1306
1337
|
# Step 6: sudoers ownership. /etc/sudoers.d/lagerdata-udev must be
|
|
1307
1338
|
# root-owned or sudo refuses it; the probe gave us the owner uid.
|
|
@@ -1317,30 +1348,21 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1317
1348
|
else:
|
|
1318
1349
|
log_status(f'fixing (owned by uid {sudoers_owner})', 'yellow')
|
|
1319
1350
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1351
|
+
def _render_sudoers(ok):
|
|
1352
|
+
log('Fixing sudoers ownership...', nl=False)
|
|
1353
|
+
if ok:
|
|
1354
|
+
log_status('OK', 'green')
|
|
1355
|
+
else:
|
|
1356
|
+
log_status('FAILED', 'red')
|
|
1357
|
+
if verbose:
|
|
1358
|
+
click.echo(' Warning: could not fix sudoers ownership; sudo may not work correctly.', err=True)
|
|
1325
1359
|
|
|
1326
|
-
|
|
1360
|
+
enqueue_priv(
|
|
1361
|
+
'sudoers_owner',
|
|
1327
1362
|
'sudo chown root:root /etc/sudoers.d/lagerdata-udev',
|
|
1328
|
-
|
|
1363
|
+
_render_sudoers,
|
|
1329
1364
|
)
|
|
1330
1365
|
|
|
1331
|
-
if not verbose and progress:
|
|
1332
|
-
progress.resume()
|
|
1333
|
-
elif verbose:
|
|
1334
|
-
click.echo()
|
|
1335
|
-
|
|
1336
|
-
log('Fixing sudoers ownership...', nl=False)
|
|
1337
|
-
if fix_result.returncode == 0:
|
|
1338
|
-
log_status('OK', 'green')
|
|
1339
|
-
else:
|
|
1340
|
-
log_status('FAILED', 'red')
|
|
1341
|
-
if verbose:
|
|
1342
|
-
click.echo(' Warning: could not fix sudoers ownership; sudo may not work correctly.', err=True)
|
|
1343
|
-
|
|
1344
1366
|
# Step 7: passwordless sudo for `lager box config apply`.
|
|
1345
1367
|
#
|
|
1346
1368
|
# `lager box config apply` needs root on the host for apt-get install,
|
|
@@ -1359,12 +1381,6 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1359
1381
|
else:
|
|
1360
1382
|
log_status('needs bootstrap', 'yellow')
|
|
1361
1383
|
|
|
1362
|
-
if not verbose and progress:
|
|
1363
|
-
progress.pause()
|
|
1364
|
-
click.echo('Installing box-config sudoers rule (may require sudo password)...')
|
|
1365
|
-
elif verbose:
|
|
1366
|
-
click.echo()
|
|
1367
|
-
|
|
1368
1384
|
boxcfg_sudoers_cmd = (
|
|
1369
1385
|
"printf '%s\\n' "
|
|
1370
1386
|
"'lagerdata ALL=(root) NOPASSWD: SETENV: /usr/bin/apt-get' "
|
|
@@ -1379,18 +1395,17 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1379
1395
|
"&& sudo chmod 644 /etc/lager/.boxcfg-sudoers-v2"
|
|
1380
1396
|
)
|
|
1381
1397
|
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
if boxcfg_install_result.returncode == 0:
|
|
1398
|
+
def _render_boxcfg(ok):
|
|
1399
|
+
log('Installing box-config sudoers...', nl=False)
|
|
1400
|
+
if not ok:
|
|
1401
|
+
log_status('FAILED', 'yellow')
|
|
1402
|
+
if verbose:
|
|
1403
|
+
click.echo(
|
|
1404
|
+
' Warning: box-config sudoers rule could not be installed. '
|
|
1405
|
+
'`lager box config apply` will need manual sudoers setup on this box.',
|
|
1406
|
+
err=True,
|
|
1407
|
+
)
|
|
1408
|
+
return
|
|
1394
1409
|
# `sudo tee` succeeds even if the sudoers content is malformed,
|
|
1395
1410
|
# so this functional re-check is genuinely needed (unlike the
|
|
1396
1411
|
# udev path above, where the `&&` chain is self-verifying).
|
|
@@ -1407,14 +1422,55 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1407
1422
|
'Check /etc/sudoers.d/lager-box-config syntax on the box.',
|
|
1408
1423
|
err=True,
|
|
1409
1424
|
)
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1425
|
+
|
|
1426
|
+
enqueue_priv('boxcfg', boxcfg_sudoers_cmd, _render_boxcfg)
|
|
1427
|
+
|
|
1428
|
+
# Apply all queued privileged operations in ONE interactive `ssh -t`
|
|
1429
|
+
# session, so the sudo password (on a box without the passwordless grant)
|
|
1430
|
+
# is requested at most once for the whole run. We can't read the interactive
|
|
1431
|
+
# session's stdout (it streams to the terminal so the prompt is visible), so
|
|
1432
|
+
# each job records `<name>=OK|FAIL` to a results file that we read back over
|
|
1433
|
+
# the normal captured channel and hand to each job's render() for the same
|
|
1434
|
+
# per-step status output as before. A box that needs nothing skips this
|
|
1435
|
+
# entirely and never prompts.
|
|
1436
|
+
if priv_jobs:
|
|
1437
|
+
wrapped = [f'rm -f {_priv_results_path}']
|
|
1438
|
+
for job in priv_jobs:
|
|
1439
|
+
# Subshell so one job's failure doesn't abort the rest; record the
|
|
1440
|
+
# outcome regardless. The first sudo in this single tty prompts (if
|
|
1441
|
+
# needed); subsequent sudos reuse the cached credential.
|
|
1442
|
+
wrapped.append(
|
|
1443
|
+
f'if ( {job["snippet"]} ); then '
|
|
1444
|
+
f'echo "{job["name"]}=OK" >> {_priv_results_path}; '
|
|
1445
|
+
f'else echo "{job["name"]}=FAIL" >> {_priv_results_path}; fi'
|
|
1446
|
+
)
|
|
1447
|
+
combined_priv_cmd = '\n'.join(wrapped)
|
|
1448
|
+
|
|
1449
|
+
if not verbose and progress:
|
|
1450
|
+
progress.pause()
|
|
1451
|
+
click.echo('Applying box settings (may require the sudo password once)...')
|
|
1452
|
+
elif verbose:
|
|
1453
|
+
click.echo()
|
|
1454
|
+
|
|
1455
|
+
run_ssh_command_interactive(combined_priv_cmd, allow_sudo_prompt=True)
|
|
1456
|
+
|
|
1457
|
+
if not verbose and progress:
|
|
1458
|
+
progress.resume()
|
|
1459
|
+
elif verbose:
|
|
1460
|
+
click.echo()
|
|
1461
|
+
|
|
1462
|
+
# Read back per-job results over the captured channel, then clean up.
|
|
1463
|
+
priv_read = run_ssh_command_with_output(
|
|
1464
|
+
f'cat {_priv_results_path} 2>/dev/null; rm -f {_priv_results_path}'
|
|
1465
|
+
)
|
|
1466
|
+
priv_results = {}
|
|
1467
|
+
for line in (priv_read.stdout or '').splitlines():
|
|
1468
|
+
if '=' in line:
|
|
1469
|
+
k, _, v = line.partition('=')
|
|
1470
|
+
priv_results[k.strip()] = v.strip()
|
|
1471
|
+
|
|
1472
|
+
for job in priv_jobs:
|
|
1473
|
+
job['render'](priv_results.get(job['name']) == 'OK')
|
|
1418
1474
|
|
|
1419
1475
|
# No git updates, no box/→root flatten work, and the docker-build inputs
|
|
1420
1476
|
# match what's already cached: a second consecutive `lager update` would
|
|
@@ -1523,6 +1579,42 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1523
1579
|
)
|
|
1524
1580
|
log_status('OK', 'green')
|
|
1525
1581
|
|
|
1582
|
+
# BuildKit preflight. box.Dockerfile uses a `# syntax=` directive and
|
|
1583
|
+
# `RUN --mount=type=cache` cache mounts that keep the cargo (defmt-print)
|
|
1584
|
+
# compile and pip wheel work warm across rebuilds — turning a from-scratch
|
|
1585
|
+
# rebuild from ~20 min into a few minutes. These require BuildKit: Docker
|
|
1586
|
+
# >= 23 enables it by default and 18.09+ honors DOCKER_BUILDKIT=1, while a
|
|
1587
|
+
# legacy builder errors on `--mount`. Probe once and fail fast with an
|
|
1588
|
+
# actionable message rather than wasting a long build that dies on a
|
|
1589
|
+
# confusing parse error minutes in.
|
|
1590
|
+
def _docker_supports_buildkit():
|
|
1591
|
+
probe = run_ssh_command_with_output(
|
|
1592
|
+
"docker buildx version >/dev/null 2>&1 && echo BUILDX || "
|
|
1593
|
+
"docker version --format '{{.Server.Version}}' 2>/dev/null",
|
|
1594
|
+
timeout_secs=20,
|
|
1595
|
+
)
|
|
1596
|
+
out = (probe.stdout or '').strip()
|
|
1597
|
+
if 'BUILDX' in out:
|
|
1598
|
+
return True, out
|
|
1599
|
+
try:
|
|
1600
|
+
parts = out.split('-')[0].split('.')
|
|
1601
|
+
ver = (int(parts[0]), int(parts[1]) if len(parts) > 1 else 0)
|
|
1602
|
+
return ver >= (18, 9), out
|
|
1603
|
+
except (ValueError, IndexError):
|
|
1604
|
+
return False, out
|
|
1605
|
+
|
|
1606
|
+
buildkit_ok, docker_ver = _docker_supports_buildkit()
|
|
1607
|
+
if not buildkit_ok:
|
|
1608
|
+
if progress:
|
|
1609
|
+
progress.finish(success=False)
|
|
1610
|
+
log_error(
|
|
1611
|
+
"Error: this box's Docker does not support BuildKit, which the box "
|
|
1612
|
+
"image now requires (RUN --mount cache mounts). Detected: "
|
|
1613
|
+
f"{docker_ver or 'unknown'}. Upgrade Docker to >= 23 (or install the "
|
|
1614
|
+
"docker-buildx-plugin) on the box, then re-run `lager update`."
|
|
1615
|
+
)
|
|
1616
|
+
ctx.exit(1)
|
|
1617
|
+
|
|
1526
1618
|
# Step 9: Rebuild Docker container (the slow part)
|
|
1527
1619
|
if progress:
|
|
1528
1620
|
progress.update("Building container...")
|
|
@@ -1536,7 +1628,7 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1536
1628
|
ssh_cmd.extend(_ssh_mux_opts)
|
|
1537
1629
|
ssh_cmd.extend([ssh_host,
|
|
1538
1630
|
'cd ~/box/lager && '
|
|
1539
|
-
'docker build -f docker/box.Dockerfile -t lager .'])
|
|
1631
|
+
'DOCKER_BUILDKIT=1 docker build -f docker/box.Dockerfile -t lager .'])
|
|
1540
1632
|
|
|
1541
1633
|
build_output_lines = []
|
|
1542
1634
|
if verbose:
|
|
@@ -1590,14 +1682,10 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1590
1682
|
if verbose:
|
|
1591
1683
|
click.secho(' Build complete', fg='green')
|
|
1592
1684
|
|
|
1593
|
-
#
|
|
1594
|
-
#
|
|
1595
|
-
#
|
|
1596
|
-
|
|
1597
|
-
run_ssh_command_with_output(
|
|
1598
|
-
f'echo "{new_build_hash}" > /etc/lager/build-hash',
|
|
1599
|
-
timeout_secs=15,
|
|
1600
|
-
)
|
|
1685
|
+
# The build-inputs hash is persisted later (after Step 10 ensures
|
|
1686
|
+
# /etc/lager is world-writable) via store_build_hash — writing it here, to a
|
|
1687
|
+
# possibly www-data-owned file, failed silently and left a stale hash that
|
|
1688
|
+
# forced a rebuild on every subsequent run.
|
|
1601
1689
|
|
|
1602
1690
|
# Reclaim disk from *superseded* images while preserving the build cache.
|
|
1603
1691
|
#
|
|
@@ -1655,6 +1743,18 @@ def _update_logic(ctx, *, box, yes, version, verbose, check, force=False):
|
|
|
1655
1743
|
ctx.exit(1)
|
|
1656
1744
|
log_status('OK', 'green')
|
|
1657
1745
|
|
|
1746
|
+
# Persist the build-inputs hash now that /etc/lager is world-writable (Step
|
|
1747
|
+
# 10). This is what lets the next run's cache-validity check short-circuit to
|
|
1748
|
+
# the no-op fast path instead of rebuilding; a stale hash defeats it. Unlike
|
|
1749
|
+
# the old unchecked write, store_build_hash verifies success and we surface a
|
|
1750
|
+
# visible warning on failure rather than silently leaving a stale hash.
|
|
1751
|
+
if new_build_hash and not store_build_hash(new_build_hash):
|
|
1752
|
+
click.secho(
|
|
1753
|
+
'Warning: could not persist build hash to /etc/lager/build-hash; '
|
|
1754
|
+
'the next `lager update` may rebuild even when nothing changed.',
|
|
1755
|
+
fg='yellow', err=True,
|
|
1756
|
+
)
|
|
1757
|
+
|
|
1658
1758
|
# Write the version file BEFORE the container restart (SSH is stable here).
|
|
1659
1759
|
# A version tag (v0.3.14 / 0.3.14) is used directly. For a branch target
|
|
1660
1760
|
# we ask the box for the closest preceding `vX.Y.Z` tag at HEAD via
|
|
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
|