amp 0.5.2 → 0.5.3
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 +12 -0
- data/.hgignore +3 -0
- data/AUTHORS +1 -1
- data/Manifest.txt +99 -38
- data/README.md +3 -3
- data/Rakefile +53 -18
- data/SCHEDULE.markdown +5 -1
- data/TODO.markdown +120 -149
- data/ampfile.rb +3 -1
- data/bin/amp +4 -1
- data/ext/amp/bz2/extconf.rb +1 -1
- data/ext/amp/mercurial_patch/extconf.rb +1 -1
- data/ext/amp/mercurial_patch/mpatch.c +4 -3
- data/ext/amp/priority_queue/extconf.rb +1 -1
- data/ext/amp/support/extconf.rb +1 -1
- data/ext/amp/support/support.c +1 -1
- data/lib/amp.rb +125 -67
- data/lib/amp/commands/command.rb +12 -10
- data/lib/amp/commands/command_support.rb +8 -1
- data/lib/amp/commands/commands/help.rb +2 -20
- data/lib/amp/commands/commands/init.rb +14 -2
- data/lib/amp/commands/commands/templates.rb +6 -4
- data/lib/amp/commands/commands/version.rb +15 -1
- data/lib/amp/commands/commands/workflow.rb +3 -3
- data/lib/amp/commands/commands/workflows/git/add.rb +3 -3
- data/lib/amp/commands/commands/workflows/git/copy.rb +1 -1
- data/lib/amp/commands/commands/workflows/git/rm.rb +4 -2
- data/lib/amp/commands/commands/workflows/hg/add.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/addremove.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/annotate.rb +8 -2
- data/lib/amp/commands/commands/workflows/hg/bisect.rb +253 -0
- data/lib/amp/commands/commands/workflows/hg/branch.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/branches.rb +3 -3
- data/lib/amp/commands/commands/workflows/hg/bundle.rb +3 -3
- data/lib/amp/commands/commands/workflows/hg/clone.rb +4 -5
- data/lib/amp/commands/commands/workflows/hg/commit.rb +37 -1
- data/lib/amp/commands/commands/workflows/hg/copy.rb +2 -1
- data/lib/amp/commands/commands/workflows/hg/debug/index.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/diff.rb +3 -8
- data/lib/amp/commands/commands/workflows/hg/forget.rb +5 -4
- data/lib/amp/commands/commands/workflows/hg/identify.rb +6 -6
- data/lib/amp/commands/commands/workflows/hg/import.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/incoming.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/log.rb +5 -4
- data/lib/amp/commands/commands/workflows/hg/merge.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/move.rb +5 -3
- data/lib/amp/commands/commands/workflows/hg/outgoing.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/push.rb +6 -7
- data/lib/amp/commands/commands/workflows/hg/remove.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/resolve.rb +6 -23
- data/lib/amp/commands/commands/workflows/hg/root.rb +1 -2
- data/lib/amp/commands/commands/workflows/hg/status.rb +21 -12
- data/lib/amp/commands/commands/workflows/hg/tag.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/untrack.rb +12 -0
- data/lib/amp/commands/commands/workflows/hg/verify.rb +13 -3
- data/lib/amp/commands/commands/workflows/hg/what_changed.rb +18 -0
- data/lib/amp/commands/dispatch.rb +12 -13
- data/lib/amp/dependencies/amp_support.rb +1 -1
- data/lib/amp/dependencies/amp_support/ruby_amp_support.rb +1 -0
- data/lib/amp/dependencies/maruku.rb +136 -0
- data/lib/amp/dependencies/maruku/attributes.rb +227 -0
- data/lib/amp/dependencies/maruku/defaults.rb +71 -0
- data/lib/amp/dependencies/maruku/errors_management.rb +92 -0
- data/lib/amp/dependencies/maruku/helpers.rb +260 -0
- data/lib/amp/dependencies/maruku/input/charsource.rb +326 -0
- data/lib/amp/dependencies/maruku/input/extensions.rb +69 -0
- data/lib/amp/dependencies/maruku/input/html_helper.rb +189 -0
- data/lib/amp/dependencies/maruku/input/linesource.rb +111 -0
- data/lib/amp/dependencies/maruku/input/parse_block.rb +615 -0
- data/lib/amp/dependencies/maruku/input/parse_doc.rb +234 -0
- data/lib/amp/dependencies/maruku/input/parse_span_better.rb +746 -0
- data/lib/amp/dependencies/maruku/input/rubypants.rb +225 -0
- data/lib/amp/dependencies/maruku/input/type_detection.rb +147 -0
- data/lib/amp/dependencies/maruku/input_textile2/t2_parser.rb +163 -0
- data/lib/amp/dependencies/maruku/maruku.rb +33 -0
- data/lib/amp/dependencies/maruku/output/to_ansi.rb +223 -0
- data/lib/amp/dependencies/maruku/output/to_html.rb +991 -0
- data/lib/amp/dependencies/maruku/output/to_markdown.rb +164 -0
- data/lib/amp/dependencies/maruku/output/to_s.rb +56 -0
- data/lib/amp/dependencies/maruku/string_utils.rb +191 -0
- data/lib/amp/dependencies/maruku/structures.rb +167 -0
- data/lib/amp/dependencies/maruku/structures_inspect.rb +87 -0
- data/lib/amp/dependencies/maruku/structures_iterators.rb +61 -0
- data/lib/amp/dependencies/maruku/textile2.rb +1 -0
- data/lib/amp/dependencies/maruku/toc.rb +199 -0
- data/lib/amp/dependencies/maruku/usage/example1.rb +33 -0
- data/lib/amp/dependencies/maruku/version.rb +40 -0
- data/lib/amp/dependencies/priority_queue.rb +2 -1
- data/lib/amp/dependencies/python_config.rb +2 -1
- data/lib/amp/graphs/ancestor.rb +2 -1
- data/lib/amp/graphs/copies.rb +236 -233
- data/lib/amp/help/entries/__default__.erb +31 -0
- data/lib/amp/help/entries/commands.erb +6 -0
- data/lib/amp/help/entries/mdtest.md +35 -0
- data/lib/amp/help/entries/silly +3 -0
- data/lib/amp/help/help.rb +288 -0
- data/lib/amp/profiling_hacks.rb +5 -3
- data/lib/amp/repository/abstract/abstract_changeset.rb +97 -0
- data/lib/amp/repository/abstract/abstract_local_repo.rb +181 -0
- data/lib/amp/repository/abstract/abstract_staging_area.rb +180 -0
- data/lib/amp/repository/abstract/abstract_versioned_file.rb +100 -0
- data/lib/amp/repository/abstract/common_methods/changeset.rb +75 -0
- data/lib/amp/repository/abstract/common_methods/local_repo.rb +277 -0
- data/lib/amp/repository/abstract/common_methods/staging_area.rb +233 -0
- data/lib/amp/repository/abstract/common_methods/versioned_file.rb +71 -0
- data/lib/amp/repository/generic_repo_picker.rb +78 -0
- data/lib/amp/repository/git/repo_format/changeset.rb +336 -0
- data/lib/amp/repository/git/repo_format/staging_area.rb +192 -0
- data/lib/amp/repository/git/repo_format/versioned_file.rb +119 -0
- data/lib/amp/repository/git/repositories/local_repository.rb +164 -0
- data/lib/amp/repository/git/repository.rb +41 -0
- data/lib/amp/repository/mercurial/encoding/mercurial_diff.rb +382 -0
- data/lib/amp/repository/mercurial/encoding/mercurial_patch.rb +1 -0
- data/lib/amp/repository/mercurial/encoding/patch.rb +294 -0
- data/lib/amp/repository/mercurial/encoding/pure_ruby/ruby_mercurial_patch.rb +124 -0
- data/lib/amp/repository/mercurial/merging/merge_ui.rb +327 -0
- data/lib/amp/repository/mercurial/merging/simple_merge.rb +452 -0
- data/lib/amp/repository/mercurial/repo_format/branch_manager.rb +266 -0
- data/lib/amp/repository/mercurial/repo_format/changeset.rb +768 -0
- data/lib/amp/repository/mercurial/repo_format/dir_state.rb +716 -0
- data/lib/amp/repository/mercurial/repo_format/journal.rb +218 -0
- data/lib/amp/repository/mercurial/repo_format/lock.rb +210 -0
- data/lib/amp/repository/mercurial/repo_format/merge_state.rb +228 -0
- data/lib/amp/repository/mercurial/repo_format/staging_area.rb +367 -0
- data/lib/amp/repository/mercurial/repo_format/store.rb +487 -0
- data/lib/amp/repository/mercurial/repo_format/tag_manager.rb +322 -0
- data/lib/amp/repository/mercurial/repo_format/updatable.rb +543 -0
- data/lib/amp/repository/mercurial/repo_format/updater.rb +848 -0
- data/lib/amp/repository/mercurial/repo_format/verification.rb +433 -0
- data/lib/amp/repository/mercurial/repositories/bundle_repository.rb +216 -0
- data/lib/amp/repository/mercurial/repositories/http_repository.rb +386 -0
- data/lib/amp/repository/mercurial/repositories/local_repository.rb +2034 -0
- data/lib/amp/repository/mercurial/repository.rb +119 -0
- data/lib/amp/repository/mercurial/revlogs/bundle_revlogs.rb +249 -0
- data/lib/amp/repository/mercurial/revlogs/changegroup.rb +217 -0
- data/lib/amp/repository/mercurial/revlogs/changelog.rb +339 -0
- data/lib/amp/repository/mercurial/revlogs/file_log.rb +152 -0
- data/lib/amp/repository/mercurial/revlogs/index.rb +500 -0
- data/lib/amp/repository/mercurial/revlogs/manifest.rb +201 -0
- data/lib/amp/repository/mercurial/revlogs/node.rb +20 -0
- data/lib/amp/repository/mercurial/revlogs/revlog.rb +1026 -0
- data/lib/amp/repository/mercurial/revlogs/revlog_support.rb +129 -0
- data/lib/amp/repository/mercurial/revlogs/versioned_file.rb +597 -0
- data/lib/amp/repository/repository.rb +11 -88
- data/lib/amp/server/extension/amp_extension.rb +3 -3
- data/lib/amp/server/fancy_http_server.rb +1 -1
- data/lib/amp/server/fancy_views/_browser.haml +1 -1
- data/lib/amp/server/fancy_views/_diff_file.haml +1 -8
- data/lib/amp/server/fancy_views/changeset.haml +2 -2
- data/lib/amp/server/fancy_views/file.haml +1 -1
- data/lib/amp/server/fancy_views/file_diff.haml +1 -1
- data/lib/amp/support/amp_ui.rb +13 -29
- data/lib/amp/support/generator.rb +1 -1
- data/lib/amp/support/loaders.rb +1 -2
- data/lib/amp/support/logger.rb +10 -16
- data/lib/amp/support/match.rb +18 -4
- data/lib/amp/support/mercurial/ignore.rb +151 -0
- data/lib/amp/support/openers.rb +8 -3
- data/lib/amp/support/support.rb +91 -46
- data/lib/amp/templates/{blank.commit.erb → mercurial/blank.commit.erb} +0 -0
- data/lib/amp/templates/{blank.log.erb → mercurial/blank.log.erb} +0 -0
- data/lib/amp/templates/{default.commit.erb → mercurial/default.commit.erb} +0 -0
- data/lib/amp/templates/{default.log.erb → mercurial/default.log.erb} +0 -0
- data/lib/amp/templates/template.rb +18 -18
- data/man/amp.1 +51 -0
- data/site/src/about/commands.haml +1 -1
- data/site/src/css/amp.css +1 -1
- data/site/src/index.haml +3 -3
- data/tasks/man.rake +39 -0
- data/tasks/stats.rake +1 -10
- data/tasks/yard.rake +1 -50
- data/test/dirstate_tests/test_dir_state.rb +10 -8
- data/test/functional_tests/annotate.out +31 -0
- data/test/functional_tests/test_functional.rb +155 -63
- data/test/localrepo_tests/ampfile.rb +12 -0
- data/test/localrepo_tests/test_local_repo.rb +56 -57
- data/test/manifest_tests/test_manifest.rb +3 -5
- data/test/merge_tests/test_merge.rb +3 -3
- data/test/revlog_tests/test_revlog.rb +14 -6
- data/test/store_tests/test_fncache_store.rb +19 -19
- data/test/test_19_compatibility.rb +46 -0
- data/test/test_base85.rb +2 -2
- data/test/test_bdiff.rb +2 -2
- data/test/test_changegroup.rb +59 -0
- data/test/test_commands.rb +2 -2
- data/test/test_difflib.rb +2 -2
- data/test/test_generator.rb +34 -0
- data/test/test_ignore.rb +203 -0
- data/test/test_journal.rb +18 -13
- data/test/test_match.rb +2 -2
- data/test/test_mdiff.rb +3 -3
- data/test/test_mpatch.rb +3 -3
- data/test/test_multi_io.rb +40 -0
- data/test/test_support.rb +18 -2
- data/test/test_templates.rb +38 -0
- data/test/test_ui.rb +79 -0
- data/test/testutilities.rb +56 -0
- metadata +168 -49
- data/ext/amp/bz2/mkmf.log +0 -38
- data/lib/amp/encoding/mercurial_diff.rb +0 -378
- data/lib/amp/encoding/mercurial_patch.rb +0 -1
- data/lib/amp/encoding/patch.rb +0 -292
- data/lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb +0 -123
- data/lib/amp/merges/merge_state.rb +0 -164
- data/lib/amp/merges/merge_ui.rb +0 -322
- data/lib/amp/merges/simple_merge.rb +0 -450
- data/lib/amp/repository/branch_manager.rb +0 -234
- data/lib/amp/repository/dir_state.rb +0 -950
- data/lib/amp/repository/journal.rb +0 -203
- data/lib/amp/repository/lock.rb +0 -207
- data/lib/amp/repository/repositories/bundle_repository.rb +0 -214
- data/lib/amp/repository/repositories/http_repository.rb +0 -377
- data/lib/amp/repository/repositories/local_repository.rb +0 -2661
- data/lib/amp/repository/store.rb +0 -485
- data/lib/amp/repository/tag_manager.rb +0 -319
- data/lib/amp/repository/updatable.rb +0 -532
- data/lib/amp/repository/verification.rb +0 -431
- data/lib/amp/repository/versioned_file.rb +0 -475
- data/lib/amp/revlogs/bundle_revlogs.rb +0 -246
- data/lib/amp/revlogs/changegroup.rb +0 -217
- data/lib/amp/revlogs/changelog.rb +0 -338
- data/lib/amp/revlogs/changeset.rb +0 -521
- data/lib/amp/revlogs/file_log.rb +0 -165
- data/lib/amp/revlogs/index.rb +0 -493
- data/lib/amp/revlogs/manifest.rb +0 -195
- data/lib/amp/revlogs/node.rb +0 -18
- data/lib/amp/revlogs/revlog.rb +0 -1045
- data/lib/amp/revlogs/revlog_support.rb +0 -126
- data/lib/amp/support/ignore.rb +0 -144
- data/site/Rakefile +0 -38
- data/test/test_amp.rb +0 -9
- data/test/test_helper.rb +0 -15
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
module Diffs
|
|
3
|
+
module Mercurial
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This handles applying patches in mercurial. yay!!!!
|
|
7
|
+
module MercurialPatch
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# This attempts to apply a series of patches in time proportional to
|
|
11
|
+
# the total size of the patches, rather than patches * len(text). This
|
|
12
|
+
# means rather than shuffling strings around, we shuffle around
|
|
13
|
+
# pointers to fragments with fragment lists.
|
|
14
|
+
#
|
|
15
|
+
# When the fragment lists get too long, we collapse them. To do this
|
|
16
|
+
# efficiently, we do all our operations inside a buffer created by
|
|
17
|
+
# mmap and simply use memmove. This avoids creating a bunch of large
|
|
18
|
+
# temporary string buffers.
|
|
19
|
+
#
|
|
20
|
+
# UPDATE 2AM BEFORE I GO BACK TO SCHOOL
|
|
21
|
+
# I FUCKING HATE PYTHON
|
|
22
|
+
def self.apply_patches(source, patches)
|
|
23
|
+
return source if patches.empty?
|
|
24
|
+
patch_lens = patches.map {|patch| patch.size}
|
|
25
|
+
pl = patch_lens.sum
|
|
26
|
+
bl = source.size + pl
|
|
27
|
+
tl = bl + bl + pl
|
|
28
|
+
b1, b2 = 0, bl
|
|
29
|
+
|
|
30
|
+
return a if tl == 0 #empty patches. lame.
|
|
31
|
+
|
|
32
|
+
output = StringIO.new "",(ruby_19? ? "r+:ASCII-8BIT" : "r+")
|
|
33
|
+
output.write source
|
|
34
|
+
|
|
35
|
+
frags = [[source.size, b1]]
|
|
36
|
+
|
|
37
|
+
pos = b2 + bl
|
|
38
|
+
output.seek pos
|
|
39
|
+
patches.each {|patch| output.write(patch)}
|
|
40
|
+
patch_lens.each do |plen|
|
|
41
|
+
if frags.size > 128
|
|
42
|
+
b2, b1 = b1, b2
|
|
43
|
+
frags = [self.collect(output,b1,frags)]
|
|
44
|
+
end
|
|
45
|
+
newarr = []
|
|
46
|
+
endpt = pos + plen
|
|
47
|
+
last = 0
|
|
48
|
+
while pos < endpt
|
|
49
|
+
output.seek pos
|
|
50
|
+
p1, p2, l = output.read(12).unpack("NNN")
|
|
51
|
+
self.pull(newarr, frags, p1 - last)
|
|
52
|
+
self.pull([], frags, p2 - p1)
|
|
53
|
+
newarr << [l, pos + 12]
|
|
54
|
+
pos += l + 12
|
|
55
|
+
last = p2
|
|
56
|
+
end
|
|
57
|
+
frags = newarr + frags
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
t = self.collect output, b2, frags
|
|
61
|
+
output.seek t[1]
|
|
62
|
+
output.read t[0]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def self.patched_size(orig, delta)
|
|
67
|
+
outlen, last, bin = 0, 0, 0
|
|
68
|
+
binend = delta.size
|
|
69
|
+
data = 12 # size of the delta instruction values (3 longs)
|
|
70
|
+
while data <= binend
|
|
71
|
+
decode = delta[bin..(bin+11)]
|
|
72
|
+
start, endpt, length = decode.unpack("NNN")
|
|
73
|
+
break if start > endpt
|
|
74
|
+
|
|
75
|
+
bin = data + length
|
|
76
|
+
data = bin + 12
|
|
77
|
+
outlen += start - last
|
|
78
|
+
last = endpt
|
|
79
|
+
outlen += length
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
raise "patch cannot be decoded" if bin != binend
|
|
83
|
+
|
|
84
|
+
outlen += orig - last
|
|
85
|
+
outlen
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def self.copy_block(io, destination, source, count)
|
|
89
|
+
io.seek(source)
|
|
90
|
+
buf = io.read(count)
|
|
91
|
+
io.seek(destination)
|
|
92
|
+
io.write(buf)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
#
|
|
97
|
+
def self.pull(dst, src, l)
|
|
98
|
+
until l == 0
|
|
99
|
+
f = src.shift
|
|
100
|
+
if f[0] > l
|
|
101
|
+
src.unshift [f[0] - l, f[1] + l]
|
|
102
|
+
dst << [l, f[1]]
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
dst << f
|
|
106
|
+
l -= f[0]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
##
|
|
111
|
+
# Takes the fragments we've accumulated and applies them all to the IO.
|
|
112
|
+
def self.collect(io, buf, list)
|
|
113
|
+
start = buf
|
|
114
|
+
list.each do |l, p|
|
|
115
|
+
self.copy_block(io, buf, p, l)
|
|
116
|
+
buf += l
|
|
117
|
+
end
|
|
118
|
+
[buf - start, start]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
|
|
3
|
+
module Amp
|
|
4
|
+
module Merges
|
|
5
|
+
module Mercurial
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# This module handles figuring out how to merge files using the user's
|
|
9
|
+
# preferences. It is mixed into the UI class. The UI class must implement
|
|
10
|
+
# the "config" method.
|
|
11
|
+
module MergeUI
|
|
12
|
+
extend self
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Performs a 3-way merge in the working directory from vf_local to vf_other,
|
|
16
|
+
# using the common ancestor vf_ancestor.
|
|
17
|
+
#
|
|
18
|
+
# @todo change 1s and 0s to bools
|
|
19
|
+
# @todo consistent return type
|
|
20
|
+
#
|
|
21
|
+
# @param [Repository] repo the repository in which we are merging files
|
|
22
|
+
# @param [String] parent_node the node_id of the parent node before the merge
|
|
23
|
+
# @param [String] original_fn the original local filename before the merge
|
|
24
|
+
# @param [WorkingVersionedFile] vf_local the current, working-directory versioned file
|
|
25
|
+
# @param [VersionedFile] vf_other the file's changeset to which we are migrating
|
|
26
|
+
# @param [VersionedFile] vf_ancestor the common ancestor between vf_local and vf_other
|
|
27
|
+
# @return [Boolean] true if there were conflicts during the merge
|
|
28
|
+
def file_merge(repo, parent_node, original_fn, vf_local, vf_other, vf_ancestor)
|
|
29
|
+
is_binary = proc {|ctx| ctx.data.binary? rescue false}
|
|
30
|
+
|
|
31
|
+
return nil if !(vf_other.cmp vf_local.data)
|
|
32
|
+
|
|
33
|
+
path = vf_local.path
|
|
34
|
+
binary = is_binary[vf_local] || is_binary[vf_other] || is_binary[vf_ancestor]
|
|
35
|
+
symlink = (vf_local.flags + vf_other.flags).include? "l"
|
|
36
|
+
|
|
37
|
+
tool, tool_path = pick_tool(repo, path, binary, symlink)
|
|
38
|
+
UI.status("Picked tool #{tool} for #{path} (binary #{binary} symlink #{symlink})")
|
|
39
|
+
|
|
40
|
+
unless tool
|
|
41
|
+
tool = "internal:local"
|
|
42
|
+
if UI.ask("no tool found to merge #{path}\n"+
|
|
43
|
+
"keep (l)ocal or take (o)ther?") != "l"
|
|
44
|
+
tool = "internal:other"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
case tool
|
|
49
|
+
when "internal:local"
|
|
50
|
+
return 0
|
|
51
|
+
when "internal:other"
|
|
52
|
+
repo.working_write(path, vf_other.data, vf_other.flags)
|
|
53
|
+
return 0
|
|
54
|
+
when "internal:fail"
|
|
55
|
+
return 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
a = repo.working_join(path)
|
|
59
|
+
b_file = save_versioned_file_temp("base", vf_ancestor)
|
|
60
|
+
c_file = save_versioned_file_temp("other", vf_other)
|
|
61
|
+
b, c = b_file.path, c_file.path
|
|
62
|
+
|
|
63
|
+
out = ""
|
|
64
|
+
back = a + ".orig" + File.extname(a)
|
|
65
|
+
File.copy(a, back)
|
|
66
|
+
|
|
67
|
+
if original_fn != vf_other.path
|
|
68
|
+
UI.status("merging #{original_fn} and #{vf_other.path} to #{path}")
|
|
69
|
+
else
|
|
70
|
+
UI.status("merging #{path}")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if tool_setting(tool, "premerge", !(binary || symlink))
|
|
74
|
+
ret = ThreeWayMerger.three_way_merge(a, b, c, :quiet => true)
|
|
75
|
+
unless ret
|
|
76
|
+
UI.debug("premerge successful")
|
|
77
|
+
File.unlink(back)
|
|
78
|
+
File.safe_unlink(b)
|
|
79
|
+
File.safe_unlink(c)
|
|
80
|
+
return false
|
|
81
|
+
end
|
|
82
|
+
File.copy(back, a) # restore frmo backup and try again
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
environment = {"HG_FILE" => path,
|
|
86
|
+
"HG_MY_NODE" => parent_node.hexlify[0..11],
|
|
87
|
+
"HG_OTHER_NODE" => vf_other.changeset.to_s,
|
|
88
|
+
"HG_MY_ISLINK" => vf_local.flags.include?("l"),
|
|
89
|
+
"HG_OTHER_ISLINK" => vf_other.flags.include?("l"),
|
|
90
|
+
"HG_BASE_ISLINK" => vf_ancestor.flags.include?("l")}
|
|
91
|
+
if tool == "internal:merge"
|
|
92
|
+
ret = ThreeWayMerger.three_way_merge(a, b, c, :label => ['local', 'other'])
|
|
93
|
+
else
|
|
94
|
+
args = tool_setting_string(tool, "args", "$local $base $other")
|
|
95
|
+
if args.include?("$output")
|
|
96
|
+
out, a = a, back # read input from backup, write to original
|
|
97
|
+
end
|
|
98
|
+
replace = {"local" => a, "base" => b, "other" => c, "output" => out}
|
|
99
|
+
args.gsub!(/\$(local|base|other|output)/) { replace[$1]}
|
|
100
|
+
# shelling out
|
|
101
|
+
ret = Amp::Support::system(tool_path+" "+args, :chdir => repo.root, :environ => environment)
|
|
102
|
+
end
|
|
103
|
+
ret = (ret == true ? 1 : (ret == false ? 0 : ret))
|
|
104
|
+
if ret == 0 && tool_setting(tool, "checkconflicts")
|
|
105
|
+
if vf_local.data =~ /^(<<<<<<< .*|=======|>>>>>>> .*)$/
|
|
106
|
+
ret = 1
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if ret == 0 && tool_setting(tool, "checkchanged")
|
|
111
|
+
if File.stat(repo.working_join(path)) === File.stat(back)
|
|
112
|
+
if UI::yes_or_no "output file #{path} appears unchanged\nwas merge successful?"
|
|
113
|
+
r = 1
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
fix_end_of_lines(repo.working_join(path), back) if tool_setting(tool, "fixeol")
|
|
119
|
+
|
|
120
|
+
if ret == 1
|
|
121
|
+
UI::warn "merging #{path} failed!"
|
|
122
|
+
else
|
|
123
|
+
File.unlink back
|
|
124
|
+
end
|
|
125
|
+
File.unlink b
|
|
126
|
+
File.unlink c
|
|
127
|
+
|
|
128
|
+
!ret.zero? # return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
def save_versioned_file_temp(prefix, versioned_file)
|
|
134
|
+
prefix = "#{File.basename versioned_file.path}~#{prefix}"
|
|
135
|
+
|
|
136
|
+
tempfile = Tempfile.new prefix
|
|
137
|
+
path = tempfile.path
|
|
138
|
+
tempfile.write versioned_file.data
|
|
139
|
+
tempfile.close false # DON'T unlink it
|
|
140
|
+
|
|
141
|
+
tempfile
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
# Converts the end-of-line characters in a file to match the original file.
|
|
146
|
+
# Thus, if we merge from our copy to a new one, and there foreign
|
|
147
|
+
# end-of-line characters got merged in, we want to nuke them and put in our own!
|
|
148
|
+
#
|
|
149
|
+
# @param [String] new_file the path to the newly merged file
|
|
150
|
+
# @param [String] original_file the path to the original file
|
|
151
|
+
def fix_end_of_lines(new_file, original_file)
|
|
152
|
+
new_eol = guess_end_of_line(File.read(original_file))
|
|
153
|
+
if new_eol
|
|
154
|
+
data = File.read(new_file)
|
|
155
|
+
old_eol = guess_end_of_line(data)
|
|
156
|
+
if old_eol
|
|
157
|
+
new_data = data.gsub(old_eol, new_eol)
|
|
158
|
+
|
|
159
|
+
File.open(file, "w") {|f| f.write new_data } if new_data != data
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
##
|
|
166
|
+
# Guesses the end-of-line character for a file in a very lazy fashion.
|
|
167
|
+
#
|
|
168
|
+
# @param [String] data the file data to guess from
|
|
169
|
+
# @return [String, nil] the guessed end-of-line character(s).
|
|
170
|
+
def guess_end_of_line(data)
|
|
171
|
+
return nil if data.include?("\0") # binary
|
|
172
|
+
return "\r\n" if data.include?("\r\n") # windows
|
|
173
|
+
return "\r" if data.include?("\r") # old mac
|
|
174
|
+
return "\n" if data.include?("\n") # *nix
|
|
175
|
+
return nil # wtf?
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def config; UI.config; end
|
|
179
|
+
|
|
180
|
+
##
|
|
181
|
+
# Picks a merge tool based on the user's settings in hgrc files and environment
|
|
182
|
+
# variables. Returns a hash specifying both the name and path of the
|
|
183
|
+
# merge tool's executable.
|
|
184
|
+
#
|
|
185
|
+
# @todo merge-patterns, line 56 of filemerge.py
|
|
186
|
+
# @param [Repository] repo the repository we are performing a merge upon
|
|
187
|
+
# @param [String] path the path to the file we're merging
|
|
188
|
+
# @param [Boolean] binary is the file a binary file?
|
|
189
|
+
# @param [Boolean] symlink is the file a symlink?
|
|
190
|
+
# @return [Hash] keyed as follows:
|
|
191
|
+
# :name => the name of the chosen tool
|
|
192
|
+
# :path => the path to the tool (if an executable is to be used)
|
|
193
|
+
def pick_tool(repo, path, binary, symlink)
|
|
194
|
+
hgmerge = ENV["HGMERGE"]
|
|
195
|
+
return [hgmerge, hgmerge] if hgmerge
|
|
196
|
+
|
|
197
|
+
# @todo: add merge-patterns support
|
|
198
|
+
|
|
199
|
+
# scan the merge-tools section
|
|
200
|
+
tools = {}
|
|
201
|
+
config["merge-tools"].each do |k, v|
|
|
202
|
+
t = k.split(".").first
|
|
203
|
+
unless tools[t]
|
|
204
|
+
tools[t] = tool_setting_string(t, "priority", "0").to_i
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# go through the list of tools and sort by priority
|
|
209
|
+
tool_names = tools.keys
|
|
210
|
+
tools = tools.map {|tool, prio| [-prio, tool]}.sort
|
|
211
|
+
# check the [ui] section for a "merge" setting
|
|
212
|
+
uimerge = config["ui","merge"]
|
|
213
|
+
if uimerge
|
|
214
|
+
unless tool_names.include?(uimerge)
|
|
215
|
+
return [uimerge, uimerge]
|
|
216
|
+
end
|
|
217
|
+
tools.unshift([nil, uimerge]) # highest priority
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# add the "hgmerge" binary
|
|
221
|
+
tools << [nil, "hgmerge"] # the old default, if found
|
|
222
|
+
# check everything in our list, and if we actually find one that works,
|
|
223
|
+
# return it
|
|
224
|
+
tools.each do |priority, tool|
|
|
225
|
+
if check_tool(tool, nil, symlink, binary)
|
|
226
|
+
tool_path = find_tool(tool)
|
|
227
|
+
return [tool, "\"#{tool_path}\""]
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
# last but not least, do a simple_merge.
|
|
231
|
+
return (!symlink && !binary) ? "internal:merge" : [nil, nil]
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
##
|
|
235
|
+
# Quick access to the merge-tools section of the configuration files.
|
|
236
|
+
# A merge tool will set it up with data like this:
|
|
237
|
+
# [merge-tools]
|
|
238
|
+
# awesometool.executable = /usr/bin/awesometool
|
|
239
|
+
# awesometool.regkey = HKEY_USELESS_INFO
|
|
240
|
+
# and so on. This method abstracts away the scheme for encoding this information
|
|
241
|
+
# gets string values from the configuration.
|
|
242
|
+
#
|
|
243
|
+
# @param [String] tool the name of the tool to look up data for
|
|
244
|
+
# @param [String] part the specific information about the tool to look up
|
|
245
|
+
# @param [String] default the default value, if the configuration setting
|
|
246
|
+
# can't be found
|
|
247
|
+
# @return [String] the setting for the given merge tool we're looking up, as
|
|
248
|
+
# as a string.
|
|
249
|
+
def tool_setting_string(tool, part, default="")
|
|
250
|
+
config["merge-tools", "#{tool}.#{part}", String, default]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
##
|
|
254
|
+
# Quick access to the merge-tools section of the configuration files.
|
|
255
|
+
# Returns boolean values.
|
|
256
|
+
#
|
|
257
|
+
# @see check_tool_string
|
|
258
|
+
# @param [String] tool the name of the tool to look up data for
|
|
259
|
+
# @param [String] part the specific information about the tool to look up
|
|
260
|
+
# @param [Boolean] default the default value, if the configuration setting
|
|
261
|
+
# can't be found
|
|
262
|
+
# @return [Boolean] the setting for the given merge tool we're looking up, as
|
|
263
|
+
# as a string.
|
|
264
|
+
def tool_setting(tool, part, default=false)
|
|
265
|
+
config["merge-tools", "#{tool}.#{part}", Boolean, default]
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
##
|
|
269
|
+
# Given the name of a merge tool, attempt to locate an executable file
|
|
270
|
+
# for the tool.
|
|
271
|
+
#
|
|
272
|
+
# @param [String] tool the name of the merge tool to locate
|
|
273
|
+
# @return [String] the path to the executable for the merge tool, or nil
|
|
274
|
+
# if the tool cannot be found
|
|
275
|
+
def find_tool(tool)
|
|
276
|
+
if ["internal:fail", "internal:local", "internal:other"].include?(tool)
|
|
277
|
+
return tool
|
|
278
|
+
end
|
|
279
|
+
# windows stuff
|
|
280
|
+
k = tool_setting_string(tool, "regkey")
|
|
281
|
+
if k && k.any?
|
|
282
|
+
p = File.amp_lookup_reg(k, tool_setting_string(tool, "regname"))
|
|
283
|
+
if p && p.any?
|
|
284
|
+
p = File.amp_find_executable(p + check_tool_string(tool, "regappend"))
|
|
285
|
+
if p
|
|
286
|
+
return p
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
# normal *nix lookup
|
|
291
|
+
return File.amp_find_executable(tool_setting_string(tool, "executable", tool))
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
##
|
|
295
|
+
# Checks to see if a given tool is available given the necessary settings.
|
|
296
|
+
#
|
|
297
|
+
# @todo add GUI check
|
|
298
|
+
# @param [String] tool the name of the tool we want to check
|
|
299
|
+
# @param [String] pat the pattern we matched to get here. Could be nil.
|
|
300
|
+
# @param [Boolean] symlink are we merging across a symlink here?
|
|
301
|
+
# @param [Boolean] binary are we merging a binary file? you crazy?!
|
|
302
|
+
# @return [Boolean] is the given tool available?
|
|
303
|
+
def check_tool(tool, pat, symlink, binary)
|
|
304
|
+
tool_msg = tool
|
|
305
|
+
tool_msg += " specified for " + pat if pat
|
|
306
|
+
|
|
307
|
+
if !(find_tool tool)
|
|
308
|
+
if pat
|
|
309
|
+
UI.warn("couldn't find merge tool #{tool}")
|
|
310
|
+
else
|
|
311
|
+
UI.note("couldn't find merge tool #{tool}")
|
|
312
|
+
end
|
|
313
|
+
elsif symlink && !(tool_setting(tool, "symlink"))
|
|
314
|
+
UI.warn("tool #{tool} can't handle symlinks")
|
|
315
|
+
elsif binary && !(tool_setting(tool, "binary"))
|
|
316
|
+
UI.warn("tool #{tool} can't handle binary files")
|
|
317
|
+
elsif false # TODO: add GUI check
|
|
318
|
+
else
|
|
319
|
+
return true
|
|
320
|
+
end
|
|
321
|
+
return false # we're here if any of the previous checks created a warning
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|