You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

479 lines
14 KiB

  1. package git
  2. import (
  3. "errors"
  4. "regexp"
  5. "strings"
  6. "golang.org/x/crypto/openpgp"
  7. "gopkg.in/src-d/go-git.v4/config"
  8. "gopkg.in/src-d/go-git.v4/plumbing"
  9. "gopkg.in/src-d/go-git.v4/plumbing/object"
  10. "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband"
  11. "gopkg.in/src-d/go-git.v4/plumbing/transport"
  12. )
  13. // SubmoduleRescursivity defines how depth will affect any submodule recursive
  14. // operation.
  15. type SubmoduleRescursivity uint
  16. const (
  17. // DefaultRemoteName name of the default Remote, just like git command.
  18. DefaultRemoteName = "origin"
  19. // NoRecurseSubmodules disables the recursion for a submodule operation.
  20. NoRecurseSubmodules SubmoduleRescursivity = 0
  21. // DefaultSubmoduleRecursionDepth allow recursion in a submodule operation.
  22. DefaultSubmoduleRecursionDepth SubmoduleRescursivity = 10
  23. )
  24. var (
  25. ErrMissingURL = errors.New("URL field is required")
  26. )
  27. // CloneOptions describes how a clone should be performed.
  28. type CloneOptions struct {
  29. // The (possibly remote) repository URL to clone from.
  30. URL string
  31. // Auth credentials, if required, to use with the remote repository.
  32. Auth transport.AuthMethod
  33. // Name of the remote to be added, by default `origin`.
  34. RemoteName string
  35. // Remote branch to clone.
  36. ReferenceName plumbing.ReferenceName
  37. // Fetch only ReferenceName if true.
  38. SingleBranch bool
  39. // No checkout of HEAD after clone if true.
  40. NoCheckout bool
  41. // Limit fetching to the specified number of commits.
  42. Depth int
  43. // RecurseSubmodules after the clone is created, initialize all submodules
  44. // within, using their default settings. This option is ignored if the
  45. // cloned repository does not have a worktree.
  46. RecurseSubmodules SubmoduleRescursivity
  47. // Progress is where the human readable information sent by the server is
  48. // stored, if nil nothing is stored and the capability (if supported)
  49. // no-progress, is sent to the server to avoid send this information.
  50. Progress sideband.Progress
  51. // Tags describe how the tags will be fetched from the remote repository,
  52. // by default is AllTags.
  53. Tags TagMode
  54. }
  55. // Validate validates the fields and sets the default values.
  56. func (o *CloneOptions) Validate() error {
  57. if o.URL == "" {
  58. return ErrMissingURL
  59. }
  60. if o.RemoteName == "" {
  61. o.RemoteName = DefaultRemoteName
  62. }
  63. if o.ReferenceName == "" {
  64. o.ReferenceName = plumbing.HEAD
  65. }
  66. if o.Tags == InvalidTagMode {
  67. o.Tags = AllTags
  68. }
  69. return nil
  70. }
  71. // PullOptions describes how a pull should be performed.
  72. type PullOptions struct {
  73. // Name of the remote to be pulled. If empty, uses the default.
  74. RemoteName string
  75. // Remote branch to clone. If empty, uses HEAD.
  76. ReferenceName plumbing.ReferenceName
  77. // Fetch only ReferenceName if true.
  78. SingleBranch bool
  79. // Limit fetching to the specified number of commits.
  80. Depth int
  81. // Auth credentials, if required, to use with the remote repository.
  82. Auth transport.AuthMethod
  83. // RecurseSubmodules controls if new commits of all populated submodules
  84. // should be fetched too.
  85. RecurseSubmodules SubmoduleRescursivity
  86. // Progress is where the human readable information sent by the server is
  87. // stored, if nil nothing is stored and the capability (if supported)
  88. // no-progress, is sent to the server to avoid send this information.
  89. Progress sideband.Progress
  90. // Force allows the pull to update a local branch even when the remote
  91. // branch does not descend from it.
  92. Force bool
  93. }
  94. // Validate validates the fields and sets the default values.
  95. func (o *PullOptions) Validate() error {
  96. if o.RemoteName == "" {
  97. o.RemoteName = DefaultRemoteName
  98. }
  99. if o.ReferenceName == "" {
  100. o.ReferenceName = plumbing.HEAD
  101. }
  102. return nil
  103. }
  104. type TagMode int
  105. const (
  106. InvalidTagMode TagMode = iota
  107. // TagFollowing any tag that points into the histories being fetched is also
  108. // fetched. TagFollowing requires a server with `include-tag` capability
  109. // in order to fetch the annotated tags objects.
  110. TagFollowing
  111. // AllTags fetch all tags from the remote (i.e., fetch remote tags
  112. // refs/tags/* into local tags with the same name)
  113. AllTags
  114. //NoTags fetch no tags from the remote at all
  115. NoTags
  116. )
  117. // FetchOptions describes how a fetch should be performed
  118. type FetchOptions struct {
  119. // Name of the remote to fetch from. Defaults to origin.
  120. RemoteName string
  121. RefSpecs []config.RefSpec
  122. // Depth limit fetching to the specified number of commits from the tip of
  123. // each remote branch history.
  124. Depth int
  125. // Auth credentials, if required, to use with the remote repository.
  126. Auth transport.AuthMethod
  127. // Progress is where the human readable information sent by the server is
  128. // stored, if nil nothing is stored and the capability (if supported)
  129. // no-progress, is sent to the server to avoid send this information.
  130. Progress sideband.Progress
  131. // Tags describe how the tags will be fetched from the remote repository,
  132. // by default is TagFollowing.
  133. Tags TagMode
  134. // Force allows the fetch to update a local branch even when the remote
  135. // branch does not descend from it.
  136. Force bool
  137. }
  138. // Validate validates the fields and sets the default values.
  139. func (o *FetchOptions) Validate() error {
  140. if o.RemoteName == "" {
  141. o.RemoteName = DefaultRemoteName
  142. }
  143. if o.Tags == InvalidTagMode {
  144. o.Tags = TagFollowing
  145. }
  146. for _, r := range o.RefSpecs {
  147. if err := r.Validate(); err != nil {
  148. return err
  149. }
  150. }
  151. return nil
  152. }
  153. // PushOptions describes how a push should be performed.
  154. type PushOptions struct {
  155. // RemoteName is the name of the remote to be pushed to.
  156. RemoteName string
  157. // RefSpecs specify what destination ref to update with what source
  158. // object. A refspec with empty src can be used to delete a reference.
  159. RefSpecs []config.RefSpec
  160. // Auth credentials, if required, to use with the remote repository.
  161. Auth transport.AuthMethod
  162. // Progress is where the human readable information sent by the server is
  163. // stored, if nil nothing is stored.
  164. Progress sideband.Progress
  165. }
  166. // Validate validates the fields and sets the default values.
  167. func (o *PushOptions) Validate() error {
  168. if o.RemoteName == "" {
  169. o.RemoteName = DefaultRemoteName
  170. }
  171. if len(o.RefSpecs) == 0 {
  172. o.RefSpecs = []config.RefSpec{
  173. config.RefSpec(config.DefaultPushRefSpec),
  174. }
  175. }
  176. for _, r := range o.RefSpecs {
  177. if err := r.Validate(); err != nil {
  178. return err
  179. }
  180. }
  181. return nil
  182. }
  183. // SubmoduleUpdateOptions describes how a submodule update should be performed.
  184. type SubmoduleUpdateOptions struct {
  185. // Init, if true initializes the submodules recorded in the index.
  186. Init bool
  187. // NoFetch tell to the update command to not fetch new objects from the
  188. // remote site.
  189. NoFetch bool
  190. // RecurseSubmodules the update is performed not only in the submodules of
  191. // the current repository but also in any nested submodules inside those
  192. // submodules (and so on). Until the SubmoduleRescursivity is reached.
  193. RecurseSubmodules SubmoduleRescursivity
  194. // Auth credentials, if required, to use with the remote repository.
  195. Auth transport.AuthMethod
  196. }
  197. var (
  198. ErrBranchHashExclusive = errors.New("Branch and Hash are mutually exclusive")
  199. ErrCreateRequiresBranch = errors.New("Branch is mandatory when Create is used")
  200. )
  201. // CheckoutOptions describes how a checkout 31operation should be performed.
  202. type CheckoutOptions struct {
  203. // Hash is the hash of the commit to be checked out. If used, HEAD will be
  204. // in detached mode. If Create is not used, Branch and Hash are mutually
  205. // exclusive.
  206. Hash plumbing.Hash
  207. // Branch to be checked out, if Branch and Hash are empty is set to `master`.
  208. Branch plumbing.ReferenceName
  209. // Create a new branch named Branch and start it at Hash.
  210. Create bool
  211. // Force, if true when switching branches, proceed even if the index or the
  212. // working tree differs from HEAD. This is used to throw away local changes
  213. Force bool
  214. }
  215. // Validate validates the fields and sets the default values.
  216. func (o *CheckoutOptions) Validate() error {
  217. if !o.Create && !o.Hash.IsZero() && o.Branch != "" {
  218. return ErrBranchHashExclusive
  219. }
  220. if o.Create && o.Branch == "" {
  221. return ErrCreateRequiresBranch
  222. }
  223. if o.Branch == "" {
  224. o.Branch = plumbing.Master
  225. }
  226. return nil
  227. }
  228. // ResetMode defines the mode of a reset operation.
  229. type ResetMode int8
  230. const (
  231. // MixedReset resets the index but not the working tree (i.e., the changed
  232. // files are preserved but not marked for commit) and reports what has not
  233. // been updated. This is the default action.
  234. MixedReset ResetMode = iota
  235. // HardReset resets the index and working tree. Any changes to tracked files
  236. // in the working tree are discarded.
  237. HardReset
  238. // MergeReset resets the index and updates the files in the working tree
  239. // that are different between Commit and HEAD, but keeps those which are
  240. // different between the index and working tree (i.e. which have changes
  241. // which have not been added).
  242. //
  243. // If a file that is different between Commit and the index has unstaged
  244. // changes, reset is aborted.
  245. MergeReset
  246. // SoftReset does not touch the index file or the working tree at all (but
  247. // resets the head to <commit>, just like all modes do). This leaves all
  248. // your changed files "Changes to be committed", as git status would put it.
  249. SoftReset
  250. )
  251. // ResetOptions describes how a reset operation should be performed.
  252. type ResetOptions struct {
  253. // Commit, if commit is pressent set the current branch head (HEAD) to it.
  254. Commit plumbing.Hash
  255. // Mode, form resets the current branch head to Commit and possibly updates
  256. // the index (resetting it to the tree of Commit) and the working tree
  257. // depending on Mode. If empty MixedReset is used.
  258. Mode ResetMode
  259. }
  260. // Validate validates the fields and sets the default values.
  261. func (o *ResetOptions) Validate(r *Repository) error {
  262. if o.Commit == plumbing.ZeroHash {
  263. ref, err := r.Head()
  264. if err != nil {
  265. return err
  266. }
  267. o.Commit = ref.Hash()
  268. }
  269. return nil
  270. }
  271. type LogOrder int8
  272. const (
  273. LogOrderDefault LogOrder = iota
  274. LogOrderDFS
  275. LogOrderDFSPost
  276. LogOrderBSF
  277. LogOrderCommitterTime
  278. )
  279. // LogOptions describes how a log action should be performed.
  280. type LogOptions struct {
  281. // When the From option is set the log will only contain commits
  282. // reachable from it. If this option is not set, HEAD will be used as
  283. // the default From.
  284. From plumbing.Hash
  285. // The default traversal algorithm is Depth-first search
  286. // set Order=LogOrderCommitterTime for ordering by committer time (more compatible with `git log`)
  287. // set Order=LogOrderBSF for Breadth-first search
  288. Order LogOrder
  289. // Show only those commits in which the specified file was inserted/updated.
  290. // It is equivalent to running `git log -- <file-name>`.
  291. FileName *string
  292. }
  293. var (
  294. ErrMissingAuthor = errors.New("author field is required")
  295. )
  296. // CommitOptions describes how a commit operation should be performed.
  297. type CommitOptions struct {
  298. // All automatically stage files that have been modified and deleted, but
  299. // new files you have not told Git about are not affected.
  300. All bool
  301. // Author is the author's signature of the commit.
  302. Author *object.Signature
  303. // Committer is the committer's signature of the commit. If Committer is
  304. // nil the Author signature is used.
  305. Committer *object.Signature
  306. // Parents are the parents commits for the new commit, by default when
  307. // len(Parents) is zero, the hash of HEAD reference is used.
  308. Parents []plumbing.Hash
  309. // SignKey denotes a key to sign the commit with. A nil value here means the
  310. // commit will not be signed. The private key must be present and already
  311. // decrypted.
  312. SignKey *openpgp.Entity
  313. }
  314. // Validate validates the fields and sets the default values.
  315. func (o *CommitOptions) Validate(r *Repository) error {
  316. if o.Author == nil {
  317. return ErrMissingAuthor
  318. }
  319. if o.Committer == nil {
  320. o.Committer = o.Author
  321. }
  322. if len(o.Parents) == 0 {
  323. head, err := r.Head()
  324. if err != nil && err != plumbing.ErrReferenceNotFound {
  325. return err
  326. }
  327. if head != nil {
  328. o.Parents = []plumbing.Hash{head.Hash()}
  329. }
  330. }
  331. return nil
  332. }
  333. var (
  334. ErrMissingName = errors.New("name field is required")
  335. ErrMissingTagger = errors.New("tagger field is required")
  336. ErrMissingMessage = errors.New("message field is required")
  337. )
  338. // CreateTagOptions describes how a tag object should be created.
  339. type CreateTagOptions struct {
  340. // Tagger defines the signature of the tag creator.
  341. Tagger *object.Signature
  342. // Message defines the annotation of the tag. It is canonicalized during
  343. // validation into the format expected by git - no leading whitespace and
  344. // ending in a newline.
  345. Message string
  346. // SignKey denotes a key to sign the tag with. A nil value here means the tag
  347. // will not be signed. The private key must be present and already decrypted.
  348. SignKey *openpgp.Entity
  349. }
  350. // Validate validates the fields and sets the default values.
  351. func (o *CreateTagOptions) Validate(r *Repository, hash plumbing.Hash) error {
  352. if o.Tagger == nil {
  353. return ErrMissingTagger
  354. }
  355. if o.Message == "" {
  356. return ErrMissingMessage
  357. }
  358. // Canonicalize the message into the expected message format.
  359. o.Message = strings.TrimSpace(o.Message) + "\n"
  360. return nil
  361. }
  362. // ListOptions describes how a remote list should be performed.
  363. type ListOptions struct {
  364. // Auth credentials, if required, to use with the remote repository.
  365. Auth transport.AuthMethod
  366. }
  367. // CleanOptions describes how a clean should be performed.
  368. type CleanOptions struct {
  369. Dir bool
  370. }
  371. // GrepOptions describes how a grep should be performed.
  372. type GrepOptions struct {
  373. // Patterns are compiled Regexp objects to be matched.
  374. Patterns []*regexp.Regexp
  375. // InvertMatch selects non-matching lines.
  376. InvertMatch bool
  377. // CommitHash is the hash of the commit from which worktree should be derived.
  378. CommitHash plumbing.Hash
  379. // ReferenceName is the branch or tag name from which worktree should be derived.
  380. ReferenceName plumbing.ReferenceName
  381. // PathSpecs are compiled Regexp objects of pathspec to use in the matching.
  382. PathSpecs []*regexp.Regexp
  383. }
  384. var (
  385. ErrHashOrReference = errors.New("ambiguous options, only one of CommitHash or ReferenceName can be passed")
  386. )
  387. // Validate validates the fields and sets the default values.
  388. func (o *GrepOptions) Validate(w *Worktree) error {
  389. if !o.CommitHash.IsZero() && o.ReferenceName != "" {
  390. return ErrHashOrReference
  391. }
  392. // If none of CommitHash and ReferenceName are provided, set commit hash of
  393. // the repository's head.
  394. if o.CommitHash.IsZero() && o.ReferenceName == "" {
  395. ref, err := w.r.Head()
  396. if err != nil {
  397. return err
  398. }
  399. o.CommitHash = ref.Hash()
  400. }
  401. return nil
  402. }
  403. // PlainOpenOptions describes how opening a plain repository should be
  404. // performed.
  405. type PlainOpenOptions struct {
  406. // DetectDotGit defines whether parent directories should be
  407. // walked until a .git directory or file is found.
  408. DetectDotGit bool
  409. }
  410. // Validate validates the fields and sets the default values.
  411. func (o *PlainOpenOptions) Validate() error { return nil }