rosette-core 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +26 -0
  3. data/History.txt +3 -0
  4. data/README.md +94 -0
  5. data/Rakefile +18 -0
  6. data/lib/rosette/core.rb +110 -0
  7. data/lib/rosette/core/branch_utils.rb +152 -0
  8. data/lib/rosette/core/commands.rb +139 -0
  9. data/lib/rosette/core/commands/errors.rb +17 -0
  10. data/lib/rosette/core/commands/git/commit_command.rb +65 -0
  11. data/lib/rosette/core/commands/git/diff_base_command.rb +301 -0
  12. data/lib/rosette/core/commands/git/diff_command.rb +188 -0
  13. data/lib/rosette/core/commands/git/diff_entry.rb +44 -0
  14. data/lib/rosette/core/commands/git/fetch_command.rb +27 -0
  15. data/lib/rosette/core/commands/git/repo_snapshot_command.rb +40 -0
  16. data/lib/rosette/core/commands/git/show_command.rb +70 -0
  17. data/lib/rosette/core/commands/git/snapshot_command.rb +50 -0
  18. data/lib/rosette/core/commands/git/status_command.rb +128 -0
  19. data/lib/rosette/core/commands/git/with_non_merge_ref.rb +48 -0
  20. data/lib/rosette/core/commands/git/with_ref.rb +92 -0
  21. data/lib/rosette/core/commands/git/with_refs.rb +92 -0
  22. data/lib/rosette/core/commands/git/with_repo_name.rb +50 -0
  23. data/lib/rosette/core/commands/git/with_snapshots.rb +45 -0
  24. data/lib/rosette/core/commands/queuing/enqueue_commit_command.rb +37 -0
  25. data/lib/rosette/core/commands/queuing/requeue_commit_command.rb +46 -0
  26. data/lib/rosette/core/commands/translations/export_command.rb +257 -0
  27. data/lib/rosette/core/commands/translations/translation_lookup_command.rb +66 -0
  28. data/lib/rosette/core/commands/translations/with_locale.rb +47 -0
  29. data/lib/rosette/core/configurator.rb +160 -0
  30. data/lib/rosette/core/error_reporters/buffered_error_reporter.rb +96 -0
  31. data/lib/rosette/core/error_reporters/error_reporter.rb +31 -0
  32. data/lib/rosette/core/error_reporters/nil_error_reporter.rb +25 -0
  33. data/lib/rosette/core/error_reporters/printing_error_reporter.rb +58 -0
  34. data/lib/rosette/core/error_reporters/raising_error_reporter.rb +27 -0
  35. data/lib/rosette/core/errors.rb +93 -0
  36. data/lib/rosette/core/extractor/commit_log.rb +33 -0
  37. data/lib/rosette/core/extractor/commit_log_status.rb +57 -0
  38. data/lib/rosette/core/extractor/commit_processor.rb +109 -0
  39. data/lib/rosette/core/extractor/extractor.rb +72 -0
  40. data/lib/rosette/core/extractor/extractor_config.rb +74 -0
  41. data/lib/rosette/core/extractor/locale.rb +118 -0
  42. data/lib/rosette/core/extractor/phrase.rb +76 -0
  43. data/lib/rosette/core/extractor/phrase/phrase_index_policy.rb +108 -0
  44. data/lib/rosette/core/extractor/phrase/phrase_to_hash.rb +33 -0
  45. data/lib/rosette/core/extractor/repo_config.rb +339 -0
  46. data/lib/rosette/core/extractor/serializer_config.rb +55 -0
  47. data/lib/rosette/core/extractor/static_extractor.rb +44 -0
  48. data/lib/rosette/core/extractor/translation.rb +44 -0
  49. data/lib/rosette/core/extractor/translation/translation_to_hash.rb +28 -0
  50. data/lib/rosette/core/git/diff_finder.rb +131 -0
  51. data/lib/rosette/core/git/ref.rb +116 -0
  52. data/lib/rosette/core/git/repo.rb +378 -0
  53. data/lib/rosette/core/path_matcher_factory.rb +330 -0
  54. data/lib/rosette/core/resolvers/extractor_id.rb +37 -0
  55. data/lib/rosette/core/resolvers/integration_id.rb +37 -0
  56. data/lib/rosette/core/resolvers/preprocessor_id.rb +38 -0
  57. data/lib/rosette/core/resolvers/resolver.rb +115 -0
  58. data/lib/rosette/core/resolvers/serializer_id.rb +37 -0
  59. data/lib/rosette/core/snapshots/cached_head_snapshot_factory.rb +51 -0
  60. data/lib/rosette/core/snapshots/cached_snapshot_factory.rb +67 -0
  61. data/lib/rosette/core/snapshots/head_snapshot_factory.rb +58 -0
  62. data/lib/rosette/core/snapshots/repo_config_path_filter.rb +83 -0
  63. data/lib/rosette/core/snapshots/snapshot_factory.rb +184 -0
  64. data/lib/rosette/core/string_utils.rb +23 -0
  65. data/lib/rosette/core/translation_status.rb +81 -0
  66. data/lib/rosette/core/validators.rb +18 -0
  67. data/lib/rosette/core/validators/commit_validator.rb +62 -0
  68. data/lib/rosette/core/validators/commits_validator.rb +32 -0
  69. data/lib/rosette/core/validators/encoding_validator.rb +32 -0
  70. data/lib/rosette/core/validators/locale_validator.rb +37 -0
  71. data/lib/rosette/core/validators/repo_validator.rb +33 -0
  72. data/lib/rosette/core/validators/serializer_validator.rb +37 -0
  73. data/lib/rosette/core/validators/validator.rb +31 -0
  74. data/lib/rosette/core/version.rb +8 -0
  75. data/lib/rosette/data_stores.rb +11 -0
  76. data/lib/rosette/data_stores/errors.rb +26 -0
  77. data/lib/rosette/data_stores/phrase_status.rb +59 -0
  78. data/lib/rosette/integrations.rb +12 -0
  79. data/lib/rosette/integrations/errors.rb +15 -0
  80. data/lib/rosette/integrations/integratable.rb +58 -0
  81. data/lib/rosette/integrations/integration.rb +23 -0
  82. data/lib/rosette/preprocessors.rb +11 -0
  83. data/lib/rosette/preprocessors/errors.rb +14 -0
  84. data/lib/rosette/preprocessors/preprocessor.rb +48 -0
  85. data/lib/rosette/queuing.rb +14 -0
  86. data/lib/rosette/queuing/commits.rb +19 -0
  87. data/lib/rosette/queuing/commits/commit_conductor.rb +90 -0
  88. data/lib/rosette/queuing/commits/commit_job.rb +93 -0
  89. data/lib/rosette/queuing/commits/commits_queue_configurator.rb +60 -0
  90. data/lib/rosette/queuing/commits/extract_stage.rb +46 -0
  91. data/lib/rosette/queuing/commits/fetch_stage.rb +51 -0
  92. data/lib/rosette/queuing/commits/finalize_stage.rb +76 -0
  93. data/lib/rosette/queuing/commits/phrase_storage_granularity.rb +20 -0
  94. data/lib/rosette/queuing/commits/push_stage.rb +91 -0
  95. data/lib/rosette/queuing/commits/stage.rb +96 -0
  96. data/lib/rosette/queuing/job.rb +74 -0
  97. data/lib/rosette/queuing/queue.rb +28 -0
  98. data/lib/rosette/queuing/queue_configurator.rb +76 -0
  99. data/lib/rosette/queuing/worker.rb +30 -0
  100. data/lib/rosette/serializers.rb +10 -0
  101. data/lib/rosette/serializers/serializer.rb +98 -0
  102. data/lib/rosette/tms.rb +9 -0
  103. data/lib/rosette/tms/repository.rb +95 -0
  104. data/rosette-core.gemspec +24 -0
  105. data/spec/core/branch_utils_spec.rb +110 -0
  106. data/spec/core/commands/git/commit_command_spec.rb +60 -0
  107. data/spec/core/commands/git/diff_command_spec.rb +263 -0
  108. data/spec/core/commands/git/fetch_command_spec.rb +61 -0
  109. data/spec/core/commands/git/repo_snapshot_command_spec.rb +72 -0
  110. data/spec/core/commands/git/show_command_spec.rb +128 -0
  111. data/spec/core/commands/git/snapshot_command_spec.rb +86 -0
  112. data/spec/core/commands/git/status_command_spec.rb +154 -0
  113. data/spec/core/commands/queuing/enqueue_commit_command_spec.rb +34 -0
  114. data/spec/core/commands/queuing/requeue_commit_command_spec.rb +46 -0
  115. data/spec/core/commands/translations/export_command_spec.rb +113 -0
  116. data/spec/core/commands/translations/translation_lookup_command_spec.rb +58 -0
  117. data/spec/core/configurator_spec.rb +47 -0
  118. data/spec/core/error_reporters/buffered_error_reporter_spec.rb +61 -0
  119. data/spec/core/error_reporters/nil_error_reporter_spec.rb +16 -0
  120. data/spec/core/error_reporters/printing_error_reporter_spec.rb +60 -0
  121. data/spec/core/extractor/commit_log_status_spec.rb +216 -0
  122. data/spec/core/extractor/commit_processor_spec.rb +68 -0
  123. data/spec/core/extractor/extractor_config_spec.rb +47 -0
  124. data/spec/core/extractor/extractor_spec.rb +26 -0
  125. data/spec/core/extractor/locale_spec.rb +92 -0
  126. data/spec/core/extractor/phrase/phrase_index_policy_spec.rb +116 -0
  127. data/spec/core/extractor/phrase/phrase_to_hash_spec.rb +18 -0
  128. data/spec/core/extractor/repo_config_spec.rb +147 -0
  129. data/spec/core/extractor/translation/translation_to_hash_spec.rb +25 -0
  130. data/spec/core/git/diff_finder_spec.rb +74 -0
  131. data/spec/core/git/ref_spec.rb +118 -0
  132. data/spec/core/git/repo_spec.rb +216 -0
  133. data/spec/core/path_matcher_factory_spec.rb +139 -0
  134. data/spec/core/resolvers/extractor_id_spec.rb +47 -0
  135. data/spec/core/resolvers/integration_id_spec.rb +47 -0
  136. data/spec/core/resolvers/preprocessor_id_spec.rb +47 -0
  137. data/spec/core/resolvers/serializer_id_spec.rb +47 -0
  138. data/spec/core/snapshots/snapshot_factory_spec.rb +145 -0
  139. data/spec/core/string_utils_spec.rb +19 -0
  140. data/spec/core/translation_status_spec.rb +91 -0
  141. data/spec/core/validators/commit_validator_spec.rb +40 -0
  142. data/spec/core/validators/encoding_validator_spec.rb +30 -0
  143. data/spec/core/validators/locale_validator_spec.rb +31 -0
  144. data/spec/core/validators/repo_validator_spec.rb +30 -0
  145. data/spec/core/validators/serializer_validator_spec.rb +31 -0
  146. data/spec/integrations/integratable_spec.rb +58 -0
  147. data/spec/queuing/commits/commit_conductor_spec.rb +71 -0
  148. data/spec/queuing/commits/commit_job_spec.rb +87 -0
  149. data/spec/queuing/commits/extract_stage_spec.rb +68 -0
  150. data/spec/queuing/commits/fetch_stage_spec.rb +101 -0
  151. data/spec/queuing/commits/finalize_stage_spec.rb +88 -0
  152. data/spec/queuing/commits/push_stage_spec.rb +145 -0
  153. data/spec/queuing/commits/stage_spec.rb +80 -0
  154. data/spec/queuing/job_spec.rb +33 -0
  155. data/spec/queuing/queue_configurator_spec.rb +44 -0
  156. data/spec/spec_helper.rb +90 -0
  157. data/spec/test_helpers/fake_commit_stage.rb +17 -0
  158. metadata +257 -0
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rosette
4
+ module Core
5
+
6
+ # Logic for handling serializer ids. Serializer ids are strings that refer to
7
+ # a particular serializer class. For example, the id 'yaml/rails' refers to
8
+ # +Rosette::Serializers::YamlSerializer::RailsSerializer+.
9
+ #
10
+ # @example
11
+ # SerializerId.resolve('yaml/rails')
12
+ # # => Rosette::Serializers::YamlSerializer::RailsSerializer
13
+ class SerializerId < Resolver
14
+ class << self
15
+
16
+ # Parses and identifies the class constant for the given serializer id.
17
+ #
18
+ # @param [Class, String] serializer_id When given a class, returns the
19
+ # class. When given a string, parses and identifies the corresponding
20
+ # class constant in +namespace+.
21
+ # @param [Class] namespace The namespace to look in.
22
+ # @return [Class] The identified class constant.
23
+ def resolve(serializer_id, namespace = Rosette::Serializers)
24
+ super
25
+ end
26
+
27
+ private
28
+
29
+ def suffix
30
+ 'Serializer'
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'digest/sha1'
4
+
5
+ module Rosette
6
+ module Core
7
+
8
+ # Takes head snapshots and caches the results. Take a look at
9
+ # +ActiveSupport::Cache+ for a good set of cache stores that conform to the
10
+ # right interface.
11
+ #
12
+ # @see http://api.rubyonrails.org/classes/ActiveSupport/Cache.html
13
+ #
14
+ # @!attribute [r] cache
15
+ # @return [#fetch] the cache store. This can be any object that responds
16
+ # to +#fetch+ (and passes a block).
17
+ class CachedHeadSnapshotFactory < HeadSnapshotFactory
18
+ attr_reader :cache
19
+
20
+ # Creates a new cached head snapshot factory that uses the given cache.
21
+ #
22
+ # @param [#fetch] cache The cache to use.
23
+ def initialize(cache)
24
+ @cache = cache
25
+ end
26
+
27
+ protected
28
+
29
+ def process_ref(rev_walk, ref)
30
+ cache_key = head_snapshot_cache_key(
31
+ repo_config.name,
32
+ repo_config.repo.get_rev_commit(ref, rev_walk).getId.name
33
+ )
34
+
35
+ cache.fetch(cache_key) do
36
+ super
37
+ end
38
+ end
39
+
40
+ def head_snapshot_cache_key(repo_name, commit_id)
41
+ ['head_snapshots', repo_config.name, commit_id].join('/')
42
+ end
43
+
44
+ def head_snapshot_factory
45
+ Rosette::Core::HeadSnapshotFactory
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'digest/sha1'
4
+
5
+ module Rosette
6
+ module Core
7
+
8
+ # Takes snapshots and caches the results. Take a look at
9
+ # +ActiveSupport::Cache+ for a good set of cache stores that conform to the
10
+ # right interface.
11
+ #
12
+ # @see http://api.rubyonrails.org/classes/ActiveSupport/Cache.html
13
+ #
14
+ # @!attribute [r] cache
15
+ # @return [#fetch] the cache store. This can be any object that responds
16
+ # to +#fetch+ (and passes a block).
17
+ class CachedSnapshotFactory
18
+ attr_reader :cache
19
+
20
+ # Creates a new cached snapshot factory that uses the given cache.
21
+ #
22
+ # @param [#fetch] cache The cache to use.
23
+ def initialize(cache)
24
+ @cache = cache
25
+ end
26
+
27
+ # Takes the snapshot.
28
+ #
29
+ # @param [RepoConfig] repo_config The repo config for the repo to take
30
+ # the snapshot for.
31
+ # @param [String] commit_id The commit id to take the snapshot of.
32
+ # @param [Array<String>] paths The list of paths to include in the
33
+ # snapshot. If +paths+ is empty, this method will return a snapshot
34
+ # that contains all paths.
35
+ # @return [Hash<String, String>] The snapshot hash (path to commit id
36
+ # pairs).
37
+ def take_snapshot(repo_config, commit_id, paths = [])
38
+ paths = Array(paths)
39
+ cache_key = snapshot_cache_key(repo_config.name, commit_id, paths)
40
+
41
+ cache.fetch(cache_key) do
42
+ factory = snapshot_factory.new
43
+ .set_repo_config(repo_config)
44
+ .set_start_commit_id(commit_id)
45
+
46
+ factory.set_paths(paths) if paths.size > 0
47
+ factory.take_snapshot
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def snapshot_cache_key(repo_name, commit_id, paths)
54
+ ['snapshots', repo_name, commit_id, path_digest(paths)].join('/')
55
+ end
56
+
57
+ def path_digest(paths)
58
+ Digest::MD5.hexdigest(paths.join)
59
+ end
60
+
61
+ def snapshot_factory
62
+ Rosette::Core::SnapshotFactory
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+
3
+ java_import 'org.eclipse.jgit.revwalk.RevWalk'
4
+ java_import 'org.eclipse.jgit.revwalk.filter.RevFilter'
5
+
6
+ module Rosette
7
+ module Core
8
+
9
+ # Takes a snapshot of all the repository's heads. A "head" snapshot is a
10
+ # key/value map (hash) of git refs (i.e. branch names) to commit ids,
11
+ # where the commit ids are the first non-merge commits for each branch.
12
+ #
13
+ # @example
14
+ # snapshot = HeadSnapshotFactory.new
15
+ # .set_repo_config(config)
16
+ # .take_snapshot
17
+ #
18
+ # @!attribute [r] repo_config
19
+ # @return [RepoConfig] the repo config that contains the repo to take
20
+ # the snapshot for.
21
+ class HeadSnapshotFactory
22
+ attr_reader :repo_config
23
+
24
+ # Sets the repo config that contains the repo to take the snapshot for.
25
+ #
26
+ # @param [RepoConfig] repo_config
27
+ # @return [self]
28
+ def set_repo_config(repo_config)
29
+ @repo_config = repo_config
30
+ self
31
+ end
32
+
33
+ # Takes the snapshot.
34
+ #
35
+ # @return [Hash<String, String>] The head snapshot hash of refs to
36
+ # commit ids.
37
+ def take_snapshot
38
+ rev_walk = RevWalk.new(repo_config.repo.jgit_repo)
39
+ repo_config.repo.all_head_refs.each_with_object({}) do |ref, snapshot|
40
+ snapshot[ref] = process_ref(rev_walk, ref)
41
+ end
42
+ end
43
+
44
+ protected
45
+
46
+ def process_ref(rev_walk, ref)
47
+ rev_walk.reset
48
+ rev_walk.markStart(repo_config.repo.get_rev_commit(ref, rev_walk))
49
+ rev_walk.setRevFilter(RevFilter::NO_MERGES)
50
+
51
+ if rev_commit = rev_walk.next
52
+ rev_commit.getId.name
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+
3
+ java_import 'org.eclipse.jgit.treewalk.filter.TreeFilter'
4
+
5
+ module Rosette
6
+ module Core
7
+
8
+ # A jgit tree filter that filters by the path rules specified in the given
9
+ # {RepoConfig}.
10
+ #
11
+ # @example
12
+ # filter = RepoConfigPathFilter.create(repo_config)
13
+ # factory = Rosette::Core::SnapshotFactory.new
14
+ # .set_repo('my_repo')
15
+ #
16
+ # factory.add_filter(filter)
17
+ # factory.take_snapshot(...)
18
+ #
19
+ # @!attribute [rw] repo_config
20
+ # @return [Array<String>] the configuration to use when filtering paths
21
+ class RepoConfigPathFilter < TreeFilter
22
+ # Creates a new filter with the given repo config.
23
+ #
24
+ # @param [RepoConfig] repo_config The configuration to use when
25
+ # filtering paths
26
+ # @return [FileTypeFilter]
27
+ def self.create(repo_config)
28
+ # Do this because jruby is dumb (i.e. doesn't let you override java
29
+ # constructors)
30
+ new.tap do |obj|
31
+ obj.repo_config = repo_config
32
+ end
33
+ end
34
+
35
+ attr_accessor :repo_config
36
+
37
+ # Overridden. Returns true if the current file matches false otherwise.
38
+ # Generally this method is only called by Jgit internals.
39
+ #
40
+ # @param [Java::OrgEclipseJgitTreewalk::TreeWalk] walker The walker with
41
+ # the current file.
42
+ # @return [Boolean]
43
+ def include(walker)
44
+ if walker.isSubtree
45
+ true
46
+ else
47
+ path = walker.getPathString
48
+
49
+ if repo_config.extractor_configs.size > 0
50
+ repo_config.extractor_configs.any? do |extractor_config|
51
+ extractor_config.matches?(path)
52
+ end
53
+ else
54
+ true
55
+ end
56
+ end
57
+ end
58
+
59
+ # Returns true if this filter should be applied recursively, false otherwise.
60
+ # For this particular filter, always returns true.
61
+ #
62
+ # @return [Boolean]
63
+ def shouldBeRecursive
64
+ true
65
+ end
66
+
67
+ # Clones this filter. For this particular filter, always returns self.
68
+ #
69
+ # @return [self]
70
+ def clone
71
+ self
72
+ end
73
+
74
+ # Returns a string representation of this filter.
75
+ #
76
+ # @return [String]
77
+ def to_s
78
+ "REPO_CONFIG_FILTER"
79
+ end
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,184 @@
1
+ # encoding: UTF-8
2
+
3
+ java_import 'org.eclipse.jgit.revwalk.RevWalk'
4
+ java_import 'org.eclipse.jgit.revwalk.filter.RevFilter'
5
+ java_import 'org.eclipse.jgit.treewalk.EmptyTreeIterator'
6
+ java_import 'org.eclipse.jgit.treewalk.TreeWalk'
7
+ java_import 'org.eclipse.jgit.treewalk.filter.AndTreeFilter'
8
+ java_import 'org.eclipse.jgit.treewalk.filter.PathFilter'
9
+ java_import 'org.eclipse.jgit.treewalk.filter.PathFilterGroup'
10
+ java_import 'org.eclipse.jgit.treewalk.filter.TreeFilter'
11
+
12
+ require 'set'
13
+
14
+ module Rosette
15
+ module Core
16
+
17
+ # Takes snapshots of git repos. A snapshot is a simple key/value map (hash)
18
+ # of paths to commit ids. The commit id is the last time the file changed.
19
+ #
20
+ # @example
21
+ # snapshot = SnapshotFactory.new
22
+ # .set_repo_config(repo_config)
23
+ # .set_start_commit_id('73cd130a42017d794ffa86ef0d255541d518a7b3')
24
+ # .take_snapshot
25
+ #
26
+ # @!attribute [r] repo_config
27
+ # @return [Repo] the +RepoConfig+ object to use when filtering paths, etc.
28
+ # @!attribute [r] start_commit_id
29
+ # @return [String] the git commit id to start at. File changes that
30
+ # occurred more recently than this commit will not be reflected in
31
+ # the snapshot.
32
+ class SnapshotFactory
33
+ attr_reader :repo_config, :start_commit_id, :paths
34
+
35
+ # Creates a new factory.
36
+ def initialize
37
+ reset
38
+ end
39
+
40
+ # Sets the Rosette repo object to use.
41
+ #
42
+ # @param [Repo] repo The Rosette repo object to use.
43
+ # @return [self]
44
+ def set_repo_config(repo_config)
45
+ @repo_config = repo_config
46
+ self
47
+ end
48
+
49
+ # Sets the starting commit id. File changes that occurred more recently
50
+ # than this commit will not be reflected in the snapshot. In other words,
51
+ # this is the commit id to take the snapshot of.
52
+ #
53
+ # @param [String] commit_id The starting commit id.
54
+ # @return [self]
55
+ def set_start_commit_id(commit_id)
56
+ @start_commit_id = commit_id
57
+ self
58
+ end
59
+
60
+ # Set the paths that will be included in the snapshot.
61
+ #
62
+ # @param [Array] paths The paths to include in the snapshot.
63
+ # @return [self]
64
+ def set_paths(paths)
65
+ @paths = paths
66
+ self
67
+ end
68
+
69
+ # Takes the snapshot.
70
+ #
71
+ # @return [Hash<String, String>] The snapshot hash (path to commit id
72
+ # pairs).
73
+ def take_snapshot
74
+ build_hash.tap do
75
+ reset
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def build_hash
82
+ repo = repo_config.repo
83
+ rev_walk = RevWalk.new(repo.jgit_repo)
84
+ rev_commit = repo.get_rev_commit(start_commit_id, rev_walk)
85
+ path_set = (make_path_set(rev_commit) + paths).to_a
86
+ num_replacements = 0
87
+
88
+ tree_filter = if path_set.size > 0
89
+ path_filter = if repo_config && path_set.empty?
90
+ RepoConfigPathFilter.create(repo_config)
91
+ else
92
+ PathFilterGroup.createFromStrings(path_set)
93
+ end
94
+
95
+ AndTreeFilter.create(path_filter, TreeFilter::ANY_DIFF)
96
+ end
97
+
98
+ {}.tap do |path_hash|
99
+ tree_walk = TreeWalk.new(repo.jgit_repo)
100
+ rev_walk.markStart(rev_commit)
101
+
102
+ while cur_commit = rev_walk.next
103
+ cur_commit_id = cur_commit.getId.name
104
+
105
+ tree_walk.reset
106
+ parent_count = cur_commit.getParentCount
107
+
108
+ if parent_count == 0
109
+ tree_walk.addTree(EmptyTreeIterator.new)
110
+ else
111
+ parent_count.times do |i|
112
+ tree_walk.addTree(cur_commit.getParent(i).getTree)
113
+ end
114
+ end
115
+
116
+ tree_walk.addTree(cur_commit.getTree)
117
+ tree_walk.setFilter(tree_filter)
118
+ tree_walk.setRecursive(true)
119
+
120
+ each_file_in(tree_walk) do |walker|
121
+ path = walker.getPathString
122
+
123
+ unless path_hash[path]
124
+ path_hash[path] = cur_commit_id
125
+ num_replacements += 1
126
+ end
127
+ end
128
+
129
+ if num_replacements > path_hash.size
130
+ break
131
+ end
132
+ end
133
+
134
+ rev_walk.dispose
135
+ tree_walk.release
136
+ end
137
+ end
138
+
139
+ def make_path_set(rev_commit)
140
+ path_gatherer = make_path_gatherer(rev_commit)
141
+
142
+ files = each_file_in(path_gatherer).each_with_object(Set.new) do |walker, ret|
143
+ ret << walker.getPathString
144
+ end
145
+
146
+ path_gatherer.release
147
+ files
148
+ end
149
+
150
+ def make_path_gatherer(rev_commit)
151
+ TreeWalk.new(repo_config.repo.jgit_repo).tap do |walker|
152
+ walker.addTree(rev_commit.getTree)
153
+ walker.setRecursive(true)
154
+
155
+ # explicit paths take precedence over repo config ones
156
+ filter = if paths.size > 0
157
+ PathFilterGroup.createFromStrings(paths)
158
+ elsif repo_config
159
+ RepoConfigPathFilter.create(repo_config)
160
+ end
161
+
162
+ walker.setFilter(filter) if filter
163
+ end
164
+ end
165
+
166
+ def reset
167
+ @repo_config = nil
168
+ @start_commit_id = nil
169
+ @paths = []
170
+ end
171
+
172
+ def each_file_in(tree_walk)
173
+ if block_given?
174
+ while tree_walk.next
175
+ yield tree_walk
176
+ end
177
+ else
178
+ to_enum(__method__, tree_walk)
179
+ end
180
+ end
181
+ end
182
+
183
+ end
184
+ end