amp 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.hgignore +26 -0
- data/AUTHORS +2 -0
- data/History.txt +6 -0
- data/LICENSE +37 -0
- data/MANIFESTO +7 -0
- data/Manifest.txt +294 -0
- data/README.md +129 -0
- data/Rakefile +102 -0
- data/SCHEDULE.markdown +12 -0
- data/STYLE +27 -0
- data/TODO.markdown +149 -0
- data/ampfile.rb +47 -0
- data/bin/amp +30 -0
- data/bin/amp1.9 +30 -0
- data/ext/amp/bz2/README.txt +39 -0
- data/ext/amp/bz2/bz2.c +1582 -0
- data/ext/amp/bz2/extconf.rb +77 -0
- data/ext/amp/bz2/mkmf.log +29 -0
- data/ext/amp/mercurial_patch/extconf.rb +5 -0
- data/ext/amp/mercurial_patch/mpatch.c +405 -0
- data/ext/amp/priority_queue/extconf.rb +5 -0
- data/ext/amp/priority_queue/priority_queue.c +947 -0
- data/ext/amp/support/extconf.rb +5 -0
- data/ext/amp/support/support.c +250 -0
- data/lib/amp.rb +200 -0
- data/lib/amp/commands/command.rb +507 -0
- data/lib/amp/commands/command_support.rb +137 -0
- data/lib/amp/commands/commands/config.rb +143 -0
- data/lib/amp/commands/commands/help.rb +29 -0
- data/lib/amp/commands/commands/init.rb +10 -0
- data/lib/amp/commands/commands/templates.rb +137 -0
- data/lib/amp/commands/commands/version.rb +7 -0
- data/lib/amp/commands/commands/workflow.rb +28 -0
- data/lib/amp/commands/commands/workflows/git/add.rb +65 -0
- data/lib/amp/commands/commands/workflows/git/copy.rb +27 -0
- data/lib/amp/commands/commands/workflows/git/mv.rb +23 -0
- data/lib/amp/commands/commands/workflows/git/rm.rb +60 -0
- data/lib/amp/commands/commands/workflows/hg/add.rb +53 -0
- data/lib/amp/commands/commands/workflows/hg/addremove.rb +86 -0
- data/lib/amp/commands/commands/workflows/hg/annotate.rb +46 -0
- data/lib/amp/commands/commands/workflows/hg/archive.rb +126 -0
- data/lib/amp/commands/commands/workflows/hg/branch.rb +28 -0
- data/lib/amp/commands/commands/workflows/hg/branches.rb +30 -0
- data/lib/amp/commands/commands/workflows/hg/bundle.rb +115 -0
- data/lib/amp/commands/commands/workflows/hg/clone.rb +95 -0
- data/lib/amp/commands/commands/workflows/hg/commit.rb +42 -0
- data/lib/amp/commands/commands/workflows/hg/copy.rb +31 -0
- data/lib/amp/commands/commands/workflows/hg/debug/dirstate.rb +32 -0
- data/lib/amp/commands/commands/workflows/hg/debug/index.rb +36 -0
- data/lib/amp/commands/commands/workflows/hg/default.rb +9 -0
- data/lib/amp/commands/commands/workflows/hg/diff.rb +30 -0
- data/lib/amp/commands/commands/workflows/hg/forget.rb +11 -0
- data/lib/amp/commands/commands/workflows/hg/heads.rb +25 -0
- data/lib/amp/commands/commands/workflows/hg/identify.rb +23 -0
- data/lib/amp/commands/commands/workflows/hg/import.rb +135 -0
- data/lib/amp/commands/commands/workflows/hg/incoming.rb +85 -0
- data/lib/amp/commands/commands/workflows/hg/info.rb +18 -0
- data/lib/amp/commands/commands/workflows/hg/log.rb +21 -0
- data/lib/amp/commands/commands/workflows/hg/manifest.rb +13 -0
- data/lib/amp/commands/commands/workflows/hg/merge.rb +53 -0
- data/lib/amp/commands/commands/workflows/hg/move.rb +28 -0
- data/lib/amp/commands/commands/workflows/hg/outgoing.rb +61 -0
- data/lib/amp/commands/commands/workflows/hg/pull.rb +74 -0
- data/lib/amp/commands/commands/workflows/hg/push.rb +20 -0
- data/lib/amp/commands/commands/workflows/hg/remove.rb +45 -0
- data/lib/amp/commands/commands/workflows/hg/resolve.rb +83 -0
- data/lib/amp/commands/commands/workflows/hg/revert.rb +53 -0
- data/lib/amp/commands/commands/workflows/hg/root.rb +13 -0
- data/lib/amp/commands/commands/workflows/hg/serve.rb +38 -0
- data/lib/amp/commands/commands/workflows/hg/status.rb +116 -0
- data/lib/amp/commands/commands/workflows/hg/tag.rb +69 -0
- data/lib/amp/commands/commands/workflows/hg/tags.rb +27 -0
- data/lib/amp/commands/commands/workflows/hg/tip.rb +13 -0
- data/lib/amp/commands/commands/workflows/hg/update.rb +27 -0
- data/lib/amp/commands/commands/workflows/hg/verify.rb +9 -0
- data/lib/amp/commands/commands/workflows/hg/view.rb +36 -0
- data/lib/amp/commands/dispatch.rb +181 -0
- data/lib/amp/commands/hooks.rb +81 -0
- data/lib/amp/dependencies/amp_support.rb +1 -0
- data/lib/amp/dependencies/amp_support/ruby_amp_support.rb +103 -0
- data/lib/amp/dependencies/minitar.rb +979 -0
- data/lib/amp/dependencies/priority_queue.rb +18 -0
- data/lib/amp/dependencies/priority_queue/c_priority_queue.rb +1 -0
- data/lib/amp/dependencies/priority_queue/poor_priority_queue.rb +46 -0
- data/lib/amp/dependencies/priority_queue/ruby_priority_queue.rb +525 -0
- data/lib/amp/dependencies/python_config.rb +211 -0
- data/lib/amp/dependencies/trollop.rb +713 -0
- data/lib/amp/dependencies/zip/ioextras.rb +155 -0
- data/lib/amp/dependencies/zip/stdrubyext.rb +111 -0
- data/lib/amp/dependencies/zip/tempfile_bugfixed.rb +186 -0
- data/lib/amp/dependencies/zip/zip.rb +1850 -0
- data/lib/amp/dependencies/zip/zipfilesystem.rb +609 -0
- data/lib/amp/dependencies/zip/ziprequire.rb +90 -0
- data/lib/amp/encoding/base85.rb +97 -0
- data/lib/amp/encoding/binary_diff.rb +82 -0
- data/lib/amp/encoding/difflib.rb +166 -0
- data/lib/amp/encoding/mercurial_diff.rb +378 -0
- data/lib/amp/encoding/mercurial_patch.rb +1 -0
- data/lib/amp/encoding/patch.rb +292 -0
- data/lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb +123 -0
- data/lib/amp/extensions/ditz.rb +41 -0
- data/lib/amp/extensions/lighthouse.rb +167 -0
- data/lib/amp/graphs/ancestor.rb +147 -0
- data/lib/amp/graphs/copies.rb +261 -0
- data/lib/amp/merges/merge_state.rb +164 -0
- data/lib/amp/merges/merge_ui.rb +322 -0
- data/lib/amp/merges/simple_merge.rb +450 -0
- data/lib/amp/profiling_hacks.rb +36 -0
- data/lib/amp/repository/branch_manager.rb +234 -0
- data/lib/amp/repository/dir_state.rb +950 -0
- data/lib/amp/repository/journal.rb +203 -0
- data/lib/amp/repository/lock.rb +207 -0
- data/lib/amp/repository/repositories/bundle_repository.rb +214 -0
- data/lib/amp/repository/repositories/http_repository.rb +377 -0
- data/lib/amp/repository/repositories/local_repository.rb +2661 -0
- data/lib/amp/repository/repository.rb +94 -0
- data/lib/amp/repository/store.rb +485 -0
- data/lib/amp/repository/tag_manager.rb +319 -0
- data/lib/amp/repository/updatable.rb +532 -0
- data/lib/amp/repository/verification.rb +431 -0
- data/lib/amp/repository/versioned_file.rb +475 -0
- data/lib/amp/revlogs/bundle_revlogs.rb +246 -0
- data/lib/amp/revlogs/changegroup.rb +217 -0
- data/lib/amp/revlogs/changelog.rb +338 -0
- data/lib/amp/revlogs/changeset.rb +521 -0
- data/lib/amp/revlogs/file_log.rb +165 -0
- data/lib/amp/revlogs/index.rb +493 -0
- data/lib/amp/revlogs/manifest.rb +195 -0
- data/lib/amp/revlogs/node.rb +18 -0
- data/lib/amp/revlogs/revlog.rb +1032 -0
- data/lib/amp/revlogs/revlog_support.rb +126 -0
- data/lib/amp/server/amp_user.rb +44 -0
- data/lib/amp/server/extension/amp_extension.rb +396 -0
- data/lib/amp/server/extension/authorization.rb +201 -0
- data/lib/amp/server/fancy_http_server.rb +252 -0
- data/lib/amp/server/fancy_views/_browser.haml +28 -0
- data/lib/amp/server/fancy_views/_diff_file.haml +13 -0
- data/lib/amp/server/fancy_views/_navbar.haml +17 -0
- data/lib/amp/server/fancy_views/changeset.haml +31 -0
- data/lib/amp/server/fancy_views/commits.haml +32 -0
- data/lib/amp/server/fancy_views/file.haml +35 -0
- data/lib/amp/server/fancy_views/file_diff.haml +23 -0
- data/lib/amp/server/fancy_views/harshcss/all_hallows_eve.css +72 -0
- data/lib/amp/server/fancy_views/harshcss/amy.css +147 -0
- data/lib/amp/server/fancy_views/harshcss/twilight.css +138 -0
- data/lib/amp/server/fancy_views/stylesheet.sass +175 -0
- data/lib/amp/server/http_server.rb +140 -0
- data/lib/amp/server/repo_user_management.rb +287 -0
- data/lib/amp/support/amp_config.rb +164 -0
- data/lib/amp/support/amp_ui.rb +287 -0
- data/lib/amp/support/docs.rb +54 -0
- data/lib/amp/support/generator.rb +78 -0
- data/lib/amp/support/ignore.rb +144 -0
- data/lib/amp/support/loaders.rb +93 -0
- data/lib/amp/support/logger.rb +103 -0
- data/lib/amp/support/match.rb +151 -0
- data/lib/amp/support/multi_io.rb +87 -0
- data/lib/amp/support/openers.rb +121 -0
- data/lib/amp/support/ruby_19_compatibility.rb +66 -0
- data/lib/amp/support/support.rb +1095 -0
- data/lib/amp/templates/blank.commit.erb +23 -0
- data/lib/amp/templates/blank.log.erb +18 -0
- data/lib/amp/templates/default.commit.erb +23 -0
- data/lib/amp/templates/default.log.erb +26 -0
- data/lib/amp/templates/template.rb +165 -0
- data/site/Rakefile +24 -0
- data/site/src/about/ampfile.haml +57 -0
- data/site/src/about/commands.haml +106 -0
- data/site/src/about/index.haml +33 -0
- data/site/src/about/performance.haml +31 -0
- data/site/src/about/workflows.haml +34 -0
- data/site/src/contribute/index.haml +65 -0
- data/site/src/contribute/style.haml +297 -0
- data/site/src/css/active4d.css +114 -0
- data/site/src/css/all_hallows_eve.css +72 -0
- data/site/src/css/all_themes.css +3299 -0
- data/site/src/css/amp.css +260 -0
- data/site/src/css/amy.css +147 -0
- data/site/src/css/blackboard.css +88 -0
- data/site/src/css/brilliance_black.css +605 -0
- data/site/src/css/brilliance_dull.css +599 -0
- data/site/src/css/cobalt.css +149 -0
- data/site/src/css/cur_amp.css +185 -0
- data/site/src/css/dawn.css +121 -0
- data/site/src/css/eiffel.css +121 -0
- data/site/src/css/espresso_libre.css +109 -0
- data/site/src/css/idle.css +62 -0
- data/site/src/css/iplastic.css +80 -0
- data/site/src/css/lazy.css +73 -0
- data/site/src/css/mac_classic.css +123 -0
- data/site/src/css/magicwb_amiga.css +104 -0
- data/site/src/css/pastels_on_dark.css +188 -0
- data/site/src/css/reset.css +55 -0
- data/site/src/css/slush_poppies.css +85 -0
- data/site/src/css/spacecadet.css +51 -0
- data/site/src/css/sunburst.css +180 -0
- data/site/src/css/twilight.css +137 -0
- data/site/src/css/zenburnesque.css +91 -0
- data/site/src/get/index.haml +32 -0
- data/site/src/helpers.rb +121 -0
- data/site/src/images/amp_logo.png +0 -0
- data/site/src/images/carbonica.png +0 -0
- data/site/src/images/revolution.png +0 -0
- data/site/src/images/tab-bg.png +0 -0
- data/site/src/images/tab-sliding-left.png +0 -0
- data/site/src/images/tab-sliding-right.png +0 -0
- data/site/src/include/_footer.haml +22 -0
- data/site/src/include/_header.haml +17 -0
- data/site/src/index.haml +104 -0
- data/site/src/learn/index.haml +46 -0
- data/site/src/scripts/jquery-1.3.2.min.js +19 -0
- data/site/src/scripts/jquery.cookie.js +96 -0
- data/tasks/stats.rake +155 -0
- data/tasks/yard.rake +171 -0
- data/test/dirstate_tests/dirstate +0 -0
- data/test/dirstate_tests/hgrc +5 -0
- data/test/dirstate_tests/test_dir_state.rb +192 -0
- data/test/functional_tests/resources/.hgignore +2 -0
- data/test/functional_tests/resources/STYLE.txt +25 -0
- data/test/functional_tests/resources/command.rb +372 -0
- data/test/functional_tests/resources/commands/annotate.rb +57 -0
- data/test/functional_tests/resources/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/commands/heads.rb +22 -0
- data/test/functional_tests/resources/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/commands/status.rb +90 -0
- data/test/functional_tests/resources/version2/.hgignore +5 -0
- data/test/functional_tests/resources/version2/STYLE.txt +25 -0
- data/test/functional_tests/resources/version2/command.rb +372 -0
- data/test/functional_tests/resources/version2/commands/annotate.rb +45 -0
- data/test/functional_tests/resources/version2/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version2/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version2/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version2/commands/status.rb +90 -0
- data/test/functional_tests/resources/version3/.hgignore +5 -0
- data/test/functional_tests/resources/version3/STYLE.txt +31 -0
- data/test/functional_tests/resources/version3/command.rb +376 -0
- data/test/functional_tests/resources/version3/commands/annotate.rb +45 -0
- data/test/functional_tests/resources/version3/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version3/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version3/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version3/commands/status.rb +90 -0
- data/test/functional_tests/resources/version4/.hgignore +5 -0
- data/test/functional_tests/resources/version4/STYLE.txt +31 -0
- data/test/functional_tests/resources/version4/command.rb +376 -0
- data/test/functional_tests/resources/version4/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version4/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version4/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version4/commands/stats.rb +25 -0
- data/test/functional_tests/resources/version4/commands/status.rb +90 -0
- data/test/functional_tests/resources/version5_1/.hgignore +5 -0
- data/test/functional_tests/resources/version5_1/STYLE.txt +2 -0
- data/test/functional_tests/resources/version5_1/command.rb +374 -0
- data/test/functional_tests/resources/version5_1/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version5_1/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version5_1/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version5_1/commands/stats.rb +25 -0
- data/test/functional_tests/resources/version5_1/commands/status.rb +90 -0
- data/test/functional_tests/resources/version5_2/.hgignore +5 -0
- data/test/functional_tests/resources/version5_2/STYLE.txt +14 -0
- data/test/functional_tests/resources/version5_2/command.rb +376 -0
- data/test/functional_tests/resources/version5_2/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version5_2/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version5_2/commands/newz.rb +12 -0
- data/test/functional_tests/resources/version5_2/commands/stats.rb +25 -0
- data/test/functional_tests/resources/version5_2/commands/status.rb +90 -0
- data/test/functional_tests/test_functional.rb +604 -0
- data/test/localrepo_tests/test_local_repo.rb +121 -0
- data/test/localrepo_tests/testrepo.tar.gz +0 -0
- data/test/manifest_tests/00manifest.i +0 -0
- data/test/manifest_tests/test_manifest.rb +72 -0
- data/test/merge_tests/base.txt +10 -0
- data/test/merge_tests/expected.local.txt +16 -0
- data/test/merge_tests/local.txt +11 -0
- data/test/merge_tests/remote.txt +11 -0
- data/test/merge_tests/test_merge.rb +26 -0
- data/test/revlog_tests/00changelog.i +0 -0
- data/test/revlog_tests/revision_added_changelog.i +0 -0
- data/test/revlog_tests/test_adding_index.i +0 -0
- data/test/revlog_tests/test_revlog.rb +333 -0
- data/test/revlog_tests/testindex.i +0 -0
- data/test/store_tests/store.tar.gz +0 -0
- data/test/store_tests/test_fncache_store.rb +122 -0
- data/test/test_amp.rb +9 -0
- data/test/test_base85.rb +14 -0
- data/test/test_bdiff.rb +42 -0
- data/test/test_commands.rb +122 -0
- data/test/test_difflib.rb +50 -0
- data/test/test_helper.rb +15 -0
- data/test/test_journal.rb +29 -0
- data/test/test_match.rb +134 -0
- data/test/test_mdiff.rb +74 -0
- data/test/test_mpatch.rb +14 -0
- data/test/test_support.rb +24 -0
- metadata +385 -0
@@ -0,0 +1,450 @@
|
|
1
|
+
module Amp
|
2
|
+
module Merges
|
3
|
+
|
4
|
+
class MergeAssertion < StandardError; end
|
5
|
+
##
|
6
|
+
# SimpleMerge - basic 3-way merging
|
7
|
+
#
|
8
|
+
# This class takes 2 texts and a common ancestor text, and tries
|
9
|
+
# to produce a text incorporating all the changes from ancestor->local
|
10
|
+
# and ancestor->remote. It will produce the annoying >>>>>> ====== <<<<<
|
11
|
+
# markers just like mercurial/cvs does.
|
12
|
+
#
|
13
|
+
# For the record, for any methods that don't have comments in the code, I
|
14
|
+
# have an excuse: I don't understand the code.
|
15
|
+
#
|
16
|
+
# p.s. threeway. hehe. three way.
|
17
|
+
class ThreeWayMerger
|
18
|
+
|
19
|
+
def assert(val, msg="Assertion failed")
|
20
|
+
raise MergeAssertion.new(msg) unless val
|
21
|
+
end
|
22
|
+
|
23
|
+
# Have there been any conflicts in the merge?
|
24
|
+
attr_accessor :conflicts
|
25
|
+
|
26
|
+
##
|
27
|
+
# Performs a 3-way merge on the 3 files provided. Saves the merged file over the
|
28
|
+
# local file. This basically handles the file juggling while applying the instance
|
29
|
+
# methods to do merging.
|
30
|
+
#
|
31
|
+
# @param [String] local path to the original local file
|
32
|
+
# @param [String] base path to a (temporary) base file
|
33
|
+
# @param [String] other path to a (temporary) target file
|
34
|
+
# @param [Hash] opts additional options for merging
|
35
|
+
# @return [Boolean] were there conflicts during the merge?
|
36
|
+
def self.three_way_merge(local, base, other, opts={})
|
37
|
+
name_a = local
|
38
|
+
name_b = other
|
39
|
+
labels = opts[:labels] || []
|
40
|
+
|
41
|
+
name_a = labels.shift if labels.any?
|
42
|
+
name_b = labels.shift if labels.any?
|
43
|
+
raise abort("You can only specify 2 labels") if labels.any?
|
44
|
+
|
45
|
+
local_text = read_file local
|
46
|
+
base_text = read_file base
|
47
|
+
other_text = read_file other
|
48
|
+
local = Pathname.new(local).realpath
|
49
|
+
unless opts[:print]
|
50
|
+
# special temp name for our new merged file
|
51
|
+
newname = File.amp_make_tmpname local
|
52
|
+
out = File.open newname, "w"
|
53
|
+
|
54
|
+
# add rename method to this object to do atomicity
|
55
|
+
def out.rename(local, newname)
|
56
|
+
self.close
|
57
|
+
File.unlink(local)
|
58
|
+
File.move(newname, local)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
out = STDOUT
|
62
|
+
end
|
63
|
+
|
64
|
+
reprocess = !opts[:no_minimal]
|
65
|
+
merger = ThreeWayMerger.new(base_text, local_text, other_text)
|
66
|
+
merger.merge_lines(:name_a => name_a, :name_b => name_b, :reprocess => reprocess) do |line|
|
67
|
+
out.write line
|
68
|
+
end
|
69
|
+
|
70
|
+
out.rename(local, newname) unless opts[:print]
|
71
|
+
|
72
|
+
if merger.conflicts
|
73
|
+
unless opts[:quiet]
|
74
|
+
UI.warn("conflicts during merge.")
|
75
|
+
end
|
76
|
+
return true # yes conflicts
|
77
|
+
end
|
78
|
+
|
79
|
+
false # no conflicts
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Initializes the merger object with the 3 necessary texts, as well as
|
84
|
+
# subsections to merge (if we don't want to merge the entire texts).
|
85
|
+
#
|
86
|
+
# @param [String] base_text the common ancestor text, from which we
|
87
|
+
# are merging changes
|
88
|
+
# @param [String] a_text one descendent text - typically the local copy
|
89
|
+
# of the file
|
90
|
+
# @param [String] b_text the other descendent text - typically a copy
|
91
|
+
# committed by somebody else.
|
92
|
+
# @param [String] base_subset (base_text.split_newlines) the subsection
|
93
|
+
# of the common ancestor we are concerned with (if not merging full texts)
|
94
|
+
# @param [String] a_subset (a_text.split_newlines) the subsection
|
95
|
+
# of the first text we are concerned with (if not merging full texts)
|
96
|
+
# @param [String] b_subset (b_text.split_newlines) the subsection
|
97
|
+
# of the second text we are concerned with (if not merging full texts)
|
98
|
+
def initialize(base_text, a_text, b_text, base=nil, a=nil, b=nil)
|
99
|
+
@base_text, @a_text, @b_text = base_text, a_text, b_text
|
100
|
+
@base = base || @base_text.split_lines_better
|
101
|
+
@a = a || @a_text.split_lines_better
|
102
|
+
@b = b || @b_text.split_lines_better
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Merges the texts in a CVS-like form. The start_marker, mid_markers, and end_marker
|
107
|
+
# arguments are used to delimit conflicts. Yields lines - doesn't return anything.
|
108
|
+
#
|
109
|
+
# @yield the merged lines
|
110
|
+
# @yieldparam [String] line 1 line that belongs in the merged file.
|
111
|
+
def merge_lines(opts = {})
|
112
|
+
defaults = {:name_a => nil, :name_b => nil, :name_base => nil,
|
113
|
+
:start_marker => "<<<<<<<", :mid_marker => "=======",
|
114
|
+
:end_marker => ">>>>>>>", :base_marker => nil, :reprocess => false}
|
115
|
+
opts = defaults.merge(opts)
|
116
|
+
|
117
|
+
@conflicts = false # no conflicts yet!
|
118
|
+
# Figure out what our newline character is (silly windows)
|
119
|
+
newline = "\n"
|
120
|
+
if @a.size > 0
|
121
|
+
newline = "\r\n" if @a.first.end_with?("\r\n")
|
122
|
+
newline = "\r" if @a.first.end_with?("\r")
|
123
|
+
end
|
124
|
+
|
125
|
+
if opts[:base_marker] && opts[:reprocess]
|
126
|
+
raise ArgumentError.new("Can't reprocess and show base markers!")
|
127
|
+
end
|
128
|
+
|
129
|
+
# Add revision names to the markers
|
130
|
+
opts[:start_marker] += " #{opts[:name_a]}" if opts[:name_a]
|
131
|
+
opts[:end_marker] += " #{opts[:name_b]}" if opts[:name_b]
|
132
|
+
opts[:base_marker] += " #{opts[:name_base]}" if opts[:name_base] && opts[:base_marker]
|
133
|
+
|
134
|
+
merge_method = opts[:reprocess] ? :reprocessed_merge_regions : :merge_regions
|
135
|
+
self.send(merge_method) do |*t|
|
136
|
+
status = t[0]
|
137
|
+
case status
|
138
|
+
when :unchanged
|
139
|
+
t[1].upto(t[2]-1) {|i| yield @base[i] } # nothing changed, use base
|
140
|
+
when :a, :same
|
141
|
+
t[1].upto(t[2]-1) {|i| yield @a[i] } # local (A) insertion
|
142
|
+
when :b
|
143
|
+
t[1].upto(t[2]-1) {|i| yield @b[i] } # remote (B) insertion
|
144
|
+
when :conflict
|
145
|
+
@conflicts = true # :-( we have conflicts
|
146
|
+
|
147
|
+
yield opts[:start_marker] + newline # do the <<<<<<
|
148
|
+
t[3].upto(t[4]-1) {|i| yield @a[i]} # and the local copy
|
149
|
+
|
150
|
+
if opts[:base_marker]
|
151
|
+
yield base_marker + newline # do the base
|
152
|
+
t[1].upto(t[2]-1) {|i| yield @base[i]} # and the base lines
|
153
|
+
end
|
154
|
+
|
155
|
+
yield opts[:mid_marker] + newline # do the =====
|
156
|
+
t[5].upto(t[6]-1) {|i| yield @b[i]} # and the remote copy
|
157
|
+
yield opts[:end_marker] + newline # and then >>>>>>
|
158
|
+
else
|
159
|
+
raise ArgumentError.new("invalid region: #{status.inspect}")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Yield sequence of line groups. Each one is a tuple:
|
167
|
+
#
|
168
|
+
# :unchanged, lines
|
169
|
+
# Lines unchanged from base
|
170
|
+
#
|
171
|
+
# :a, lines
|
172
|
+
# Lines taken from a
|
173
|
+
#
|
174
|
+
# :same, lines
|
175
|
+
# Lines taken from a (and equal to b)
|
176
|
+
#
|
177
|
+
# :b, lines
|
178
|
+
# Lines taken from b
|
179
|
+
#
|
180
|
+
# :conflict, base_lines, a_lines, b_lines
|
181
|
+
# Lines from base were changed to either a or b and conflict.
|
182
|
+
def merge_groups
|
183
|
+
merge_regions do |list|
|
184
|
+
case list[0]
|
185
|
+
when :unchanged
|
186
|
+
yield list[0], @base[list[1]..(list[2]-1)]
|
187
|
+
when :a, :same
|
188
|
+
yield list[0], @a[list[1]..(list[2]-1)]
|
189
|
+
when :b
|
190
|
+
yield list[0], @b[list[1]..(list[2]-1)]
|
191
|
+
when :conflict
|
192
|
+
yield list[0], @base[list[1]..(list[2]-1)],
|
193
|
+
@a[list[3]..(list[4]-1)],
|
194
|
+
@b[list[5]..(list[6]-1)]
|
195
|
+
else
|
196
|
+
raise ArgumentError.new(list[0])
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Yield sequences of matching and conflicting regions.
|
203
|
+
#
|
204
|
+
# This returns tuples, where the first value says what kind we
|
205
|
+
# have:
|
206
|
+
#
|
207
|
+
# 'unchanged', start, end
|
208
|
+
# Take a region of base[start:end]
|
209
|
+
#
|
210
|
+
# 'same', astart, aend
|
211
|
+
# b and a are different from base but give the same result
|
212
|
+
#
|
213
|
+
# 'a', start, end
|
214
|
+
# Non-clashing insertion from a[start:end]
|
215
|
+
#
|
216
|
+
# Method is as follows:
|
217
|
+
#
|
218
|
+
# The two sequences align only on regions which match the base
|
219
|
+
# and both descendents. These are found by doing a two-way diff
|
220
|
+
# of each one against the base, and then finding the
|
221
|
+
# intersections between those regions. These "sync regions"
|
222
|
+
# are by definition unchanged in both and easily dealt with.
|
223
|
+
#
|
224
|
+
# The regions in between can be in any of three cases:
|
225
|
+
# conflicted, or changed on only one side.
|
226
|
+
#
|
227
|
+
# @yield Arrays of regions that require merging
|
228
|
+
def merge_regions
|
229
|
+
## NOTE: we use "z" as an abbreviation for "base" or the "ancestor", because
|
230
|
+
# we can't very well abbreviate "ancestor" as "a" or "base" as "b".
|
231
|
+
idx_z = idx_a = idx_b = 0
|
232
|
+
|
233
|
+
find_sync_regions.each do |match|
|
234
|
+
z_match, z_end = match[:base_start], match[:base_end]
|
235
|
+
a_match, a_end = match[:a_start ], match[:a_end ]
|
236
|
+
b_match, b_end = match[:b_start ], match[:b_end ]
|
237
|
+
|
238
|
+
match_len = z_end - z_match
|
239
|
+
assert match_len >= 0
|
240
|
+
assert match_len == (a_end - a_match), "expected #{match_len}, got #{(a_end - a_match)} (#{a_end} - #{a_match})"
|
241
|
+
assert match_len == (b_end - b_match)
|
242
|
+
|
243
|
+
len_a = a_match - idx_a
|
244
|
+
len_b = b_match - idx_b
|
245
|
+
len_base = z_match - idx_z
|
246
|
+
assert len_a >= 0
|
247
|
+
assert len_b >= 0
|
248
|
+
assert len_base >= 0
|
249
|
+
|
250
|
+
if len_a > 0 || len_b > 0
|
251
|
+
equal_a = compare_range(@a, idx_a, a_match, @base, idx_z, z_match)
|
252
|
+
equal_b = compare_range(@b, idx_b, b_match, @base, idx_z, z_match)
|
253
|
+
same = compare_range(@a, idx_a, a_match, @b, idx_b, b_match)
|
254
|
+
|
255
|
+
if same
|
256
|
+
yield :same, idx_a, a_match
|
257
|
+
elsif equal_a && !equal_b
|
258
|
+
yield :b, idx_b, b_match
|
259
|
+
elsif equal_b && !equal_a
|
260
|
+
yield :a, idx_a, a_match
|
261
|
+
elsif !equal_a && !equal_b
|
262
|
+
yield :conflict, idx_z, z_match, idx_a, a_match, idx_b, b_match
|
263
|
+
else
|
264
|
+
raise AssertionError.new("can't handle a=b=base but unmatched!")
|
265
|
+
end
|
266
|
+
|
267
|
+
idx_a = a_match
|
268
|
+
idx_b = b_match
|
269
|
+
end
|
270
|
+
idx_z = z_match
|
271
|
+
|
272
|
+
if match_len > 0
|
273
|
+
assert idx_a == a_match
|
274
|
+
assert idx_b == b_match
|
275
|
+
assert idx_z == z_match
|
276
|
+
|
277
|
+
yield :unchanged, z_match, z_end
|
278
|
+
|
279
|
+
idx_a = a_end
|
280
|
+
idx_b = b_end
|
281
|
+
idx_z = z_end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Take the merge regions yielded by merge_regions, and remove lines where both A and
|
288
|
+
# B (local & remote) have made the same changes.
|
289
|
+
def reprocessed_merge_regions
|
290
|
+
merge_regions do |*region|
|
291
|
+
if region[0] != :conflict
|
292
|
+
yield *region
|
293
|
+
next
|
294
|
+
end
|
295
|
+
type, idx_z, z_match, idx_a, a_match, idx_b, b_match = region
|
296
|
+
a_region = @a[idx_a..(a_match-1)]
|
297
|
+
b_region = @b[idx_b..(b_match-1)]
|
298
|
+
matches = Amp::Diffs::MercurialDiff.get_matching_blocks(a_region.join, b_region.join)
|
299
|
+
|
300
|
+
next_a = idx_a
|
301
|
+
next_b = idx_b
|
302
|
+
|
303
|
+
matches[0..-2].each do |block|
|
304
|
+
region_ia, region_ib, region_len = block[:start_a], block[:start_b], block[:length]
|
305
|
+
region_ia += idx_a
|
306
|
+
region_ib += idx_b
|
307
|
+
|
308
|
+
reg = mismatch_region(next_a, region_ia, next_b, region_ib)
|
309
|
+
|
310
|
+
yield *reg if reg
|
311
|
+
yield :same, region_ia, region_len + region_ia
|
312
|
+
|
313
|
+
next_a = region_ia + region_len
|
314
|
+
next_b = region_ib + region_len
|
315
|
+
|
316
|
+
end
|
317
|
+
reg = mismatch_region(next_a, a_match, next_b, b_match)
|
318
|
+
yield *reg if reg
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
|
324
|
+
##
|
325
|
+
# Returns a list of sync'd regions, where both descendents match the base.
|
326
|
+
# Generates a list of {:base_start, :base_end, :a_start, :a_end, :b_start, :b_end}
|
327
|
+
#
|
328
|
+
# @return [Array<Hash>] A list of sync regions, each stored as a hash, with the
|
329
|
+
# keys {:base_start, :base_end, :a_start, :a_end, :b_start, :b_end}. There is
|
330
|
+
# always a zero-length sync region at the end of any file (because the EOF always
|
331
|
+
# matches).
|
332
|
+
def find_sync_regions
|
333
|
+
idx_a = idx_b = 0
|
334
|
+
a_matches = Amp::Diffs::MercurialDiff.get_matching_blocks(@base_text, @a_text)
|
335
|
+
b_matches = Amp::Diffs::MercurialDiff.get_matching_blocks(@base_text, @b_text)
|
336
|
+
|
337
|
+
len_a, len_b = a_matches.size, b_matches.size
|
338
|
+
sync_regions = []
|
339
|
+
|
340
|
+
while idx_a < len_a && idx_b < len_b
|
341
|
+
next_a, next_b = a_matches[idx_a], b_matches[idx_b]
|
342
|
+
|
343
|
+
a_base, a_match, a_len = next_a[:start_a], next_a[:start_b], next_a[:length]
|
344
|
+
b_base, b_match, b_len = next_b[:start_a], next_b[:start_b], next_b[:length]
|
345
|
+
|
346
|
+
intersection = (a_base..(a_base+a_len)) - (b_base..(b_base+b_len))
|
347
|
+
if intersection
|
348
|
+
# add the sync region
|
349
|
+
sync_regions << synced_region_for_intersection(intersection, a_base, b_base, a_match, b_match)
|
350
|
+
end
|
351
|
+
if (a_base + a_len) < (b_base + b_len)
|
352
|
+
idx_a += 1
|
353
|
+
else
|
354
|
+
idx_b += 1
|
355
|
+
end
|
356
|
+
end
|
357
|
+
# add the EOF-marker
|
358
|
+
inter_base = @base.size
|
359
|
+
a_base = @a.size
|
360
|
+
b_base = @b.size
|
361
|
+
sync_regions << {:base_start => inter_base, :base_end => inter_base,
|
362
|
+
:a_start => a_base, :a_end => a_base ,
|
363
|
+
:b_start => b_base, :b_end => b_base }
|
364
|
+
|
365
|
+
sync_regions
|
366
|
+
end
|
367
|
+
|
368
|
+
def synced_region_for_intersection(intersection, a_base, b_base, a_match, b_match)
|
369
|
+
inter_base = intersection.begin
|
370
|
+
inter_end = intersection.end
|
371
|
+
inter_len = inter_end - inter_base
|
372
|
+
|
373
|
+
# found a match of base[inter_base..inter_end] - this may be less than the region
|
374
|
+
# that matches in either one. Let's do some assertions
|
375
|
+
#assert inter_len <= a_len
|
376
|
+
#assert inter_len <= b_len
|
377
|
+
assert a_base <= inter_base
|
378
|
+
assert b_base <= inter_base
|
379
|
+
|
380
|
+
# shift section downward or upward
|
381
|
+
a_sub = a_match + (inter_base - a_base)
|
382
|
+
b_sub = b_match + (inter_base - b_base)
|
383
|
+
# end points = base_len + starts
|
384
|
+
a_end = a_sub + inter_len
|
385
|
+
b_end = b_sub + inter_len
|
386
|
+
|
387
|
+
# make sure the texts are equal of course....
|
388
|
+
assert @base[inter_base..(inter_end-1)] == @a[a_sub..(a_end-1)]
|
389
|
+
assert @base[inter_base..(inter_end-1)] == @b[b_sub..(b_end-1)]
|
390
|
+
|
391
|
+
# return the sync region
|
392
|
+
{:base_start => inter_base, :base_end => inter_end,
|
393
|
+
:a_start => a_sub, :a_end => a_end ,
|
394
|
+
:b_start => b_sub, :b_end => b_end }
|
395
|
+
end
|
396
|
+
|
397
|
+
private
|
398
|
+
|
399
|
+
def mismatch_region(next_a, region_ia, next_b, region_ib)
|
400
|
+
if next_a < region_ia || next_b < region_ib
|
401
|
+
return :conflict, nil, nil, next_a, region_ia, next_b, region_ib
|
402
|
+
end
|
403
|
+
nil
|
404
|
+
end
|
405
|
+
|
406
|
+
##
|
407
|
+
# Reads a file, but raises warnings if it's binary and we shouldn't be
|
408
|
+
# working with it.
|
409
|
+
#
|
410
|
+
# @param [String] filename the path to the file to read
|
411
|
+
# @param [Hash] opts the options for handling binary files
|
412
|
+
def self.read_file(filename, opts={})
|
413
|
+
text = File.read filename
|
414
|
+
if text.binary?
|
415
|
+
message = "#{filename} appears to be a binary file."
|
416
|
+
raise abort(message) unless opts[:text]
|
417
|
+
UI.warn(message) unless opts[:quiet]
|
418
|
+
end
|
419
|
+
text
|
420
|
+
end
|
421
|
+
|
422
|
+
##
|
423
|
+
# Compares arr_a[a_start...a_end] == arr_b[b_start...b_end], without
|
424
|
+
# actually cutting up the array and thus allocating memory.
|
425
|
+
#
|
426
|
+
# @param [Array<Comparable>] arr_a an array of objects that can be compared to arr_b
|
427
|
+
# @param [Integer] a_start the index to begin comparison
|
428
|
+
# @param [Integer] a_end the index to end comparison (exclusive - arr_a[a_end] is NOT
|
429
|
+
# compared to arr_b[b_end])
|
430
|
+
# @param [Array<Comparable>] arr_b an array of objects that can be compared to arr_a
|
431
|
+
# @param [Integer] b_start the index to begin comparison
|
432
|
+
# @param [Integer] b_end the index to end comparison (exclusive - arr_a[a_end] is NOT
|
433
|
+
# compared to arr_b[b_end])
|
434
|
+
# @return [Boolean] true if arr_a == arr_b, false if arr_a != arr_b
|
435
|
+
def compare_range(arr_a, a_start, a_end, arr_b, b_start, b_end)
|
436
|
+
return false if (a_end - a_start) != (b_end - b_start)
|
437
|
+
idx_a, idx_b = a_start, b_start
|
438
|
+
while idx_a < a_end && idx_b < b_end
|
439
|
+
return false if arr_a[idx_a] != arr_b[idx_b]
|
440
|
+
idx_a += 1
|
441
|
+
idx_b += 1
|
442
|
+
end
|
443
|
+
true
|
444
|
+
end
|
445
|
+
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
Threesome = Amp::Merges::ThreeWayMerger
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# alias old_puts puts
|
2
|
+
# def puts(*args)
|
3
|
+
# return if args.empty?
|
4
|
+
# old_puts (['[', caller[0].inspect, ' -- ', *args] << ']').join
|
5
|
+
# end
|
6
|
+
#
|
7
|
+
# alias old_p p
|
8
|
+
# def p(*args)
|
9
|
+
# args.map! {|a| a.inspect }
|
10
|
+
# old_puts (['[', caller[0].inspect, ' -- ', *args] << ']').join
|
11
|
+
# end
|
12
|
+
|
13
|
+
##
|
14
|
+
def show_caller_for(meth, lines, new_meth="__#{meth}__")
|
15
|
+
lines = [*lines]
|
16
|
+
alias_method "#{new_meth}".to_sym, meth
|
17
|
+
self.class_eval(<<-HELP)
|
18
|
+
def #{meth}(*args, &block)
|
19
|
+
#{lines.join("\n")}
|
20
|
+
#{new_meth}(*args, &block)
|
21
|
+
end
|
22
|
+
HELP
|
23
|
+
end
|
24
|
+
|
25
|
+
$hash = Hash.new {|h, k| h[k] = 0 }
|
26
|
+
#
|
27
|
+
# String.class_eval do
|
28
|
+
# show_caller_for :split_newlines, "$hash[caller[0]] += 1"
|
29
|
+
# end
|
30
|
+
|
31
|
+
if ENV["TESTING"] == "true"
|
32
|
+
END {
|
33
|
+
require 'pp'
|
34
|
+
STDERR.puts $hash.inspect if $hash.any?
|
35
|
+
}
|
36
|
+
end
|