amp 0.5.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.
- 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
|