rosette-core 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1e9c9e17cffceee3657ed1dce1aba43c06e66873
|
4
|
+
data.tar.gz: 4b0170aa075e3ba248ccfe49dc8d042fb6578d35
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c4fc6828341aafeed4ccfbd42034337c001ff0562f234d29f2d00fc296b10af0e74ee4fded6b8cb0f3498d7f5932a1f9edcff715f86af618936242947ff04788
|
7
|
+
data.tar.gz: 415b95e177ab76034b84f3262fa93c3d5c02c3b18552e2a9040dc06653036d1958b143ccd495ce376e12454f2a9f2c4c37fe5f2d616afed66ab1b6fea215d951
|
data/Gemfile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
ruby '2.0.0', engine: 'jruby', engine_version: '1.7.15'
|
6
|
+
|
7
|
+
gem 'rosette-datastore-memory', github: 'rosette-proj/rosette-datastore-memory'
|
8
|
+
|
9
|
+
group :development, :test do
|
10
|
+
gem 'activemodel', '>= 3.2.20'
|
11
|
+
gem 'expert', '~> 1.0'
|
12
|
+
gem 'pry-nav'
|
13
|
+
gem 'rake'
|
14
|
+
gem 'repo-fixture'
|
15
|
+
end
|
16
|
+
|
17
|
+
group :development do
|
18
|
+
gem 'yard', '~> 0.8.0'
|
19
|
+
end
|
20
|
+
|
21
|
+
group :test do
|
22
|
+
gem 'codeclimate-test-reporter', require: nil
|
23
|
+
gem 'simplecov'
|
24
|
+
gem 'rspec'
|
25
|
+
gem 'rosette-test-helpers', github: 'rosette-proj/rosette-test-helpers'
|
26
|
+
end
|
data/History.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
rosette-core
|
2
|
+
========
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/rosette-proj/rosette-core.svg?branch=master)](https://travis-ci.org/rosette-proj/rosette-core.svg?branch=master) [![Code Climate](https://codeclimate.com/github/rosette-proj/rosette-core/badges/gpa.svg)](https://codeclimate.com/github/rosette-proj/rosette-core) [![Test Coverage](https://codeclimate.com/github/rosette-proj/rosette-core/badges/coverage.svg)](https://codeclimate.com/github/rosette-proj/rosette-core/coverage)
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
`gem install rosette-core`
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
require 'rosette/core'
|
14
|
+
```
|
15
|
+
|
16
|
+
## Intro
|
17
|
+
|
18
|
+
This repository contains the core classes for the Rosette internationalizaton framework. Full documentation can be found on [rubydoc.info](http://www.rubydoc.info/github/rosette-proj/rosette-core).
|
19
|
+
|
20
|
+
Generally, this library is required by other projects like [rosette-server](https://github.com/rosette-proj/rosette-server), which means that most likely you'll make use of it indirectly. Please refer to the documentation that accompanies these other projects to set up and use Rosette.
|
21
|
+
|
22
|
+
## Major Components
|
23
|
+
|
24
|
+
What follows is a list of the major components in rosette-core. It's not meant to be an exhaustive list, but should give a decent overview of what's going on.
|
25
|
+
|
26
|
+
### Commands
|
27
|
+
|
28
|
+
Rosette commands are designed to mimic git operations. For example, use the `DiffCommand` to show the added/removed/changed phrases between two git refs. Use the `StatusCommand` to compute the status of a git ref i.e. the percent translated per locale. Commands all follow the builder pattern, meaning you create a blank instance, call setter methods for required fields, then call the `#execute` method. Here's an example for the `ShowCommand`:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
Rosette::Core::Commands::ShowCommand.new(rosette_config)
|
32
|
+
.set_repo_name('my_awesome_repo')
|
33
|
+
.set_ref('master')
|
34
|
+
.execute
|
35
|
+
```
|
36
|
+
|
37
|
+
### Git Classes
|
38
|
+
|
39
|
+
Rosette manages git repos by leveraging the open-source [jGit library](https://eclipse.org/jgit), which is a full git implementation for the JVM. The `Repo` and `DiffFinder` classes wrap jGit and provide a set of methods for interacting with git repositories in a slightly more Ruby-ish way. Specifically, `Repo` offers generic methods like `#parents_of` and `#read_object_bytes`, while `DiffFinder` finds diffs between git refs. Here's an example of creating a `Repo` instance and calculating a diff:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
repo = Rosette::Core::Repo.from_path('/path/to/my_repo/.git')
|
43
|
+
repo.diff('master', 'my_branch') # you can optionally specify a list of paths as well
|
44
|
+
```
|
45
|
+
|
46
|
+
### Resolvers
|
47
|
+
|
48
|
+
The resolvers provide a way of looking up class constants for a number of Rosette's sub-components using slash-separated strings. For example, the `ExtractorId` class will resolve the string 'xml/android' into `Rosette::Extractors::XmlExtractor::AndroidExtractor`. Resolvers exist for extractors, integrations, pre-processors, and serializers.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Rosette::Core::ExtractorId.resolve('xml/android')
|
52
|
+
Rosette::Core::SerializerId.resolve('yaml/rails')
|
53
|
+
```
|
54
|
+
|
55
|
+
### Snapshot Classes
|
56
|
+
|
57
|
+
Snapshots are Ruby hashes of file paths to git commit ids. The idea of the snapshot is central to Rosette's git model in that Rosette uses them to know when files that contain translatable content last changed. Rather than storing phrases for every file for every commit, Rosette only stores content when files change. Rosette can use a snapshot to gather a complete list of phrases for each commit in the repository.
|
58
|
+
|
59
|
+
You probably won't have to take snapshots manually, but if you do, here's an example:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
Rosette::Core::SnapshotFactory.new
|
63
|
+
.set_repo_config(repo_config)
|
64
|
+
.set_start_commit_id('abc123')
|
65
|
+
.set_paths('path/to/snapshot') # looks at all paths in repo by default
|
66
|
+
.take_snapshot
|
67
|
+
```
|
68
|
+
|
69
|
+
### Queue Classes
|
70
|
+
|
71
|
+
You can choose to process new commits by placing them in a queue (perhaps in combination with a github webhook or a plain 'ol git hook). The queuing logic and various queue stages all live in rosette-core. The stages are:
|
72
|
+
|
73
|
+
1. Fetch/pull the repo
|
74
|
+
2. Extract phrases for the given commit, store in datastore
|
75
|
+
3. Push phrases to TMS (translation management system) for translation
|
76
|
+
4. Finalize the TMS submission (perform any necessary clean-up)
|
77
|
+
|
78
|
+
If you're not using a queue to process new commits, you'll have to process them some other way to stay current.
|
79
|
+
|
80
|
+
### Interfaces
|
81
|
+
|
82
|
+
rosette-core contains a few base classes that serve as interfaces for implementations that live in other gems. For example, the [rosette-extractor-yaml gem](https://github.com/rosette-proj/rosette-extractor-yaml) defines the `YamlExtractor` class, which inherits from `Rosette::Core::Extractor`. Other interfaces include `Rosette::Tms::Repository`, `Rosette::Serializers::Serializer`, `Rosette::Preprocessors::Preprocessor`, and more.
|
83
|
+
|
84
|
+
## Requirements
|
85
|
+
|
86
|
+
All Rosette components only run under jRuby. Java dependencies are managed via the [expert gem](https://github.com/camertron/expert). Run `bundle exec expert install` to install Java dependencies.
|
87
|
+
|
88
|
+
## Running Tests
|
89
|
+
|
90
|
+
`bundle`, then `bundle exec expert install`, then `bundle exec rspec`.
|
91
|
+
|
92
|
+
## Authors
|
93
|
+
|
94
|
+
* Cameron C. Dutro: http://github.com/camertron
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'rubygems/package_task'
|
8
|
+
|
9
|
+
require './lib/rosette/core'
|
10
|
+
|
11
|
+
Bundler::GemHelper.install_tasks
|
12
|
+
|
13
|
+
task :default => :spec
|
14
|
+
|
15
|
+
desc 'Run specs'
|
16
|
+
RSpec::Core::RakeTask.new do |t|
|
17
|
+
t.pattern = './spec/**/*_spec.rb'
|
18
|
+
end
|
data/lib/rosette/core.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'rosette/core/errors'
|
5
|
+
|
6
|
+
java_import java.lang.System
|
7
|
+
|
8
|
+
# Rosette is a modular internationalization platform written in Ruby.
|
9
|
+
module Rosette
|
10
|
+
# Get the current Rosette logger. Defaults to a logger that logs to STDOUT.
|
11
|
+
#
|
12
|
+
# @return [#info, #warning, #error] The current logger.
|
13
|
+
def self.logger
|
14
|
+
@logger ||= Logger.new(STDOUT)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set the Rosette logger.
|
18
|
+
#
|
19
|
+
# @param [#info, #warning, #error] new_logger The new logger.
|
20
|
+
# @return [void]
|
21
|
+
def self.logger=(new_logger)
|
22
|
+
@logger = new_logger
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get the current Rosette environment name. Defaults to "development".
|
26
|
+
#
|
27
|
+
# @return [String] The current environment name.
|
28
|
+
def self.env
|
29
|
+
@env || 'development'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Set the Rosette environment name.
|
33
|
+
#
|
34
|
+
# @param [String] new_env The new environment name.
|
35
|
+
# @return [void]
|
36
|
+
def self.env=(new_env)
|
37
|
+
@env = new_env
|
38
|
+
end
|
39
|
+
|
40
|
+
# Constructs a new Rosette configurator object and yields it to the block.
|
41
|
+
#
|
42
|
+
# @return [Configurator] The configurator object that was yielded.
|
43
|
+
# @yield [configuration]
|
44
|
+
# @yieldparam configuration [Configurator]
|
45
|
+
def self.build_config
|
46
|
+
configuration = Rosette::Core::Configurator.new
|
47
|
+
yield configuration
|
48
|
+
configuration.apply_integrations(configuration)
|
49
|
+
configuration
|
50
|
+
end
|
51
|
+
|
52
|
+
# Namespace for all Rosette core classes.
|
53
|
+
module Core
|
54
|
+
# The default encoding for all of Rosette.
|
55
|
+
DEFAULT_ENCODING = Encoding::UTF_8
|
56
|
+
|
57
|
+
autoload :Configurator, 'rosette/core/configurator'
|
58
|
+
|
59
|
+
autoload :StringUtils, 'rosette/core/string_utils'
|
60
|
+
|
61
|
+
autoload :Ref, 'rosette/core/git/ref'
|
62
|
+
autoload :Repo, 'rosette/core/git/repo'
|
63
|
+
autoload :DiffFinder, 'rosette/core/git/diff_finder'
|
64
|
+
|
65
|
+
autoload :Snapshot, 'rosette/core/snapshots/snapshot'
|
66
|
+
autoload :SnapshotFactory, 'rosette/core/snapshots/snapshot_factory'
|
67
|
+
autoload :CachedSnapshotFactory, 'rosette/core/snapshots/cached_snapshot_factory'
|
68
|
+
autoload :HeadSnapshotFactory, 'rosette/core/snapshots/head_snapshot_factory'
|
69
|
+
autoload :CachedHeadSnapshotFactory, 'rosette/core/snapshots/cached_head_snapshot_factory'
|
70
|
+
autoload :SnapshotFilterable, 'rosette/core/snapshots/snapshot_filterable'
|
71
|
+
autoload :RepoConfigPathFilter, 'rosette/core/snapshots/repo_config_path_filter'
|
72
|
+
|
73
|
+
autoload :Extractor, 'rosette/core/extractor/extractor'
|
74
|
+
autoload :StaticExtractor, 'rosette/core/extractor/static_extractor'
|
75
|
+
autoload :Phrase, 'rosette/core/extractor/phrase'
|
76
|
+
autoload :Translation, 'rosette/core/extractor/translation'
|
77
|
+
autoload :CommitLog, 'rosette/core/extractor/commit_log'
|
78
|
+
autoload :CommitLogStatus, 'rosette/core/extractor/commit_log_status'
|
79
|
+
autoload :ExtractorConfig, 'rosette/core/extractor/extractor_config'
|
80
|
+
autoload :PathMatcherFactory, 'rosette/core/path_matcher_factory'
|
81
|
+
autoload :TranslationsPathConfig, 'rosette/core/extractor/translations_path_config'
|
82
|
+
autoload :RepoConfig, 'rosette/core/extractor/repo_config'
|
83
|
+
autoload :SerializerConfig, 'rosette/core/extractor/serializer_config'
|
84
|
+
autoload :CommitProcessor, 'rosette/core/extractor/commit_processor'
|
85
|
+
autoload :Locale, 'rosette/core/extractor/locale'
|
86
|
+
|
87
|
+
autoload :PhraseIndexPolicy, 'rosette/core/extractor/phrase/phrase_index_policy'
|
88
|
+
autoload :PhraseToHash, 'rosette/core/extractor/phrase/phrase_to_hash'
|
89
|
+
|
90
|
+
autoload :TranslationToHash, 'rosette/core/extractor/translation/translation_to_hash'
|
91
|
+
|
92
|
+
autoload :ErrorReporter, 'rosette/core/error_reporters/error_reporter'
|
93
|
+
autoload :NilErrorReporter, 'rosette/core/error_reporters/nil_error_reporter'
|
94
|
+
autoload :PrintingErrorReporter, 'rosette/core/error_reporters/printing_error_reporter'
|
95
|
+
autoload :BufferedErrorReporter, 'rosette/core/error_reporters/buffered_error_reporter'
|
96
|
+
autoload :RaisingErrorReporter, 'rosette/core/error_reporters/raising_error_reporter'
|
97
|
+
|
98
|
+
autoload :Validators, 'rosette/core/validators'
|
99
|
+
|
100
|
+
autoload :Resolver, 'rosette/core/resolvers/resolver'
|
101
|
+
autoload :ExtractorId, 'rosette/core/resolvers/extractor_id'
|
102
|
+
autoload :IntegrationId, 'rosette/core/resolvers/integration_id'
|
103
|
+
autoload :SerializerId, 'rosette/core/resolvers/serializer_id'
|
104
|
+
autoload :PreprocessorId, 'rosette/core/resolvers/preprocessor_id'
|
105
|
+
|
106
|
+
autoload :Commands, 'rosette/core/commands'
|
107
|
+
autoload :BranchUtils, 'rosette/core/branch_utils'
|
108
|
+
autoload :TranslationStatus, 'rosette/core/translation_status'
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'digest/sha1'
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Core
|
7
|
+
|
8
|
+
# Utility methods that work at the branch level.
|
9
|
+
class BranchUtils
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# Computes the status for an array of commit logs. Determining the
|
13
|
+
# aggregate status of more than one commit log means choosing the least
|
14
|
+
# far-along status from the list. In other words, if the list contains
|
15
|
+
# two commit logs with FETCHED and FINALIZED statuses respectively, this
|
16
|
+
# method will return FETCHED because that's the least advanced status in
|
17
|
+
# the list. A list of commit logs is only as advanced as its 'weakest',
|
18
|
+
# least advanced element.
|
19
|
+
#
|
20
|
+
# @param [Array<CommitLog>] commit_logs The list of commit logs to
|
21
|
+
# derive the status from.
|
22
|
+
# @return [PhraseStatus]
|
23
|
+
def derive_status_from(commit_logs)
|
24
|
+
ps = Rosette::DataStores::PhraseStatus
|
25
|
+
entry = commit_logs.min_by { |entry| ps.index(entry.status) }
|
26
|
+
|
27
|
+
if entry
|
28
|
+
entry.status
|
29
|
+
else
|
30
|
+
# since FINALIZED commit_logs aren't considered, the absence of any
|
31
|
+
# commit logs (i.e. a nil entry) indicates the branch is fully
|
32
|
+
# processed
|
33
|
+
Rosette::DataStores::PhraseStatus::FINALIZED
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Computes the phrase count for the given list of commit logs. This is
|
38
|
+
# simply the sum of all the commit log's phrase counts.
|
39
|
+
#
|
40
|
+
# @param [Array<CommitLog>] commit_logs The list of commit logs to
|
41
|
+
# compute the phrase count from.
|
42
|
+
# @return [Fixnum]
|
43
|
+
def derive_phrase_count_from(commit_logs)
|
44
|
+
commit_logs.inject(0) { |sum, entry| sum + entry.phrase_count }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Computes the status for each individual locale contained in the
|
48
|
+
# given list of commit logs. Locale statuses are hashes that contain a
|
49
|
+
# count of the number of translated phrases for that locale as well as
|
50
|
+
# the percent translated.
|
51
|
+
#
|
52
|
+
# @param [Array<CommitLog>] commit_logs The list of commit logs to
|
53
|
+
# compute locale statuses from.
|
54
|
+
# @param [String] repo_name The name of the repo these commit logs came
|
55
|
+
# from.
|
56
|
+
# @param [Object] datastore The datastore to query for locale data.
|
57
|
+
# @param [Fixnum] phrase_count The aggregate number of phrases for the
|
58
|
+
# list of commit logs. If +nil+, the +derive_phrase_count+ method
|
59
|
+
# will be called to fill in this parameter.
|
60
|
+
# @return [Hash] the locale status hash. Contains locale codes as
|
61
|
+
# top-level keys and hashes as values. Each locale hash contains the
|
62
|
+
# keys +:translated_count+ and +:percent_translated+.
|
63
|
+
def derive_locale_statuses_from(commit_logs, repo_name, datastore, phrase_count = nil)
|
64
|
+
phrase_count ||= derive_phrase_count_from(commit_logs)
|
65
|
+
|
66
|
+
locale_statuses = commit_logs.each_with_object({}) do |commit_log, ret|
|
67
|
+
locale_entries = datastore.commit_log_locales_for(
|
68
|
+
repo_name, commit_log.commit_id
|
69
|
+
)
|
70
|
+
|
71
|
+
locale_entries.each do |locale_entry|
|
72
|
+
ret[locale_entry.locale] ||= { translated_count: 0 }
|
73
|
+
|
74
|
+
ret[locale_entry.locale].tap do |locale_hash|
|
75
|
+
locale_hash[:translated_count] += locale_entry.translated_count
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
add_translation_percentages(locale_statuses, phrase_count)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds any missing locale keys to a hash of locale statuses.
|
84
|
+
#
|
85
|
+
# @param [Array<Locale>] all_locales The complete list of locales that
|
86
|
+
# +locale_statuses+ should contain.
|
87
|
+
# @param [Hash] locale_statuses The locale statuses hash such as is
|
88
|
+
# returned by +derive_locale_statuses_from+.
|
89
|
+
# @return [Hash] a copy of +locale_statuses+ that contains entries for
|
90
|
+
# all the locales in +all_locales+. Any locale entries missing from
|
91
|
+
# +locale_statuses+ will have been filled in with blank data, i.e.
|
92
|
+
# +:translated_count+ will be 0 and +:percent_translated+ will be 0.0.
|
93
|
+
def fill_in_missing_locales(all_locales, locale_statuses)
|
94
|
+
all_locales.each_with_object({}) do |locale, ret|
|
95
|
+
if found_locale_status = locale_statuses[locale.code]
|
96
|
+
ret[locale.code] = found_locale_status
|
97
|
+
else
|
98
|
+
ret[locale.code] = {
|
99
|
+
percent_translated: 0.0,
|
100
|
+
translated_count: 0
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def derive_branch_name(commit_id, repo)
|
107
|
+
refs = repo.refs_containing(commit_id).map(&:getName)
|
108
|
+
|
109
|
+
if refs.include?('refs/remotes/origin/master')
|
110
|
+
'refs/remotes/origin/master'
|
111
|
+
else
|
112
|
+
filter_refs(refs).first
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def filter_refs(refs)
|
119
|
+
refs.each_with_object([]) do |ref, ret|
|
120
|
+
ret << ref if valid_ref?(ref)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def valid_ref?(ref_text)
|
125
|
+
ref = Rosette::Core::Ref.parse(ref_text)
|
126
|
+
ref && ref.remote? && ref.name != 'master' && ref.name != 'HEAD'
|
127
|
+
end
|
128
|
+
|
129
|
+
def add_translation_percentages(locale_statuses, phrase_count)
|
130
|
+
locale_statuses.each_with_object({}) do |(locale, locale_status), ret|
|
131
|
+
ret[locale] = locale_status.merge(
|
132
|
+
percent_translated: percentage(
|
133
|
+
locale_status.fetch(:translated_count, 0) || 0,
|
134
|
+
phrase_count || 0
|
135
|
+
)
|
136
|
+
)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def percentage(dividend, divisor)
|
141
|
+
if divisor > 0
|
142
|
+
(dividend.to_f / divisor.to_f).round(2)
|
143
|
+
else
|
144
|
+
0.0
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'digest/sha1'
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Core
|
7
|
+
|
8
|
+
# Namespace for all Rosette commands.
|
9
|
+
module Commands
|
10
|
+
|
11
|
+
autoload :Errors, 'rosette/core/commands/errors'
|
12
|
+
|
13
|
+
autoload :CommitCommand, 'rosette/core/commands/git/commit_command'
|
14
|
+
autoload :DiffBaseCommand, 'rosette/core/commands/git/diff_base_command'
|
15
|
+
autoload :DiffCommand, 'rosette/core/commands/git/diff_command'
|
16
|
+
autoload :ShowCommand, 'rosette/core/commands/git/show_command'
|
17
|
+
autoload :StatusCommand, 'rosette/core/commands/git/status_command'
|
18
|
+
autoload :FetchCommand, 'rosette/core/commands/git/fetch_command'
|
19
|
+
autoload :SnapshotCommand, 'rosette/core/commands/git/snapshot_command'
|
20
|
+
autoload :RepoSnapshotCommand, 'rosette/core/commands/git/repo_snapshot_command'
|
21
|
+
autoload :WithRepoName, 'rosette/core/commands/git/with_repo_name'
|
22
|
+
autoload :WithRef, 'rosette/core/commands/git/with_ref'
|
23
|
+
autoload :WithRefs, 'rosette/core/commands/git/with_refs'
|
24
|
+
autoload :WithNonMergeRef, 'rosette/core/commands/git/with_non_merge_ref'
|
25
|
+
autoload :WithSnapshots, 'rosette/core/commands/git/with_snapshots'
|
26
|
+
autoload :DiffEntry, 'rosette/core/commands/git/diff_entry'
|
27
|
+
|
28
|
+
autoload :WithLocale, 'rosette/core/commands/translations/with_locale'
|
29
|
+
autoload :ExportCommand, 'rosette/core/commands/translations/export_command'
|
30
|
+
autoload :TranslationLookupCommand, 'rosette/core/commands/translations/translation_lookup_command'
|
31
|
+
|
32
|
+
autoload :EnqueueCommitCommand, 'rosette/core/commands/queuing/enqueue_commit_command'
|
33
|
+
autoload :RequeueCommitCommand, 'rosette/core/commands/queuing/requeue_commit_command'
|
34
|
+
|
35
|
+
# Base class for all Rosette commands.
|
36
|
+
#
|
37
|
+
# @!attribute [r] configuration
|
38
|
+
# @return [Configurator] Rosette configuration.
|
39
|
+
class Command
|
40
|
+
attr_reader :configuration
|
41
|
+
|
42
|
+
class << self
|
43
|
+
# Validates a single field.
|
44
|
+
#
|
45
|
+
# @param [Symbol] field The field to validate.
|
46
|
+
# @param [Hash] validator_hash The hash of options for this
|
47
|
+
# validation. For now, should just contain +:type+ which contains
|
48
|
+
# to a symbol corresponding to the type of validator to use.
|
49
|
+
# @return [void]
|
50
|
+
def validate(field, validator_hash)
|
51
|
+
validators[field] << instantiate_validator(validator_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
# A hash of all the currently configured validators.
|
55
|
+
#
|
56
|
+
# @return [Hash<Symbol, Array<Validator>>] The hash of fields to
|
57
|
+
# valdiator instances.
|
58
|
+
def validators
|
59
|
+
@validators ||= Hash.new { |hash, key| hash[key] = [] }
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def instantiate_validator(validator_hash)
|
65
|
+
validator_type = validator_hash.fetch(:type)
|
66
|
+
validator_class_for(validator_type).new(validator_hash)
|
67
|
+
end
|
68
|
+
|
69
|
+
def validator_class_for(validator_type)
|
70
|
+
klass = "#{Rosette::Core::StringUtils.camelize(validator_type.to_s)}Validator"
|
71
|
+
if Rosette::Core::Validators.const_defined?(klass)
|
72
|
+
Rosette::Core::Validators.const_get(klass)
|
73
|
+
else
|
74
|
+
raise TypeError, "couldn't find #{validator_type} validator"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Creates a new command instance.
|
80
|
+
#
|
81
|
+
# @param [Configurator] configuration The Rosette configuration to use.
|
82
|
+
def initialize(configuration)
|
83
|
+
@configuration = configuration
|
84
|
+
end
|
85
|
+
|
86
|
+
# Gets the hash of current error messages.
|
87
|
+
#
|
88
|
+
# @return [Hash<Symbol, Array<String>>] The hash of current messages.
|
89
|
+
# The hash's keys are field names and the values are arrays of error
|
90
|
+
# messages for that field.
|
91
|
+
def messages
|
92
|
+
@messages ||= {}
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns true if the command's validators all pass, false otherwise.
|
96
|
+
#
|
97
|
+
# @raise [NotImplementedError]
|
98
|
+
def valid?
|
99
|
+
raise NotImplementedError, 'please use a Command subclass.'
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
def datastore
|
105
|
+
configuration.datastore
|
106
|
+
end
|
107
|
+
|
108
|
+
def path_digest(paths)
|
109
|
+
Digest::MD5.hexdigest(paths.join)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Base class for all of Rosette's git-based commands.
|
114
|
+
class GitCommand < Command
|
115
|
+
# Returns true if the command's validators all pass, false otherwise.
|
116
|
+
# After this method is finished executing, the +messages+ hash will
|
117
|
+
# have been populated with error messages per field.
|
118
|
+
#
|
119
|
+
# @return [Boolean]
|
120
|
+
def valid?
|
121
|
+
self.class.validators.all? do |name, validators|
|
122
|
+
validators.all? do |validator|
|
123
|
+
valid = validator.valid?(send(name), repo_name, configuration)
|
124
|
+
messages[name] = validator.messages unless valid
|
125
|
+
valid
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
def get_repo(name)
|
133
|
+
configuration.get_repo(name)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|