2828 bat_env_var_esc ,
2929 copy_conda_exe ,
3030 filename_dist ,
31+ get_final_channels ,
3132 shortcuts_flags ,
3233)
3334
@@ -151,11 +152,50 @@ def _get_script_env_variables(info: dict) -> dict[str, str]:
151152 return escaped_vars
152153
153154
155+ def _setup_envs_commands (info : dict ) -> list [dict ]:
156+ """Build environment setup data for base and extra_envs.
157+
158+ Returns a list of dicts, each containing the data needed to install
159+ one environment. Used by the run_installation.bat template.
160+ """
161+ environments = []
162+
163+ # Base environment
164+ environments .append (
165+ {
166+ "name" : "base" ,
167+ "prefix" : "%BASE_PATH%" ,
168+ "lockfile" : r"%BASE_PATH%\conda-meta\initial-state.explicit.txt" ,
169+ "channels" : "," .join (get_final_channels (info )),
170+ "shortcuts" : shortcuts_flags (info ),
171+ }
172+ )
173+
174+ # Extra environments
175+ for env_name in info .get ("_extra_envs_info" , {}):
176+ env_config = info ["extra_envs" ][env_name ]
177+ # Needed for shortcuts_flags function
178+ if "_conda_exe_type" not in env_config :
179+ env_config ["_conda_exe_type" ] = info .get ("_conda_exe_type" )
180+ channel_info = {
181+ "channels" : env_config .get ("channels" , info .get ("channels" , ())),
182+ "channels_remap" : env_config .get ("channels_remap" , info .get ("channels_remap" , ())),
183+ }
184+ environments .append (
185+ {
186+ "name" : env_name ,
187+ "prefix" : rf"%BASE_PATH%\envs\{ env_name } " ,
188+ "lockfile" : rf"%BASE_PATH%\envs\{ env_name } \conda-meta\initial-state.explicit.txt" ,
189+ "channels" : "," .join (get_final_channels (channel_info )),
190+ "shortcuts" : shortcuts_flags (env_config ),
191+ }
192+ )
193+
194+ return environments
195+
196+
154197def create_uninstall_options_list (info : dict ) -> list [dict ]:
155- """Returns a list of dicts with data formatted for the uninstallation options page.
156- Options are currently only shown when uninstall_with_conda_exe is True."""
157- if not bool (info .get ("uninstall_with_conda_exe" )):
158- return []
198+ """Returns a list of dicts with data formatted for the uninstallation options page."""
159199 return [
160200 {
161201 "name" : "remove_user_data" ,
@@ -243,7 +283,7 @@ def create_install_options_list(info: dict) -> list[dict]:
243283 "name" : "enable_shortcuts" ,
244284 "title" : "Create shortcuts" ,
245285 "description" : "Create shortcuts (supported packages only)." ,
246- "default" : False ,
286+ "default" : True ,
247287 }
248288 )
249289
@@ -411,14 +451,8 @@ def render_templates(self) -> list[Path]:
411451 # In the .bat template this is used in the "shortcuts enabled" branch,
412452 # so passing an empty string here is correct when all shortcuts are wanted.
413453 "shortcuts" : shortcuts_flags (self .info ),
414- # --- uninstall_with_conda_exe ---
415- "uninstall_with_conda_exe" : bool (self .info .get ("uninstall_with_conda_exe" )),
416- # --- has_conda ---
417- "has_conda" : self .info .get ("_has_conda" , False ),
418454 # --- setup_envs ---
419- # Placeholder for extra_envs support. Currently only contains base env.
420- # Will be expanded when extra_envs is implemented for MSI installers.
421- "setup_envs" : [{"name" : "base" , "prefix" : "%BASE_PATH%" }],
455+ "setup_envs" : _setup_envs_commands (self .info ),
422456 # --- virtual_specs ---
423457 # virtual_specs: quoted for command-line use
424458 # virtual_specs_debug: unquoted for display
@@ -475,7 +509,11 @@ def write_pyproject_toml(self, root: Path, external: Path) -> None:
475509
476510 def _stage_dists (self , pkgs_dir : Path ) -> None :
477511 download_dir = Path (self .info ["_download_dir" ])
478- for dist in self .info ["_dists" ]:
512+ # Collect dists from base and extra_envs, de-duplicated
513+ dists = set (self .info ["_dists" ])
514+ for env_info in self .info .get ("_extra_envs_info" , {}).values ():
515+ dists .update (env_info .get ("_dists" , []))
516+ for dist in sorted (dists ):
479517 shutil .copy (download_dir / filename_dist (dist ), pkgs_dir )
480518
481519 def _stage_conda (self , external_dir : Path ) -> None :
@@ -489,6 +527,11 @@ def create(info, verbose=False):
489527 if not info .get ("_conda_exe_supports_logging" ):
490528 raise Exception ("MSI installers require conda-standalone with logging support." )
491529
530+ # MSI installers always use conda-standalone for uninstallation.
531+ # This ensures proper cleanup of conda init, environments, and shortcuts
532+ # via the `conda constructor uninstall` command.
533+ info ["uninstall_with_conda_exe" ] = True
534+
492535 payload = Payload (info )
493536 payload .prepare ()
494537
0 commit comments