mercurial-ruby 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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