@@ -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,73 @@ 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 < & str > {
381+ let filename = archive_path. file_name ( ) ?. to_str ( ) ?;
382+ filename
383+ . strip_suffix ( ".tar.gz" )
384+ . or_else ( || filename. strip_suffix ( ".tgz" ) )
385+ }
386+ let env_name = match args. common . name {
387+ Some ( name) => name,
388+ None => match archive_name_to_env_name ( & args. archive_path ) {
389+ Some ( name) => {
390+ info ! (
391+ "Using '{}' as environment name, based on archive filename" ,
392+ name
393+ ) ;
394+ String :: from ( name)
395+ }
396+ None => {
397+ error ! (
398+ "Could not determine environment name from archive filename. Please specify an environment name with --name."
399+ ) ;
400+ return Err ( ExitCode :: FAILURE ) ;
401+ }
402+ } ,
403+ } ;
404+
405+ // TODO: We really need a more generic error type to avoid this kind of mapping everywhere
406+ let target_env_path = micromamba:: create_env_dir ( & config, & env_name) . map_err ( |e| {
407+ error ! ( "{}" , e) ;
408+ ExitCode :: FAILURE
409+ } ) ?;
410+
411+ // Send the archive to flate2 to decompress and untar
412+ info ! (
413+ "Unpacking archive '{}' to create environment '{}'" ,
414+ args. archive_path. display( ) ,
415+ env_name
416+ ) ;
417+ debug ! ( "Opening '{}' for read" , args. archive_path. display( ) ) ;
418+ let archive_file = fs:: File :: open ( & args. archive_path ) . map_err ( |e| {
419+ error ! ( "{}" , e) ;
420+ ExitCode :: FAILURE
421+ } ) ?;
422+ let decompressor = flate2:: read:: GzDecoder :: new ( archive_file) ;
423+ let mut archive = tar:: Archive :: new ( decompressor) ;
424+ archive. unpack ( & target_env_path) . map_err ( |e| {
425+ error ! (
426+ "Could not unpack archive to '{}': {}" ,
427+ target_env_path. display( ) ,
428+ e
429+ ) ;
430+ ExitCode :: FAILURE
431+ } ) ?;
432+ info ! (
433+ "Successfully unpacked environment to '{}'" ,
434+ target_env_path. display( )
435+ ) ;
436+
437+ info ! ( "Running 'conda-unpack' in the new environment to fix paths..." ) ;
438+ let result = micromamba (
439+ & config,
440+ vec ! [ "run" , "--name" , & env_name, "conda-unpack" ] ,
441+ config. verbose ,
442+ ) ;
443+ let rc = result. exit_code ( ) ;
444+ dump_micromamba_captured_output_on_error ( & result, rc) ;
445+ result. into ( )
372446 }
373447 }
374448}
0 commit comments