github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/init.go (about)

     1  package git
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  )
     9  
    10  type InitOptions struct {
    11  	Quiet bool
    12  	Bare  bool
    13  
    14  	Template File
    15  
    16  	// Not implemented
    17  	SeparateGitDir File
    18  
    19  	// Not implemented
    20  	Shared os.FileMode
    21  }
    22  
    23  func Init(c *Client, opts InitOptions, dir string) (*Client, error) {
    24  	if dir == "" {
    25  		dir2, err := os.Getwd()
    26  		if err != nil {
    27  			return nil, err
    28  		}
    29  		dir = dir2
    30  	}
    31  
    32  	if err := os.MkdirAll(dir, 0755); err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	reinit := false
    37  	if !opts.Bare {
    38  		if File(dir + "/.git").Exists() {
    39  			reinit = true
    40  		} else if err := os.Mkdir(dir+"/.git", 0755); err != nil {
    41  			return nil, err
    42  		}
    43  		if c != nil {
    44  			// These must be absolute to be sure that filepath.Rel
    45  			// will work when cloning.
    46  			gd, err := filepath.Abs(filepath.Join(dir, ".git"))
    47  			if err != nil {
    48  				return nil, err
    49  			}
    50  			wd, err := filepath.Abs(dir)
    51  			if err != nil {
    52  				return nil, err
    53  			}
    54  			c.GitDir = GitDir(gd)
    55  			c.WorkDir = WorkDir(wd)
    56  
    57  			od, err := filepath.Abs(c.GetObjectsDir().String())
    58  			if err != nil {
    59  				return nil, err
    60  			}
    61  			c.ObjectDir = od
    62  		} else {
    63  			c2, err := NewClient(dir+"/.git", dir)
    64  			if err != nil {
    65  				return nil, err
    66  			}
    67  			od, err := filepath.Abs(c2.ObjectDir)
    68  			if err != nil {
    69  				return nil, err
    70  			}
    71  			c2.ObjectDir = od
    72  			c = c2
    73  		}
    74  	} else {
    75  		if c != nil {
    76  			c.GitDir = GitDir(dir)
    77  			c.ObjectDir = c.GetObjectsDir().String()
    78  		} else {
    79  			c2, err := NewClient(dir, "")
    80  			if err != nil {
    81  				return nil, err
    82  			}
    83  			c = c2
    84  		}
    85  	}
    86  
    87  	// These are all the directories created by a clean "git init"
    88  	// with the canonical git implementation
    89  	if err := os.MkdirAll(filepath.Join(c.ObjectDir, "pack"), 0755); err != nil {
    90  		return nil, err
    91  	}
    92  	if err := os.MkdirAll(filepath.Join(c.ObjectDir, "info"), 0755); err != nil {
    93  		return nil, err
    94  	}
    95  	if err := os.MkdirAll(c.GitDir.String()+"/info", 0755); err != nil {
    96  		// FIXME: Should have exclude file in it
    97  		return nil, err
    98  	}
    99  	if err := os.MkdirAll(c.GitDir.String()+"/hooks", 0755); err != nil {
   100  		// FIXME: Should have sample hooks in it.
   101  		return nil, err
   102  	}
   103  	if err := os.MkdirAll(c.GitDir.String()+"/branches", 0755); err != nil {
   104  		return nil, err
   105  	}
   106  	if err := os.MkdirAll(c.GitDir.String()+"/refs/heads", 0755); err != nil {
   107  		return nil, err
   108  	}
   109  	if err := os.MkdirAll(c.GitDir.String()+"/refs/tags", 0755); err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	bareConf := "bare = false"
   114  	if opts.Bare {
   115  		bareConf = "bare = true"
   116  	}
   117  
   118  	if c.GitDir.File("HEAD").Exists() {
   119  		reinit = true
   120  	} else if err := c.GitDir.WriteFile("HEAD", []byte("ref: refs/heads/master\n"), 0644); err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	if c.GitDir.File("config").Exists() {
   125  		reinit = true
   126  	} else if err := c.GitDir.WriteFile("config", []byte("[core]\n\trepositoryformatversion = 0\n\t"+bareConf+"\n"), 0644); err != nil {
   127  		return nil, err
   128  	}
   129  	if c.GitDir.File("description").Exists() {
   130  		reinit = true
   131  	} else if err := c.GitDir.WriteFile("description", []byte("Unnamed repository; edit this file 'description' to name the repository.\n"), 0644); err != nil {
   132  		return nil, err
   133  	}
   134  	if !opts.Quiet {
   135  		dir, err := filepath.Abs(c.GitDir.String())
   136  		if err != nil {
   137  			return c, err
   138  		}
   139  		if reinit {
   140  			fmt.Printf("Reinitialized existing Git repository in %v/\n", dir)
   141  		} else {
   142  			fmt.Printf("Initialized empty Git repository in %v/\n", dir)
   143  		}
   144  	}
   145  
   146  	if opts.Template != "" {
   147  		err := filepath.Walk(opts.Template.String(), func(path string, info os.FileInfo, err error) error {
   148  			if err != nil {
   149  				return err
   150  			}
   151  			path, err = filepath.Rel(opts.Template.String(), path)
   152  			if err != nil {
   153  				return err
   154  			}
   155  
   156  			if info.IsDir() {
   157  				os.MkdirAll(filepath.Join(c.GitDir.String(), path), 0777)
   158  			} else {
   159  				if c.GitDir.File(File(path)).Exists() {
   160  					return nil
   161  				}
   162  				newFile, err := c.GitDir.Create(File(path))
   163  				if err != nil {
   164  					return err
   165  				}
   166  				defer newFile.Close()
   167  				f, err := os.Open(filepath.Join(opts.Template.String(), path))
   168  				if err != nil {
   169  					return err
   170  				}
   171  				defer f.Close()
   172  				_, err = io.Copy(newFile, f)
   173  				if err != nil {
   174  					return err
   175  				}
   176  			}
   177  
   178  			return nil
   179  		})
   180  
   181  		return c, err
   182  	}
   183  
   184  	return c, nil
   185  }