1414from cs_tools .cli .types import Directory
1515from cs_tools .cli .ux import CSToolsCommand , CSToolsGroup , rich_console
1616from cs_tools .settings import _meta_config as meta
17+ from cs_tools .sync import base
1718from cs_tools .updater import cs_tools_venv
1819from cs_tools .updater ._bootstrapper import get_latest_cs_tools_release
1920import rich
@@ -140,10 +141,11 @@ def analytics():
140141def download (
141142 directory : pathlib .Path = typer .Option (help = "location to download the python binaries to" , click_type = Directory ()),
142143 platform : str = typer .Option (help = "tag describing the OS and CPU architecture of the target environment" ),
143- python_version : str = typer .Option (
144+ python_version : AwesomeVersion = typer .Option (
144145 metavar = "X.Y" , help = "major and minor version of your python install" , parser = AwesomeVersion
145146 ),
146147 beta : bool = typer .Option (False , "--beta" , help = "if included, download the latest pre-release binary" ),
148+ syncer_dialect : str = typer .Option (None , help = "the name of the dialect to fetch dependencies for" ),
147149):
148150 """
149151 Generate an offline binary.
@@ -156,14 +158,35 @@ def download(
156158 [b yellow]python -m sysconfig[/]
157159
158160 """
161+ # DEV NOTE: @boonhapus, 2024/05/21
162+ #
163+ # The idea behind the offline installer is to simulate `pip install` by downloading
164+ # all the necessary packages to build our environment.
165+ #
159166 requirements = directory .joinpath ("requirements" )
167+
168+ log .info ("Fetching latest CS Tools release from GitHub" )
160169 release_info = get_latest_cs_tools_release (allow_beta = beta )
161170 release_tag = release_info ["tag_name" ]
162171
163- venv = cs_tools_venv
172+ if syncer_dialect is not None :
173+ syncer_dir = utils .get_package_directory ("cs_tools" ) / "sync" / syncer_dialect
174+
175+ if not syncer_dir .exists ():
176+ log .error (f"Syncer dialect { syncer_dialect } not found" )
177+ raise typer .Exit (1 )
178+
179+ log .info (f"Fetching { syncer_dialect } syncer dependencies.." )
180+ manifest = base .SyncerManifest .model_validate_json (syncer_dir .joinpath ("MANIFEST.json" ).read_text ())
181+ manifest .__ensure_pip_requirements__ ()
164182
165183 # freeze our own environment, which has all the dependencies needed to build
166- frozen = {req for req in venv .pip ("freeze" , "--quiet" ).stdout .decode ().split ("\n " ) if "cs_tools" not in req }
184+ log .info ("Freezing existing virtual environment.." )
185+ frozen = {
186+ r
187+ for r in cs_tools_venv .pip ("freeze" , "--quiet" , visible_output = False ).stdout .decode ().split ("\n " )
188+ if "cs_tools" not in r
189+ }
167190
168191 # add in the latest release
169192 frozen .add (f"cs_tools @ https://github.com/thoughtspot/cs_tools/archive/{ release_tag } .zip" )
@@ -183,7 +206,8 @@ def download(
183206 if "win" in platform :
184207 frozen .add ("pyreadline3 == 3.4.1" ) # from cs_tools
185208
186- venv .pip (
209+ log .info ("Downloading dependent packages.." )
210+ cs_tools_venv .pip (
187211 "download" , * frozen ,
188212 "--no-deps" , # we shouldn't need transitive dependencies, since we've build all the dependencies above
189213 "--dest" , requirements .as_posix (),
@@ -199,6 +223,8 @@ def download(
199223 from cs_tools .updater import _bootstrapper , _updater
200224
201225 zip_fp = directory .joinpath (f"cs-tools_{ __version__ } _{ platform } _{ python_version } " )
226+
227+ log .info (f"Preparing your download at { zip_fp } .." )
202228 shutil .copy (_bootstrapper .__file__ , requirements .joinpath ("_bootstrapper.py" ))
203229 shutil .copy (_updater .__file__ , requirements .joinpath ("_updater.py" ))
204230 shutil .make_archive (zip_fp .as_posix (), "zip" , requirements )
0 commit comments