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,164 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
module Merges
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# = MergeState
|
|
6
|
+
# MergeState handles the merge/ directory in the repository, in order
|
|
7
|
+
# to keep track of how well the current merge is progressing. There is
|
|
8
|
+
# a file called merge/state that lists all the files that need merging
|
|
9
|
+
# and a little info about whether it has beeen merged or not.
|
|
10
|
+
#
|
|
11
|
+
# You can add a file to the mergestate, iterate over all of them, quickly
|
|
12
|
+
# look up to see if a file is still dirty, and so on.
|
|
13
|
+
class MergeState
|
|
14
|
+
include Enumerable
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Initializes a new mergestate with the given repo, and reads in all the
|
|
18
|
+
# information from merge/state.
|
|
19
|
+
#
|
|
20
|
+
# @param repo the repository being inspected
|
|
21
|
+
def initialize(repo)
|
|
22
|
+
@repo = repo
|
|
23
|
+
read!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Resets the merge status, by clearing all merge information and files
|
|
28
|
+
#
|
|
29
|
+
# @param node the node we're working with? seems kinda useless
|
|
30
|
+
def reset(node = nil)
|
|
31
|
+
@state = {}
|
|
32
|
+
@local = node if node
|
|
33
|
+
FileUtils.rm_rf @repo.join("merge")
|
|
34
|
+
end
|
|
35
|
+
alias_method :reset!, :reset
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Returns whether the file is part of a merge or not
|
|
39
|
+
#
|
|
40
|
+
# @return [Boolean] if the dirty file in our state and not nil?
|
|
41
|
+
def include?(dirty_file)
|
|
42
|
+
not @state[dirty_file].nil?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Accesses the the given file's merge status - can be "u" for unmerged,
|
|
47
|
+
# or other stuff we haven't figured out yet.
|
|
48
|
+
#
|
|
49
|
+
# @param [String] dirty_file the path to the file for merging.
|
|
50
|
+
# @return [String] the status as a letter - so far "u" means unmerged or "r"
|
|
51
|
+
# for resolved.
|
|
52
|
+
def [](dirty_file)
|
|
53
|
+
@state[dirty_file] ? @state[dirty_file][0, 1] : ""
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# Adds a file to the mergestate, which creates a separate file
|
|
58
|
+
# in the merge directory with all the information. I don't know
|
|
59
|
+
# what these parameters are for yet.
|
|
60
|
+
def add(fcl, fco, fca, fd, flags)
|
|
61
|
+
hash = Digest::SHA1.new.update(fcl.path).hexdigest
|
|
62
|
+
@repo.open("merge/#{hash}", "w") do |file|
|
|
63
|
+
file.write fcl.data
|
|
64
|
+
end
|
|
65
|
+
@state[fd] = ["u", hash, fcl.path, fca.path, fca.file_node.hexlify,
|
|
66
|
+
fco.path, flags]
|
|
67
|
+
save
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
# Iterates over all the files that are involved in the current
|
|
72
|
+
# merging transaction.
|
|
73
|
+
#
|
|
74
|
+
# @yield each file, sorted by filename, that needs merging.
|
|
75
|
+
# @yieldparam file the filename that needs (or has been) merged.
|
|
76
|
+
# @yieldparam state all the information about the current merge with
|
|
77
|
+
# this file.
|
|
78
|
+
def each
|
|
79
|
+
@state.keys.sort.each do |key|
|
|
80
|
+
yield(key, @state[key])
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
##
|
|
85
|
+
# Marks the given file with a given state, which is 1 letter. "u" means
|
|
86
|
+
# unmerged, "r" means resolved.
|
|
87
|
+
#
|
|
88
|
+
# @param [String] dirty_file the file path for marking
|
|
89
|
+
# @param [String] state the state - "u" for unmerged, "r" for resolved.
|
|
90
|
+
def mark(dirty_file, state)
|
|
91
|
+
@state[dirty_file][0] = state
|
|
92
|
+
save
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Resolves the given file for a merge between 2 changesets.
|
|
97
|
+
#
|
|
98
|
+
# @param dirty_file the path to the file for merging
|
|
99
|
+
# @param working_changeset the current changeset that is the destination
|
|
100
|
+
# of the merge
|
|
101
|
+
# @param other_changeset the newer changeset, which we're merging to
|
|
102
|
+
def resolve(dirty_file, working_changeset, other_changeset)
|
|
103
|
+
return 0 if self[dirty_file] == "r"
|
|
104
|
+
state, hash, lfile, afile, anode, ofile, flags = @state[dirty_file]
|
|
105
|
+
r = true
|
|
106
|
+
@repo.open("merge/#{hash}") do |file|
|
|
107
|
+
@repo.working_write(dirty_file, file.read, flags)
|
|
108
|
+
working_file = working_changeset[dirty_file]
|
|
109
|
+
other_file = other_changeset[ofile]
|
|
110
|
+
ancestor_file = @repo.versioned_file(afile, :file_id => anode)
|
|
111
|
+
r = UI.file_merge(@repo, @local, lfile, working_file, other_file, ancestor_file)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
mark(dirty_file, "r") if r.nil? || r == false
|
|
115
|
+
return r
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
##
|
|
119
|
+
# Public access to writing the file.
|
|
120
|
+
def save
|
|
121
|
+
write!
|
|
122
|
+
end
|
|
123
|
+
alias_method :save!, :save
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
##
|
|
128
|
+
# Reads in the merge state and sets up all our instance variables.
|
|
129
|
+
#
|
|
130
|
+
def read!
|
|
131
|
+
@state = {}
|
|
132
|
+
ignore_missing_files do
|
|
133
|
+
local_node = nil
|
|
134
|
+
@repo.open("merge/state") do |file|
|
|
135
|
+
get_node = true
|
|
136
|
+
file.each_line do |line|
|
|
137
|
+
if get_node
|
|
138
|
+
local_node = line.chomp
|
|
139
|
+
get_node = false
|
|
140
|
+
else
|
|
141
|
+
parts = line.chomp.split("\0")
|
|
142
|
+
@state[parts[0]] = parts[1..-1]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
@local = local_node.unhexlify
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
##
|
|
151
|
+
# Saves the merge state to disk.
|
|
152
|
+
#
|
|
153
|
+
def write!
|
|
154
|
+
@repo.open("merge/state","w") do |file|
|
|
155
|
+
file.write @local.hexlify + "\n"
|
|
156
|
+
@state.each do |key, val|
|
|
157
|
+
file.write "#{([key] + val).join("\0")}\n"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
|
|
3
|
+
module Amp
|
|
4
|
+
module Merges
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# This module handles figuring out how to merge files using the user's
|
|
8
|
+
# preferences. It is mixed into the UI class. The UI class must implement
|
|
9
|
+
# the "config" method.
|
|
10
|
+
module MergeUI
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Performs a 3-way merge in the working directory from vf_local to vf_other,
|
|
14
|
+
# using the common ancestor vf_ancestor.
|
|
15
|
+
#
|
|
16
|
+
# @todo change 1s and 0s to bools
|
|
17
|
+
# @todo consistent return type
|
|
18
|
+
#
|
|
19
|
+
# @param [Repository] repo the repository in which we are merging files
|
|
20
|
+
# @param [String] parent_node the node_id of the parent node before the merge
|
|
21
|
+
# @param [String] original_fn the original local filename before the merge
|
|
22
|
+
# @param [WorkingVersionedFile] vf_local the current, working-directory versioned file
|
|
23
|
+
# @param [VersionedFile] vf_other the file's changeset to which we are migrating
|
|
24
|
+
# @param [VersionedFile] vf_ancestor the common ancestor between vf_local and vf_other
|
|
25
|
+
# @return [Boolean] true if there were conflicts during the merge
|
|
26
|
+
def file_merge(repo, parent_node, original_fn, vf_local, vf_other, vf_ancestor)
|
|
27
|
+
is_binary = proc {|ctx| ctx.data.binary? rescue false}
|
|
28
|
+
|
|
29
|
+
return nil if !(vf_other.cmp vf_local.data)
|
|
30
|
+
|
|
31
|
+
path = vf_local.path
|
|
32
|
+
binary = is_binary[vf_local] || is_binary[vf_other] || is_binary[vf_ancestor]
|
|
33
|
+
symlink = (vf_local.flags + vf_other.flags).include? "l"
|
|
34
|
+
|
|
35
|
+
tool, tool_path = pick_tool(repo, path, binary, symlink)
|
|
36
|
+
UI.status("Picked tool #{tool} for #{path} (binary #{binary} symlink #{symlink})")
|
|
37
|
+
|
|
38
|
+
unless tool
|
|
39
|
+
tool = "internal:local"
|
|
40
|
+
if UI.ask("no tool found to merge #{path}\n"+
|
|
41
|
+
"keep (l)ocal or take (o)ther?") != "l"
|
|
42
|
+
tool = "internal:other"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
case tool
|
|
47
|
+
when "internal:local"
|
|
48
|
+
return 0
|
|
49
|
+
when "internal:other"
|
|
50
|
+
repo.working_write(path, vf_other.data, vf_other.flags)
|
|
51
|
+
return 0
|
|
52
|
+
when "internal:fail"
|
|
53
|
+
return 1
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
a = repo.working_join(path)
|
|
57
|
+
b_file = save_versioned_file_temp("base", vf_ancestor)
|
|
58
|
+
c_file = save_versioned_file_temp("other", vf_other)
|
|
59
|
+
b, c = b_file.path, c_file.path
|
|
60
|
+
|
|
61
|
+
out = ""
|
|
62
|
+
back = a + ".orig" + File.extname(a)
|
|
63
|
+
File.copy(a, back)
|
|
64
|
+
|
|
65
|
+
if original_fn != vf_other.path
|
|
66
|
+
UI.status("merging #{original_fn} and #{vf_other.path} to #{path}")
|
|
67
|
+
else
|
|
68
|
+
UI.status("merging #{path}")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if tool_setting(tool, "premerge", !(binary || symlink))
|
|
72
|
+
ret = ThreeWayMerger.three_way_merge(a, b, c, :quiet => true)
|
|
73
|
+
unless ret
|
|
74
|
+
UI.debug("premerge successful")
|
|
75
|
+
File.unlink(back)
|
|
76
|
+
File.safe_unlink(b)
|
|
77
|
+
File.safe_unlink(c)
|
|
78
|
+
return false
|
|
79
|
+
end
|
|
80
|
+
File.copy(back, a) # restore frmo backup and try again
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
environment = {"HG_FILE" => path,
|
|
84
|
+
"HG_MY_NODE" => parent_node.hexlify[0..11],
|
|
85
|
+
"HG_OTHER_NODE" => vf_other.changeset.to_s,
|
|
86
|
+
"HG_MY_ISLINK" => vf_local.flags.include?("l"),
|
|
87
|
+
"HG_OTHER_ISLINK" => vf_other.flags.include?("l"),
|
|
88
|
+
"HG_BASE_ISLINK" => vf_ancestor.flags.include?("l")}
|
|
89
|
+
if tool == "internal:merge"
|
|
90
|
+
ret = ThreeWayMerger.three_way_merge(a, b, c, :label => ['local', 'other'])
|
|
91
|
+
else
|
|
92
|
+
args = tool_setting_string(tool, "args", "$local $base $other")
|
|
93
|
+
if args.include?("$output")
|
|
94
|
+
out, a = a, back # read input from backup, write to original
|
|
95
|
+
end
|
|
96
|
+
replace = {"local" => a, "base" => b, "other" => c, "output" => out}
|
|
97
|
+
args.gsub!(/\$(local|base|other|output)/) { replace[$1]}
|
|
98
|
+
# shelling out
|
|
99
|
+
ret = Amp::Support::system(tool_path+" "+args, :chdir => repo.root, :environ => environment)
|
|
100
|
+
end
|
|
101
|
+
ret = (ret == true ? 1 : (ret == false ? 0 : ret))
|
|
102
|
+
if ret == 0 && tool_setting(tool, "checkconflicts")
|
|
103
|
+
if vf_local.data =~ /^(<<<<<<< .*|=======|>>>>>>> .*)$/
|
|
104
|
+
ret = 1
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
if ret == 0 && tool_setting(tool, "checkchanged")
|
|
109
|
+
if File.stat(repo.working_join(path)) === File.stat(back)
|
|
110
|
+
if UI::yes_or_no "output file #{path} appears unchanged\nwas merge successful?"
|
|
111
|
+
r = 1
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
fix_end_of_lines(repo.working_join(path), back) if tool_setting(tool, "fixeol")
|
|
117
|
+
|
|
118
|
+
if ret == 1
|
|
119
|
+
UI::warn "merging #{path} failed!"
|
|
120
|
+
else
|
|
121
|
+
File.unlink back
|
|
122
|
+
end
|
|
123
|
+
File.unlink b
|
|
124
|
+
File.unlink c
|
|
125
|
+
|
|
126
|
+
!ret.zero? # return
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def save_versioned_file_temp(prefix, versioned_file)
|
|
132
|
+
prefix = "#{File.basename versioned_file.path}~#{prefix}"
|
|
133
|
+
|
|
134
|
+
tempfile = Tempfile.new prefix
|
|
135
|
+
path = tempfile.path
|
|
136
|
+
tempfile.write versioned_file.data
|
|
137
|
+
tempfile.close false # DON'T unlink it
|
|
138
|
+
|
|
139
|
+
tempfile
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
##
|
|
143
|
+
# Converts the end-of-line characters in a file to match the original file.
|
|
144
|
+
# Thus, if we merge from our copy to a new one, and there foreign
|
|
145
|
+
# end-of-line characters got merged in, we want to nuke them and put in our own!
|
|
146
|
+
#
|
|
147
|
+
# @param [String] new_file the path to the newly merged file
|
|
148
|
+
# @param [String] original_file the path to the original file
|
|
149
|
+
def fix_end_of_lines(new_file, original_file)
|
|
150
|
+
new_eol = guess_end_of_line(File.read(original_file))
|
|
151
|
+
if new_eol
|
|
152
|
+
data = File.read(new_file)
|
|
153
|
+
old_eol = guess_end_of_line(data)
|
|
154
|
+
if old_eol
|
|
155
|
+
new_data = data.gsub(old_eol, new_eol)
|
|
156
|
+
|
|
157
|
+
File.open(file, "w") {|f| f.write new_data } if new_data != data
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# Guesses the end-of-line character for a file in a very lazy fashion.
|
|
165
|
+
#
|
|
166
|
+
# @param [String] data the file data to guess from
|
|
167
|
+
# @return [String, nil] the guessed end-of-line character(s).
|
|
168
|
+
def guess_end_of_line(data)
|
|
169
|
+
return nil if data.include?("\0") # binary
|
|
170
|
+
return "\r\n" if data.include?("\r\n") # windows
|
|
171
|
+
return "\r" if data.include?("\r") # old mac
|
|
172
|
+
return "\n" if data.include?("\n") # *nix
|
|
173
|
+
return nil # wtf?
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
##
|
|
177
|
+
# Picks a merge tool based on the user's settings in hgrc files and environment
|
|
178
|
+
# variables. Returns a hash specifying both the name and path of the
|
|
179
|
+
# merge tool's executable.
|
|
180
|
+
#
|
|
181
|
+
# @todo merge-patterns, line 56 of filemerge.py
|
|
182
|
+
# @param [Repository] repo the repository we are performing a merge upon
|
|
183
|
+
# @param [String] path the path to the file we're merging
|
|
184
|
+
# @param [Boolean] binary is the file a binary file?
|
|
185
|
+
# @param [Boolean] symlink is the file a symlink?
|
|
186
|
+
# @return [Hash] keyed as follows:
|
|
187
|
+
# :name => the name of the chosen tool
|
|
188
|
+
# :path => the path to the tool (if an executable is to be used)
|
|
189
|
+
def pick_tool(repo, path, binary, symlink)
|
|
190
|
+
hgmerge = ENV["HGMERGE"]
|
|
191
|
+
return [hgmerge, hgmerge] if hgmerge
|
|
192
|
+
|
|
193
|
+
# @todo: add merge-patterns support
|
|
194
|
+
|
|
195
|
+
# scan the merge-tools section
|
|
196
|
+
tools = {}
|
|
197
|
+
config["merge-tools"].each do |k, v|
|
|
198
|
+
t = k.split(".").first
|
|
199
|
+
unless tools[t]
|
|
200
|
+
tools[t] = tool_setting_string(t, "priority", "0").to_i
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# go through the list of tools and sort by priority
|
|
205
|
+
tool_names = tools.keys
|
|
206
|
+
tools = tools.map {|tool, prio| [-prio, tool]}.sort
|
|
207
|
+
# check the [ui] section for a "merge" setting
|
|
208
|
+
uimerge = config["ui","merge"]
|
|
209
|
+
if uimerge
|
|
210
|
+
unless tool_names.include?(uimerge)
|
|
211
|
+
return [uimerge, uimerge]
|
|
212
|
+
end
|
|
213
|
+
tools.unshift([nil, uimerge]) # highest priority
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# add the "hgmerge" binary
|
|
217
|
+
tools << [nil, "hgmerge"] # the old default, if found
|
|
218
|
+
# check everything in our list, and if we actually find one that works,
|
|
219
|
+
# return it
|
|
220
|
+
tools.each do |priority, tool|
|
|
221
|
+
if check_tool(tool, nil, symlink, binary)
|
|
222
|
+
tool_path = find_tool(tool)
|
|
223
|
+
return [tool, "\"#{tool_path}\""]
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
# last but not least, do a simple_merge.
|
|
227
|
+
return (!symlink && !binary) ? "internal:merge" : [nil, nil]
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
##
|
|
231
|
+
# Quick access to the merge-tools section of the configuration files.
|
|
232
|
+
# A merge tool will set it up with data like this:
|
|
233
|
+
# [merge-tools]
|
|
234
|
+
# awesometool.executable = /usr/bin/awesometool
|
|
235
|
+
# awesometool.regkey = HKEY_USELESS_INFO
|
|
236
|
+
# and so on. This method abstracts away the scheme for encoding this information
|
|
237
|
+
# gets string values from the configuration.
|
|
238
|
+
#
|
|
239
|
+
# @param [String] tool the name of the tool to look up data for
|
|
240
|
+
# @param [String] part the specific information about the tool to look up
|
|
241
|
+
# @param [String] default the default value, if the configuration setting
|
|
242
|
+
# can't be found
|
|
243
|
+
# @return [String] the setting for the given merge tool we're looking up, as
|
|
244
|
+
# as a string.
|
|
245
|
+
def tool_setting_string(tool, part, default="")
|
|
246
|
+
config["merge-tools", "#{tool}.#{part}", String, default]
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
##
|
|
250
|
+
# Quick access to the merge-tools section of the configuration files.
|
|
251
|
+
# Returns boolean values.
|
|
252
|
+
#
|
|
253
|
+
# @see check_tool_string
|
|
254
|
+
# @param [String] tool the name of the tool to look up data for
|
|
255
|
+
# @param [String] part the specific information about the tool to look up
|
|
256
|
+
# @param [Boolean] default the default value, if the configuration setting
|
|
257
|
+
# can't be found
|
|
258
|
+
# @return [Boolean] the setting for the given merge tool we're looking up, as
|
|
259
|
+
# as a string.
|
|
260
|
+
def tool_setting(tool, part, default=false)
|
|
261
|
+
config["merge-tools", "#{tool}.#{part}", Boolean, default]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
##
|
|
265
|
+
# Given the name of a merge tool, attempt to locate an executable file
|
|
266
|
+
# for the tool.
|
|
267
|
+
#
|
|
268
|
+
# @param [String] tool the name of the merge tool to locate
|
|
269
|
+
# @return [String] the path to the executable for the merge tool, or nil
|
|
270
|
+
# if the tool cannot be found
|
|
271
|
+
def find_tool(tool)
|
|
272
|
+
if ["internal:fail", "internal:local", "internal:other"].include?(tool)
|
|
273
|
+
return tool
|
|
274
|
+
end
|
|
275
|
+
# windows stuff
|
|
276
|
+
k = tool_setting_string(tool, "regkey")
|
|
277
|
+
if k && k.any?
|
|
278
|
+
p = File.amp_lookup_reg(k, tool_setting_string(tool, "regname"))
|
|
279
|
+
if p && p.any?
|
|
280
|
+
p = File.amp_find_executable(p + check_tool_string(tool, "regappend"))
|
|
281
|
+
if p
|
|
282
|
+
return p
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
# normal *nix lookup
|
|
287
|
+
return File.amp_find_executable(tool_setting_string(tool, "executable", tool))
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
##
|
|
291
|
+
# Checks to see if a given tool is available given the necessary settings.
|
|
292
|
+
#
|
|
293
|
+
# @todo add GUI check
|
|
294
|
+
# @param [String] tool the name of the tool we want to check
|
|
295
|
+
# @param [String] pat the pattern we matched to get here. Could be nil.
|
|
296
|
+
# @param [Boolean] symlink are we merging across a symlink here?
|
|
297
|
+
# @param [Boolean] binary are we merging a binary file? you crazy?!
|
|
298
|
+
# @return [Boolean] is the given tool available?
|
|
299
|
+
def check_tool(tool, pat, symlink, binary)
|
|
300
|
+
tool_msg = tool
|
|
301
|
+
tool_msg += " specified for " + pat if pat
|
|
302
|
+
|
|
303
|
+
if !(find_tool tool)
|
|
304
|
+
if pat
|
|
305
|
+
warn("couldn't find merge tool #{tool}")
|
|
306
|
+
else
|
|
307
|
+
note("couldn't find merge tool #{tool}")
|
|
308
|
+
end
|
|
309
|
+
elsif symlink && !(tool_setting(tool, "symlink"))
|
|
310
|
+
warn("tool #{tool} can't handle symlinks")
|
|
311
|
+
elsif binary && !(tool_setting(tool, "binary"))
|
|
312
|
+
warn("tool #{tool} can't handle binary files")
|
|
313
|
+
elsif false # TODO: add GUI check
|
|
314
|
+
else
|
|
315
|
+
return true
|
|
316
|
+
end
|
|
317
|
+
return false # we're here if any of the previous checks created a warning
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|