@@ -4,6 +4,7 @@ use crate::shell::SupportedShell;
44
55use log:: { debug, error, info, warn} ;
66use serde:: Deserialize ;
7+ use std:: fs;
78use std:: io:: { Error , ErrorKind } ;
89use std:: path:: { Component , Path , PathBuf } ;
910use std:: process:: ExitCode ;
@@ -21,7 +22,7 @@ pub enum Subcommand {
2122 /// Create an archive from an environment. Requires `conda-pack` to be in the environment.
2223 Pack ( PackArgs ) ,
2324 /// Unpack an archive to create an environment from it.
24- Unpack ( CommonEnvArgs ) ,
25+ Unpack ( UnpackArgs ) ,
2526 /// List existing environments
2627 List ,
2728 /// Display information about the micromamba setup
@@ -73,13 +74,23 @@ pub struct PackArgs {
7374 /// Common environment arguments
7475 #[ command( flatten) ]
7576 common : CommonEnvArgs ,
76- /// Output path/filename of the packed environment. If not specified, the
77- /// same method is used to determine the environment name as for the
78- /// "--name" parameter, and the default name is <env_name>.tar.gz
77+ /// Output path/filename of the packed environment, ending in .tar.gz. If
78+ /// not specified, the same method is used to determine the environment name
79+ /// as for the "--name" parameter, and the default name is <env_name>.tar.gz
7980 #[ arg( long, short, value_name = "OUTPUT" ) ]
8081 output : Option < String > ,
8182}
8283
84+ #[ derive( Debug , clap:: Args ) ]
85+ pub struct UnpackArgs {
86+ /// Common environment arguments
87+ #[ command( flatten) ]
88+ common : CommonEnvArgs ,
89+ /// Path to a packed environment archive (ending in .tar.gz)
90+ #[ arg( value_name = "ARCHIVE" ) ]
91+ archive_path : PathBuf ,
92+ }
93+
8394/// Contains the fields we need from a parsed environment file.
8495#[ derive( Deserialize ) ]
8596struct RobotmkEnv {
@@ -365,10 +376,74 @@ pub fn run(config: Config, subcommand: Subcommand) -> Result<(), ExitCode> {
365376 )
366377 . into ( )
367378 }
368- _ => {
369- println ! ( "{:?}" , config) ;
370- println ! ( "{:?}" , subcommand) ;
371- Ok ( ( ) )
379+ Subcommand :: Unpack ( args) => {
380+ fn archive_name_to_env_name ( archive_path : & Path ) -> Option < String > {
381+ let filename = archive_path. file_name ( ) ?. to_str ( ) ?;
382+ filename
383+ . strip_suffix ( ".tar.gz" )
384+ . or_else ( || filename. strip_suffix ( ".tgz" ) )
385+ . map ( String :: from)
386+ }
387+ let env_name = match args. common . name {
388+ Some ( name) => name,
389+ None => match archive_name_to_env_name ( & args. archive_path ) {
390+ Some ( name) => {
391+ info ! (
392+ "Using '{}' as environment name, based on archive filename" ,
393+ name
394+ ) ;
395+ name
396+ }
397+ None => {
398+ error ! (
399+ "Could not determine environment name from archive filename. Please specify an environment name with --name."
400+ ) ;
401+ return Err ( ExitCode :: FAILURE ) ;
402+ }
403+ } ,
404+ } ;
405+
406+ // TODO: We really need a more generic error type to avoid this kind of mapping everywhere
407+ let target_env_path = micromamba:: create_env_dir ( & config, & env_name) . map_err ( |e| {
408+ error ! ( "{}" , e) ;
409+ ExitCode :: FAILURE
410+ } ) ?;
411+
412+ // Send the archive to flate2 to decompress and untar
413+ info ! (
414+ "Unpacking archive '{}' to create environment '{}'" ,
415+ args. archive_path. display( ) ,
416+ env_name
417+ ) ;
418+ debug ! ( "Opening '{}' for read" , args. archive_path. display( ) ) ;
419+ let archive_file = fs:: File :: open ( & args. archive_path ) . map_err ( |e| {
420+ error ! ( "{}" , e) ;
421+ ExitCode :: FAILURE
422+ } ) ?;
423+ let decompressor = flate2:: read:: GzDecoder :: new ( archive_file) ;
424+ let mut archive = tar:: Archive :: new ( decompressor) ;
425+ archive. unpack ( & target_env_path) . map_err ( |e| {
426+ error ! (
427+ "Could not unpack archive to '{}': {}" ,
428+ target_env_path. display( ) ,
429+ e
430+ ) ;
431+ ExitCode :: FAILURE
432+ } ) ?;
433+ info ! (
434+ "Successfully unpacked environment to '{}'" ,
435+ target_env_path. display( )
436+ ) ;
437+
438+ info ! ( "Running 'conda-unpack' in the new environment to fix paths..." ) ;
439+ let result = micromamba (
440+ & config,
441+ vec ! [ "run" , "--name" , & env_name, "conda-unpack" ] ,
442+ config. verbose ,
443+ ) ;
444+ let rc = result. exit_code ( ) ;
445+ dump_micromamba_captured_output_on_error ( & result, rc) ;
446+ result. into ( )
372447 }
373448 }
374449}
0 commit comments