github.com/jgrancell/metasync@v0.0.0-20220105143315-c43793d9d9c1/app/candidate.go (about)

     1  package app
     2  
     3  import (
     4  	"bytes"
     5  	"io/fs"
     6  	"io/ioutil"
     7  	"os"
     8  
     9  	diff "github.com/sergi/go-diff/diffmatchpatch"
    10  )
    11  
    12  type SyncCandidate struct {
    13  	Diff           string
    14  	Name           string
    15  	SourceContents []byte
    16  	SourceFile     string
    17  	TargetContents []byte
    18  	TargetFile     string
    19  	TargetMode     fs.FileMode
    20  }
    21  
    22  func (c *SyncCandidate) TargetExists() bool {
    23  	_, err := os.Stat(c.TargetFile)
    24  	if err != nil {
    25  		if os.IsNotExist(err) {
    26  			return false
    27  		}
    28  	}
    29  	return true
    30  }
    31  
    32  func (c *SyncCandidate) GetWriteMode(path string) error {
    33  	file, err := os.Stat(path)
    34  	if err != nil {
    35  		return err
    36  	}
    37  
    38  	c.TargetMode = file.Mode()
    39  	return nil
    40  }
    41  
    42  func (c *SyncCandidate) RequiresSync() (bool, error) {
    43  	var err error
    44  	if c.SourceContents, err = c.LoadContents(c.SourceFile); err != nil {
    45  		return false, err
    46  	}
    47  
    48  	if c.TargetExists() {
    49  		// Getting the file mode for the target file
    50  		if err := c.GetWriteMode(c.TargetFile); err != nil {
    51  			return false, err
    52  		}
    53  
    54  		c.TargetContents, err = c.LoadContents(c.TargetFile)
    55  		if err != nil {
    56  			return false, err
    57  		}
    58  
    59  		check := diff.New()
    60  		diffs := check.DiffMain(string(c.TargetContents), string(c.SourceContents), false)
    61  		c.Diff = check.DiffPrettyText(diffs)
    62  
    63  		if bytes.Equal(c.SourceContents, c.TargetContents) {
    64  			return false, nil
    65  		}
    66  	}
    67  	if err := c.GetWriteMode(c.SourceFile); err != nil {
    68  		return false, err
    69  	}
    70  	return true, nil
    71  }
    72  
    73  func (c *SyncCandidate) LoadContents(file string) ([]byte, error) {
    74  	contents, err := ioutil.ReadFile(file)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return contents, nil
    79  }
    80  
    81  func (c *SyncCandidate) Sync() error {
    82  	return os.WriteFile(c.TargetFile, c.SourceContents, c.TargetMode)
    83  }