amp 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (232) hide show
  1. data/.gitignore +12 -0
  2. data/.hgignore +3 -0
  3. data/AUTHORS +1 -1
  4. data/Manifest.txt +99 -38
  5. data/README.md +3 -3
  6. data/Rakefile +53 -18
  7. data/SCHEDULE.markdown +5 -1
  8. data/TODO.markdown +120 -149
  9. data/ampfile.rb +3 -1
  10. data/bin/amp +4 -1
  11. data/ext/amp/bz2/extconf.rb +1 -1
  12. data/ext/amp/mercurial_patch/extconf.rb +1 -1
  13. data/ext/amp/mercurial_patch/mpatch.c +4 -3
  14. data/ext/amp/priority_queue/extconf.rb +1 -1
  15. data/ext/amp/support/extconf.rb +1 -1
  16. data/ext/amp/support/support.c +1 -1
  17. data/lib/amp.rb +125 -67
  18. data/lib/amp/commands/command.rb +12 -10
  19. data/lib/amp/commands/command_support.rb +8 -1
  20. data/lib/amp/commands/commands/help.rb +2 -20
  21. data/lib/amp/commands/commands/init.rb +14 -2
  22. data/lib/amp/commands/commands/templates.rb +6 -4
  23. data/lib/amp/commands/commands/version.rb +15 -1
  24. data/lib/amp/commands/commands/workflow.rb +3 -3
  25. data/lib/amp/commands/commands/workflows/git/add.rb +3 -3
  26. data/lib/amp/commands/commands/workflows/git/copy.rb +1 -1
  27. data/lib/amp/commands/commands/workflows/git/rm.rb +4 -2
  28. data/lib/amp/commands/commands/workflows/hg/add.rb +1 -1
  29. data/lib/amp/commands/commands/workflows/hg/addremove.rb +2 -2
  30. data/lib/amp/commands/commands/workflows/hg/annotate.rb +8 -2
  31. data/lib/amp/commands/commands/workflows/hg/bisect.rb +253 -0
  32. data/lib/amp/commands/commands/workflows/hg/branch.rb +1 -1
  33. data/lib/amp/commands/commands/workflows/hg/branches.rb +3 -3
  34. data/lib/amp/commands/commands/workflows/hg/bundle.rb +3 -3
  35. data/lib/amp/commands/commands/workflows/hg/clone.rb +4 -5
  36. data/lib/amp/commands/commands/workflows/hg/commit.rb +37 -1
  37. data/lib/amp/commands/commands/workflows/hg/copy.rb +2 -1
  38. data/lib/amp/commands/commands/workflows/hg/debug/index.rb +1 -1
  39. data/lib/amp/commands/commands/workflows/hg/diff.rb +3 -8
  40. data/lib/amp/commands/commands/workflows/hg/forget.rb +5 -4
  41. data/lib/amp/commands/commands/workflows/hg/identify.rb +6 -6
  42. data/lib/amp/commands/commands/workflows/hg/import.rb +1 -1
  43. data/lib/amp/commands/commands/workflows/hg/incoming.rb +2 -2
  44. data/lib/amp/commands/commands/workflows/hg/log.rb +5 -4
  45. data/lib/amp/commands/commands/workflows/hg/merge.rb +1 -1
  46. data/lib/amp/commands/commands/workflows/hg/move.rb +5 -3
  47. data/lib/amp/commands/commands/workflows/hg/outgoing.rb +1 -1
  48. data/lib/amp/commands/commands/workflows/hg/push.rb +6 -7
  49. data/lib/amp/commands/commands/workflows/hg/remove.rb +2 -2
  50. data/lib/amp/commands/commands/workflows/hg/resolve.rb +6 -23
  51. data/lib/amp/commands/commands/workflows/hg/root.rb +1 -2
  52. data/lib/amp/commands/commands/workflows/hg/status.rb +21 -12
  53. data/lib/amp/commands/commands/workflows/hg/tag.rb +2 -2
  54. data/lib/amp/commands/commands/workflows/hg/untrack.rb +12 -0
  55. data/lib/amp/commands/commands/workflows/hg/verify.rb +13 -3
  56. data/lib/amp/commands/commands/workflows/hg/what_changed.rb +18 -0
  57. data/lib/amp/commands/dispatch.rb +12 -13
  58. data/lib/amp/dependencies/amp_support.rb +1 -1
  59. data/lib/amp/dependencies/amp_support/ruby_amp_support.rb +1 -0
  60. data/lib/amp/dependencies/maruku.rb +136 -0
  61. data/lib/amp/dependencies/maruku/attributes.rb +227 -0
  62. data/lib/amp/dependencies/maruku/defaults.rb +71 -0
  63. data/lib/amp/dependencies/maruku/errors_management.rb +92 -0
  64. data/lib/amp/dependencies/maruku/helpers.rb +260 -0
  65. data/lib/amp/dependencies/maruku/input/charsource.rb +326 -0
  66. data/lib/amp/dependencies/maruku/input/extensions.rb +69 -0
  67. data/lib/amp/dependencies/maruku/input/html_helper.rb +189 -0
  68. data/lib/amp/dependencies/maruku/input/linesource.rb +111 -0
  69. data/lib/amp/dependencies/maruku/input/parse_block.rb +615 -0
  70. data/lib/amp/dependencies/maruku/input/parse_doc.rb +234 -0
  71. data/lib/amp/dependencies/maruku/input/parse_span_better.rb +746 -0
  72. data/lib/amp/dependencies/maruku/input/rubypants.rb +225 -0
  73. data/lib/amp/dependencies/maruku/input/type_detection.rb +147 -0
  74. data/lib/amp/dependencies/maruku/input_textile2/t2_parser.rb +163 -0
  75. data/lib/amp/dependencies/maruku/maruku.rb +33 -0
  76. data/lib/amp/dependencies/maruku/output/to_ansi.rb +223 -0
  77. data/lib/amp/dependencies/maruku/output/to_html.rb +991 -0
  78. data/lib/amp/dependencies/maruku/output/to_markdown.rb +164 -0
  79. data/lib/amp/dependencies/maruku/output/to_s.rb +56 -0
  80. data/lib/amp/dependencies/maruku/string_utils.rb +191 -0
  81. data/lib/amp/dependencies/maruku/structures.rb +167 -0
  82. data/lib/amp/dependencies/maruku/structures_inspect.rb +87 -0
  83. data/lib/amp/dependencies/maruku/structures_iterators.rb +61 -0
  84. data/lib/amp/dependencies/maruku/textile2.rb +1 -0
  85. data/lib/amp/dependencies/maruku/toc.rb +199 -0
  86. data/lib/amp/dependencies/maruku/usage/example1.rb +33 -0
  87. data/lib/amp/dependencies/maruku/version.rb +40 -0
  88. data/lib/amp/dependencies/priority_queue.rb +2 -1
  89. data/lib/amp/dependencies/python_config.rb +2 -1
  90. data/lib/amp/graphs/ancestor.rb +2 -1
  91. data/lib/amp/graphs/copies.rb +236 -233
  92. data/lib/amp/help/entries/__default__.erb +31 -0
  93. data/lib/amp/help/entries/commands.erb +6 -0
  94. data/lib/amp/help/entries/mdtest.md +35 -0
  95. data/lib/amp/help/entries/silly +3 -0
  96. data/lib/amp/help/help.rb +288 -0
  97. data/lib/amp/profiling_hacks.rb +5 -3
  98. data/lib/amp/repository/abstract/abstract_changeset.rb +97 -0
  99. data/lib/amp/repository/abstract/abstract_local_repo.rb +181 -0
  100. data/lib/amp/repository/abstract/abstract_staging_area.rb +180 -0
  101. data/lib/amp/repository/abstract/abstract_versioned_file.rb +100 -0
  102. data/lib/amp/repository/abstract/common_methods/changeset.rb +75 -0
  103. data/lib/amp/repository/abstract/common_methods/local_repo.rb +277 -0
  104. data/lib/amp/repository/abstract/common_methods/staging_area.rb +233 -0
  105. data/lib/amp/repository/abstract/common_methods/versioned_file.rb +71 -0
  106. data/lib/amp/repository/generic_repo_picker.rb +78 -0
  107. data/lib/amp/repository/git/repo_format/changeset.rb +336 -0
  108. data/lib/amp/repository/git/repo_format/staging_area.rb +192 -0
  109. data/lib/amp/repository/git/repo_format/versioned_file.rb +119 -0
  110. data/lib/amp/repository/git/repositories/local_repository.rb +164 -0
  111. data/lib/amp/repository/git/repository.rb +41 -0
  112. data/lib/amp/repository/mercurial/encoding/mercurial_diff.rb +382 -0
  113. data/lib/amp/repository/mercurial/encoding/mercurial_patch.rb +1 -0
  114. data/lib/amp/repository/mercurial/encoding/patch.rb +294 -0
  115. data/lib/amp/repository/mercurial/encoding/pure_ruby/ruby_mercurial_patch.rb +124 -0
  116. data/lib/amp/repository/mercurial/merging/merge_ui.rb +327 -0
  117. data/lib/amp/repository/mercurial/merging/simple_merge.rb +452 -0
  118. data/lib/amp/repository/mercurial/repo_format/branch_manager.rb +266 -0
  119. data/lib/amp/repository/mercurial/repo_format/changeset.rb +768 -0
  120. data/lib/amp/repository/mercurial/repo_format/dir_state.rb +716 -0
  121. data/lib/amp/repository/mercurial/repo_format/journal.rb +218 -0
  122. data/lib/amp/repository/mercurial/repo_format/lock.rb +210 -0
  123. data/lib/amp/repository/mercurial/repo_format/merge_state.rb +228 -0
  124. data/lib/amp/repository/mercurial/repo_format/staging_area.rb +367 -0
  125. data/lib/amp/repository/mercurial/repo_format/store.rb +487 -0
  126. data/lib/amp/repository/mercurial/repo_format/tag_manager.rb +322 -0
  127. data/lib/amp/repository/mercurial/repo_format/updatable.rb +543 -0
  128. data/lib/amp/repository/mercurial/repo_format/updater.rb +848 -0
  129. data/lib/amp/repository/mercurial/repo_format/verification.rb +433 -0
  130. data/lib/amp/repository/mercurial/repositories/bundle_repository.rb +216 -0
  131. data/lib/amp/repository/mercurial/repositories/http_repository.rb +386 -0
  132. data/lib/amp/repository/mercurial/repositories/local_repository.rb +2034 -0
  133. data/lib/amp/repository/mercurial/repository.rb +119 -0
  134. data/lib/amp/repository/mercurial/revlogs/bundle_revlogs.rb +249 -0
  135. data/lib/amp/repository/mercurial/revlogs/changegroup.rb +217 -0
  136. data/lib/amp/repository/mercurial/revlogs/changelog.rb +339 -0
  137. data/lib/amp/repository/mercurial/revlogs/file_log.rb +152 -0
  138. data/lib/amp/repository/mercurial/revlogs/index.rb +500 -0
  139. data/lib/amp/repository/mercurial/revlogs/manifest.rb +201 -0
  140. data/lib/amp/repository/mercurial/revlogs/node.rb +20 -0
  141. data/lib/amp/repository/mercurial/revlogs/revlog.rb +1026 -0
  142. data/lib/amp/repository/mercurial/revlogs/revlog_support.rb +129 -0
  143. data/lib/amp/repository/mercurial/revlogs/versioned_file.rb +597 -0
  144. data/lib/amp/repository/repository.rb +11 -88
  145. data/lib/amp/server/extension/amp_extension.rb +3 -3
  146. data/lib/amp/server/fancy_http_server.rb +1 -1
  147. data/lib/amp/server/fancy_views/_browser.haml +1 -1
  148. data/lib/amp/server/fancy_views/_diff_file.haml +1 -8
  149. data/lib/amp/server/fancy_views/changeset.haml +2 -2
  150. data/lib/amp/server/fancy_views/file.haml +1 -1
  151. data/lib/amp/server/fancy_views/file_diff.haml +1 -1
  152. data/lib/amp/support/amp_ui.rb +13 -29
  153. data/lib/amp/support/generator.rb +1 -1
  154. data/lib/amp/support/loaders.rb +1 -2
  155. data/lib/amp/support/logger.rb +10 -16
  156. data/lib/amp/support/match.rb +18 -4
  157. data/lib/amp/support/mercurial/ignore.rb +151 -0
  158. data/lib/amp/support/openers.rb +8 -3
  159. data/lib/amp/support/support.rb +91 -46
  160. data/lib/amp/templates/{blank.commit.erb → mercurial/blank.commit.erb} +0 -0
  161. data/lib/amp/templates/{blank.log.erb → mercurial/blank.log.erb} +0 -0
  162. data/lib/amp/templates/{default.commit.erb → mercurial/default.commit.erb} +0 -0
  163. data/lib/amp/templates/{default.log.erb → mercurial/default.log.erb} +0 -0
  164. data/lib/amp/templates/template.rb +18 -18
  165. data/man/amp.1 +51 -0
  166. data/site/src/about/commands.haml +1 -1
  167. data/site/src/css/amp.css +1 -1
  168. data/site/src/index.haml +3 -3
  169. data/tasks/man.rake +39 -0
  170. data/tasks/stats.rake +1 -10
  171. data/tasks/yard.rake +1 -50
  172. data/test/dirstate_tests/test_dir_state.rb +10 -8
  173. data/test/functional_tests/annotate.out +31 -0
  174. data/test/functional_tests/test_functional.rb +155 -63
  175. data/test/localrepo_tests/ampfile.rb +12 -0
  176. data/test/localrepo_tests/test_local_repo.rb +56 -57
  177. data/test/manifest_tests/test_manifest.rb +3 -5
  178. data/test/merge_tests/test_merge.rb +3 -3
  179. data/test/revlog_tests/test_revlog.rb +14 -6
  180. data/test/store_tests/test_fncache_store.rb +19 -19
  181. data/test/test_19_compatibility.rb +46 -0
  182. data/test/test_base85.rb +2 -2
  183. data/test/test_bdiff.rb +2 -2
  184. data/test/test_changegroup.rb +59 -0
  185. data/test/test_commands.rb +2 -2
  186. data/test/test_difflib.rb +2 -2
  187. data/test/test_generator.rb +34 -0
  188. data/test/test_ignore.rb +203 -0
  189. data/test/test_journal.rb +18 -13
  190. data/test/test_match.rb +2 -2
  191. data/test/test_mdiff.rb +3 -3
  192. data/test/test_mpatch.rb +3 -3
  193. data/test/test_multi_io.rb +40 -0
  194. data/test/test_support.rb +18 -2
  195. data/test/test_templates.rb +38 -0
  196. data/test/test_ui.rb +79 -0
  197. data/test/testutilities.rb +56 -0
  198. metadata +168 -49
  199. data/ext/amp/bz2/mkmf.log +0 -38
  200. data/lib/amp/encoding/mercurial_diff.rb +0 -378
  201. data/lib/amp/encoding/mercurial_patch.rb +0 -1
  202. data/lib/amp/encoding/patch.rb +0 -292
  203. data/lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb +0 -123
  204. data/lib/amp/merges/merge_state.rb +0 -164
  205. data/lib/amp/merges/merge_ui.rb +0 -322
  206. data/lib/amp/merges/simple_merge.rb +0 -450
  207. data/lib/amp/repository/branch_manager.rb +0 -234
  208. data/lib/amp/repository/dir_state.rb +0 -950
  209. data/lib/amp/repository/journal.rb +0 -203
  210. data/lib/amp/repository/lock.rb +0 -207
  211. data/lib/amp/repository/repositories/bundle_repository.rb +0 -214
  212. data/lib/amp/repository/repositories/http_repository.rb +0 -377
  213. data/lib/amp/repository/repositories/local_repository.rb +0 -2661
  214. data/lib/amp/repository/store.rb +0 -485
  215. data/lib/amp/repository/tag_manager.rb +0 -319
  216. data/lib/amp/repository/updatable.rb +0 -532
  217. data/lib/amp/repository/verification.rb +0 -431
  218. data/lib/amp/repository/versioned_file.rb +0 -475
  219. data/lib/amp/revlogs/bundle_revlogs.rb +0 -246
  220. data/lib/amp/revlogs/changegroup.rb +0 -217
  221. data/lib/amp/revlogs/changelog.rb +0 -338
  222. data/lib/amp/revlogs/changeset.rb +0 -521
  223. data/lib/amp/revlogs/file_log.rb +0 -165
  224. data/lib/amp/revlogs/index.rb +0 -493
  225. data/lib/amp/revlogs/manifest.rb +0 -195
  226. data/lib/amp/revlogs/node.rb +0 -18
  227. data/lib/amp/revlogs/revlog.rb +0 -1045
  228. data/lib/amp/revlogs/revlog_support.rb +0 -126
  229. data/lib/amp/support/ignore.rb +0 -144
  230. data/site/Rakefile +0 -38
  231. data/test/test_amp.rb +0 -9
  232. data/test/test_helper.rb +0 -15
@@ -1,6 +1,6 @@
1
1
  module Amp
2
2
  module Graphs
3
-
3
+
4
4
  ##
5
5
  # = AncestorGenerator
6
6
  # A generator class that will allow us to only calculate one ancestor
@@ -143,5 +143,6 @@ module Amp
143
143
  return nil
144
144
  end
145
145
  end
146
+
146
147
  end
147
148
  end
@@ -1,260 +1,263 @@
1
1
  module Amp
2
2
  module Graphs
3
- ##
4
- # = CopyCalculator
5
- #
6
- # This module manages finding what files have been copied between two
7
- # changesets, using a base, ancestor changeset. Closely related to merging.
8
- # We need this class because Mercurial, by default, allows us to copy files
9
- # and move files, and be smart enough to follow these copies throughout the
10
- # version history. Other VCS's just treat the moved file as a brand-new file.
11
- # Thus, when we update from one changeset to another, we need to follow
12
- # these copies.
13
- module CopyCalculator
3
+ module Mercurial
14
4
 
15
5
  ##
16
- # Calculates the copies between 2 changesets, using a pre-calculated common ancestor
17
- # node. This is used during updates as part of Mercurial's ability to track renames
18
- # without git-style guessing. Unfortunately it does require some amount of calculation.
19
- # This method returns two hashes in an array: [renames, divergent]. "Renames" are
20
- # moves from one file to another, and "divergent" are two moves of the same file,
21
- # only with different end-names. See @example for how divergent works.
6
+ # = CopyCalculator
22
7
  #
23
- # @todo Add tracking of directory renames!
24
- #
25
- # @example
26
- # if the local changeset renamed "foo" to "bar", and the remote changeset renamed
27
- # "foo" to "baz", then the "divergent" hash would be:
28
- # {"foo" => ["bar", "baz"]}
29
- #
30
- # @param [Repository] repo The repo for which we are calculating changes. Typically
31
- # a LocalRepository.
32
- # @param [Changeset] changeset_local The local (or just 1 of the bases) changeset.
33
- # @param [Changeset] changeset_remote The remote (or the second base) changeset
34
- # @param [Changeset] changeset_ancestor The common ancestor between {changeset_local}
35
- # and {changeset_remote}
36
- # @param [Boolean] check_dirs (false) Whether or not to analyze for directory renames.
37
- # this is an expensive operation, so it defaults to false.
38
- # @return [[Hash, Hash]] This method returns two hashes in an array, where the first
39
- # is a list of normal file-moves ("foo" renamed to "bar" returns {"foo" => "bar"})
40
- # and the second is a list of divergent file-moves (see @example)
41
- #
42
- def self.find_copies(repo, changeset_local, changeset_remote, changeset_ancestor, check_dirs=false)
43
- # are we udpating from an empty directory? quite easy.
44
- if changeset_local.nil? || changeset_remote.nil? ||
45
- changeset_remote == changeset_local
46
- return {}, {}
47
- end
48
- # avoid silly behavior for parent -> working directory
49
- if changeset_remote.node == nil && c1.node == repo.dirstate.parents.first
50
- return repo.dirstate.copies, {}
51
- end
52
-
53
- limit = find_limit(repo, changeset_local.revision, changeset_remote.revision)
54
- man_local = changeset_local.manifest
55
- man_remote = changeset_remote.manifest
56
- man_ancestor = changeset_ancestor.manifest
8
+ # This module manages finding what files have been copied between two
9
+ # changesets, using a base, ancestor changeset. Closely related to merging.
10
+ # We need this class because Mercurial, by default, allows us to copy files
11
+ # and move files, and be smart enough to follow these copies throughout the
12
+ # version history. Other VCS's just treat the moved file as a brand-new file.
13
+ # Thus, when we update from one changeset to another, we need to follow
14
+ # these copies.
15
+ module CopyCalculator
57
16
 
58
- # gets the versioned_file for a given file and node ID
59
- easy_file_lookup = proc do |file, node|
60
- if node.size == 20
61
- return repo.versioned_file(file, :file_id => node)
17
+ ##
18
+ # Calculates the copies between 2 changesets, using a pre-calculated common ancestor
19
+ # node. This is used during updates as part of Mercurial's ability to track renames
20
+ # without git-style guessing. Unfortunately it does require some amount of calculation.
21
+ # This method returns two hashes in an array: [renames, divergent]. "Renames" are
22
+ # moves from one file to another, and "divergent" are two moves of the same file,
23
+ # only with different end-names. See @example for how divergent works.
24
+ #
25
+ # @todo Add tracking of directory renames!
26
+ #
27
+ # @example
28
+ # if the local changeset renamed "foo" to "bar", and the remote changeset renamed
29
+ # "foo" to "baz", then the "divergent" hash would be:
30
+ # {"foo" => ["bar", "baz"]}
31
+ #
32
+ # @param [Repository] repo The repo for which we are calculating changes. Typically
33
+ # a LocalRepository.
34
+ # @param [Changeset] changeset_local The local (or just 1 of the bases) changeset.
35
+ # @param [Changeset] changeset_remote The remote (or the second base) changeset
36
+ # @param [Changeset] changeset_ancestor The common ancestor between {changeset_local}
37
+ # and {changeset_remote}
38
+ # @param [Boolean] check_dirs (false) Whether or not to analyze for directory renames.
39
+ # this is an expensive operation, so it defaults to false.
40
+ # @return [[Hash, Hash]] This method returns two hashes in an array, where the first
41
+ # is a list of normal file-moves ("foo" renamed to "bar" returns {"foo" => "bar"})
42
+ # and the second is a list of divergent file-moves (see @example)
43
+ #
44
+ def self.find_copies(repo, changeset_local, changeset_remote, changeset_ancestor, check_dirs=false)
45
+ # are we udpating from an empty directory? quite easy.
46
+ if changeset_local.nil? || changeset_remote.nil? ||
47
+ changeset_remote == changeset_local
48
+ return {}, {}
62
49
  end
63
- cs = (changeset_local.revision == nil) ? changeset_local : changeset_remote
64
- return cs.get_file(file)
65
- end
66
-
67
- ctx = easy_file_lookup
68
- copy = {}
69
- full_copy = {}
70
- diverge = {}
71
-
72
- # check for copies from manifest1 to manifest2
73
- check_copies = proc do |file, man1, man2|
74
- vf1 = easy_file_lookup[file, man1[file]]
75
- find_old_names(vf1, limit) do |old_name|
76
- full_copy[file] = old_name # remember for dir rename detection
77
- if man2[old_name] # original file in other manifest?
78
- # if the original file is unchanged on the other branch,
79
- # no merge needed
80
- if man2[old_name] != man_ancestor[old_name]
81
- vf2 = easy_file_lookup[old_file, man2[old_file]]
82
- vfa = vf1.ancestor(vf2)
83
- # related and name changed on only one side?
84
- if vfa && (vfa.path == file || vfa.path == vf2.path) && (vf1 == vfa || vf2 == vfa)
85
- copy[file] = old_file
50
+ # avoid silly behavior for parent -> working directory
51
+ if changeset_remote.node == nil && c1.node == repo.dirstate.parents.first
52
+ return repo.dirstate.copies, {}
53
+ end
54
+
55
+ limit = find_limit(repo, changeset_local.revision, changeset_remote.revision)
56
+ man_local = changeset_local.manifest_entry
57
+ man_remote = changeset_remote.manifest_entry
58
+ man_ancestor = changeset_ancestor.manifest_entry
59
+
60
+ # gets the versioned_file for a given file and node ID
61
+ easy_file_lookup = proc do |file, node|
62
+ if node.size == 20
63
+ return repo.versioned_file(file, :file_id => node)
64
+ end
65
+ cs = (changeset_local.revision == nil) ? changeset_local : changeset_remote
66
+ return cs.get_file(file)
67
+ end
68
+
69
+ ctx = easy_file_lookup
70
+ copy = {}
71
+ full_copy = {}
72
+ diverge = {}
73
+
74
+ # check for copies from manifest1 to manifest2
75
+ check_copies = proc do |file, man1, man2|
76
+ vf1 = easy_file_lookup[file, man1[file]]
77
+ find_old_names(vf1, limit) do |old_name|
78
+ full_copy[file] = old_name # remember for dir rename detection
79
+ if man2[old_name] # original file in other manifest?
80
+ # if the original file is unchanged on the other branch,
81
+ # no merge needed
82
+ if man2[old_name] != man_ancestor[old_name]
83
+ vf2 = easy_file_lookup[old_file, man2[old_file]]
84
+ vfa = vf1.ancestor(vf2)
85
+ # related and name changed on only one side?
86
+ if vfa && (vfa.path == file || vfa.path == vf2.path) && (vf1 == vfa || vf2 == vfa)
87
+ copy[file] = old_file
88
+ end
86
89
  end
90
+ elsif man_ancestor[old_file]
91
+ (diverge[old_file] ||= []) << file
87
92
  end
88
- elsif man_ancestor[old_file]
89
- (diverge[old_file] ||= []) << file
90
93
  end
91
94
  end
92
- end
93
-
94
- UI.debug(" searching for copies back to rev #{limit}")
95
-
96
- unmatched_1 = double_intersection(man_local, man_remote, man_ancestor)
97
- unmatched_2 = double_intersection(man_remote, man_local, man_ancestor)
98
-
99
- UI.debug(" unmatched files in local:\n #{unmatched_1.join("\n")}") if unmatched_1.any?
100
- UI.debug(" unmatched files in other:\n #{unmatched_2.join("\n")}") if unmatched_2.any?
101
-
102
- unmatched_1.each {|file| check_copies[file, man_local, man_remote] }
103
- unmatched_2.each {|file| check_copies[file, man_remote, man_local] }
104
-
105
- diverge_2 = {}
106
- diverge.each do |old_file, file_list|
107
- if file_list.size == 1
108
- diverge.delete old_file
109
- else
110
- file_list.each {|file| diverge_2[file] = true}
95
+
96
+ UI.debug(" searching for copies back to rev #{limit}")
97
+
98
+ unmatched_1 = double_intersection(man_local, man_remote, man_ancestor)
99
+ unmatched_2 = double_intersection(man_remote, man_local, man_ancestor)
100
+
101
+ UI.debug(" unmatched files in local:\n #{unmatched_1.join("\n")}") if unmatched_1.any?
102
+ UI.debug(" unmatched files in other:\n #{unmatched_2.join("\n")}") if unmatched_2.any?
103
+
104
+ unmatched_1.each {|file| check_copies[file, man_local, man_remote] }
105
+ unmatched_2.each {|file| check_copies[file, man_remote, man_local] }
106
+
107
+ diverge_2 = {}
108
+ diverge.each do |old_file, file_list|
109
+ if file_list.size == 1
110
+ diverge.delete old_file
111
+ else
112
+ file_list.each {|file| diverge_2[file] = true}
113
+ end
111
114
  end
115
+
116
+ if !(full_copy.any?) || !check_dirs
117
+ return copy, diverge
118
+ end
119
+
120
+ # CHECK FOR DIRECTORY RENAMES
121
+ # TODO TODO TODO
112
122
  end
113
123
 
114
- if !(full_copy.any?) || !check_dirs
115
- return copy, diverge
116
- end
117
-
118
- # CHECK FOR DIRECTORY RENAMES
119
- # TODO TODO TODO
120
- end
121
-
122
- private
123
-
124
- ##
125
- # Find the earliest revision in the repository that is an ancestor of EITHER a OR b,
126
- # but NOT both. In other words, find the oldest ancestor on a branch.
127
- #
128
- # @param [Repository] repo the repository we're calculatizing on
129
- # @param [Integer] a one changeset's revision #
130
- # @param [Integer] b the other changeset's revision #
131
- # @return [Integer] the earliest revision index that is an ancestor of only 1 of the
132
- # two changesets.
133
- def self.find_limit(repo, a, b)
134
- # basic idea:
135
- # - mark a and b with different sides
136
- # - if a parent's children are all on the same side, the parent is
137
- # on that side, otherwise it is on no side
138
- # - walk the graph in topological order with the help of a heap;
139
- # - add unseen parents to side map
140
- # - clear side of any parent that has children on different sides
141
- # - track number of interesting revs that might still be on a side
142
- # - track the lowest interesting rev seen
143
- # - quit when interesting revs is zero
144
- changelog = repo.changelog
145
- working = changelog.size # this revision index is 1 higher than the real highest
146
- a ||= working
147
- b ||= working
124
+ private
148
125
 
149
- side = {a => -1, b => 1}
150
- visit = PriorityQueue.new # because i don't have any other data structure that
151
- visit[-a] = -a # maintains a sorted order
152
- visit[-b] = -b
153
- interesting = visit.size # could be 1 if a == b
154
- limit = working
155
- while interesting > 0
156
- r, junk = -(visit.delete_min) # get the next lowest revision
157
- if r == working
158
- # different way of getting parents in this case
159
- parents = repo.dirstate.parents.map {|p| changelog.rev(p)}
160
- else
161
- # normal way of getting parents
162
- parents = changelog.parent_indices_for_index(r)
163
- end
164
- parents.each do |parent|
165
- if !side[parent]
166
- # haven't seen the parent before, so let's put it on a side.
167
- side[parent] = side[r]
168
- interesting += 1 if side[parent] != 0 # if it's on a side
169
- visit[-parent] = -parent
170
- elsif side[parent] && side[parent] != side[r]
171
- # if we're here, then the parent has been seen by BOTH sides. so it's no good.
172
- side[parent] = 0
126
+ ##
127
+ # Find the earliest revision in the repository that is an ancestor of EITHER a OR b,
128
+ # but NOT both. In other words, find the oldest ancestor on a branch.
129
+ #
130
+ # @param [Repository] repo the repository we're calculatizing on
131
+ # @param [Integer] a one changeset's revision #
132
+ # @param [Integer] b the other changeset's revision #
133
+ # @return [Integer] the earliest revision index that is an ancestor of only 1 of the
134
+ # two changesets.
135
+ def self.find_limit(repo, a, b)
136
+ # basic idea:
137
+ # - mark a and b with different sides
138
+ # - if a parent's children are all on the same side, the parent is
139
+ # on that side, otherwise it is on no side
140
+ # - walk the graph in topological order with the help of a heap;
141
+ # - add unseen parents to side map
142
+ # - clear side of any parent that has children on different sides
143
+ # - track number of interesting revs that might still be on a side
144
+ # - track the lowest interesting rev seen
145
+ # - quit when interesting revs is zero
146
+ changelog = repo.changelog
147
+ working = changelog.size # this revision index is 1 higher than the real highest
148
+ a ||= working
149
+ b ||= working
150
+
151
+ side = {a => -1, b => 1}
152
+ visit = PriorityQueue.new # because i don't have any other data structure that
153
+ visit[-a] = -a # maintains a sorted order
154
+ visit[-b] = -b
155
+ interesting = visit.size # could be 1 if a == b
156
+ limit = working
157
+ while interesting > 0
158
+ r, junk = -(visit.delete_min) # get the next lowest revision
159
+ if r == working
160
+ # different way of getting parents in this case
161
+ parents = repo.dirstate.parents.map {|p| changelog.rev(p)}
162
+ else
163
+ # normal way of getting parents
164
+ parents = changelog.parent_indices_for_index(r)
165
+ end
166
+ parents.each do |parent|
167
+ if !side[parent]
168
+ # haven't seen the parent before, so let's put it on a side.
169
+ side[parent] = side[r]
170
+ interesting += 1 if side[parent] != 0 # if it's on a side
171
+ visit[-parent] = -parent
172
+ elsif side[parent] && side[parent] != side[r]
173
+ # if we're here, then the parent has been seen by BOTH sides. so it's no good.
174
+ side[parent] = 0
175
+ interesting -= 1
176
+ end
177
+ end
178
+ # if we're here and side[r] isn't 0, then it's an ancestor to [one and only one]
179
+ # of the 2 root nodes. so keep it.
180
+ if side[r] && side[r] != 0
181
+ limit = r
173
182
  interesting -= 1
174
183
  end
175
184
  end
176
- # if we're here and side[r] isn't 0, then it's an ancestor to [one and only one]
177
- # of the 2 root nodes. so keep it.
178
- if side[r] && side[r] != 0
179
- limit = r
180
- interesting -= 1
181
- end
185
+ limit
182
186
  end
183
- limit
184
- end
185
-
186
- ##
187
- # Go back in time until revision {limit}, grabbing old names that {versioned_file}
188
- # was moved from.
189
- #
190
- # @param [VersionedFile] versioned_file the file for which we are finding old names
191
- # @param [Integer] limit the minimum revision back in time in which we should
192
- # search for old names
193
- # @return [Array<String>] old names for the current file.
194
- def self.find_old_names(versioned_file, limit)
195
- # wooooo recursion unrolling!
196
- old = {}
197
- seen = {}
198
- orig = versioned_file.path
199
- visit = [[versioned_file, 0]]
200
- while visit.any? do
201
- file, depth = visit.shift
202
- str = file.to_s
203
- next if seen[str]
204
-
205
- seen[str] = true
206
- if file.path != orig && !old[file.path]
207
- old[file.path] = [depth, file.path]
187
+
188
+ ##
189
+ # Go back in time until revision {limit}, grabbing old names that {versioned_file}
190
+ # was moved from.
191
+ #
192
+ # @param [VersionedFile] versioned_file the file for which we are finding old names
193
+ # @param [Integer] limit the minimum revision back in time in which we should
194
+ # search for old names
195
+ # @return [Array<String>] old names for the current file.
196
+ def self.find_old_names(versioned_file, limit)
197
+ # wooooo recursion unrolling!
198
+ old = {}
199
+ seen = {}
200
+ orig = versioned_file.path
201
+ visit = [[versioned_file, 0]]
202
+ while visit.any? do
203
+ file, depth = visit.shift
204
+ str = file.to_s
205
+ next if seen[str]
206
+
207
+ seen[str] = true
208
+ if file.path != orig && !old[file.path]
209
+ old[file.path] = [depth, file.path]
210
+ end
211
+ next if file.revision < limit && file.revision != nil
212
+ visit += file.parents.each {|p| [p, depth - 1]}
208
213
  end
209
- next if file.revision < limit && file.revision != nil
210
- visit += file.parents.each {|p| [p, depth - 1]}
214
+ old.values.sort.map {|o| o[1]}
211
215
  end
212
- old.values.sort.map {|o| o[1]}
213
- end
214
-
215
- ##
216
- # Returns all the parent directories of every file in the provided array,
217
- # recursively, as a map. Each entry maps a directory to {true}. It's really
218
- # just a set, but I'm too lazy to use a set. Sorry.
219
- #
220
- # @param [Array<String>] files a list of files for which we need all the parent
221
- # directories
222
- # @return [Hash] a map: each entry maps a directory name to {true}, because it's
223
- # really just a set, because I'm too lazy to use a set.
224
- def self.all_parent_dirs(files)
225
- dirs = {}
226
- files.each do |file|
227
- file = picky_dirname file
228
- until dirs[file]
229
- dirs[file] = true
216
+
217
+ ##
218
+ # Returns all the parent directories of every file in the provided array,
219
+ # recursively, as a map. Each entry maps a directory to {true}. It's really
220
+ # just a set, but I'm too lazy to use a set. Sorry.
221
+ #
222
+ # @param [Array<String>] files a list of files for which we need all the parent
223
+ # directories
224
+ # @return [Hash] a map: each entry maps a directory name to {true}, because it's
225
+ # really just a set, because I'm too lazy to use a set.
226
+ def self.all_parent_dirs(files)
227
+ dirs = {}
228
+ files.each do |file|
230
229
  file = picky_dirname file
230
+ until dirs[file]
231
+ dirs[file] = true
232
+ file = picky_dirname file
233
+ end
231
234
  end
235
+ dirs
236
+ end
237
+
238
+ ##
239
+ # This method will find the path of the containing directory for the file
240
+ # pointed to by {path}. We use this instead of File.dirname because we
241
+ # want to return the empty string instead of "." if there is no path separator
242
+ # in the provided string.
243
+ #
244
+ # @param [String] path the path to the file we want the directory name of
245
+ # @return [String] the path of the containing directory of the provided file
246
+ def self.picky_dirname(path)
247
+ Dir.dirname path
248
+ end
249
+
250
+ ##
251
+ # Returns a list of elements in d1 that are not in d2 or d3. We have this method
252
+ # because Mercurial's source has this method.
253
+ #
254
+ # @param [Array] d1 a list of items we wish to filter
255
+ # @param [Array] d2 a list of items we do NOT want in d1
256
+ # @param [Array] d3 a list of items we do NOT want in d1
257
+ # @return [Array] a list of items in d1 that are not present in d2 or d3
258
+ def self.double_intersection(d1, d2, d3)
259
+ d1.reject {|i| d2.include?(i) || d3.include?(i) }
232
260
  end
233
- dirs
234
- end
235
-
236
- ##
237
- # This method will find the path of the containing directory for the file
238
- # pointed to by {path}. We use this instead of File.dirname because we
239
- # want to return the empty string instead of "." if there is no path separator
240
- # in the provided string.
241
- #
242
- # @param [String] path the path to the file we want the directory name of
243
- # @return [String] the path of the containing directory of the provided file
244
- def self.picky_dirname(path)
245
- Dir.dirname path
246
- end
247
-
248
- ##
249
- # Returns a list of elements in d1 that are not in d2 or d3. We have this method
250
- # because Mercurial's source has this method.
251
- #
252
- # @param [Array] d1 a list of items we wish to filter
253
- # @param [Array] d2 a list of items we do NOT want in d1
254
- # @param [Array] d3 a list of items we do NOT want in d1
255
- # @return [Array] a list of items in d1 that are not present in d2 or d3
256
- def self.double_intersection(d1, d2, d3)
257
- d1.reject {|i| d2.include?(i) || d3.include?(i) }
258
261
  end
259
262
  end
260
263
  end