github.com/vmware/govmomi@v0.51.0/cli/library/export.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package library
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"net/url"
    13  	"os"
    14  	"path/filepath"
    15  	"time"
    16  
    17  	"github.com/vmware/govmomi/cli"
    18  	"github.com/vmware/govmomi/cli/flags"
    19  	"github.com/vmware/govmomi/vapi/library"
    20  	"github.com/vmware/govmomi/vim25/soap"
    21  )
    22  
    23  type export struct {
    24  	*flags.ClientFlag
    25  	*flags.OutputFlag
    26  	library.Item
    27  }
    28  
    29  func init() {
    30  	cli.Register("library.export", &export{})
    31  }
    32  
    33  func (cmd *export) Register(ctx context.Context, f *flag.FlagSet) {
    34  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    35  	cmd.ClientFlag.Register(ctx, f)
    36  
    37  	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
    38  	cmd.OutputFlag.Register(ctx, f)
    39  }
    40  
    41  func (cmd *export) Usage() string {
    42  	return "PATH [DEST]"
    43  }
    44  
    45  func (cmd *export) Description() string {
    46  	return `Export library items.
    47  
    48  If the given PATH is a library item, all files will be downloaded.
    49  
    50  If the given PATH is a library item file, only that file will be downloaded.
    51  
    52  By default, files are saved using the library item's file names to the current directory.
    53  If DEST is given for a library item, files are saved there instead of the current directory.
    54  If DEST is given for a library item file, the file will be saved with that name.
    55  If DEST is '-', the file contents are written to stdout instead of saving to a file.
    56  
    57  Examples:
    58    govc library.export library_name/item_name
    59    govc library.export library_name/item_name/file_name
    60    govc library.export library_name/item_name/*.ovf -`
    61  }
    62  
    63  func (cmd *export) Process(ctx context.Context) error {
    64  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    65  		return err
    66  	}
    67  	return cmd.OutputFlag.Process(ctx)
    68  }
    69  
    70  func (cmd *export) Run(ctx context.Context, f *flag.FlagSet) error {
    71  	c, err := cmd.RestClient()
    72  	if err != nil {
    73  		return err
    74  	}
    75  	cmd.KeepAlive(c)
    76  
    77  	var names []string
    78  	m := library.NewManager(c)
    79  	res, err := flags.ContentLibraryResult(ctx, c, "", f.Arg(0))
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	switch t := res.GetResult().(type) {
    85  	case library.Item:
    86  		cmd.Item = t
    87  	case library.File:
    88  		names = []string{t.Name}
    89  		cmd.Item = res.GetParent().GetResult().(library.Item)
    90  	default:
    91  		return fmt.Errorf("%q is a %T", f.Arg(0), t)
    92  	}
    93  
    94  	dst := f.Arg(1)
    95  	one := len(names) == 1
    96  	var log io.Writer = os.Stdout
    97  	isStdout := one && dst == "-"
    98  	if isStdout {
    99  		log = io.Discard
   100  	}
   101  
   102  	session, err := m.CreateLibraryItemDownloadSession(ctx, library.Session{
   103  		LibraryItemID: cmd.ID,
   104  	})
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	if len(names) == 0 {
   110  		files, err := m.ListLibraryItemDownloadSessionFile(ctx, session)
   111  		if err != nil {
   112  			return err
   113  		}
   114  
   115  		for _, file := range files {
   116  			names = append(names, file.Name)
   117  		}
   118  	}
   119  
   120  	for _, name := range names {
   121  		_, err = m.PrepareLibraryItemDownloadSessionFile(ctx, session, name)
   122  		if err != nil {
   123  			return err
   124  		}
   125  	}
   126  
   127  	download := func(src *url.URL, name string) error {
   128  		p := soap.DefaultDownload
   129  
   130  		if isStdout {
   131  			s, _, err := c.Download(ctx, src, &p)
   132  			if err != nil {
   133  				return err
   134  			}
   135  			_, err = io.Copy(os.Stdout, s)
   136  			_ = s.Close()
   137  			return err
   138  		}
   139  
   140  		if cmd.OutputFlag.TTY {
   141  			logger := cmd.ProgressLogger(fmt.Sprintf("Downloading %s... ", src.String()))
   142  			defer logger.Wait()
   143  			p.Progress = logger
   144  		}
   145  
   146  		if one && dst != "" {
   147  			name = dst
   148  		} else {
   149  			name = filepath.Join(dst, name)
   150  		}
   151  		return c.DownloadFile(ctx, name, src, &p)
   152  	}
   153  
   154  	for _, name := range names {
   155  		var info *library.DownloadFile
   156  		_, _ = fmt.Fprintf(log, "Checking %s... ", name)
   157  		for {
   158  			info, err = m.GetLibraryItemDownloadSessionFile(ctx, session, name)
   159  			if err != nil {
   160  				return err
   161  			}
   162  			if info.Status == "PREPARED" {
   163  				_, _ = fmt.Fprintln(log, info.Status)
   164  				break // with this status we have a DownloadEndpoint.URI
   165  			}
   166  			time.Sleep(time.Second)
   167  		}
   168  
   169  		src, err := url.Parse(info.DownloadEndpoint.URI)
   170  		if err != nil {
   171  			return err
   172  		}
   173  		err = download(src, name)
   174  		if err != nil {
   175  			return err
   176  		}
   177  	}
   178  
   179  	return nil
   180  }