mercurial-ruby 0.3.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/.document +5 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +32 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +86 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/mercurial-ruby.rb +66 -0
- data/lib/mercurial-ruby/branch.rb +45 -0
- data/lib/mercurial-ruby/changed_file.rb +51 -0
- data/lib/mercurial-ruby/command.rb +77 -0
- data/lib/mercurial-ruby/commit.rb +152 -0
- data/lib/mercurial-ruby/config_file.rb +119 -0
- data/lib/mercurial-ruby/configuration.rb +14 -0
- data/lib/mercurial-ruby/diff.rb +50 -0
- data/lib/mercurial-ruby/factories/branch_factory.rb +91 -0
- data/lib/mercurial-ruby/factories/changed_file_factory.rb +50 -0
- data/lib/mercurial-ruby/factories/commit_factory.rb +154 -0
- data/lib/mercurial-ruby/factories/diff_factory.rb +63 -0
- data/lib/mercurial-ruby/factories/hook_factory.rb +45 -0
- data/lib/mercurial-ruby/factories/node_factory.rb +111 -0
- data/lib/mercurial-ruby/factories/tag_factory.rb +48 -0
- data/lib/mercurial-ruby/file_index.rb +209 -0
- data/lib/mercurial-ruby/helper.rb +23 -0
- data/lib/mercurial-ruby/hook.rb +23 -0
- data/lib/mercurial-ruby/manifest.rb +58 -0
- data/lib/mercurial-ruby/node.rb +100 -0
- data/lib/mercurial-ruby/repository.rb +94 -0
- data/lib/mercurial-ruby/root_node.rb +27 -0
- data/lib/mercurial-ruby/shell.rb +64 -0
- data/lib/mercurial-ruby/style.rb +23 -0
- data/lib/mercurial-ruby/tag.rb +33 -0
- data/lib/stdlib_exts/string.rb +12 -0
- data/lib/styles/changeset.style +5 -0
- data/lib/styles/file_index.style +3 -0
- data/mercurial-ruby.gemspec +227 -0
- data/test/fixtures.rb +28 -0
- data/test/fixtures/test-repo/.DotFile +1 -0
- data/test/fixtures/test-repo/.hg/00changelog.i +0 -0
- data/test/fixtures/test-repo/.hg/branch +1 -0
- data/test/fixtures/test-repo/.hg/cache/branchheads +6 -0
- data/test/fixtures/test-repo/.hg/cache/tags +7 -0
- data/test/fixtures/test-repo/.hg/dirstate +0 -0
- data/test/fixtures/test-repo/.hg/hgrc +3 -0
- data/test/fixtures/test-repo/.hg/last-message.txt +1 -0
- data/test/fixtures/test-repo/.hg/requires +4 -0
- data/test/fixtures/test-repo/.hg/store/00changelog.i +0 -0
- data/test/fixtures/test-repo/.hg/store/00manifest.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_file _with _whitespace.pdf.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e2.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e3.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_l_i_c_e_n_s_e4.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_r_e_a_d_m_e.markdown.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_r_e_a_d_m_e.markup.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_rakefile.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_rakefile2.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/_rakefile3.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/check ~5c this ~5c out ~22 now.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/minitest__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/options.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/rdoc__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/rspec__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/shindo__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/shoulda__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_gemfile.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_l_i_c_e_n_s_e.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_r_e_a_d_m_e.rdoc.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/_rakefile.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/bacon/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/bacon/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/bundler__setup.erb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/features/default.feature.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/features/support/env.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/jeweler__tasks.erb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/micronaut/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/micronaut/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/minitest/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/minitest/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/other__tasks.erb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/riot/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/riot/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/rspec/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/rspec/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/rspec/~2erspec.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shindo/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shindo/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shoulda/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/shoulda/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testspec/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testspec/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testunit/flunking.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/testunit/helper.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/~2edocument.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/templates/~2egitignore.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory two/~2e_d_s___store.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory__1/rubygems__dot__org__tasks.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory__1/rubygems__tasks.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory__1/specification.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory__1/tasks.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/directory__1/~2e_d_s___store.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/empty-file.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/goose.png.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/goose/pretty-thing.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-directory/another-boring-file.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-directory/something.csv.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/_e_u_l_a5seat___chin___sim02.03.04.pdf.d +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/_e_u_l_a5seat___chin___sim02.03.04.pdf.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/_file _with _whitespace.pdf.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-directory/subdirectory/beansprout.png.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/new-file.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/old-directory/minitest__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/old-directory/options.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/old-directory/rspec__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/old-directory/shindo__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/old-directory/testunit__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/old-directory/yard__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/riot__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/riot__mixin__copy.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/style.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/super-cow.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/superman.txt.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/testspec__mixin.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/testspec__mixin__new.rb.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/~2e_dot_file.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/~2ehgignore.i +0 -0
- data/test/fixtures/test-repo/.hg/store/data/~2ehgtags.i +0 -0
- data/test/fixtures/test-repo/.hg/store/fncache +79 -0
- data/test/fixtures/test-repo/.hg/store/undo +0 -0
- data/test/fixtures/test-repo/.hg/undo.bookmarks +0 -0
- data/test/fixtures/test-repo/.hg/undo.branch +1 -0
- data/test/fixtures/test-repo/.hg/undo.desc +2 -0
- data/test/fixtures/test-repo/.hg/undo.dirstate +0 -0
- data/test/fixtures/test-repo/.hgignore +1 -0
- data/test/fixtures/test-repo/.hgtags +1 -0
- data/test/fixtures/test-repo/LICENSE3.txt +15 -0
- data/test/fixtures/test-repo/LICENSE4.txt +17 -0
- data/test/fixtures/test-repo/README.markup +218 -0
- data/test/fixtures/test-repo/Rakefile3 +83 -0
- data/test/fixtures/test-repo/check // this // out /" now" "b/data/test/fixtures/test-repo/check // this // out / → now +0 -0
- data/test/fixtures/test-repo/empty-file +0 -0
- data/test/fixtures/test-repo/goose.png +0 -0
- data/test/fixtures/test-repo/goose/pretty-thing.txt +0 -0
- data/test/fixtures/test-repo/new-directory/another-boring-file +78 -0
- data/test/fixtures/test-repo/new-directory/something.csv +1 -0
- data/test/fixtures/test-repo/new-directory/subdirectory/EULA5seat_Chin_Sim02.03.04.pdf +0 -0
- data/test/fixtures/test-repo/new-directory/subdirectory/File With Whitespace.pdf b/data/test/fixtures/test-repo/new-directory/subdirectory/File With → Whitespace.pdf +0 -0
- data/test/fixtures/test-repo/new-directory/subdirectory/beansprout.png +0 -0
- data/test/fixtures/test-repo/riot_mixin.rb +45 -0
- data/test/fixtures/test-repo/style +4 -0
- data/test/fixtures/test-repo/superman.txt +1 -0
- data/test/fixtures/test-repo/testspec_mixin_new.rb +44 -0
- data/test/helper.rb +41 -0
- data/test/test_branch_factory.rb +46 -0
- data/test/test_changed_file.rb +46 -0
- data/test/test_changed_file_factory.rb +16 -0
- data/test/test_command.rb +62 -0
- data/test/test_commit.rb +66 -0
- data/test/test_commit_factory.rb +101 -0
- data/test/test_config_file.rb +105 -0
- data/test/test_configuration.rb +26 -0
- data/test/test_diff.rb +39 -0
- data/test/test_diff_factory.rb +38 -0
- data/test/test_file_index.rb +113 -0
- data/test/test_hook.rb +39 -0
- data/test/test_hook_factory.rb +40 -0
- data/test/test_manifest.rb +39 -0
- data/test/test_node.rb +34 -0
- data/test/test_node_factory.rb +125 -0
- data/test/test_repository.rb +58 -0
- data/test/test_shell.rb +33 -0
- data/test/test_tag_factory.rb +27 -0
- metadata +328 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module Mercurial
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# This class represents a factory for {Mercurial::Commit Commit} instances.
|
|
5
|
+
#
|
|
6
|
+
class CommitFactory
|
|
7
|
+
include Mercurial::Helper
|
|
8
|
+
|
|
9
|
+
# Instance of {Mercurial::Repository Repository}.
|
|
10
|
+
attr_reader :repository
|
|
11
|
+
|
|
12
|
+
def initialize(repository) #:nodoc:
|
|
13
|
+
@repository = repository
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Return an array of {Mercurial::Commit Commit} instances for all changesets in the repository.
|
|
17
|
+
#
|
|
18
|
+
# == Example:
|
|
19
|
+
# repository.commits.all
|
|
20
|
+
#
|
|
21
|
+
def all
|
|
22
|
+
hg_to_array ["log --style ?", style], changeset_separator do |line|
|
|
23
|
+
build(line)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Run a block for every {Mercurial::Commit Commit} instance of all changesets in the repository.
|
|
28
|
+
#
|
|
29
|
+
# == Example:
|
|
30
|
+
# repository.commits.each {|commit| ... }
|
|
31
|
+
#
|
|
32
|
+
def each(&block)
|
|
33
|
+
all.each do |commit|
|
|
34
|
+
block.call(commit)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Count all changesets in the repository.
|
|
39
|
+
#
|
|
40
|
+
# == Example:
|
|
41
|
+
# repository.commits.count
|
|
42
|
+
#
|
|
43
|
+
def count
|
|
44
|
+
hg_to_array %Q[log --template "{node}\n"], "\n" do |line|
|
|
45
|
+
line
|
|
46
|
+
end.size
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Return an array of {Mercurial::Commit Commit} instances for changesets in a specific branch.
|
|
50
|
+
#
|
|
51
|
+
# == Example:
|
|
52
|
+
# repository.commits.by_branch('brancname')
|
|
53
|
+
#
|
|
54
|
+
def by_branch(branch)
|
|
55
|
+
hg_to_array ["log -b ? --style ?", branch, style], changeset_separator do |line|
|
|
56
|
+
build(line)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Return an instance of {Mercurial::Commit Commit} for a changeset with a specified id.
|
|
61
|
+
#
|
|
62
|
+
# == Example:
|
|
63
|
+
# repository.commits.by_hash_id('291a498f04e9')
|
|
64
|
+
#
|
|
65
|
+
def by_hash_id(hash)
|
|
66
|
+
build do
|
|
67
|
+
hg(["log -r ? --style ?", hash, style])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Return an array of {Mercurial::Commit Commit} instances for changesets with specified ids.
|
|
72
|
+
#
|
|
73
|
+
# == Example:
|
|
74
|
+
# repository.commits.by_hash_ids('291a498f04e9', '63f70b2314ed')
|
|
75
|
+
#
|
|
76
|
+
def by_hash_ids(*args)
|
|
77
|
+
if args.size == 1 && args.first.kind_of?(Array)
|
|
78
|
+
array = args.first
|
|
79
|
+
else
|
|
80
|
+
array = args
|
|
81
|
+
end
|
|
82
|
+
return [] if array.empty?
|
|
83
|
+
|
|
84
|
+
args = array.map{|hash| " -r#{ hash }"}
|
|
85
|
+
hg_to_array ["log#{ args } --style ?", style], changeset_separator do |line|
|
|
86
|
+
build(line)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Return an array of {Mercurial::Commit Commit} instances for a specified range of changeset ids.
|
|
91
|
+
#
|
|
92
|
+
# == Example:
|
|
93
|
+
# repository.commits.for_range('bf6386c0a0cc', '63f70b2314ed')
|
|
94
|
+
#
|
|
95
|
+
def for_range(hash_a, hash_b)
|
|
96
|
+
hg_to_array ["log -r ?:? --style ?", hash_a, hash_b, style], changeset_separator do |line|
|
|
97
|
+
build(line)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Return an instance of {Mercurial::Commit Commit} for a repository's tip changeset (latest).
|
|
102
|
+
#
|
|
103
|
+
# == Example:
|
|
104
|
+
# repository.commits.tip
|
|
105
|
+
#
|
|
106
|
+
def tip
|
|
107
|
+
build do
|
|
108
|
+
hg(["tip --style ?", style])
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
alias :latest :tip
|
|
112
|
+
|
|
113
|
+
protected
|
|
114
|
+
|
|
115
|
+
def changeset_separator
|
|
116
|
+
Mercurial::Style::CHANGESET_SEPARATOR
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def field_separator
|
|
120
|
+
Mercurial::Style::FIELD_SEPARATOR
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def build(data=nil, &block)
|
|
124
|
+
data ||= block.call
|
|
125
|
+
return if data.empty?
|
|
126
|
+
data = data.gsub(/#{ Regexp.escape(changeset_separator) }$/, '')
|
|
127
|
+
data = data.split(field_separator)
|
|
128
|
+
commit = Mercurial::Commit.new(
|
|
129
|
+
repository,
|
|
130
|
+
:hash_id => data[0],
|
|
131
|
+
:author => data[1],
|
|
132
|
+
:author_email => data[2],
|
|
133
|
+
:date => data[3],
|
|
134
|
+
:message => data[4],
|
|
135
|
+
:changed_files => [data[5], data[6], data[7], data[8]],
|
|
136
|
+
:branches_names => data[9],
|
|
137
|
+
:tags_names => data[10],
|
|
138
|
+
:parents => data[11]
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
if commit.blank?
|
|
142
|
+
nil
|
|
143
|
+
else
|
|
144
|
+
commit
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def style
|
|
149
|
+
Mercurial::Style.changeset
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Mercurial
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# This class represents a factory for {Mercurial::Diff Diff} instances.
|
|
5
|
+
#
|
|
6
|
+
class DiffFactory
|
|
7
|
+
include Mercurial::Helper
|
|
8
|
+
|
|
9
|
+
# Instance of {Mercurial::Repository Repository}.
|
|
10
|
+
attr_reader :repository
|
|
11
|
+
|
|
12
|
+
def initialize(repository)
|
|
13
|
+
@repository = repository
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Returns an array of {Mercurial::Diff Diff} instances for a specified
|
|
17
|
+
# instance of {Mercurial::Commit Commit}. Represents changeset's diffs.
|
|
18
|
+
#
|
|
19
|
+
# == Example:
|
|
20
|
+
# commit = repository.commits.by_hash_id('291a498f04e9')
|
|
21
|
+
# repository.diffs.for_commit(commit)
|
|
22
|
+
#
|
|
23
|
+
def for_commit(commit)
|
|
24
|
+
[].tap do |returning|
|
|
25
|
+
data = hg(["diff -c ?", commit.hash_id])
|
|
26
|
+
chunks = data.split(/^diff/)[1..-1]
|
|
27
|
+
unless chunks.nil?
|
|
28
|
+
chunks.map do |piece|
|
|
29
|
+
piece = "diff" << piece
|
|
30
|
+
returning << build(commit, piece)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def build(commit, data)
|
|
39
|
+
return if data.empty?
|
|
40
|
+
hash_a, hash_b = *data.scan(/^diff -r (\w+) -r (\w+)/).first
|
|
41
|
+
|
|
42
|
+
if binary_file = data.scan(/^Binary file (.+) has changed/).flatten.first
|
|
43
|
+
file_a = binary_file
|
|
44
|
+
body = 'Binary files differ'
|
|
45
|
+
else
|
|
46
|
+
file_a = data.scan(/^--- (?:a\/(.+)|\/dev\/null)\t/).flatten.first
|
|
47
|
+
file_b = data.scan(/^\+\+\+ (?:b\/(.+)|\/dev\/null)\t/).flatten.first
|
|
48
|
+
body = data[data.index("\n")+1..-1]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
Mercurial::Diff.new(commit,
|
|
52
|
+
:hash_a => hash_a,
|
|
53
|
+
:hash_b => hash_b,
|
|
54
|
+
:file_a => file_a,
|
|
55
|
+
:file_b => file_b,
|
|
56
|
+
:body => body,
|
|
57
|
+
:binary => !!binary_file
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Mercurial
|
|
2
|
+
|
|
3
|
+
class HookFactory
|
|
4
|
+
|
|
5
|
+
attr_reader :repository
|
|
6
|
+
|
|
7
|
+
def initialize(repository)
|
|
8
|
+
@repository = repository
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def all
|
|
12
|
+
[].tap do |returning|
|
|
13
|
+
repository.config.find_header('hooks').each_pair do |name, value|
|
|
14
|
+
returning << build(name, value)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def by_name(name)
|
|
20
|
+
all.find do |h|
|
|
21
|
+
h.name == name
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def add(name, value)
|
|
26
|
+
build(name, value).tap do |hook|
|
|
27
|
+
hook.save
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def remove(name)
|
|
32
|
+
if hook = by_name(name)
|
|
33
|
+
hook.destroy!
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
|
|
39
|
+
def build(name, value)
|
|
40
|
+
Mercurial::Hook.new(repository, name, value)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module Mercurial
|
|
2
|
+
class NodeMissing < Error; end
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This class represents a factory for {Mercurial::Node Node} instances.
|
|
6
|
+
#
|
|
7
|
+
class NodeFactory
|
|
8
|
+
include Mercurial::Helper
|
|
9
|
+
|
|
10
|
+
# Instance of {Mercurial::Repository Repository}.
|
|
11
|
+
attr_reader :repository
|
|
12
|
+
|
|
13
|
+
def initialize(repository)
|
|
14
|
+
@repository = repository
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Finds a specified file or a directory in the repository at a specified revision.
|
|
18
|
+
# Returns an instance of {Mercurial::Node Node}.
|
|
19
|
+
#
|
|
20
|
+
# Will find node in the latest version of repo if revision is ommitted.
|
|
21
|
+
# Will return nil if node wasn't found.
|
|
22
|
+
#
|
|
23
|
+
# == Example:
|
|
24
|
+
# repository.nodes.find('/')
|
|
25
|
+
# repository.nodes.find('some-fancy-directory/Weird File Name.pdf', '291a498f04e9')
|
|
26
|
+
# repository.nodes.find('some-fancy-directory/subdirectory/', '291a498f04e9')
|
|
27
|
+
#
|
|
28
|
+
def find(path, revision=nil)
|
|
29
|
+
revision ||= 'tip'
|
|
30
|
+
return RootNode.new(:repository => repository, :revision => revision) if path == '/'
|
|
31
|
+
entry = repository.manifest.scan_for_path(path, revision).first
|
|
32
|
+
return unless entry
|
|
33
|
+
if exact_path = entry[3].scan(/^(#{ Regexp.escape(path.without_trailing_slash) }\/)/).flatten.first
|
|
34
|
+
name = exact_path.split('/').last + '/'
|
|
35
|
+
build(
|
|
36
|
+
:path => exact_path,
|
|
37
|
+
:name => name,
|
|
38
|
+
:revision => revision
|
|
39
|
+
)
|
|
40
|
+
else
|
|
41
|
+
build(
|
|
42
|
+
:path => entry[3],
|
|
43
|
+
:name => entry[3].split('/').last,
|
|
44
|
+
:revision => revision,
|
|
45
|
+
:nodeid => entry[0],
|
|
46
|
+
:fmode => entry[1],
|
|
47
|
+
:exec => entry[2]
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Same as +find+ but will raise a NodeMissing exception if node wasn't found.
|
|
53
|
+
def find!(path, revision=nil)
|
|
54
|
+
find(path, revision) || raise(NodeMissing, "#{ path } at revision #{ revision }")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Find all entries (files and directories) inside a specified path and revision.
|
|
58
|
+
# Returns an array of {Mercurial::Node Node} instances.
|
|
59
|
+
#
|
|
60
|
+
# Will find node in the latest version of repo if revision is ommitted.
|
|
61
|
+
#
|
|
62
|
+
# == Example:
|
|
63
|
+
# repository.nodes.entries_for('/')
|
|
64
|
+
# repository.nodes.entries_for('some-fancy-directory/subdirectory/', '291a498f04e9')
|
|
65
|
+
#
|
|
66
|
+
def entries_for(path, revision=nil, parent=nil)
|
|
67
|
+
revision ||= 'tip'
|
|
68
|
+
entries = []
|
|
69
|
+
manifest_entries = repository.manifest.scan_for_path(path, revision)
|
|
70
|
+
manifest_entries.each do |me|
|
|
71
|
+
path_without_source = me[3].gsub(/^#{ Regexp.escape(path.without_trailing_slash) }\//, '')
|
|
72
|
+
entry_name = path_without_source.split('/').first
|
|
73
|
+
entry_path = File.join(path, entry_name).gsub(/^\//, '')
|
|
74
|
+
dir = me[3].scan(/^(#{ Regexp.escape(entry_path) }\/)/).flatten.first ? true : false
|
|
75
|
+
entry_name << '/' if dir
|
|
76
|
+
|
|
77
|
+
entries << build(
|
|
78
|
+
:path => entry_path,
|
|
79
|
+
:name => entry_name,
|
|
80
|
+
:revision => revision,
|
|
81
|
+
:nodeid => (me[0] unless dir),
|
|
82
|
+
:fmode => dir ? nil : me[1],
|
|
83
|
+
:exec => dir ? nil : me[2],
|
|
84
|
+
:parent => parent
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
entries = entries.inject({}) do |hash,item|
|
|
89
|
+
hash[item.name] ||= item
|
|
90
|
+
hash
|
|
91
|
+
end.values
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def build(opts={})
|
|
97
|
+
Mercurial::Node.new(
|
|
98
|
+
:repository => repository,
|
|
99
|
+
:path => opts[:path],
|
|
100
|
+
:name => opts[:name],
|
|
101
|
+
:revision => opts[:revision],
|
|
102
|
+
:nodeid => opts[:nodeid],
|
|
103
|
+
:fmode => opts[:fmode],
|
|
104
|
+
:executable => opts[:exec],
|
|
105
|
+
:parent => opts[:parent]
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Mercurial
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# This class represents a factory for {Mercurial::Tag Tag} instances.
|
|
5
|
+
#
|
|
6
|
+
class TagFactory
|
|
7
|
+
include Mercurial::Helper
|
|
8
|
+
|
|
9
|
+
# Instance of {Mercurial::Repository Repository}.
|
|
10
|
+
attr_reader :repository
|
|
11
|
+
|
|
12
|
+
def initialize(repository)
|
|
13
|
+
@repository = repository
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Return an array of {Mercurial::Tag Tag} instances for all tags in the repository.
|
|
17
|
+
#
|
|
18
|
+
# == Example:
|
|
19
|
+
# repository.tags.all
|
|
20
|
+
#
|
|
21
|
+
def all
|
|
22
|
+
hg_to_array "tags" do |line|
|
|
23
|
+
build(line)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Return a {Mercurial::Tag Tag} instance for a tag with a specified name.
|
|
28
|
+
#
|
|
29
|
+
# == Example:
|
|
30
|
+
# repository.tags.by_name('tagname')
|
|
31
|
+
#
|
|
32
|
+
def by_name(name)
|
|
33
|
+
all.find do |b|
|
|
34
|
+
b.name == name
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def build(data)
|
|
41
|
+
name, hash_id = *data.scan(/([\w-]+)\s+\d+:(\w+)\s*/).first
|
|
42
|
+
return if name == 'tip'
|
|
43
|
+
Mercurial::Tag.new(repository, name, hash_id)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
module Mercurial
|
|
2
|
+
|
|
3
|
+
# This class was ported from grit.
|
|
4
|
+
#
|
|
5
|
+
# This implements a file-based 'file index', an simple index of
|
|
6
|
+
# all of the reachable commits in a repo, along with the parents
|
|
7
|
+
# and which files were modified during each commit.
|
|
8
|
+
#
|
|
9
|
+
# This class creates and reads a file named '[.hg]/file-index'.
|
|
10
|
+
#
|
|
11
|
+
class FileIndex
|
|
12
|
+
include Mercurial::Helper
|
|
13
|
+
|
|
14
|
+
class IndexFileNotFound < StandardError
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class UnsupportedRef < StandardError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
attr_accessor :max_file_size
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
self.max_file_size = 10_000_000 # ~10M
|
|
25
|
+
|
|
26
|
+
attr_reader :repository
|
|
27
|
+
|
|
28
|
+
# initializes index given repository
|
|
29
|
+
def initialize(repository)
|
|
30
|
+
@repository = repository
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def reload
|
|
34
|
+
@_read_complete = false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# updates file index
|
|
38
|
+
def update(oldrev=nil, newrev=nil)
|
|
39
|
+
if index_file_exists? && oldrev != "0"*40
|
|
40
|
+
hg([
|
|
41
|
+
"log --debug -r ?:? --style ? >> ?",
|
|
42
|
+
oldrev, newrev, Style.file_index, path
|
|
43
|
+
])
|
|
44
|
+
else
|
|
45
|
+
hg(["log --debug -r : --style ? > ?", Style.file_index, path])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# returns count of all commits
|
|
50
|
+
def count_all
|
|
51
|
+
read_if_needed
|
|
52
|
+
@sha_count
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# returns count of all commits reachable from SHA
|
|
56
|
+
# note: originally did this recursively, but ruby gets pissed about that on
|
|
57
|
+
# really big repos where the stack level gets 'too deep' (thats what she said)
|
|
58
|
+
def count(commit_sha)
|
|
59
|
+
read_if_needed
|
|
60
|
+
commits_from(commit_sha).size
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# builds a list of all commits reachable from a single commit
|
|
64
|
+
def commits_from(commit_sha)
|
|
65
|
+
raise UnsupportedRef if commit_sha.is_a? Array
|
|
66
|
+
read_if_needed
|
|
67
|
+
|
|
68
|
+
already = {}
|
|
69
|
+
final = []
|
|
70
|
+
left_to_do = [commit_sha]
|
|
71
|
+
|
|
72
|
+
while commit_sha = left_to_do.shift
|
|
73
|
+
next if already[commit_sha]
|
|
74
|
+
|
|
75
|
+
final << commit_sha
|
|
76
|
+
already[commit_sha] = true
|
|
77
|
+
|
|
78
|
+
commit = @commit_index[commit_sha]
|
|
79
|
+
commit[:parents].each do |sha|
|
|
80
|
+
left_to_do << sha
|
|
81
|
+
end if commit
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sort_commits(final)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# returns files changed at commit sha
|
|
88
|
+
def files(commit_sha)
|
|
89
|
+
read_if_needed
|
|
90
|
+
if commit = @commit_index[commit_sha]
|
|
91
|
+
commit[:files]
|
|
92
|
+
else
|
|
93
|
+
[]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# returns all commits for a file
|
|
98
|
+
def commits_for(file)
|
|
99
|
+
read_if_needed
|
|
100
|
+
@all_files[file] || []
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# returns the shas of the last commits for all
|
|
104
|
+
# the files in [] from commit_sha
|
|
105
|
+
# files_matcher can be a regexp or an array
|
|
106
|
+
def last_commits(commit_sha, files_matcher)
|
|
107
|
+
read_if_needed
|
|
108
|
+
acceptable = commits_from(commit_sha)
|
|
109
|
+
|
|
110
|
+
matches = {}
|
|
111
|
+
|
|
112
|
+
if files_matcher.is_a? Regexp
|
|
113
|
+
files = @all_files.keys.select { |file| file =~ files_matcher }
|
|
114
|
+
files_matcher = files
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if files_matcher.is_a? Array
|
|
118
|
+
# find the last commit for each file in the array
|
|
119
|
+
files_matcher.each do |f|
|
|
120
|
+
@all_files[f].each do |try|
|
|
121
|
+
if acceptable.include?(try)
|
|
122
|
+
matches[f] = try
|
|
123
|
+
break
|
|
124
|
+
end
|
|
125
|
+
end if @all_files[f]
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
matches
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def destroy!
|
|
133
|
+
FileUtils.rm_f(path)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def path
|
|
137
|
+
File.join(repository.dothg_path, 'file-index')
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def index_file_exists?
|
|
143
|
+
FileTest.exists?(path)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def index_file_valid?
|
|
147
|
+
File.file?(path) && (File.size(path) < Mercurial::FileIndex.max_file_size)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def sort_commits(sha_array)
|
|
151
|
+
read_if_needed
|
|
152
|
+
sha_array.sort { |a, b| @commit_order[b].to_i <=> @commit_order[a].to_i }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def read_if_needed
|
|
156
|
+
if @_read_complete
|
|
157
|
+
true
|
|
158
|
+
else
|
|
159
|
+
begin
|
|
160
|
+
read_index
|
|
161
|
+
rescue IndexFileNotFound => e
|
|
162
|
+
if @_tried_updating
|
|
163
|
+
raise e
|
|
164
|
+
else
|
|
165
|
+
@_tried_updating = true
|
|
166
|
+
update
|
|
167
|
+
retry
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def read_index
|
|
174
|
+
raise IndexFileNotFound unless index_file_valid?
|
|
175
|
+
f = File.new(path)
|
|
176
|
+
@sha_count = 0
|
|
177
|
+
@commit_index = {}
|
|
178
|
+
@commit_order = {}
|
|
179
|
+
@all_files = {}
|
|
180
|
+
while line = f.gets
|
|
181
|
+
if /^(\w{40})/.match(line)
|
|
182
|
+
shas = line.scan(/(\w{40})/)
|
|
183
|
+
current_sha = shas.shift.first
|
|
184
|
+
parents = shas.map { |sha| sha.first }
|
|
185
|
+
parents = parents.delete_if { |sha| sha == '0'*40 }
|
|
186
|
+
@commit_index[current_sha] = {:files => [], :parents => parents }
|
|
187
|
+
@commit_order[current_sha] = @sha_count
|
|
188
|
+
@sha_count += 1
|
|
189
|
+
else
|
|
190
|
+
file_name = line.chomp
|
|
191
|
+
unless file_name.empty?
|
|
192
|
+
tree = ''
|
|
193
|
+
File.dirname(file_name).split('/').each do |part|
|
|
194
|
+
next if part == '.'
|
|
195
|
+
tree += part + '/'
|
|
196
|
+
@all_files[tree] ||= []
|
|
197
|
+
@all_files[tree].unshift(current_sha)
|
|
198
|
+
end
|
|
199
|
+
@all_files[file_name] ||= []
|
|
200
|
+
@all_files[file_name].unshift(current_sha)
|
|
201
|
+
@commit_index[current_sha][:files] << file_name
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
@_read_complete = true
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
end
|