mercurial-ruby 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. data/.document +5 -0
  2. data/Gemfile +10 -0
  3. data/Gemfile.lock +32 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +86 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/lib/mercurial-ruby.rb +66 -0
  9. data/lib/mercurial-ruby/branch.rb +45 -0
  10. data/lib/mercurial-ruby/changed_file.rb +51 -0
  11. data/lib/mercurial-ruby/command.rb +77 -0
  12. data/lib/mercurial-ruby/commit.rb +152 -0
  13. data/lib/mercurial-ruby/config_file.rb +119 -0
  14. data/lib/mercurial-ruby/configuration.rb +14 -0
  15. data/lib/mercurial-ruby/diff.rb +50 -0
  16. data/lib/mercurial-ruby/factories/branch_factory.rb +91 -0
  17. data/lib/mercurial-ruby/factories/changed_file_factory.rb +50 -0
  18. data/lib/mercurial-ruby/factories/commit_factory.rb +154 -0
  19. data/lib/mercurial-ruby/factories/diff_factory.rb +63 -0
  20. data/lib/mercurial-ruby/factories/hook_factory.rb +45 -0
  21. data/lib/mercurial-ruby/factories/node_factory.rb +111 -0
  22. data/lib/mercurial-ruby/factories/tag_factory.rb +48 -0
  23. data/lib/mercurial-ruby/file_index.rb +209 -0
  24. data/lib/mercurial-ruby/helper.rb +23 -0
  25. data/lib/mercurial-ruby/hook.rb +23 -0
  26. data/lib/mercurial-ruby/manifest.rb +58 -0
  27. data/lib/mercurial-ruby/node.rb +100 -0
  28. data/lib/mercurial-ruby/repository.rb +94 -0
  29. data/lib/mercurial-ruby/root_node.rb +27 -0
  30. data/lib/mercurial-ruby/shell.rb +64 -0
  31. data/lib/mercurial-ruby/style.rb +23 -0
  32. data/lib/mercurial-ruby/tag.rb +33 -0
  33. data/lib/stdlib_exts/string.rb +12 -0
  34. data/lib/styles/changeset.style +5 -0
  35. data/lib/styles/file_index.style +3 -0
  36. data/mercurial-ruby.gemspec +227 -0
  37. data/test/fixtures.rb +28 -0
  38. data/test/fixtures/test-repo/.DotFile +1 -0
  39. data/test/fixtures/test-repo/.hg/00changelog.i +0 -0
  40. data/test/fixtures/test-repo/.hg/branch +1 -0
  41. data/test/fixtures/test-repo/.hg/cache/branchheads +6 -0
  42. data/test/fixtures/test-repo/.hg/cache/tags +7 -0
  43. data/test/fixtures/test-repo/.hg/dirstate +0 -0
  44. data/test/fixtures/test-repo/.hg/hgrc +3 -0
  45. data/test/fixtures/test-repo/.hg/last-message.txt +1 -0
  46. data/test/fixtures/test-repo/.hg/requires +4 -0
  47. data/test/fixtures/test-repo/.hg/store/00changelog.i +0 -0
  48. data/test/fixtures/test-repo/.hg/store/00manifest.i +0 -0
  49. data/test/fixtures/test-repo/.hg/store/data/_file _with _whitespace.pdf.i +0 -0
  50. data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e.txt.i +0 -0
  51. data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e2.txt.i +0 -0
  52. data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e3.txt.i +0 -0
  53. data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e4.txt.i +0 -0
  54. data/test/fixtures/test-repo/.hg/store/data/_r_e_a_d_m_e.markdown.i +0 -0
  55. data/test/fixtures/test-repo/.hg/store/data/_r_e_a_d_m_e.markup.i +0 -0
  56. data/test/fixtures/test-repo/.hg/store/data/_rakefile.i +0 -0
  57. data/test/fixtures/test-repo/.hg/store/data/_rakefile2.i +0 -0
  58. data/test/fixtures/test-repo/.hg/store/data/_rakefile3.i +0 -0
  59. data/test/fixtures/test-repo/.hg/store/data/check ~5c this ~5c out ~22 now.i +0 -0
  60. data/test/fixtures/test-repo/.hg/store/data/directory two/minitest__mixin.rb.i +0 -0
  61. data/test/fixtures/test-repo/.hg/store/data/directory two/options.rb.i +0 -0
  62. data/test/fixtures/test-repo/.hg/store/data/directory two/rdoc__mixin.rb.i +0 -0
  63. data/test/fixtures/test-repo/.hg/store/data/directory two/rspec__mixin.rb.i +0 -0
  64. data/test/fixtures/test-repo/.hg/store/data/directory two/shindo__mixin.rb.i +0 -0
  65. data/test/fixtures/test-repo/.hg/store/data/directory two/shoulda__mixin.rb.i +0 -0
  66. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_gemfile.i +0 -0
  67. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_l_i_c_e_n_s_e.txt.i +0 -0
  68. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_r_e_a_d_m_e.rdoc.i +0 -0
  69. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_rakefile.i +0 -0
  70. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/bacon/flunking.rb.i +0 -0
  71. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/bacon/helper.rb.i +0 -0
  72. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/bundler__setup.erb.i +0 -0
  73. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/features/default.feature.i +0 -0
  74. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/features/support/env.rb.i +0 -0
  75. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/jeweler__tasks.erb.i +0 -0
  76. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/micronaut/flunking.rb.i +0 -0
  77. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/micronaut/helper.rb.i +0 -0
  78. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/minitest/flunking.rb.i +0 -0
  79. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/minitest/helper.rb.i +0 -0
  80. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/other__tasks.erb.i +0 -0
  81. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/riot/flunking.rb.i +0 -0
  82. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/riot/helper.rb.i +0 -0
  83. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/rspec/flunking.rb.i +0 -0
  84. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/rspec/helper.rb.i +0 -0
  85. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/rspec/~2erspec.i +0 -0
  86. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shindo/flunking.rb.i +0 -0
  87. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shindo/helper.rb.i +0 -0
  88. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shoulda/flunking.rb.i +0 -0
  89. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shoulda/helper.rb.i +0 -0
  90. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testspec/flunking.rb.i +0 -0
  91. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testspec/helper.rb.i +0 -0
  92. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testunit/flunking.rb.i +0 -0
  93. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testunit/helper.rb.i +0 -0
  94. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/~2edocument.i +0 -0
  95. data/test/fixtures/test-repo/.hg/store/data/directory two/templates/~2egitignore.i +0 -0
  96. data/test/fixtures/test-repo/.hg/store/data/directory two/~2e_d_s___store.i +0 -0
  97. data/test/fixtures/test-repo/.hg/store/data/directory__1/rubygems__dot__org__tasks.rb.i +0 -0
  98. data/test/fixtures/test-repo/.hg/store/data/directory__1/rubygems__tasks.rb.i +0 -0
  99. data/test/fixtures/test-repo/.hg/store/data/directory__1/specification.rb.i +0 -0
  100. data/test/fixtures/test-repo/.hg/store/data/directory__1/tasks.rb.i +0 -0
  101. data/test/fixtures/test-repo/.hg/store/data/directory__1/~2e_d_s___store.i +0 -0
  102. data/test/fixtures/test-repo/.hg/store/data/empty-file.i +0 -0
  103. data/test/fixtures/test-repo/.hg/store/data/goose.png.i +0 -0
  104. data/test/fixtures/test-repo/.hg/store/data/goose/pretty-thing.txt.i +0 -0
  105. data/test/fixtures/test-repo/.hg/store/data/new-directory/another-boring-file.i +0 -0
  106. data/test/fixtures/test-repo/.hg/store/data/new-directory/something.csv.i +0 -0
  107. data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/_e_u_l_a5seat___chin___sim02.03.04.pdf.d +0 -0
  108. data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/_e_u_l_a5seat___chin___sim02.03.04.pdf.i +0 -0
  109. data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/_file _with _whitespace.pdf.i +0 -0
  110. data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/beansprout.png.i +0 -0
  111. data/test/fixtures/test-repo/.hg/store/data/new-file.i +0 -0
  112. data/test/fixtures/test-repo/.hg/store/data/old-directory/minitest__mixin.rb.i +0 -0
  113. data/test/fixtures/test-repo/.hg/store/data/old-directory/options.rb.i +0 -0
  114. data/test/fixtures/test-repo/.hg/store/data/old-directory/rspec__mixin.rb.i +0 -0
  115. data/test/fixtures/test-repo/.hg/store/data/old-directory/shindo__mixin.rb.i +0 -0
  116. data/test/fixtures/test-repo/.hg/store/data/old-directory/testunit__mixin.rb.i +0 -0
  117. data/test/fixtures/test-repo/.hg/store/data/old-directory/yard__mixin.rb.i +0 -0
  118. data/test/fixtures/test-repo/.hg/store/data/riot__mixin.rb.i +0 -0
  119. data/test/fixtures/test-repo/.hg/store/data/riot__mixin__copy.rb.i +0 -0
  120. data/test/fixtures/test-repo/.hg/store/data/style.i +0 -0
  121. data/test/fixtures/test-repo/.hg/store/data/super-cow.i +0 -0
  122. data/test/fixtures/test-repo/.hg/store/data/superman.txt.i +0 -0
  123. data/test/fixtures/test-repo/.hg/store/data/testspec__mixin.rb.i +0 -0
  124. data/test/fixtures/test-repo/.hg/store/data/testspec__mixin__new.rb.i +0 -0
  125. data/test/fixtures/test-repo/.hg/store/data/~2e_dot_file.i +0 -0
  126. data/test/fixtures/test-repo/.hg/store/data/~2ehgignore.i +0 -0
  127. data/test/fixtures/test-repo/.hg/store/data/~2ehgtags.i +0 -0
  128. data/test/fixtures/test-repo/.hg/store/fncache +79 -0
  129. data/test/fixtures/test-repo/.hg/store/undo +0 -0
  130. data/test/fixtures/test-repo/.hg/undo.bookmarks +0 -0
  131. data/test/fixtures/test-repo/.hg/undo.branch +1 -0
  132. data/test/fixtures/test-repo/.hg/undo.desc +2 -0
  133. data/test/fixtures/test-repo/.hg/undo.dirstate +0 -0
  134. data/test/fixtures/test-repo/.hgignore +1 -0
  135. data/test/fixtures/test-repo/.hgtags +1 -0
  136. data/test/fixtures/test-repo/LICENSE3.txt +15 -0
  137. data/test/fixtures/test-repo/LICENSE4.txt +17 -0
  138. data/test/fixtures/test-repo/README.markup +218 -0
  139. data/test/fixtures/test-repo/Rakefile3 +83 -0
  140. data/test/fixtures/test-repo/check // this // out /" now" "b/data/test/fixtures/test-repo/check // this // out / → now +0 -0
  141. data/test/fixtures/test-repo/empty-file +0 -0
  142. data/test/fixtures/test-repo/goose.png +0 -0
  143. data/test/fixtures/test-repo/goose/pretty-thing.txt +0 -0
  144. data/test/fixtures/test-repo/new-directory/another-boring-file +78 -0
  145. data/test/fixtures/test-repo/new-directory/something.csv +1 -0
  146. data/test/fixtures/test-repo/new-directory/subdirectory/EULA5seat_Chin_Sim02.03.04.pdf +0 -0
  147. data/test/fixtures/test-repo/new-directory/subdirectory/File With Whitespace.pdf b/data/test/fixtures/test-repo/new-directory/subdirectory/File With → Whitespace.pdf +0 -0
  148. data/test/fixtures/test-repo/new-directory/subdirectory/beansprout.png +0 -0
  149. data/test/fixtures/test-repo/riot_mixin.rb +45 -0
  150. data/test/fixtures/test-repo/style +4 -0
  151. data/test/fixtures/test-repo/superman.txt +1 -0
  152. data/test/fixtures/test-repo/testspec_mixin_new.rb +44 -0
  153. data/test/helper.rb +41 -0
  154. data/test/test_branch_factory.rb +46 -0
  155. data/test/test_changed_file.rb +46 -0
  156. data/test/test_changed_file_factory.rb +16 -0
  157. data/test/test_command.rb +62 -0
  158. data/test/test_commit.rb +66 -0
  159. data/test/test_commit_factory.rb +101 -0
  160. data/test/test_config_file.rb +105 -0
  161. data/test/test_configuration.rb +26 -0
  162. data/test/test_diff.rb +39 -0
  163. data/test/test_diff_factory.rb +38 -0
  164. data/test/test_file_index.rb +113 -0
  165. data/test/test_hook.rb +39 -0
  166. data/test/test_hook_factory.rb +40 -0
  167. data/test/test_manifest.rb +39 -0
  168. data/test/test_node.rb +34 -0
  169. data/test/test_node_factory.rb +125 -0
  170. data/test/test_repository.rb +58 -0
  171. data/test/test_shell.rb +33 -0
  172. data/test/test_tag_factory.rb +27 -0
  173. metadata +328 -0
@@ -0,0 +1,152 @@
1
+ module Mercurial
2
+
3
+ #
4
+ # The class represents Mercurial changeset. Obtained by running an +hg log+ command.
5
+ # Contains a lot of information, including it's hash ID, author name and email, list of changed files, etc.
6
+ #
7
+ # The class represents Commit object itself, {Mercurial::CommitFactory CommitFactory} is responsible
8
+ # for assembling instances of Commit. For the list of all possible commit-related operations please
9
+ # look documentation for {Mercurial::CommitFactory CommitFactory}.
10
+ #
11
+ # Read more about Mercurial commits:
12
+ #
13
+ # http://mercurial.selenic.com/wiki/Commit
14
+ #
15
+ class Commit
16
+ include Mercurial::Helper
17
+
18
+ # Instance of {Mercurial::Repository Repository}.
19
+ attr_reader :repository
20
+
21
+ # Mercurial changeset ID. 40-chars long SHA1 hash.
22
+ attr_reader :hash_id
23
+
24
+ # Name of the user committed the change.
25
+ attr_reader :author
26
+
27
+ # Email of the user committed the change.
28
+ attr_reader :author_email
29
+
30
+ # Exact date and time of the commit. Contains Ruby Time object.
31
+ attr_reader :date
32
+
33
+ # Full commit message, with line breaks and other stuff.
34
+ attr_reader :message
35
+
36
+ # Array of {Mercurial::ChangedFile ChangedFile} objects.
37
+ attr_reader :changed_files
38
+
39
+ # Array of commit's branches.
40
+ attr_reader :branches_names
41
+
42
+ # Array of commit's tags.
43
+ attr_reader :tags_names
44
+
45
+ # Array of commit's parents.
46
+ attr_reader :parents_ids
47
+
48
+ alias :id :hash_id
49
+
50
+ def initialize(repository, opts={}) #:nodoc:
51
+ @repository = repository
52
+ @hash_id = opts[:hash_id]
53
+ @author = opts[:author]
54
+ @author_email = opts[:author_email]
55
+ @date = Time.iso8601(opts[:date])
56
+ @message = opts[:message]
57
+ @changed_files = files_to_array(opts[:changed_files])
58
+ @branches_names = branches_or_tags_to_array(opts[:branches_names])
59
+ @tags_names = branches_or_tags_to_array(opts[:tags_names])
60
+ @parents_ids = parents_to_array(opts[:parents])
61
+ end
62
+
63
+ def merge?
64
+ parents.size > 1
65
+ end
66
+
67
+ def blank?
68
+ hash_id == '0'*40
69
+ end
70
+
71
+ def diffs
72
+ repository.diffs.for_commit(self)
73
+ end
74
+
75
+ def parents
76
+ repository.commits.by_hash_ids(parents_ids)
77
+ end
78
+
79
+ def parent_id
80
+ parents_ids.first
81
+ end
82
+
83
+ def exist_in_branches
84
+ repository.branches.for_commit(hash_id)
85
+ end
86
+
87
+ def to_hash
88
+ {
89
+ 'id' => hash_id,
90
+ 'parents' => parents_ids.map { |p| { 'id' => p.id } },
91
+ 'branches' => branches_names,
92
+ 'tags' => tags_names,
93
+ 'message' => message,
94
+ 'date' => date,
95
+ 'author' => {
96
+ 'name' => author,
97
+ 'email' => author_email
98
+ }
99
+ }
100
+ end
101
+
102
+ protected
103
+
104
+ def files_to_array(array)
105
+ [].tap do |returning|
106
+ array.each do |files|
107
+ if files
108
+ files.split(';').map do |file_with_mode|
109
+ returning << Mercurial::ChangedFileFactory.new_from_hg(file_with_mode)
110
+ end
111
+ end
112
+ end
113
+
114
+ remove_files_duplicates(returning)
115
+ end
116
+ end
117
+
118
+ def remove_files_duplicates(files)
119
+ Mercurial::ChangedFileFactory.delete_hg_artefacts(files)
120
+ end
121
+
122
+ def branches_or_tags_to_array(branches_str)
123
+ string_to_array(branches_str) do |returning|
124
+ returning << branches_str
125
+ end
126
+ end
127
+
128
+ def parents_to_array(string)
129
+ string_to_array(string) do |returning|
130
+ string.split(' ').map do |hg_hash|
131
+ returning << hg_hash_to_hash_id(hg_hash)
132
+ end
133
+ end
134
+ end
135
+
136
+ def string_to_array(string, &block)
137
+ if string && !string.empty?
138
+ [].tap do |returning|
139
+ block.call(returning)
140
+ end
141
+ else
142
+ []
143
+ end
144
+ end
145
+
146
+ def hg_hash_to_hash_id(hg_hash)
147
+ hg_hash.split(':').last
148
+ end
149
+
150
+ end
151
+
152
+ end
@@ -0,0 +1,119 @@
1
+ module Mercurial
2
+
3
+ #
4
+ # Represents +.hg/hgrc+ configuration file stored in the repository.
5
+ # Useful for adding/removing various settings.
6
+ #
7
+ # You can read more about hgrc here:
8
+ #
9
+ # http://www.selenic.com/mercurial/hgrc.5.html
10
+ #
11
+ class ConfigFile
12
+
13
+ attr_reader :repository
14
+
15
+ def initialize(repository)
16
+ @repository = repository
17
+ end
18
+
19
+ #
20
+ # Returns absolute path to the config file:
21
+ #
22
+ # config.path # => /home/ilya/repos/fancyrepo/.hg/hgrc
23
+ #
24
+ def path
25
+ File.join(repository.path, '.hg', 'hgrc')
26
+ end
27
+
28
+ #
29
+ # Returns true if the config file actually exists on disk.
30
+ # For new repositories it's missing by default.
31
+ #
32
+ def exists?
33
+ File.exists?(path)
34
+ end
35
+
36
+ #
37
+ # Returns contents of the config file as a string.
38
+ #
39
+ def contents
40
+ File.read(path) if exists?
41
+ end
42
+
43
+ #
44
+ # Adds specified setting to a specified section of the config:
45
+ #
46
+ # config.add_setting('merge-tools', 'kdiff3.executable', '~/bin/kdiff3')
47
+ #
48
+ # It will write the following content to the +hgrc+:
49
+ #
50
+ # [merge-tools]
51
+ # kdiff3.executable = ~/bin/kdiff3
52
+ #
53
+ def add_setting(header, name, value)
54
+ new_setting = %Q{[#{ header }]\n#{ name } = #{ value }\n}
55
+ write do
56
+ if contents.nil?
57
+ new_setting
58
+ elsif contents.scan(header_regexp(header)).empty?
59
+ contents << "\n\n#{ new_setting }"
60
+ else
61
+ contents.gsub(header_regexp(header), new_setting)
62
+ end
63
+ end
64
+ end
65
+
66
+ #
67
+ # Removes specified setting from the hgrc:
68
+ #
69
+ # config.delete_setting!('merge-tools', 'kdiff3.executable')
70
+ #
71
+ def delete_setting!(header, name)
72
+ write do
73
+ contents.gsub(find_setting(header, name), '')
74
+ end
75
+ end
76
+
77
+ #
78
+ # Returns content of the specified section of hgrc.
79
+ #
80
+ def find_header(header)
81
+ {}.tap do |returning|
82
+ contents.scan(header_with_content_regexp(header)).flatten.first.split("\n").each do |setting|
83
+ name, value = *setting.split('=').map(&:strip)
84
+ returning[name] = value
85
+ end
86
+ end
87
+ end
88
+
89
+ #
90
+ # Returns content of the specified setting from a section.
91
+ #
92
+ def find_setting(header, setting) #:nodoc:
93
+ contents.scan(setting_regexp(header, setting)).flatten.first
94
+ end
95
+
96
+ private
97
+
98
+ def write(&block)
99
+ new_content = block.call
100
+ File.open(path, 'w') do |f|
101
+ f << new_content
102
+ end
103
+ end
104
+
105
+ def header_regexp(header)
106
+ /(\[#{ Regexp.escape(header) }\]\s*)/
107
+ end
108
+
109
+ def header_with_content_regexp(header)
110
+ /\[#{ Regexp.escape(header) }\]\s*([^\[\]]*)/i
111
+ end
112
+
113
+ def setting_regexp(header, setting)
114
+ /\[#{ Regexp.escape(header) }\]\s*[^\[\]]*(^#{ Regexp.escape(setting) }.+\n*)/i
115
+ end
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,14 @@
1
+ module Mercurial
2
+
3
+ class Configuration
4
+
5
+ attr_accessor :hg_binary_path, :shell_timeout, :cache_store
6
+
7
+ def initialize
8
+ @hg_binary_path = '/usr/local/bin/hg'
9
+ @shell_timeout = 3000
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,50 @@
1
+ module Mercurial
2
+
3
+ #
4
+ # The class represents Mercurial diff. Obtained by running an +hg diff+ command.
5
+ #
6
+ # The class represents Diff object itself, {Mercurial::DiffFactory DiffFactory} is responsible
7
+ # for assembling instances of Diff. For the list of all possible diff-related operations please
8
+ # look documentation for {Mercurial::DiffFactory DiffFactory}.
9
+ #
10
+ class Diff
11
+
12
+ # Instance of {Mercurial::Commit Commit}.
13
+ attr_reader :commit
14
+
15
+ # SHA1 hash of version a of the file.
16
+ attr_reader :hash_a
17
+
18
+ # SHA1 hash of version b of the file.
19
+ attr_reader :hash_b
20
+
21
+ # Version a if the file name.
22
+ attr_reader :file_a
23
+
24
+ # Version b of the file name.
25
+ attr_reader :file_b
26
+
27
+ # Diff body.
28
+ attr_reader :body
29
+
30
+ def initialize(commit, opts={})
31
+ @commit = commit
32
+ @hash_a = opts[:hash_a]
33
+ @hash_b = opts[:hash_b]
34
+ @file_a = opts[:file_a]
35
+ @file_b = opts[:file_b]
36
+ @body = opts[:body]
37
+ @binary = opts[:binary]
38
+ end
39
+
40
+ def file_name
41
+ file_b || file_a
42
+ end
43
+
44
+ def binary?
45
+ !! @binary
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,91 @@
1
+ module Mercurial
2
+
3
+ #
4
+ # This class represents a factory for {Mercurial::Branch Branch} instances.
5
+ #
6
+ class BranchFactory
7
+ include Mercurial::Helper
8
+
9
+ # Instance of {Mercurial::Repository Repository}.
10
+ attr_reader :repository
11
+
12
+ def initialize(repository)
13
+ @repository = repository
14
+ end
15
+
16
+ # Return an array of {Mercurial::Branch Branch} instances for all branches in the repository.
17
+ #
18
+ # == Example:
19
+ # repository.branches.all
20
+ #
21
+ def all
22
+ hg_to_array "branches -c" do |line|
23
+ build(line)
24
+ end
25
+ end
26
+
27
+ # Return an array of {Mercurial::Branch Branch} instances for all active branches in the repository.
28
+ #
29
+ # == Example:
30
+ # repository.branches.active
31
+ #
32
+ def active
33
+ all.find_all do |b|
34
+ b.active?
35
+ end
36
+ end
37
+
38
+ # Return an array of {Mercurial::Branch Branch} instances for all closed branches in the repository.
39
+ #
40
+ # == Example:
41
+ # repository.branches.closed
42
+ #
43
+ def closed
44
+ all.find_all do |b|
45
+ b.closed?
46
+ end
47
+ end
48
+
49
+ # Return a {Mercurial::Branch Branch} instance for a branch with a specified name.
50
+ #
51
+ # == Example:
52
+ # repository.branches.by_name('branchname')
53
+ #
54
+ def by_name(name)
55
+ all.find do |b|
56
+ b.name == name
57
+ end
58
+ end
59
+
60
+ # Return an array of {Mercurial::Branch Branch} instances where a specified commit exists.
61
+ # Experimental, doesn't always return a correct list of branches.
62
+ #
63
+ # == Example:
64
+ # repository.branches.for_commit('291a498f04e9')
65
+ #
66
+ def for_commit(hash_id)
67
+ hg_to_array ["log -r 'descendants(?) and head()' --template '\n{branches}'", hash_id] do |line|
68
+ build_with_name_only(line)
69
+ end.compact.uniq
70
+ end
71
+
72
+ private
73
+
74
+ def build(data)
75
+ name, last_commit, status = *data.scan(/([\w-]+)\s+\d+:(\w+)\s*\(*(\w*)\)*/).first
76
+ Mercurial::Branch.new(
77
+ repository,
78
+ name,
79
+ :commit => last_commit,
80
+ :status => status
81
+ )
82
+ end
83
+
84
+ def build_with_name_only(name)
85
+ name = 'default' if name == ''
86
+ Mercurial::Branch.new(repository, name)
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,50 @@
1
+ module Mercurial
2
+
3
+ class ChangedFileFactory
4
+
5
+ FILE_COPY_SEPARATOR = '->'
6
+
7
+ def self.new_from_hg(str)
8
+ if str.include?(FILE_COPY_SEPARATOR)
9
+ copied_file = str.split(FILE_COPY_SEPARATOR)
10
+ initial_name = copied_file.first[2..-1]
11
+ name = copied_file[1]
12
+ else
13
+ initial_name = nil
14
+ name = str[2..-1]
15
+ end
16
+
17
+ Mercurial::ChangedFile.new(
18
+ :initial_name => initial_name,
19
+ :name => name,
20
+ :mode => str[0..0]
21
+ )
22
+ end
23
+
24
+ def self.delete_hg_artefacts(files)
25
+ #
26
+ # For unknown reason Mercurial post duplicated
27
+ # entries for moved and copied files. First as
28
+ # a pair of A and D operations, then as C.
29
+ #
30
+ files.reverse.each do |file|
31
+ if file.copied?
32
+ add = files.find{|f| f.added? && f.name == file.name}
33
+ delete = files.find{|f| f.deleted? && f.name == file.initial_name}
34
+
35
+ if add && delete
36
+ file.mode_letter = 'R'
37
+ files.delete_at(files.index(add))
38
+ files.delete_at(files.index(delete))
39
+
40
+ elsif add
41
+ files.delete_at(files.index(add))
42
+ end
43
+ end
44
+ end
45
+ files
46
+ end
47
+
48
+ end
49
+
50
+ end