github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/resource/context/internal/download.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package internal
     5  
     6  // TODO(ericsnow) Move this file elsewhere?
     7  //  (e.g. top-level resource pkg, charm/resource)
     8  
     9  import (
    10  	"io"
    11  
    12  	"github.com/juju/errors"
    13  )
    14  
    15  // Download downloads the resource from the provied source to the target.
    16  func Download(target DownloadTarget, remote ContentSource) error {
    17  	resDir, err := target.Initialize()
    18  	if err != nil {
    19  		return errors.Trace(err)
    20  	}
    21  
    22  	if err := resDir.Write(remote); err != nil {
    23  		return errors.Trace(err)
    24  	}
    25  
    26  	return nil
    27  }
    28  
    29  // DownloadIndirect downloads the resource from the source into a temp
    30  // directory. Then the target is replaced by the temp directory.
    31  func DownloadIndirect(target DownloadTarget, remote ContentSource, deps DownloadIndirectDeps) error {
    32  	tempDirSpec, err := deps.NewTempDirSpec()
    33  	defer deps.CloseAndLog(tempDirSpec, "resource temp dir")
    34  	if err != nil {
    35  		return errors.Trace(err)
    36  	}
    37  
    38  	if err := deps.DownloadDirect(tempDirSpec, remote); err != nil {
    39  		return errors.Trace(err)
    40  	}
    41  
    42  	resDir, err := target.Initialize()
    43  	if err != nil {
    44  		return errors.Trace(err)
    45  	}
    46  
    47  	oldDir := tempDirSpec.Resolve()
    48  	newDir := resDir.Resolve()
    49  	if err := deps.ReplaceDirectory(newDir, oldDir); err != nil {
    50  		return errors.Annotate(err, "could not replace existing resource directory")
    51  	}
    52  
    53  	return nil
    54  }
    55  
    56  // DownloadIndirectDeps exposes the external functionality needed
    57  // by DownloadIndirect.
    58  type DownloadIndirectDeps interface {
    59  	// NewTempDirSpec returns a directory spec for the resource under a temporary datadir.
    60  	NewTempDirSpec() (DownloadTempTarget, error)
    61  
    62  	// CloseAndLog closes the closer and logs any error.
    63  	CloseAndLog(io.Closer, string)
    64  
    65  	// DownloadDirect downloads the source into the target.
    66  	DownloadDirect(DownloadTarget, ContentSource) error
    67  
    68  	// ReplaceDirectory moves the source directory path to the target
    69  	// path. If the target path already exists then it is replaced atomically.
    70  	ReplaceDirectory(tgt, src string) error
    71  }
    72  
    73  // DownloadTarget exposes the functionality of a directory spec
    74  // needed by Download().
    75  type DownloadTarget interface {
    76  	// Initialize prepares the target directory and returns it.
    77  	Initialize() (DownloadDirectory, error)
    78  }
    79  
    80  // DownloadDirectory exposes the functionality of a resource directory
    81  // needed by Download().
    82  type DownloadDirectory interface {
    83  	Resolver
    84  
    85  	// Write writes all the relevant files for the provided source
    86  	// to the directory.
    87  	Write(ContentSource) error
    88  }
    89  
    90  // DownloadTempTarget represents a temporary download directory.
    91  type DownloadTempTarget interface {
    92  	DownloadTarget
    93  	Resolver
    94  	io.Closer
    95  }
    96  
    97  // Resolver exposes the functionality of DirectorySpec needed
    98  // by DownloadIndirect.
    99  type Resolver interface {
   100  	// Resolve returns the fully resolved path for the provided path items.
   101  	Resolve(...string) string
   102  }