Guest User

Untitled

a guest
Oct 23rd, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.17 KB | None | 0 0
  1. // Adding a file directly to index (stage area), without using working tree.
  2. //
  3. // $ go build index-add.go && yes | mv index-add ~/code/workspace/bin
  4. // $ mkdir -p /tmp/sample && cd /tmp/sample
  5. // $ index-add
  6. package main
  7.  
  8. import (
  9. "bytes"
  10. "fmt"
  11. "path"
  12. "sort"
  13. "strconv"
  14. "strings"
  15. "time"
  16.  
  17. "golang.org/x/crypto/openpgp"
  18. "gopkg.in/src-d/go-billy.v4"
  19. "gopkg.in/src-d/go-billy.v4/osfs"
  20. "gopkg.in/src-d/go-git.v4"
  21. . "gopkg.in/src-d/go-git.v4/_examples"
  22. "gopkg.in/src-d/go-git.v4/plumbing"
  23. "gopkg.in/src-d/go-git.v4/plumbing/filemode"
  24. "gopkg.in/src-d/go-git.v4/plumbing/format/index"
  25. "gopkg.in/src-d/go-git.v4/plumbing/object"
  26. "gopkg.in/src-d/go-git.v4/storage"
  27. fsfs "gopkg.in/src-d/go-git.v4/storage/filesystem"
  28. )
  29.  
  30. // 获取git log
  31. func gitLog(r *git.Repository) {
  32. // ... retrieves the branch pointed by HEAD
  33. ref, err := r.Head()
  34. CheckIfError(err)
  35.  
  36. // ... retrieves the commit history
  37. cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
  38. CheckIfError(err)
  39.  
  40. // ... just iterates over the commits, printing it
  41. err = cIter.ForEach(func(c *object.Commit) error {
  42. fmt.Println(c)
  43. return nil
  44. })
  45. CheckIfError(err)
  46. }
  47.  
  48. // 创建一个新的 bare repository
  49. func gitInit(repoPath string) *git.Repository {
  50. s := fsfs.NewStorage(osfs.New(repoPath), nil)
  51. r, err := git.Init(s, nil)
  52. CheckIfError(err)
  53. return r
  54. }
  55.  
  56. // 打开一个已经存在的 repository
  57. func gitPlainOpen(repoPath string) *git.Repository {
  58.  
  59. r, err := git.PlainOpen(repoPath)
  60. CheckIfError(err)
  61. return r
  62. }
  63.  
  64. // 添加文件到 index cache
  65. func gitAdd(r *git.Repository, path string, content []byte) {
  66. // Find index from Storer, here we are using filesystem.
  67. idx, err := r.Storer.Index()
  68. CheckIfError(err)
  69.  
  70. // Get an object, write data into the object, then save to object storage.
  71. obj := r.Storer.NewEncodedObject()
  72. obj.SetType(plumbing.BlobObject)
  73. obj.SetSize(int64(len(content)))
  74.  
  75. // The implementation of "obj.Writer.Write()" is MemoryObject, which
  76. // makes a copy of the object.
  77. writer, err := obj.Writer()
  78. CheckIfError(err)
  79. _, err = writer.Write(content)
  80. CheckIfError(err)
  81. writer.Close()
  82.  
  83. // Here we again copy the object from "obj" to underline storage. Once
  84. // saved, it is officially considered part of git database.
  85. // ** Improvement Needed to avoid Double Copy**
  86. h, err := r.Storer.SetEncodedObject(obj)
  87. CheckIfError(err)
  88.  
  89. e := idx.Add(path)
  90.  
  91. // Add a new entry (we can use "idx.Entry(path)" to check if path exists).
  92. e.Hash = h
  93. e.Mode = filemode.Regular
  94. // Set index, which will be translated to tree object once we commit.
  95. r.Storer.SetIndex(idx)
  96. }
  97.  
  98. func gitDelete(r *git.Repository, filePath string) {
  99. // Find index from Storer, here we are using filesystem.
  100. idx, err := r.Storer.Index()
  101. CheckIfError(err)
  102.  
  103. _, err = idx.Remove(filePath)
  104. CheckIfError(err)
  105.  
  106. err = r.Storer.SetIndex(idx)
  107. CheckIfError(err)
  108. }
  109.  
  110. // 发布变更
  111. func gitCommit(r *git.Repository, msg string, opts *git.CommitOptions) (plumbing.Hash, error) {
  112. if err := opts.Validate(r); err != nil {
  113. return plumbing.ZeroHash, err
  114. }
  115.  
  116. idx, err := r.Storer.Index()
  117. if err != nil {
  118. return plumbing.ZeroHash, err
  119. }
  120.  
  121. h := &buildTreeHelper{
  122. s: r.Storer,
  123. }
  124.  
  125. tree, err := h.BuildTree(idx)
  126. if err != nil {
  127. return plumbing.ZeroHash, err
  128. }
  129.  
  130. commit, err := buildCommitObject(r, msg, opts, tree)
  131. if err != nil {
  132. return plumbing.ZeroHash, err
  133. }
  134.  
  135. // updateHEAD
  136. head, err := r.Storer.Reference(plumbing.HEAD)
  137. if err != nil {
  138. return commit, err
  139. }
  140.  
  141. name := plumbing.HEAD
  142. if head.Type() != plumbing.HashReference {
  143. name = head.Target()
  144. }
  145.  
  146. ref := plumbing.NewHashReference(name, commit)
  147. return commit, r.Storer.SetReference(ref)
  148. }
  149.  
  150. func main() {
  151. // repoPath = "/tmp/interesting"
  152. // gitInit or gitPlainOpen
  153. r := gitInit("/tmp/interesting")
  154.  
  155. // gitAdd
  156. for i := 0; i < 10; i++ {
  157. content := []byte(strconv.Itoa(i))
  158. filePath := strconv.Itoa(i)
  159. gitAdd(r, filePath, content)
  160. }
  161.  
  162. // gitCommit
  163. _, err := gitCommit(r, "add files", &git.CommitOptions{
  164. Author: &object.Signature{
  165. Name: "John Doe",
  166. Email: "john@doe.org",
  167. When: time.Now(),
  168. },
  169. Parents: []plumbing.Hash{},
  170. })
  171. CheckIfError(err)
  172.  
  173. // gitDelete
  174. gitDelete(r, "3")
  175.  
  176. // gitCommit
  177. _, err = gitCommit(r, "remove file", &git.CommitOptions{
  178. Author: &object.Signature{
  179. Name: "John Doe",
  180. Email: "john@doe.org",
  181. When: time.Now(),
  182. },
  183. Parents: []plumbing.Hash{},
  184. })
  185. CheckIfError(err)
  186.  
  187. // gitLog
  188. gitLog(r)
  189. }
  190.  
  191. /////////////////////////////////////////////////////////////////////
  192. ///////////////// ///////////////
  193. ///////////////// The following copy from work tree ///////////////
  194. ///////////////// ///////////////
  195. /////////////////////////////////////////////////////////////////////
  196.  
  197. // buildTreeHelper converts a given index.Index file into multiple git objects
  198. // reading the blobs from the given filesystem and creating the trees from the
  199. // index structure. The created objects are pushed to a given Storer.
  200. type buildTreeHelper struct {
  201. fs billy.Filesystem
  202. s storage.Storer
  203.  
  204. trees map[string]*object.Tree
  205. entries map[string]*object.TreeEntry
  206. }
  207.  
  208. // BuildTree builds the tree objects and push its to the storer, the hash
  209. // of the root tree is returned.
  210. func (h *buildTreeHelper) BuildTree(idx *index.Index) (plumbing.Hash, error) {
  211. const rootNode = ""
  212. h.trees = map[string]*object.Tree{rootNode: {}}
  213. h.entries = map[string]*object.TreeEntry{}
  214.  
  215. for _, e := range idx.Entries {
  216. if err := h.commitIndexEntry(e); err != nil {
  217. return plumbing.ZeroHash, err
  218. }
  219. }
  220.  
  221. return h.copyTreeToStorageRecursive(rootNode, h.trees[rootNode])
  222. }
  223.  
  224. func (h *buildTreeHelper) commitIndexEntry(e *index.Entry) error {
  225. parts := strings.Split(e.Name, "/")
  226.  
  227. var fullpath string
  228. for _, part := range parts {
  229. parent := fullpath
  230. fullpath = path.Join(fullpath, part)
  231.  
  232. h.doBuildTree(e, parent, fullpath)
  233. }
  234.  
  235. return nil
  236. }
  237.  
  238. func (h *buildTreeHelper) doBuildTree(e *index.Entry, parent, fullpath string) {
  239. if _, ok := h.trees[fullpath]; ok {
  240. return
  241. }
  242.  
  243. if _, ok := h.entries[fullpath]; ok {
  244. return
  245. }
  246.  
  247. te := object.TreeEntry{Name: path.Base(fullpath)}
  248.  
  249. if fullpath == e.Name {
  250. te.Mode = e.Mode
  251. te.Hash = e.Hash
  252. } else {
  253. te.Mode = filemode.Dir
  254. h.trees[fullpath] = &object.Tree{}
  255. }
  256.  
  257. h.trees[parent].Entries = append(h.trees[parent].Entries, te)
  258. }
  259.  
  260. type sortableEntries []object.TreeEntry
  261.  
  262. func (sortableEntries) sortName(te object.TreeEntry) string {
  263. if te.Mode == filemode.Dir {
  264. return te.Name + "/"
  265. }
  266. return te.Name
  267. }
  268. func (se sortableEntries) Len() int { return len(se) }
  269. func (se sortableEntries) Less(i int, j int) bool { return se.sortName(se[i]) < se.sortName(se[j]) }
  270. func (se sortableEntries) Swap(i int, j int) { se[i], se[j] = se[j], se[i] }
  271.  
  272. func (h *buildTreeHelper) copyTreeToStorageRecursive(parent string, t *object.Tree) (plumbing.Hash, error) {
  273. sort.Sort(sortableEntries(t.Entries))
  274. for i, e := range t.Entries {
  275. if e.Mode != filemode.Dir && !e.Hash.IsZero() {
  276. continue
  277. }
  278.  
  279. path := path.Join(parent, e.Name)
  280.  
  281. var err error
  282. e.Hash, err = h.copyTreeToStorageRecursive(path, h.trees[path])
  283. if err != nil {
  284. return plumbing.ZeroHash, err
  285. }
  286.  
  287. t.Entries[i] = e
  288. }
  289.  
  290. o := h.s.NewEncodedObject()
  291. if err := t.Encode(o); err != nil {
  292. return plumbing.ZeroHash, err
  293. }
  294.  
  295. return h.s.SetEncodedObject(o)
  296. }
  297.  
  298. func buildCommitObject(r *git.Repository, msg string, opts *git.CommitOptions, tree plumbing.Hash) (plumbing.Hash, error) {
  299. commit := &object.Commit{
  300. Author: *opts.Author,
  301. Committer: *opts.Committer,
  302. Message: msg,
  303. TreeHash: tree,
  304. ParentHashes: opts.Parents,
  305. }
  306.  
  307. if opts.SignKey != nil {
  308. sig, err := buildCommitSignature(commit, opts.SignKey)
  309. if err != nil {
  310. return plumbing.ZeroHash, err
  311. }
  312. commit.PGPSignature = sig
  313. }
  314.  
  315. obj := r.Storer.NewEncodedObject()
  316. if err := commit.Encode(obj); err != nil {
  317. return plumbing.ZeroHash, err
  318. }
  319. return r.Storer.SetEncodedObject(obj)
  320. }
  321.  
  322. func buildCommitSignature(commit *object.Commit, signKey *openpgp.Entity) (string, error) {
  323. encoded := &plumbing.MemoryObject{}
  324. if err := commit.Encode(encoded); err != nil {
  325. return "", err
  326. }
  327. r, err := encoded.Reader()
  328. if err != nil {
  329. return "", err
  330. }
  331. var b bytes.Buffer
  332. if err := openpgp.ArmoredDetachSign(&b, signKey, r, nil); err != nil {
  333. return "", err
  334. }
  335. return b.String(), nil
  336. }
Add Comment
Please, Sign In to add comment