本站源代码
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.

493 lines
15KB

  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. // Prune specify that remote refs that match given RefSpecs and that do
  166. // not exist locally will be removed.
  167. Prune bool
  168. }
  169. // Validate validates the fields and sets the default values.
  170. func (o *PushOptions) Validate() error {
  171. if o.RemoteName == "" {
  172. o.RemoteName = DefaultRemoteName
  173. }
  174. if len(o.RefSpecs) == 0 {
  175. o.RefSpecs = []config.RefSpec{
  176. config.RefSpec(config.DefaultPushRefSpec),
  177. }
  178. }
  179. for _, r := range o.RefSpecs {
  180. if err := r.Validate(); err != nil {
  181. return err
  182. }
  183. }
  184. return nil
  185. }
  186. // SubmoduleUpdateOptions describes how a submodule update should be performed.
  187. type SubmoduleUpdateOptions struct {
  188. // Init, if true initializes the submodules recorded in the index.
  189. Init bool
  190. // NoFetch tell to the update command to not fetch new objects from the
  191. // remote site.
  192. NoFetch bool
  193. // RecurseSubmodules the update is performed not only in the submodules of
  194. // the current repository but also in any nested submodules inside those
  195. // submodules (and so on). Until the SubmoduleRescursivity is reached.
  196. RecurseSubmodules SubmoduleRescursivity
  197. // Auth credentials, if required, to use with the remote repository.
  198. Auth transport.AuthMethod
  199. }
  200. var (
  201. ErrBranchHashExclusive = errors.New("Branch and Hash are mutually exclusive")
  202. ErrCreateRequiresBranch = errors.New("Branch is mandatory when Create is used")
  203. )
  204. // CheckoutOptions describes how a checkout operation should be performed.
  205. type CheckoutOptions struct {
  206. // Hash is the hash of the commit to be checked out. If used, HEAD will be
  207. // in detached mode. If Create is not used, Branch and Hash are mutually
  208. // exclusive.
  209. Hash plumbing.Hash
  210. // Branch to be checked out, if Branch and Hash are empty is set to `master`.
  211. Branch plumbing.ReferenceName
  212. // Create a new branch named Branch and start it at Hash.
  213. Create bool
  214. // Force, if true when switching branches, proceed even if the index or the
  215. // working tree differs from HEAD. This is used to throw away local changes
  216. Force bool
  217. // Keep, if true when switching branches, local changes (the index or the
  218. // working tree changes) will be kept so that they can be committed to the
  219. // target branch. Force and Keep are mutually exclusive, should not be both
  220. // set to true.
  221. Keep bool
  222. }
  223. // Validate validates the fields and sets the default values.
  224. func (o *CheckoutOptions) Validate() error {
  225. if !o.Create && !o.Hash.IsZero() && o.Branch != "" {
  226. return ErrBranchHashExclusive
  227. }
  228. if o.Create && o.Branch == "" {
  229. return ErrCreateRequiresBranch
  230. }
  231. if o.Branch == "" {
  232. o.Branch = plumbing.Master
  233. }
  234. return nil
  235. }
  236. // ResetMode defines the mode of a reset operation.
  237. type ResetMode int8
  238. const (
  239. // MixedReset resets the index but not the working tree (i.e., the changed
  240. // files are preserved but not marked for commit) and reports what has not
  241. // been updated. This is the default action.
  242. MixedReset ResetMode = iota
  243. // HardReset resets the index and working tree. Any changes to tracked files
  244. // in the working tree are discarded.
  245. HardReset
  246. // MergeReset resets the index and updates the files in the working tree
  247. // that are different between Commit and HEAD, but keeps those which are
  248. // different between the index and working tree (i.e. which have changes
  249. // which have not been added).
  250. //
  251. // If a file that is different between Commit and the index has unstaged
  252. // changes, reset is aborted.
  253. MergeReset
  254. // SoftReset does not touch the index file or the working tree at all (but
  255. // resets the head to <commit>, just like all modes do). This leaves all
  256. // your changed files "Changes to be committed", as git status would put it.
  257. SoftReset
  258. )
  259. // ResetOptions describes how a reset operation should be performed.
  260. type ResetOptions struct {
  261. // Commit, if commit is present set the current branch head (HEAD) to it.
  262. Commit plumbing.Hash
  263. // Mode, form resets the current branch head to Commit and possibly updates
  264. // the index (resetting it to the tree of Commit) and the working tree
  265. // depending on Mode. If empty MixedReset is used.
  266. Mode ResetMode
  267. }
  268. // Validate validates the fields and sets the default values.
  269. func (o *ResetOptions) Validate(r *Repository) error {
  270. if o.Commit == plumbing.ZeroHash {
  271. ref, err := r.Head()
  272. if err != nil {
  273. return err
  274. }
  275. o.Commit = ref.Hash()
  276. }
  277. return nil
  278. }
  279. type LogOrder int8
  280. const (
  281. LogOrderDefault LogOrder = iota
  282. LogOrderDFS
  283. LogOrderDFSPost
  284. LogOrderBSF
  285. LogOrderCommitterTime
  286. )
  287. // LogOptions describes how a log action should be performed.
  288. type LogOptions struct {
  289. // When the From option is set the log will only contain commits
  290. // reachable from it. If this option is not set, HEAD will be used as
  291. // the default From.
  292. From plumbing.Hash
  293. // The default traversal algorithm is Depth-first search
  294. // set Order=LogOrderCommitterTime for ordering by committer time (more compatible with `git log`)
  295. // set Order=LogOrderBSF for Breadth-first search
  296. Order LogOrder
  297. // Show only those commits in which the specified file was inserted/updated.
  298. // It is equivalent to running `git log -- <file-name>`.
  299. FileName *string
  300. // Pretend as if all the refs in refs/, along with HEAD, are listed on the command line as <commit>.
  301. // It is equivalent to running `git log --all`.
  302. // If set on true, the From option will be ignored.
  303. All bool
  304. }
  305. var (
  306. ErrMissingAuthor = errors.New("author field is required")
  307. )
  308. // CommitOptions describes how a commit operation should be performed.
  309. type CommitOptions struct {
  310. // All automatically stage files that have been modified and deleted, but
  311. // new files you have not told Git about are not affected.
  312. All bool
  313. // Author is the author's signature of the commit.
  314. Author *object.Signature
  315. // Committer is the committer's signature of the commit. If Committer is
  316. // nil the Author signature is used.
  317. Committer *object.Signature
  318. // Parents are the parents commits for the new commit, by default when
  319. // len(Parents) is zero, the hash of HEAD reference is used.
  320. Parents []plumbing.Hash
  321. // SignKey denotes a key to sign the commit with. A nil value here means the
  322. // commit will not be signed. The private key must be present and already
  323. // decrypted.
  324. SignKey *openpgp.Entity
  325. }
  326. // Validate validates the fields and sets the default values.
  327. func (o *CommitOptions) Validate(r *Repository) error {
  328. if o.Author == nil {
  329. return ErrMissingAuthor
  330. }
  331. if o.Committer == nil {
  332. o.Committer = o.Author
  333. }
  334. if len(o.Parents) == 0 {
  335. head, err := r.Head()
  336. if err != nil && err != plumbing.ErrReferenceNotFound {
  337. return err
  338. }
  339. if head != nil {
  340. o.Parents = []plumbing.Hash{head.Hash()}
  341. }
  342. }
  343. return nil
  344. }
  345. var (
  346. ErrMissingName = errors.New("name field is required")
  347. ErrMissingTagger = errors.New("tagger field is required")
  348. ErrMissingMessage = errors.New("message field is required")
  349. )
  350. // CreateTagOptions describes how a tag object should be created.
  351. type CreateTagOptions struct {
  352. // Tagger defines the signature of the tag creator.
  353. Tagger *object.Signature
  354. // Message defines the annotation of the tag. It is canonicalized during
  355. // validation into the format expected by git - no leading whitespace and
  356. // ending in a newline.
  357. Message string
  358. // SignKey denotes a key to sign the tag with. A nil value here means the tag
  359. // will not be signed. The private key must be present and already decrypted.
  360. SignKey *openpgp.Entity
  361. }
  362. // Validate validates the fields and sets the default values.
  363. func (o *CreateTagOptions) Validate(r *Repository, hash plumbing.Hash) error {
  364. if o.Tagger == nil {
  365. return ErrMissingTagger
  366. }
  367. if o.Message == "" {
  368. return ErrMissingMessage
  369. }
  370. // Canonicalize the message into the expected message format.
  371. o.Message = strings.TrimSpace(o.Message) + "\n"
  372. return nil
  373. }
  374. // ListOptions describes how a remote list should be performed.
  375. type ListOptions struct {
  376. // Auth credentials, if required, to use with the remote repository.
  377. Auth transport.AuthMethod
  378. }
  379. // CleanOptions describes how a clean should be performed.
  380. type CleanOptions struct {
  381. Dir bool
  382. }
  383. // GrepOptions describes how a grep should be performed.
  384. type GrepOptions struct {
  385. // Patterns are compiled Regexp objects to be matched.
  386. Patterns []*regexp.Regexp
  387. // InvertMatch selects non-matching lines.
  388. InvertMatch bool
  389. // CommitHash is the hash of the commit from which worktree should be derived.
  390. CommitHash plumbing.Hash
  391. // ReferenceName is the branch or tag name from which worktree should be derived.
  392. ReferenceName plumbing.ReferenceName
  393. // PathSpecs are compiled Regexp objects of pathspec to use in the matching.
  394. PathSpecs []*regexp.Regexp
  395. }
  396. var (
  397. ErrHashOrReference = errors.New("ambiguous options, only one of CommitHash or ReferenceName can be passed")
  398. )
  399. // Validate validates the fields and sets the default values.
  400. func (o *GrepOptions) Validate(w *Worktree) error {
  401. if !o.CommitHash.IsZero() && o.ReferenceName != "" {
  402. return ErrHashOrReference
  403. }
  404. // If none of CommitHash and ReferenceName are provided, set commit hash of
  405. // the repository's head.
  406. if o.CommitHash.IsZero() && o.ReferenceName == "" {
  407. ref, err := w.r.Head()
  408. if err != nil {
  409. return err
  410. }
  411. o.CommitHash = ref.Hash()
  412. }
  413. return nil
  414. }
  415. // PlainOpenOptions describes how opening a plain repository should be
  416. // performed.
  417. type PlainOpenOptions struct {
  418. // DetectDotGit defines whether parent directories should be
  419. // walked until a .git directory or file is found.
  420. DetectDotGit bool
  421. }
  422. // Validate validates the fields and sets the default values.
  423. func (o *PlainOpenOptions) Validate() error { return nil }
上海开阖软件有限公司 沪ICP备12045867号-1