github.com/masahide/goansible@v0.0.0-20160116054156-01eac649e9f2/template.go (about)

     1  package goansible
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"syscall"
    11  )
    12  
    13  type TemplateCmd struct {
    14  	Src   string `goansible:"src,required"`
    15  	Dest  string `goansible:"dest,required"`
    16  	Owner string `goansible:"owner"`
    17  	Uid   int    `goansible:"uid"`
    18  	Gid   int    `goansible:"gid"`
    19  	Mode  int    `goansible:"mode"`
    20  }
    21  
    22  func (cmd *TemplateCmd) Run(env *CommandEnv) (*Result, error) {
    23  	var src string
    24  	//pp.Print(env)
    25  	if cmd.Mode == 0 {
    26  		cmd.Mode = 0644
    27  	}
    28  
    29  	if cmd.Src[0] == '/' {
    30  		src = cmd.Src
    31  	} else {
    32  		src = env.Paths.TemplateFile(cmd.Src)
    33  	}
    34  
    35  	//input, err := os.Open(src)
    36  	b, err := ioutil.ReadFile(src)
    37  
    38  	if err != nil {
    39  		return FailureResult(err), err
    40  	}
    41  
    42  	expand, err := ExpandTemplates(env.Env.Vars, string(b))
    43  	if err != nil {
    44  		return FailureResult(err), err
    45  	}
    46  
    47  	srcDigest := md5string(expand)
    48  
    49  	var dstDigest []byte
    50  
    51  	dest := cmd.Dest
    52  
    53  	link := false
    54  
    55  	destStat, err := os.Lstat(dest)
    56  	if err == nil {
    57  		if destStat.IsDir() {
    58  			dest = filepath.Join(dest, filepath.Base(src))
    59  		} else {
    60  			dstDigest, _ = md5file(dest)
    61  		}
    62  
    63  		link = destStat.Mode()&os.ModeSymlink != 0
    64  	}
    65  
    66  	rd := ResultData{
    67  		"md5sum": Any(hex.EncodeToString(srcDigest)),
    68  		"src":    Any(src),
    69  		"dest":   Any(dest),
    70  	}
    71  
    72  	//pp.Print(dstDigest, srcDigest)
    73  	if dstDigest != nil && bytes.Equal(srcDigest, dstDigest) {
    74  		changed := false
    75  
    76  		if cmd.Mode != 0 && destStat.Mode() != os.FileMode(cmd.Mode) {
    77  			changed = true
    78  			if err := os.Chmod(dest, os.FileMode(cmd.Mode)); err != nil {
    79  				return FailureResult(err), err
    80  			}
    81  		}
    82  		if cmd.Uid, cmd.Gid, err = ChangePerm(cmd.Owner, cmd.Uid, cmd.Gid); err != nil {
    83  			return FailureResult(err), err
    84  		}
    85  		if estat, ok := destStat.Sys().(*syscall.Stat_t); ok {
    86  			if cmd.Uid != int(estat.Uid) || cmd.Gid != int(estat.Gid) {
    87  				changed = true
    88  				os.Chown(dest, cmd.Uid, cmd.Gid)
    89  			}
    90  		}
    91  
    92  		return WrapResult(changed, rd), nil
    93  	}
    94  
    95  	tmp := fmt.Sprintf("%s.tmp.%d", cmd.Dest, os.Getpid())
    96  
    97  	//	output, err := os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY, 0644)
    98  	err = ioutil.WriteFile(tmp, []byte(expand), 0644)
    99  
   100  	if err != nil {
   101  		return FailureResult(err), err
   102  	}
   103  
   104  	if link {
   105  		os.Remove(dest)
   106  	}
   107  
   108  	if err := os.Chmod(tmp, os.FileMode(cmd.Mode)); err != nil {
   109  		os.Remove(tmp)
   110  		return FailureResult(err), err
   111  	}
   112  
   113  	if cmd.Uid, cmd.Gid, err = ChangePerm(cmd.Owner, cmd.Uid, cmd.Gid); err != nil {
   114  		return FailureResult(err), err
   115  	}
   116  	os.Chown(tmp, cmd.Uid, cmd.Gid)
   117  
   118  	err = os.Rename(tmp, dest)
   119  	if err != nil {
   120  		os.Remove(tmp)
   121  		return FailureResult(err), err
   122  	}
   123  
   124  	return WrapResult(true, rd), nil
   125  }
   126  
   127  func init() {
   128  	RegisterCommand("template", &TemplateCmd{})
   129  }