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,339 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
module Mercurial
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# This is used for faking data writing, until we're totally done
|
|
6
|
+
# accumulating data.
|
|
7
|
+
class FakeFileAppender
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Initializes the fake file with the pointer to the real deal,
|
|
11
|
+
# and also the current data
|
|
12
|
+
def initialize(fp, buffer, size)
|
|
13
|
+
@data = buffer
|
|
14
|
+
@fp = fp
|
|
15
|
+
@offset = fp.tell
|
|
16
|
+
@size = size
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Returns the endpoint of the data in the (fake) file
|
|
21
|
+
def endpt
|
|
22
|
+
@size + @data.join.size
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Returns the current offset of the (fake) file
|
|
27
|
+
def tell
|
|
28
|
+
@offset
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Nothing, since we don't flush, we just sit here
|
|
33
|
+
def flush; end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Closes the real file pointer for this fake file
|
|
37
|
+
def close
|
|
38
|
+
@fp.close
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# Seeks to the position requested. We're faking this, but it's a little
|
|
43
|
+
# tougher, because if we break the fake file down like this:
|
|
44
|
+
#
|
|
45
|
+
# [ actual file size = 10 | pending data size = 10 ]
|
|
46
|
+
#
|
|
47
|
+
# If the user seeks to 15, we need to make sure we don't try to seek to
|
|
48
|
+
# 15 in the file, as that would cause errors.
|
|
49
|
+
def seek(offset, whence)
|
|
50
|
+
if whence == IO::SEEK_SET
|
|
51
|
+
@offset = offset
|
|
52
|
+
elsif whence == IO::SEEK_CUR
|
|
53
|
+
@offset += offset
|
|
54
|
+
elsif whence == IO::SEEK_END
|
|
55
|
+
@offset = self.endpt + offset
|
|
56
|
+
end
|
|
57
|
+
if @offset < @size
|
|
58
|
+
@fp.seek @offset
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Reads from the fake file, for _count_ bytes. This is a little sketchy
|
|
64
|
+
# because we might be reading some real data and some fake data, or all
|
|
65
|
+
# real, or all fake.
|
|
66
|
+
#
|
|
67
|
+
# @param [Integer] count how much to read. -1 will read it all.
|
|
68
|
+
# @return [String] the contents
|
|
69
|
+
def read(count=-1)
|
|
70
|
+
ret = ""
|
|
71
|
+
|
|
72
|
+
if @offset < @size
|
|
73
|
+
s = @fp.read(count)
|
|
74
|
+
ret = s
|
|
75
|
+
@offset += s.size
|
|
76
|
+
if count > 0
|
|
77
|
+
count -= s.size
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
unless count.zero?
|
|
82
|
+
doff = @offset - @size
|
|
83
|
+
@data.unshift @data.join
|
|
84
|
+
@data.delete_range(1..-1)
|
|
85
|
+
s = @data[0][doff..(doff+count-1)]
|
|
86
|
+
@offset += s.size
|
|
87
|
+
ret += s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
ret
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# Writes to the fake file. Notice - this will only work because we only
|
|
95
|
+
# append to the file - we don't write in the middle anywhere, or this
|
|
96
|
+
# scheme would fail.
|
|
97
|
+
#
|
|
98
|
+
# @param [#to_s] s data to write
|
|
99
|
+
def write(s)
|
|
100
|
+
@data << s.to_s
|
|
101
|
+
@offset += s.size
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class DelayedOpener
|
|
106
|
+
attr_accessor :default
|
|
107
|
+
|
|
108
|
+
##
|
|
109
|
+
# Initializes the delayed opener, needing the real deal, and the owner
|
|
110
|
+
# of the delayed opener.
|
|
111
|
+
#
|
|
112
|
+
# @param [Opener] realopener the actual opener. Since the DelayedOpener
|
|
113
|
+
# doesn't know how to open files, we'll need this!
|
|
114
|
+
# @param [ChangeLog] owner the owner of the delayed opener. This reference
|
|
115
|
+
# is needed because we need to check on the state of the delayed_buffer
|
|
116
|
+
# and what not.
|
|
117
|
+
def initialize(realopener, owner)
|
|
118
|
+
@real_opener, @owner = realopener, owner
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
##
|
|
122
|
+
# Specialized opener that will fake writing when asked to. We need to
|
|
123
|
+
# know who our owner is and we need a real opener so we can actually
|
|
124
|
+
# open files. The DelayedOpener doesn't know how to do real IO.
|
|
125
|
+
def open(name, mode="r")
|
|
126
|
+
fp = @real_opener.open(name, mode)
|
|
127
|
+
return fp if name != @owner.index_file
|
|
128
|
+
|
|
129
|
+
# Are we holding off on writing? if so, set up the file where we
|
|
130
|
+
# writing pending data.
|
|
131
|
+
|
|
132
|
+
if @owner.delay_count == 0
|
|
133
|
+
@owner.delay_name = File.amp_name(fp)
|
|
134
|
+
mode.gsub!(/a/, 'w') if @owner.empty?
|
|
135
|
+
return @real_opener.open(name+".a", mode) # See what I did there?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# FakeFileAppender = fake file so we don't do any real writing yet
|
|
139
|
+
size = File.stat(@real_opener.join(name)).size
|
|
140
|
+
ffa = FakeFileAppender.new(fp, @owner.delay_buffer, size)
|
|
141
|
+
|
|
142
|
+
return ffa
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
##
|
|
147
|
+
# A ChangeLog is a special revision log that stores the actual commit data,
|
|
148
|
+
# including usernames, dates, messages, all kinds of stuff.
|
|
149
|
+
#
|
|
150
|
+
# This version of the revision log is special though, because sometimes
|
|
151
|
+
# we have to hold off on writing until all other updates are done, for
|
|
152
|
+
# example during merges that might fail. So we have to actually have
|
|
153
|
+
# a real Opener and a fake one, which will save the data in memory.
|
|
154
|
+
# When you call #finalize, the fake file will replace the real deal.
|
|
155
|
+
class ChangeLog < Revlog
|
|
156
|
+
attr_accessor :delay_count, :delay_name, :index_file, :delay_buffer, :node_map
|
|
157
|
+
|
|
158
|
+
##
|
|
159
|
+
# Initializes the revision log. Just pass in an Opener. Amp::Opener.new(path)
|
|
160
|
+
# will do just fine.
|
|
161
|
+
#
|
|
162
|
+
# @param [Amp::Opener] opener an object that knows how to open
|
|
163
|
+
# and return files based on a root directory.
|
|
164
|
+
def initialize(opener)
|
|
165
|
+
super(opener, "00changelog.i")
|
|
166
|
+
@node_map = @index.node_map
|
|
167
|
+
end
|
|
168
|
+
alias_method :changelog_initialize, :initialize
|
|
169
|
+
|
|
170
|
+
##
|
|
171
|
+
# Tells the changelog to stop writing updates directly to the file,
|
|
172
|
+
# and start saving any new info to memory/other files. Used when the
|
|
173
|
+
# changelog has to be the last file saved.
|
|
174
|
+
def delay_update
|
|
175
|
+
@_real_opener = @opener
|
|
176
|
+
@opener = DelayedOpener.new(@_real_opener, self) # Our fake Opener
|
|
177
|
+
@delay_count = self.size
|
|
178
|
+
@delay_buffer = []
|
|
179
|
+
@delay_name = nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
##
|
|
183
|
+
# Finalizes the changelog by swapping out the fake file if it has to.
|
|
184
|
+
# If there's any other data left in the buffer, it will be written
|
|
185
|
+
# as well.
|
|
186
|
+
def finalize(journal)
|
|
187
|
+
if @delay_name
|
|
188
|
+
src = @_real_opener.join(@index_file+".a")
|
|
189
|
+
dest = @_real_opener.join(@index_file)
|
|
190
|
+
@opener = @_real_opener # switch back to normal mode....
|
|
191
|
+
return File.amp_force_rename(src, dest)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
if @delay_buffer && @delay_buffer.any?
|
|
195
|
+
@fp = open(@index_file, "a")
|
|
196
|
+
@fp.write @delay_buffer.join
|
|
197
|
+
@fp.close
|
|
198
|
+
@delay_buffer = []
|
|
199
|
+
end
|
|
200
|
+
# check_inline_size journal
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
##
|
|
204
|
+
# Reads while we're blocking this changelog's output.
|
|
205
|
+
# @param file the file to read in as a revision log
|
|
206
|
+
def read_pending(file)
|
|
207
|
+
r = Revlog.new(@opener, file)
|
|
208
|
+
@index = r.index
|
|
209
|
+
@node_map = r.index.node_map
|
|
210
|
+
@chunk_cache = r.chunk_cache
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
##
|
|
214
|
+
# Writes our data, while being aware of the delay buffer when we're holding
|
|
215
|
+
# off on finalizing the changelog.
|
|
216
|
+
def write_pending
|
|
217
|
+
if @delay_buffer && @delay_buffer.size > 0
|
|
218
|
+
fp1 = @_real_opener.open(@index_file)
|
|
219
|
+
fp2 = @_real_opener.open(@index_file + ".a", "w+")
|
|
220
|
+
UI.debug "trying to open #{@index_file + ".a"}..."
|
|
221
|
+
fp2.write fp1.read
|
|
222
|
+
fp2.write @delay_buffer.join
|
|
223
|
+
fp2.close
|
|
224
|
+
fp1.close
|
|
225
|
+
@delay_buffer = []
|
|
226
|
+
@delay_name = @index_file
|
|
227
|
+
end
|
|
228
|
+
return true if @delay_name && @delay_name.any?
|
|
229
|
+
false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
##
|
|
233
|
+
# Does a check on our size, but knows enough to quit if we're still in
|
|
234
|
+
# delayed-writing mode.
|
|
235
|
+
# @param [Amp::Mercurial::Journal] journal the journal to use to keep track of our transaction
|
|
236
|
+
# @param [File] fp the file pointer to use to check our size
|
|
237
|
+
def check_inline_size(journal, fp=nil)
|
|
238
|
+
return if @opener.is_a? DelayedOpener
|
|
239
|
+
super(journal, fp)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
##
|
|
243
|
+
# Decodes the extra data stored with the commit, such as requirements
|
|
244
|
+
# or just about anything else we need to save
|
|
245
|
+
# @param [String] text the data in the revision, decompressed
|
|
246
|
+
# @return [Hash] key-value pairs, joining each file with its extra data
|
|
247
|
+
def decode_extra(text)
|
|
248
|
+
extra = {}
|
|
249
|
+
text.split("\0").select {|l| l.any? }.
|
|
250
|
+
map {|l| l.remove_slashes.split(":",2) }.
|
|
251
|
+
each {|k,v| extra[k]=v }
|
|
252
|
+
extra
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
##
|
|
256
|
+
# Encodes the extra data in a format we can use for writing.
|
|
257
|
+
# @param [Hash] data the extra data to format
|
|
258
|
+
# @return [String] the encoded data
|
|
259
|
+
def encode_extra(data)
|
|
260
|
+
" " + data.sort.map {|k| "#{k}:#{data[k]}".add_slashes }.join("\0")
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
##
|
|
264
|
+
# Reads the revision at the given node_id. It returns it in a format
|
|
265
|
+
# that tells us everything about the revision - the manifest_entry, the user
|
|
266
|
+
# who committed it, timestamps, the relevant filenames, the description
|
|
267
|
+
# message, and any extra data.
|
|
268
|
+
#
|
|
269
|
+
# @todo Text encodings, I hate you. but i must do them
|
|
270
|
+
# @param [Fixnum] node the node ID to lookup into the revision log
|
|
271
|
+
# @return [(String, String, [Float, Integer], [String], String, Hash)]
|
|
272
|
+
# The format is [ManifestEntry, Username, [Time, Timezone], [Filenames],
|
|
273
|
+
# Message, ExtraData].
|
|
274
|
+
def read(node)
|
|
275
|
+
text = decompress_revision node
|
|
276
|
+
if text.nil? || text.empty?
|
|
277
|
+
return [NULL_ID, "", [0,0], [], "", {"branch" => "default"}]
|
|
278
|
+
end
|
|
279
|
+
#p text
|
|
280
|
+
last = text.index("\n\n")
|
|
281
|
+
desc = text[last+2..-1] #TODO: encoding
|
|
282
|
+
l = text[0..last].split("\n")
|
|
283
|
+
manifest = l[0].unhexlify
|
|
284
|
+
user = l[1] #TODO: encoding
|
|
285
|
+
extra_data = l[2].split(' ', 3)
|
|
286
|
+
if extra_data.size != 3
|
|
287
|
+
time = extra_data.shift.to_f
|
|
288
|
+
timezone = extra_data.shift.to_i
|
|
289
|
+
extra = {}
|
|
290
|
+
else
|
|
291
|
+
time, timezone, extra = extra_data
|
|
292
|
+
time, timezone = time.to_f, timezone.to_i
|
|
293
|
+
extra = decode_extra text
|
|
294
|
+
end
|
|
295
|
+
extra["branch"] = "default" unless extra["branch"]
|
|
296
|
+
|
|
297
|
+
files = l[3..-1]
|
|
298
|
+
|
|
299
|
+
[manifest, user, [time, timezone], files, desc, extra]
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
##
|
|
303
|
+
# Adds the given commit to the changelog.
|
|
304
|
+
#
|
|
305
|
+
# @todo Handle text encodings
|
|
306
|
+
# @todo figure out what the fuck is going on with these parameters
|
|
307
|
+
# @param [Amp::Mercurial::Manifest] manifest a hex-version of a node_id or something?
|
|
308
|
+
# @param [String] files the files relevant to the commit, to be included
|
|
309
|
+
# @param [String] desc the commit message from the user
|
|
310
|
+
# @param [Amp::Mercurial::Journal] journal the transaction journal to write to for rollbacks if
|
|
311
|
+
# something goes horribly wrong
|
|
312
|
+
# @param [String] p1 the first parent of this node
|
|
313
|
+
# @param [String] p2 the second parent of this node
|
|
314
|
+
# @param [Strng] user the username of the committer
|
|
315
|
+
# @param [Time] date the date of the commit
|
|
316
|
+
# @param [Hash] extra any extra data
|
|
317
|
+
def add(manifest, files, desc, journal, p1=nil, p2=nil, user=nil, date=nil, extra={})
|
|
318
|
+
user = user.strip
|
|
319
|
+
raise RevlogSupport::RevlogError.new("no \\n in username") if user=~ /\n/
|
|
320
|
+
user, desc = user, desc #TODO: encoding!
|
|
321
|
+
|
|
322
|
+
date = Time.now unless date
|
|
323
|
+
parsed_date = "#{date.to_i} #{-1 * date.utc_offset}"
|
|
324
|
+
|
|
325
|
+
if extra && ["default", "", nil].include?(extra["branch"])
|
|
326
|
+
extra.delete "branch"
|
|
327
|
+
end
|
|
328
|
+
if extra
|
|
329
|
+
extra = (extra.any?) ? encode_extra(extra) : ""
|
|
330
|
+
parsed_date = "#{parsed_date}#{extra}"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
l = [manifest.hexlify, user, parsed_date] + files.sort + ["", desc]
|
|
334
|
+
text = l.join "\n"
|
|
335
|
+
add_revision text, journal, self.size, p1, p2
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
module Mercurial
|
|
3
|
+
##
|
|
4
|
+
# = FileLog
|
|
5
|
+
# A FileLog is the revision log that stores revision history for
|
|
6
|
+
# each individual file tracked by the system. It stores special meta-data
|
|
7
|
+
# for handling files that have been copied over their history.
|
|
8
|
+
#
|
|
9
|
+
class FileLog < Revlog
|
|
10
|
+
##
|
|
11
|
+
# Initializes the revision log, being sure to encode directories
|
|
12
|
+
# to avoid naming conflicts
|
|
13
|
+
# @param [Opener] opener the opener to use for opening the file
|
|
14
|
+
# @param [String] path the path to the file, excluding "data".
|
|
15
|
+
#
|
|
16
|
+
def initialize(opener, path)
|
|
17
|
+
super(opener, ["data", encode_dir(path + ".i")].join("/"))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Encodes the directory to avoid naming conflicts
|
|
22
|
+
# @param [String] path the path to encode for naming conflict issues
|
|
23
|
+
# @return [String] the encoded directory path
|
|
24
|
+
#
|
|
25
|
+
def encode_dir(path)
|
|
26
|
+
path.gsub(".hg/",".hg.hg/").gsub(".i/",".i.hg/").gsub(".d/",".d.hg/")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Decodes the directory to avoid naming conflicts
|
|
31
|
+
# @param [String] path the path to decode for naming conflict issues
|
|
32
|
+
# @return [String] the decoded directory path
|
|
33
|
+
#
|
|
34
|
+
def decode_dir(path)
|
|
35
|
+
path.gsub(".d.hg/",".d/").gsub(".i.hg/",".i/").gsub(".hg.hg/",".hg/")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Reads the data of the revision, ignoring the meta data for copied files
|
|
40
|
+
# @param [String] node the node_id to read
|
|
41
|
+
# @return [String] the data of the revision
|
|
42
|
+
#
|
|
43
|
+
def read(node)
|
|
44
|
+
t = decompress_revision(node)
|
|
45
|
+
return t unless t.start_with?("\1\n")
|
|
46
|
+
|
|
47
|
+
start = t.index("\1\n", 2)
|
|
48
|
+
t[(start+2)..-1]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Reads the meta data in the node
|
|
53
|
+
# @param [String] node the node_id to read the meta of
|
|
54
|
+
# @return [Hash] the meta data in this revision. Could be empty hash.
|
|
55
|
+
#
|
|
56
|
+
def read_meta(node)
|
|
57
|
+
t = decompress_revision(node)
|
|
58
|
+
return {} unless t.start_with?("\1\n")
|
|
59
|
+
|
|
60
|
+
start = t.index("\1\n", 2)
|
|
61
|
+
mt = t[2..(start-1)]
|
|
62
|
+
m = {}
|
|
63
|
+
mt.split("\n").each do |l|
|
|
64
|
+
k, v = l.split(": ", 2)
|
|
65
|
+
m[k] = v
|
|
66
|
+
end
|
|
67
|
+
m
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
# Adds a revision to the file's history. Overridden for special metadata
|
|
72
|
+
#
|
|
73
|
+
# @param [String] text the new text of the file
|
|
74
|
+
# @param [Hash] meta the meta data to use (if we copied)
|
|
75
|
+
# @param [Journal] journal for aborting transaction
|
|
76
|
+
# @param [Integer] link the revision number this is linked to
|
|
77
|
+
# @param [Integer] p1 (nil) the first parent of this new revision
|
|
78
|
+
# @param [Integer] p2 (nil) the second parent of this new revision
|
|
79
|
+
# @param [String] digest referring to the node this makes
|
|
80
|
+
def add(text, meta, journal, link, p1=nil, p2=nil)
|
|
81
|
+
if (meta && meta.any?) || text.start_with?("\1\n")
|
|
82
|
+
mt = ""
|
|
83
|
+
mt = meta.map {|k, v| "#{k}: #{v}\n"} if meta
|
|
84
|
+
text = "\1\n" + mt.join + "\1\n" + text
|
|
85
|
+
end
|
|
86
|
+
add_revision(text, journal, link, p1, p2)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# Returns whether or not the file at _node_ has been renamed or
|
|
91
|
+
# copied in the immediate revision.
|
|
92
|
+
#
|
|
93
|
+
# @param [String] node the node_id of the revision
|
|
94
|
+
# @return [Array<String, String>] [new_path, flags]
|
|
95
|
+
def renamed?(node)
|
|
96
|
+
return false if parents_for_node(node).first != NULL_ID
|
|
97
|
+
|
|
98
|
+
m = read_meta node
|
|
99
|
+
|
|
100
|
+
if m.any? && m["copy"]
|
|
101
|
+
return [m["copy"], m["copyrev"].unhexlify]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
false
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
##
|
|
108
|
+
# Yields a block for every revision, while being sure to follow copies.
|
|
109
|
+
def each(&block)
|
|
110
|
+
if @index[0].parent_one_rev == NULL_REV
|
|
111
|
+
meta_info = renamed?(@index[0].node_id)
|
|
112
|
+
if meta_info
|
|
113
|
+
copied_log = FileLog.new(@opener, meta_info.first)
|
|
114
|
+
copied_log.each(&block)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
super(&block)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
##
|
|
121
|
+
# Gets the size of the file. Overridden because of the metadata for
|
|
122
|
+
# copied files.
|
|
123
|
+
#
|
|
124
|
+
# @param [Integer] rev the number of the revision to lookup
|
|
125
|
+
# @return [String] the file's data
|
|
126
|
+
def size(rev)
|
|
127
|
+
node = self.node rev
|
|
128
|
+
if renamed? node
|
|
129
|
+
read(node).size
|
|
130
|
+
else
|
|
131
|
+
self[rev].compressed_len
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
##
|
|
136
|
+
# Converts a given node in this revision with the text provided.
|
|
137
|
+
# overridden because it handles renamed files.
|
|
138
|
+
#
|
|
139
|
+
# @param [String] thenode the node ID to use
|
|
140
|
+
# @param [String] text the text to compare against
|
|
141
|
+
# @return [Boolean] true if they're different, false if not. silly, isn't
|
|
142
|
+
# it?
|
|
143
|
+
def cmp(thenode, text)
|
|
144
|
+
if renamed? thenode
|
|
145
|
+
t2 = read thenode
|
|
146
|
+
return t2 != text
|
|
147
|
+
end
|
|
148
|
+
super(thenode, text)
|
|
149
|
+
end
|
|
150
|
+
end # class FileLog
|
|
151
|
+
end # module Mercurial
|
|
152
|
+
end # module Amp
|