11package cli
22
33import (
4+ "archive/zip"
45 "encoding/json"
56 "fmt"
67 "io"
@@ -12,6 +13,8 @@ import (
1213 "sync/atomic"
1314 "time"
1415
16+ "github.com/skratchdot/open-golang/open"
17+
1518 "github.com/rwx-cloud/cli/internal/accesstoken"
1619 "github.com/rwx-cloud/cli/internal/api"
1720 "github.com/rwx-cloud/cli/internal/dotenv"
@@ -587,20 +590,139 @@ func (s Service) DownloadLogs(cfg DownloadLogsConfig) error {
587590 return errors .Wrap (err , "unable to download logs" )
588591 }
589592
590- outputPath := filepath .Join (cfg .OutputDir , LogDownloadRequest .Filename )
593+ var outputPath string
594+ if cfg .OutputFile != "" {
595+ outputPath = cfg .OutputFile
596+ } else {
597+ outputPath = filepath .Join (cfg .OutputDir , LogDownloadRequest .Filename )
598+ }
599+
600+ outputDir := filepath .Dir (outputPath )
601+ if err := os .MkdirAll (outputDir , 0755 ); err != nil {
602+ return errors .Wrapf (err , "unable to create output directory %s" , outputDir )
603+ }
591604
592605 if _ , err := os .Stat (outputPath ); err == nil {
593- fmt .Fprintf (s .Stdout , "Overwriting existing file at %s\n " , outputPath )
606+ if ! cfg .Json {
607+ fmt .Fprintf (s .Stdout , "Overwriting existing file at %s\n " , outputPath )
608+ }
594609 }
595610
596611 if err := os .WriteFile (outputPath , logBytes , 0644 ); err != nil {
597612 return errors .Wrapf (err , "unable to write log file to %s" , outputPath )
598613 }
599614
600- fmt .Fprintf (s .Stdout , "Logs downloaded to %s\n " , outputPath )
615+ var outputFiles []string
616+ outputFiles = append (outputFiles , outputPath )
617+
618+ if cfg .AutoExtract && strings .HasSuffix (strings .ToLower (outputPath ), ".zip" ) {
619+ // Create a directory named after the zip file (without .zip extension)
620+ zipName := filepath .Base (outputPath )
621+ extractDirName := strings .TrimSuffix (zipName , filepath .Ext (zipName ))
622+ extractDir := filepath .Join (filepath .Dir (outputPath ), extractDirName )
623+
624+ if err := os .MkdirAll (extractDir , 0755 ); err != nil {
625+ return errors .Wrapf (err , "unable to create extraction directory %s" , extractDir )
626+ }
627+
628+ extractedFiles , err := extractZip (outputPath , extractDir )
629+ if err != nil {
630+ return errors .Wrapf (err , "unable to extract zip archive %s" , outputPath )
631+ }
632+ outputFiles = extractedFiles
633+
634+ if ! cfg .Json {
635+ fmt .Fprintf (s .Stdout , "Extracted %d file(s) from %s to %s\n " , len (extractedFiles ), outputPath , extractDir )
636+ }
637+ }
638+
639+ if cfg .Open {
640+ for _ , file := range outputFiles {
641+ if err := open .Run (file ); err != nil {
642+ if ! cfg .Json {
643+ fmt .Fprintf (s .Stderr , "Failed to open %s: %v\n " , file , err )
644+ }
645+ }
646+ }
647+ }
648+
649+ if cfg .Json {
650+ output := struct {
651+ OutputFiles []string `json:"outputFiles"`
652+ }{
653+ OutputFiles : outputFiles ,
654+ }
655+ if err := json .NewEncoder (s .Stdout ).Encode (output ); err != nil {
656+ return errors .Wrap (err , "unable to encode JSON output" )
657+ }
658+ } else {
659+ if len (outputFiles ) == 1 {
660+ fmt .Fprintf (s .Stdout , "Logs downloaded to %s\n " , outputFiles [0 ])
661+ } else {
662+ fmt .Fprintf (s .Stdout , "Logs downloaded and extracted:\n " )
663+ for _ , file := range outputFiles {
664+ fmt .Fprintf (s .Stdout , " %s\n " , file )
665+ }
666+ }
667+ }
601668 return nil
602669}
603670
671+ func extractZip (zipPath , destDir string ) ([]string , error ) {
672+ reader , err := zip .OpenReader (zipPath )
673+ if err != nil {
674+ return nil , errors .Wrap (err , "unable to open zip file" )
675+ }
676+ defer reader .Close ()
677+
678+ var extractedFiles []string
679+
680+ for _ , file := range reader .File {
681+ filePath := filepath .Join (destDir , file .Name )
682+ if ! strings .HasPrefix (filePath , filepath .Clean (destDir )+ string (os .PathSeparator )) {
683+ return nil , fmt .Errorf ("invalid file path in zip: %s" , file .Name )
684+ }
685+
686+ if file .FileInfo ().IsDir () {
687+ if err := os .MkdirAll (filePath , 0755 ); err != nil {
688+ return nil , errors .Wrapf (err , "unable to create directory %s" , filePath )
689+ }
690+ continue
691+ }
692+
693+ if err := os .MkdirAll (filepath .Dir (filePath ), 0755 ); err != nil {
694+ return nil , errors .Wrapf (err , "unable to create directory for %s" , filePath )
695+ }
696+
697+ rc , err := file .Open ()
698+ if err != nil {
699+ return nil , errors .Wrapf (err , "unable to open file %s in zip" , file .Name )
700+ }
701+
702+ outFile , err := os .Create (filePath )
703+ if err != nil {
704+ rc .Close ()
705+ return nil , errors .Wrapf (err , "unable to create file %s" , filePath )
706+ }
707+
708+ _ , err = io .Copy (outFile , rc )
709+ outFile .Close ()
710+ rc .Close ()
711+
712+ if err != nil {
713+ return nil , errors .Wrapf (err , "unable to extract file %s" , filePath )
714+ }
715+
716+ if err := os .Chmod (filePath , file .FileInfo ().Mode ()); err != nil {
717+ return nil , errors .Wrapf (err , "unable to set permissions for %s" , filePath )
718+ }
719+
720+ extractedFiles = append (extractedFiles , filePath )
721+ }
722+
723+ return extractedFiles , nil
724+ }
725+
604726func (s Service ) SetSecretsInVault (cfg SetSecretsInVaultConfig ) error {
605727 defer s .outputLatestVersionMessage ()
606728 err := cfg .Validate ()
0 commit comments