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

     1  package app
     2  
     3  import (
     4  	"fmt"
     5  	"io/fs"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	git "github.com/go-git/go-git/v5"
    11  	plumbing "github.com/go-git/go-git/v5/plumbing"
    12  
    13  	"github.com/jgrancell/metasync/utils"
    14  )
    15  
    16  type Repository struct {
    17  	CandidateFiles         []*SyncCandidate
    18  	FilesystemPath         string
    19  	RawRepository          *git.Repository
    20  	Ref                    string
    21  	RefType                string
    22  	RequiresAuthentication bool
    23  	ShowDiffs              bool
    24  	TemplatesDirectory     string
    25  	Url                    string
    26  }
    27  
    28  func (r *Repository) Clone(tempdir string, verbose bool) error {
    29  	repo, err := git.PlainClone(tempdir, false, &git.CloneOptions{
    30  		URL: r.Url,
    31  	})
    32  	r.RawRepository = repo
    33  	r.FilesystemPath = tempdir
    34  	return utils.ReturnError("failed to clone source repository", err)
    35  }
    36  
    37  func (r *Repository) Checkout() error {
    38  	w, err := r.RawRepository.Worktree()
    39  	if err != nil {
    40  		return utils.ReturnError("unable to open source repository worktree", err)
    41  	}
    42  
    43  	var opts *git.CheckoutOptions
    44  	if r.RefType == "branch" {
    45  		opts = &git.CheckoutOptions{
    46  			Branch: plumbing.ReferenceName("refs/remotes/origin/" + r.Ref),
    47  		}
    48  	} else {
    49  		opts = &git.CheckoutOptions{
    50  			Hash: plumbing.NewHash(r.Ref),
    51  		}
    52  	}
    53  	err = w.Checkout(opts)
    54  	return utils.ReturnError("unable to checkout target ref", err)
    55  }
    56  
    57  func (r *Repository) FindSyncCandidates() error {
    58  	sourceFiles, err := r.ListFiles()
    59  	if err != nil {
    60  		return utils.ReturnError("unable to list files from source repository", err)
    61  	}
    62  
    63  	cwd, err := os.Getwd()
    64  	if err != nil {
    65  		return utils.ReturnError("unable to determine the current working directory", err)
    66  	}
    67  
    68  	for _, source := range sourceFiles {
    69  
    70  		c := &SyncCandidate{
    71  			Name:       source.Name(),
    72  			SourceFile: filepath.Join(r.FilesystemPath, r.TemplatesDirectory, source.Name()),
    73  			TargetFile: filepath.Join(cwd, source.Name()),
    74  		}
    75  
    76  		ok, err := c.RequiresSync()
    77  		if err != nil {
    78  			fmt.Println("Sync candidate", c.Name, "could not be read properly. Skipping.")
    79  		}
    80  		if ok {
    81  			r.CandidateFiles = append(r.CandidateFiles, c)
    82  		}
    83  	}
    84  
    85  	r.PrintCandidates()
    86  	return nil
    87  }
    88  
    89  func (r *Repository) ExecuteCandidateSync() error {
    90  	for _, c := range r.CandidateFiles {
    91  		err := c.Sync()
    92  		if err != nil {
    93  			return err
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  func (r *Repository) ListFiles() ([]fs.FileInfo, error) {
   100  	files, err := ioutil.ReadDir(r.FilesystemPath + "/" + r.TemplatesDirectory)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return files, nil
   105  }
   106  
   107  func (r *Repository) PrintCandidates() {
   108  	if len(r.CandidateFiles) == 0 {
   109  		fmt.Println("All files are in sync.")
   110  		return
   111  	}
   112  
   113  	if !r.ShowDiffs {
   114  		fmt.Println("Out of sync files:")
   115  	}
   116  
   117  	for _, c := range r.CandidateFiles {
   118  		if r.ShowDiffs {
   119  			fmt.Println()
   120  			fmt.Println(c.Name + ":")
   121  			if len(c.Diff) > 0 {
   122  				fmt.Println(c.Diff)
   123  			} else {
   124  				fmt.Println("File does not exist in target.")
   125  			}
   126  			fmt.Println("")
   127  			fmt.Println("----------------------------------------")
   128  		} else {
   129  			fmt.Println("  -", c.Name)
   130  		}
   131  	}
   132  }