-
Notifications
You must be signed in to change notification settings - Fork 0
UN-4024 [FEAT] Ship the CLI as a standalone binary for Linux and Apple Silicon #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
pk-zipstack
wants to merge
2
commits into
feat/cli-scaffold
Choose a base branch
from
UN-4024-standalone-binary
base: feat/cli-scaffold
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| .venv/ | ||
| .venv-freeze/ | ||
| __pycache__/ | ||
| *.egg-info/ | ||
| .pytest_cache/ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/bin/sh | ||
| # Exercise a built `unstract` binary with no interpreter in reach. | ||
| # | ||
| # scripts/smoke-binary.sh dist/unstract [expected-version] | ||
| # | ||
| # Run by ci.yml on every pull request and by release.yml before a binary is | ||
| # attached to a release, so the same checks decide both. A dev box has a Python | ||
| # that would answer an import the bundle is missing, which is why every command | ||
| # below runs under `env -i` with an empty PATH. | ||
| set -eu | ||
|
|
||
| BIN=$(cd "$(dirname "$1")" && pwd)/$(basename "$1") | ||
| EXPECTED_VERSION="${2:-}" | ||
|
|
||
| mkdir -p /tmp/emptybin | ||
| run() { env -i PATH=/tmp/emptybin HOME="$HOME" "$BIN" "$@"; } | ||
|
|
||
| # Not a trivial path: importing the command modules applies the `@spec_options` | ||
| # decorators, which read `overlay.toml` and both vendored specs before Click | ||
| # parses anything. A bundle missing its data files fails here. | ||
| run --version | ||
| run --discover full >/dev/null | ||
|
|
||
| # Click wraps help text to the terminal width, so a phrase can arrive split | ||
| # across lines; squeeze the whitespace rather than pin the wrapping. | ||
| help_text() { run "$@" --help | tr -s '[:space:]' ' '; } | ||
|
|
||
| # One derived flag per vendored spec, proving each was reachable... | ||
| help_text whisper extract | grep -q -- '--add-line-nos' | ||
| help_text docstudio deployment run | grep -q -- '--hitl-packet-id' | ||
| # ...and one help string, which comes from the published client's docstring | ||
| # rather than from the spec. A build made with `-OO` passes everything above and | ||
| # fails only this. | ||
| help_text whisper extract | grep -q 'Adds line numbers' | ||
|
|
||
| # The release job stamps the version it published; a binary that disagrees with | ||
| # the release it is attached to is worse than no binary. | ||
| if [ -n "$EXPECTED_VERSION" ]; then | ||
| run --version | grep -q "$EXPECTED_VERSION" | ||
| fi | ||
|
|
||
| echo "OK $(basename "$BIN")" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| # -*- mode: python ; coding: utf-8 -*- | ||
| """One-file build of the `unstract` CLI. | ||
|
|
||
| Generated once with | ||
|
|
||
| pyinstaller --onefile --console --name unstract src/unstract_cli/__main__.py | ||
|
|
||
| and hand-edited since. This file is the build, not that command line: the | ||
| options below are decisions, and a regenerated spec would drop them silently. | ||
| """ | ||
|
|
||
| # The packaged files that are read through `importlib.resources` -- `overlay.toml` | ||
| # and the vendored specs -- and read at *import* time, by the `@spec_options` | ||
| # decorators the command modules apply at module scope. They are data, not | ||
| # modules, so nothing puts them in the PYZ, and a bundle without them builds | ||
| # clean and then fails on every invocation. | ||
| # | ||
| # Taken from `src/` rather than from `collect_data_files("unstract_cli")`, which | ||
| # reads the *installed* package. PyInstaller prepends the entry script's parent | ||
| # package directory to the module search path, so the code is frozen from `src/` | ||
| # either way; sourcing the data from site-packages would let an edited module | ||
| # ship beside a stale spec. One tree decides both. | ||
| # | ||
| # A new data file needs a line here. `ci.yml` builds this spec on every pull | ||
| # request, so one that is read at import time fails the gate rather than a | ||
| # release. | ||
| datas = [ | ||
| ("src/unstract_cli/overlay.toml", "unstract_cli"), | ||
| ("src/unstract_cli/specs", "unstract_cli/specs"), | ||
| ] | ||
|
|
||
| hiddenimports = [ | ||
| # `unstract.clone.report.CloneReport.render` imports these inside the | ||
| # function, behind `except ImportError: return self._render_plain()`. The | ||
| # module graph does follow function-level imports, but a miss here degrades | ||
| # `unstract clone`'s table to plain text without failing anything, so the | ||
| # dependency is stated rather than inferred. | ||
| "rich.console", | ||
| "rich.table", | ||
| ] | ||
|
|
||
| # A local build runs in a `.[dev]` venv, so the test and lint tooling is on the | ||
| # path even though nothing reaches it from the entry point. CI installs only the | ||
| # runtime dependencies, where these are no-ops -- they keep the two builds the | ||
| # same size rather than being load-bearing. `unittest` is deliberately absent: | ||
| # the size it saves is small, and libraries reach for `unittest.mock` in | ||
| # surprising places. | ||
| excludes = [ | ||
| "pytest", | ||
| "_pytest", | ||
| "pluggy", | ||
| "iniconfig", | ||
| "ruff", | ||
| "setuptools", | ||
| "pkg_resources", | ||
| "tkinter", | ||
| ] | ||
|
|
||
| a = Analysis( | ||
| ["src/unstract_cli/__main__.py"], | ||
|
pk-zipstack marked this conversation as resolved.
|
||
| pathex=[], | ||
| binaries=[], | ||
| datas=datas, | ||
| hiddenimports=hiddenimports, | ||
| hookspath=[], | ||
| hooksconfig={}, | ||
| runtime_hooks=[], | ||
| excludes=excludes, | ||
| noarchive=False, | ||
| # Not 1 or 2, and never build with PYTHONOPTIMIZE set. Every derived flag's | ||
| # help text comes from `inspect.getdoc()` on the published clients' methods | ||
| # -- the specs carry no parameter descriptions -- so stripping docstrings | ||
| # empties `--help` across the whole generated surface without failing a | ||
| # single check. | ||
| optimize=0, | ||
| ) | ||
|
|
||
| pyz = PYZ(a.pure) | ||
|
|
||
| exe = EXE( | ||
| pyz, | ||
| a.scripts, | ||
| # One file: the binaries and the data are folded into the executable rather | ||
| # than collected beside it, so there is no COLLECT and nothing to unpack. | ||
| a.binaries, | ||
| a.datas, | ||
| [], | ||
| name="unstract", | ||
| debug=False, | ||
| bootloader_ignore_signals=False, | ||
| # Stripping invalidates the ad-hoc signature an arm64 macOS binary needs in | ||
| # order to run at all, and occasionally produces unloadable shared objects | ||
| # on Linux. It saves a couple of megabytes out of twenty. | ||
| strip=False, | ||
| # UPX is unusable on macOS arm64, and on Linux it buys size back by adding | ||
| # decompression to every start and by looking like packed malware to EDR. | ||
| upx=False, | ||
| upx_exclude=[], | ||
| runtime_tmpdir=None, | ||
| console=True, | ||
| disable_windowed_traceback=False, | ||
| argv_emulation=False, | ||
| # The building interpreter's architecture. The runners are native, and no | ||
| # universal binary is shipped. | ||
| target_arch=None, | ||
| # Unsigned by design. PyInstaller still applies the ad-hoc signature Apple | ||
| # Silicon requires to execute a Mach-O at all; what is absent is a Developer | ||
| # ID signature and notarisation, which is why a browser download needs its | ||
| # quarantine attribute cleared. | ||
| codesign_identity=None, | ||
| entitlements_file=None, | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.