launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/utils/file.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package utils
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"os/user"
    11  	"path"
    12  	"path/filepath"
    13  	"regexp"
    14  	"runtime"
    15  
    16  	"launchpad.net/juju-core/juju/osenv"
    17  )
    18  
    19  // UserHomeDir returns the home directory for the specified user, or the
    20  // home directory for the current user if the specified user is empty.
    21  func UserHomeDir(userName string) (homeDir string, err error) {
    22  	var u *user.User
    23  	if userName == "" {
    24  		// TODO (wallyworld) - fix tests on Windows
    25  		// Ordinarily, we'd always use user.Current() to get the current user
    26  		// and then get the HomeDir from that. But our tests rely on poking
    27  		// a value into $HOME in order to override the normal home dir for the
    28  		// current user. So on *nix, we're forced to use osenv.Home() to make
    29  		// the tests pass. All of our tests currently construct paths with the
    30  		// default user in mind eg "~/foo".
    31  		if runtime.GOOS == "windows" {
    32  			u, err = user.Current()
    33  		} else {
    34  			return osenv.Home(), nil
    35  		}
    36  	} else {
    37  		u, err = user.Lookup(userName)
    38  		if err != nil {
    39  			return "", mask(err)
    40  		}
    41  	}
    42  	return u.HomeDir, nil
    43  }
    44  
    45  var userHomePathRegexp = regexp.MustCompile("(~(?P<user>[^/]*))(?P<path>.*)")
    46  
    47  // NormalizePath expands a path containing ~ to its absolute form,
    48  // and removes any .. or . path elements.
    49  func NormalizePath(dir string) (string, error) {
    50  	if userHomePathRegexp.MatchString(dir) {
    51  		user := userHomePathRegexp.ReplaceAllString(dir, "$user")
    52  		userHomeDir, err := UserHomeDir(user)
    53  		if err != nil {
    54  			return "", mask(err)
    55  		}
    56  		dir = userHomePathRegexp.ReplaceAllString(dir, fmt.Sprintf("%s$path", userHomeDir))
    57  	}
    58  	return filepath.Clean(dir), nil
    59  }
    60  
    61  // JoinServerPath joins any number of path elements into a single path, adding
    62  // a path separator (based on the current juju server OS) if necessary. The
    63  // result is Cleaned; in particular, all empty strings are ignored.
    64  func JoinServerPath(elem ...string) string {
    65  	return path.Join(elem...)
    66  }
    67  
    68  // UniqueDirectory returns "path/name" if that directory doesn't exist.  If it
    69  // does, the method starts appending .1, .2, etc until a unique name is found.
    70  func UniqueDirectory(path, name string) (string, error) {
    71  	dir := filepath.Join(path, name)
    72  	_, err := os.Stat(dir)
    73  	if os.IsNotExist(err) {
    74  		return dir, nil
    75  	}
    76  	for i := 1; ; i++ {
    77  		dir := filepath.Join(path, fmt.Sprintf("%s.%d", name, i))
    78  		_, err := os.Stat(dir)
    79  		if os.IsNotExist(err) {
    80  			return dir, nil
    81  		} else if err != nil {
    82  			return "", mask(err)
    83  		}
    84  	}
    85  }
    86  
    87  // CopyFile writes the contents of the given source file to dest.
    88  func CopyFile(dest, source string) error {
    89  	df, err := os.Create(dest)
    90  	if err != nil {
    91  		return mask(err)
    92  	}
    93  	f, err := os.Open(source)
    94  	if err != nil {
    95  		return mask(err)
    96  	}
    97  	defer f.Close()
    98  	_, err = io.Copy(df, f)
    99  	return err
   100  }