rosette-core 1.0.1
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.
- checksums.yaml +7 -0
- data/Gemfile +26 -0
- data/History.txt +3 -0
- data/README.md +94 -0
- data/Rakefile +18 -0
- data/lib/rosette/core.rb +110 -0
- data/lib/rosette/core/branch_utils.rb +152 -0
- data/lib/rosette/core/commands.rb +139 -0
- data/lib/rosette/core/commands/errors.rb +17 -0
- data/lib/rosette/core/commands/git/commit_command.rb +65 -0
- data/lib/rosette/core/commands/git/diff_base_command.rb +301 -0
- data/lib/rosette/core/commands/git/diff_command.rb +188 -0
- data/lib/rosette/core/commands/git/diff_entry.rb +44 -0
- data/lib/rosette/core/commands/git/fetch_command.rb +27 -0
- data/lib/rosette/core/commands/git/repo_snapshot_command.rb +40 -0
- data/lib/rosette/core/commands/git/show_command.rb +70 -0
- data/lib/rosette/core/commands/git/snapshot_command.rb +50 -0
- data/lib/rosette/core/commands/git/status_command.rb +128 -0
- data/lib/rosette/core/commands/git/with_non_merge_ref.rb +48 -0
- data/lib/rosette/core/commands/git/with_ref.rb +92 -0
- data/lib/rosette/core/commands/git/with_refs.rb +92 -0
- data/lib/rosette/core/commands/git/with_repo_name.rb +50 -0
- data/lib/rosette/core/commands/git/with_snapshots.rb +45 -0
- data/lib/rosette/core/commands/queuing/enqueue_commit_command.rb +37 -0
- data/lib/rosette/core/commands/queuing/requeue_commit_command.rb +46 -0
- data/lib/rosette/core/commands/translations/export_command.rb +257 -0
- data/lib/rosette/core/commands/translations/translation_lookup_command.rb +66 -0
- data/lib/rosette/core/commands/translations/with_locale.rb +47 -0
- data/lib/rosette/core/configurator.rb +160 -0
- data/lib/rosette/core/error_reporters/buffered_error_reporter.rb +96 -0
- data/lib/rosette/core/error_reporters/error_reporter.rb +31 -0
- data/lib/rosette/core/error_reporters/nil_error_reporter.rb +25 -0
- data/lib/rosette/core/error_reporters/printing_error_reporter.rb +58 -0
- data/lib/rosette/core/error_reporters/raising_error_reporter.rb +27 -0
- data/lib/rosette/core/errors.rb +93 -0
- data/lib/rosette/core/extractor/commit_log.rb +33 -0
- data/lib/rosette/core/extractor/commit_log_status.rb +57 -0
- data/lib/rosette/core/extractor/commit_processor.rb +109 -0
- data/lib/rosette/core/extractor/extractor.rb +72 -0
- data/lib/rosette/core/extractor/extractor_config.rb +74 -0
- data/lib/rosette/core/extractor/locale.rb +118 -0
- data/lib/rosette/core/extractor/phrase.rb +76 -0
- data/lib/rosette/core/extractor/phrase/phrase_index_policy.rb +108 -0
- data/lib/rosette/core/extractor/phrase/phrase_to_hash.rb +33 -0
- data/lib/rosette/core/extractor/repo_config.rb +339 -0
- data/lib/rosette/core/extractor/serializer_config.rb +55 -0
- data/lib/rosette/core/extractor/static_extractor.rb +44 -0
- data/lib/rosette/core/extractor/translation.rb +44 -0
- data/lib/rosette/core/extractor/translation/translation_to_hash.rb +28 -0
- data/lib/rosette/core/git/diff_finder.rb +131 -0
- data/lib/rosette/core/git/ref.rb +116 -0
- data/lib/rosette/core/git/repo.rb +378 -0
- data/lib/rosette/core/path_matcher_factory.rb +330 -0
- data/lib/rosette/core/resolvers/extractor_id.rb +37 -0
- data/lib/rosette/core/resolvers/integration_id.rb +37 -0
- data/lib/rosette/core/resolvers/preprocessor_id.rb +38 -0
- data/lib/rosette/core/resolvers/resolver.rb +115 -0
- data/lib/rosette/core/resolvers/serializer_id.rb +37 -0
- data/lib/rosette/core/snapshots/cached_head_snapshot_factory.rb +51 -0
- data/lib/rosette/core/snapshots/cached_snapshot_factory.rb +67 -0
- data/lib/rosette/core/snapshots/head_snapshot_factory.rb +58 -0
- data/lib/rosette/core/snapshots/repo_config_path_filter.rb +83 -0
- data/lib/rosette/core/snapshots/snapshot_factory.rb +184 -0
- data/lib/rosette/core/string_utils.rb +23 -0
- data/lib/rosette/core/translation_status.rb +81 -0
- data/lib/rosette/core/validators.rb +18 -0
- data/lib/rosette/core/validators/commit_validator.rb +62 -0
- data/lib/rosette/core/validators/commits_validator.rb +32 -0
- data/lib/rosette/core/validators/encoding_validator.rb +32 -0
- data/lib/rosette/core/validators/locale_validator.rb +37 -0
- data/lib/rosette/core/validators/repo_validator.rb +33 -0
- data/lib/rosette/core/validators/serializer_validator.rb +37 -0
- data/lib/rosette/core/validators/validator.rb +31 -0
- data/lib/rosette/core/version.rb +8 -0
- data/lib/rosette/data_stores.rb +11 -0
- data/lib/rosette/data_stores/errors.rb +26 -0
- data/lib/rosette/data_stores/phrase_status.rb +59 -0
- data/lib/rosette/integrations.rb +12 -0
- data/lib/rosette/integrations/errors.rb +15 -0
- data/lib/rosette/integrations/integratable.rb +58 -0
- data/lib/rosette/integrations/integration.rb +23 -0
- data/lib/rosette/preprocessors.rb +11 -0
- data/lib/rosette/preprocessors/errors.rb +14 -0
- data/lib/rosette/preprocessors/preprocessor.rb +48 -0
- data/lib/rosette/queuing.rb +14 -0
- data/lib/rosette/queuing/commits.rb +19 -0
- data/lib/rosette/queuing/commits/commit_conductor.rb +90 -0
- data/lib/rosette/queuing/commits/commit_job.rb +93 -0
- data/lib/rosette/queuing/commits/commits_queue_configurator.rb +60 -0
- data/lib/rosette/queuing/commits/extract_stage.rb +46 -0
- data/lib/rosette/queuing/commits/fetch_stage.rb +51 -0
- data/lib/rosette/queuing/commits/finalize_stage.rb +76 -0
- data/lib/rosette/queuing/commits/phrase_storage_granularity.rb +20 -0
- data/lib/rosette/queuing/commits/push_stage.rb +91 -0
- data/lib/rosette/queuing/commits/stage.rb +96 -0
- data/lib/rosette/queuing/job.rb +74 -0
- data/lib/rosette/queuing/queue.rb +28 -0
- data/lib/rosette/queuing/queue_configurator.rb +76 -0
- data/lib/rosette/queuing/worker.rb +30 -0
- data/lib/rosette/serializers.rb +10 -0
- data/lib/rosette/serializers/serializer.rb +98 -0
- data/lib/rosette/tms.rb +9 -0
- data/lib/rosette/tms/repository.rb +95 -0
- data/rosette-core.gemspec +24 -0
- data/spec/core/branch_utils_spec.rb +110 -0
- data/spec/core/commands/git/commit_command_spec.rb +60 -0
- data/spec/core/commands/git/diff_command_spec.rb +263 -0
- data/spec/core/commands/git/fetch_command_spec.rb +61 -0
- data/spec/core/commands/git/repo_snapshot_command_spec.rb +72 -0
- data/spec/core/commands/git/show_command_spec.rb +128 -0
- data/spec/core/commands/git/snapshot_command_spec.rb +86 -0
- data/spec/core/commands/git/status_command_spec.rb +154 -0
- data/spec/core/commands/queuing/enqueue_commit_command_spec.rb +34 -0
- data/spec/core/commands/queuing/requeue_commit_command_spec.rb +46 -0
- data/spec/core/commands/translations/export_command_spec.rb +113 -0
- data/spec/core/commands/translations/translation_lookup_command_spec.rb +58 -0
- data/spec/core/configurator_spec.rb +47 -0
- data/spec/core/error_reporters/buffered_error_reporter_spec.rb +61 -0
- data/spec/core/error_reporters/nil_error_reporter_spec.rb +16 -0
- data/spec/core/error_reporters/printing_error_reporter_spec.rb +60 -0
- data/spec/core/extractor/commit_log_status_spec.rb +216 -0
- data/spec/core/extractor/commit_processor_spec.rb +68 -0
- data/spec/core/extractor/extractor_config_spec.rb +47 -0
- data/spec/core/extractor/extractor_spec.rb +26 -0
- data/spec/core/extractor/locale_spec.rb +92 -0
- data/spec/core/extractor/phrase/phrase_index_policy_spec.rb +116 -0
- data/spec/core/extractor/phrase/phrase_to_hash_spec.rb +18 -0
- data/spec/core/extractor/repo_config_spec.rb +147 -0
- data/spec/core/extractor/translation/translation_to_hash_spec.rb +25 -0
- data/spec/core/git/diff_finder_spec.rb +74 -0
- data/spec/core/git/ref_spec.rb +118 -0
- data/spec/core/git/repo_spec.rb +216 -0
- data/spec/core/path_matcher_factory_spec.rb +139 -0
- data/spec/core/resolvers/extractor_id_spec.rb +47 -0
- data/spec/core/resolvers/integration_id_spec.rb +47 -0
- data/spec/core/resolvers/preprocessor_id_spec.rb +47 -0
- data/spec/core/resolvers/serializer_id_spec.rb +47 -0
- data/spec/core/snapshots/snapshot_factory_spec.rb +145 -0
- data/spec/core/string_utils_spec.rb +19 -0
- data/spec/core/translation_status_spec.rb +91 -0
- data/spec/core/validators/commit_validator_spec.rb +40 -0
- data/spec/core/validators/encoding_validator_spec.rb +30 -0
- data/spec/core/validators/locale_validator_spec.rb +31 -0
- data/spec/core/validators/repo_validator_spec.rb +30 -0
- data/spec/core/validators/serializer_validator_spec.rb +31 -0
- data/spec/integrations/integratable_spec.rb +58 -0
- data/spec/queuing/commits/commit_conductor_spec.rb +71 -0
- data/spec/queuing/commits/commit_job_spec.rb +87 -0
- data/spec/queuing/commits/extract_stage_spec.rb +68 -0
- data/spec/queuing/commits/fetch_stage_spec.rb +101 -0
- data/spec/queuing/commits/finalize_stage_spec.rb +88 -0
- data/spec/queuing/commits/push_stage_spec.rb +145 -0
- data/spec/queuing/commits/stage_spec.rb +80 -0
- data/spec/queuing/job_spec.rb +33 -0
- data/spec/queuing/queue_configurator_spec.rb +44 -0
- data/spec/spec_helper.rb +90 -0
- data/spec/test_helpers/fake_commit_stage.rb +17 -0
- 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
|