copy_tuner_client 2.1.2 → 2.2.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.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.rubocop.yml +46 -1
- data/CLAUDE.md +1 -0
- data/Gemfile +1 -0
- data/copy_tuner_client.gemspec +3 -3
- data/gemfiles/8.0.gemfile +3 -3
- data/gemfiles/8.1.gemfile +3 -3
- data/gemfiles/main.gemfile +3 -3
- data/lib/copy_tuner_client/cache.rb +34 -27
- data/lib/copy_tuner_client/client.rb +35 -23
- data/lib/copy_tuner_client/configuration.rb +62 -40
- data/lib/copy_tuner_client/copyray/rewriter.rb +1 -1
- data/lib/copy_tuner_client/copyray.rb +1 -0
- data/lib/copy_tuner_client/copyray_middleware.rb +31 -24
- data/lib/copy_tuner_client/dotted_hash.rb +7 -7
- data/lib/copy_tuner_client/engine.rb +4 -6
- data/lib/copy_tuner_client/helper_extension.rb +58 -54
- data/lib/copy_tuner_client/i18n_backend.rb +12 -14
- data/lib/copy_tuner_client/i18n_compat.rb +2 -1
- data/lib/copy_tuner_client/poller.rb +3 -4
- data/lib/copy_tuner_client/prefixed_logger.rb +13 -12
- data/lib/copy_tuner_client/process_guard.rb +29 -26
- data/lib/copy_tuner_client/queue_with_timeout.rb +29 -19
- data/lib/copy_tuner_client/rails.rb +9 -8
- data/lib/copy_tuner_client/request_sync.rb +26 -24
- data/lib/copy_tuner_client/simple_form_extention.rb +10 -6
- data/lib/copy_tuner_client/translation_log.rb +10 -5
- data/lib/copy_tuner_client/version.rb +1 -1
- data/lib/copy_tuner_client.rb +4 -8
- data/lib/tasks/copy_tuner_client_tasks.rake +14 -16
- data/skills/copy-tuner-to-locales-migrate-prefix/scripts/migrate_prefix.rb +14 -7
- data/skills/copy-tuner-to-t-migrate/scripts/migrate_tt.rb +19 -17
- data/spec/copy_tuner_client/cache_spec.rb +63 -57
- data/spec/copy_tuner_client/client_spec.rb +82 -81
- data/spec/copy_tuner_client/configuration_spec.rb +223 -222
- data/spec/copy_tuner_client/copyray/marker_spec.rb +2 -1
- data/spec/copy_tuner_client/copyray/rewriter_spec.rb +15 -10
- data/spec/copy_tuner_client/copyray_middleware_spec.rb +9 -6
- data/spec/copy_tuner_client/copyray_spec.rb +8 -8
- data/spec/copy_tuner_client/dotted_hash_spec.rb +33 -33
- data/spec/copy_tuner_client/helper_extension_spec.rb +47 -44
- data/spec/copy_tuner_client/i18n_backend_spec.rb +144 -143
- data/spec/copy_tuner_client/poller_spec.rb +25 -24
- data/spec/copy_tuner_client/prefixed_logger_spec.rb +15 -12
- data/spec/copy_tuner_client/process_guard_spec.rb +27 -27
- data/spec/copy_tuner_client/request_sync_spec.rb +51 -58
- data/spec/copy_tuner_client/translation_log_spec.rb +38 -24
- data/spec/copy_tuner_client_spec.rb +5 -6
- data/spec/support/client_spec_helpers.rb +1 -1
- data/spec/support/defines_constants.rb +3 -34
- data/spec/support/fake_client.rb +1 -3
- data/spec/support/fake_copy_tuner_app.rb +54 -62
- data/spec/support/fake_html_safe_string.rb +2 -3
- data/spec/support/fake_logger.rb +22 -21
- data/spec/support/fake_passenger.rb +4 -6
- data/spec/support/fake_unicorn.rb +2 -4
- data/spec/support/middleware_stack.rb +3 -3
- data/spec/support/writing_cache.rb +4 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3fb9ea1caf782db8dac7ded7d77803a61586b5369b221b62d34e9e0290c58b06
|
|
4
|
+
data.tar.gz: ad4723a7fe5af378f68af6f786644cc549a1ebbe2523c3424af8fdaba5381433
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a894e4afd8428064c4fef7dd34db7bdfaab23879b5fa3aaabc5921437a3a80b7cf036fac920f8bf76e7274141f5a522f8364a493797084e7fee879f435d7eb4
|
|
7
|
+
data.tar.gz: 34211866166e6491e7488a8f87aadc96810afcea2f3b5069ae2b29b4b9e5f0fe9a620556e3fd55d403ed419c9ab917c34f4fee0eafea90e889a7b6d5653b0540
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,7 +1,52 @@
|
|
|
1
1
|
inherit_gem:
|
|
2
|
-
sgcop:
|
|
2
|
+
sgcop:
|
|
3
|
+
- ruby/rubocop_strict.yml
|
|
4
|
+
- ruby/rubocop_rspec_strict.yml
|
|
5
|
+
|
|
6
|
+
plugins:
|
|
7
|
+
- rubocop-rake
|
|
8
|
+
- rubocop-rspec
|
|
3
9
|
|
|
4
10
|
# .ruby-version が RuboCop 未対応の新しい Ruby を指すと解析が落ちるため、
|
|
5
11
|
# サポート最低バージョンを明示する
|
|
12
|
+
# rubocop-rails は Rails プロジェクトではないため意図的に読み込まない
|
|
6
13
|
AllCops:
|
|
7
14
|
TargetRubyVersion: 3.3
|
|
15
|
+
NewCops: enable
|
|
16
|
+
SuggestExtensions: false
|
|
17
|
+
|
|
18
|
+
# gemfiles/*.gemfile が `gemspec path: '../'` で本体 gemspec の development dependency を
|
|
19
|
+
# 読み込む構成のため、Gemfile 側への移行は各 gemfiles/*.gemfile への書き戻しが必要になり
|
|
20
|
+
# 意味を変えない自動修正の範囲を超える。gemspec でのdevelopment dependency 宣言を維持する。
|
|
21
|
+
Gemspec/DevelopmentDependencies:
|
|
22
|
+
Exclude:
|
|
23
|
+
- 'copy_tuner_client.gemspec'
|
|
24
|
+
|
|
25
|
+
# middleware(テスト対象自身)の private メソッド append_js / helpers を no-op や
|
|
26
|
+
# フェイクに差し替えないと、Rails の ActionController::Base.helpers 依存を外して
|
|
27
|
+
# Rewriter の効果だけを検証できないため対象外。
|
|
28
|
+
RSpec/SubjectStub:
|
|
29
|
+
Exclude:
|
|
30
|
+
- 'spec/copy_tuner_client/copyray_middleware_spec.rb'
|
|
31
|
+
|
|
32
|
+
# Ruby 標準 Queue#pop(non_block=false) のインターフェースに意図的に合わせた実装のため、
|
|
33
|
+
# キーワード引数化すると標準 Queue との互換性が崩れる。
|
|
34
|
+
Style/OptionalBooleanParameter:
|
|
35
|
+
Exclude:
|
|
36
|
+
- 'lib/copy_tuner_client/queue_with_timeout.rb'
|
|
37
|
+
|
|
38
|
+
# Client#download は yield 前提の実装で、ブロックを渡さないと downloaded 時に
|
|
39
|
+
# LocalJumpError になる。ダウンロード結果自体を検証しないテストでは空ブロックが必須。
|
|
40
|
+
Lint/EmptyBlock:
|
|
41
|
+
Exclude:
|
|
42
|
+
- 'spec/copy_tuner_client/client_spec.rb'
|
|
43
|
+
|
|
44
|
+
# 要判断: configuration_spec.rb の i18n/config/application は Rails gem 自体を
|
|
45
|
+
# stub_const('Rails', Module.new) で丸ごと偽装するための double。ActiveSupport::OrderedOptions
|
|
46
|
+
# は method_missing 経由でアクセサを実装するため instance_double では検証できない。
|
|
47
|
+
# request_sync_spec.rb の app は Rack app プロトコル(call(env) を実装する任意オブジェクト)で
|
|
48
|
+
# 対応する具体的なクラスが存在しないため、Duck Typing 前提の double が妥当。
|
|
49
|
+
RSpec/VerifiedDoubles:
|
|
50
|
+
Exclude:
|
|
51
|
+
- 'spec/copy_tuner_client/configuration_spec.rb'
|
|
52
|
+
- 'spec/copy_tuner_client/request_sync_spec.rb'
|
data/CLAUDE.md
CHANGED
|
@@ -26,6 +26,7 @@ Rails 統合は engine.rb のイニシャライザ経由(ヘルパー/SimpleFo
|
|
|
26
26
|
- 新機能・バグ修正ともに「テスト追加 → RED 確認 → 実装 → GREEN」のサイクルを守る
|
|
27
27
|
- テストを書かずに実装を先行させない
|
|
28
28
|
- **コメントは WHY のみ日本語で書く**: 識別子やコードから読み取れる WHAT は書かない
|
|
29
|
+
(例外: RuboCop Style/Documentation 対応でクラス/モジュール直前に追加する一行の説明コメントは、名前だけでは把握しづらいクラスの役割を一目で示す目的のため、WHAT の説明も可)
|
|
29
30
|
- **テストの `describe` / `context` / `it` の説明文は日本語で書く**: 識別子(クラス名・メソッド名など)はそのまま
|
|
30
31
|
|
|
31
32
|
## Gotchas
|
data/Gemfile
CHANGED
data/copy_tuner_client.gemspec
CHANGED
|
@@ -21,9 +21,9 @@ Gem::Specification.new do |s|
|
|
|
21
21
|
s.files = `git ls-files`.split("\n")
|
|
22
22
|
s.homepage = 'https://github.com/SonicGarden/copy-tuner-ruby-client'
|
|
23
23
|
|
|
24
|
-
s.metadata[
|
|
25
|
-
s.metadata[
|
|
26
|
-
s.metadata[
|
|
24
|
+
s.metadata['homepage_uri'] = s.homepage
|
|
25
|
+
s.metadata['source_code_uri'] = 'https://github.com/SonicGarden/copy-tuner-ruby-client'
|
|
26
|
+
s.metadata['changelog_uri'] = 'https://github.com/SonicGarden/copy-tuner-ruby-client/releases'
|
|
27
27
|
s.metadata['rubygems_mfa_required'] = 'true'
|
|
28
28
|
|
|
29
29
|
s.name = 'copy_tuner_client'
|
data/gemfiles/8.0.gemfile
CHANGED
data/gemfiles/8.1.gemfile
CHANGED
data/gemfiles/main.gemfile
CHANGED
|
@@ -23,7 +23,7 @@ module CopyTunerClient
|
|
|
23
23
|
@local_first_key_regexp = options[:local_first_key_regexp]
|
|
24
24
|
@upload_disabled = options[:upload_disabled]
|
|
25
25
|
@ignored_keys = options.fetch(:ignored_keys, [])
|
|
26
|
-
@ignored_key_handler = options.fetch(:ignored_key_handler, ->
|
|
26
|
+
@ignored_key_handler = options.fetch(:ignored_key_handler, ->(e) { raise e })
|
|
27
27
|
@locales = Array(options[:locales]).map(&:to_s)
|
|
28
28
|
# mutable states
|
|
29
29
|
@blurbs = {}
|
|
@@ -48,18 +48,14 @@ module CopyTunerClient
|
|
|
48
48
|
# @param key [String] the key of the blurb to update
|
|
49
49
|
# @param value [String] the new contents of the blurb
|
|
50
50
|
def []=(key, value)
|
|
51
|
-
return
|
|
52
|
-
return if @locales.present? && !@locales.member?(key.split('.').first)
|
|
53
|
-
return if @upload_disabled
|
|
51
|
+
return if skip_upload?(key)
|
|
54
52
|
|
|
55
53
|
# NOTE: config/locales以下のファイルに除外キーが残っていた場合の対応
|
|
56
54
|
key_without_locale = key.split('.')[1..].join('.')
|
|
57
55
|
# NOTE: local_first キー(組み込みの Rails number.*.format + ユーザー設定)は copy_tuner と完全分離するためアップロードしない
|
|
58
56
|
return if local_first_key?(key_without_locale)
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
@ignored_key_handler.call(IgnoredKey.new("Ignored key: #{key_without_locale}"))
|
|
62
|
-
end
|
|
58
|
+
handle_ignored_key(key_without_locale)
|
|
63
59
|
|
|
64
60
|
lock do
|
|
65
61
|
return if @blank_keys.member?(key) || @blurbs.key?(key)
|
|
@@ -100,17 +96,16 @@ module CopyTunerClient
|
|
|
100
96
|
|
|
101
97
|
logger.info 'Waiting for first download'
|
|
102
98
|
|
|
103
|
-
if logger.respond_to?
|
|
104
|
-
logger.flush
|
|
105
|
-
end
|
|
99
|
+
logger.flush if logger.respond_to?(:flush)
|
|
106
100
|
|
|
107
|
-
sleep
|
|
101
|
+
sleep(0.1) while pending?
|
|
108
102
|
end
|
|
109
103
|
|
|
110
104
|
def flush
|
|
111
|
-
res =
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
res =
|
|
106
|
+
with_queued_changes do |queued|
|
|
107
|
+
client.upload(queued)
|
|
108
|
+
end
|
|
114
109
|
|
|
115
110
|
@last_uploaded_at = Time.now.utc
|
|
116
111
|
|
|
@@ -122,15 +117,16 @@ module CopyTunerClient
|
|
|
122
117
|
def download
|
|
123
118
|
@status = STATUS_PENDING unless ready?
|
|
124
119
|
|
|
125
|
-
res =
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
120
|
+
res =
|
|
121
|
+
client.download(cache_fallback: pending?) do |downloaded_blurbs|
|
|
122
|
+
blank_keys = Set.new
|
|
123
|
+
blurbs = {}
|
|
124
|
+
downloaded_blurbs.each { |key, value| value == '' ? blank_keys << key : blurbs[key] = value }
|
|
125
|
+
lock do
|
|
126
|
+
@blank_keys = blank_keys
|
|
127
|
+
@blurbs = blurbs
|
|
128
|
+
end
|
|
132
129
|
end
|
|
133
|
-
end
|
|
134
130
|
|
|
135
131
|
@last_downloaded_at = Time.now.utc
|
|
136
132
|
@status = STATUS_READY unless ready?
|
|
@@ -163,6 +159,13 @@ module CopyTunerClient
|
|
|
163
159
|
|
|
164
160
|
attr_reader :client, :logger
|
|
165
161
|
|
|
162
|
+
def skip_upload?(key)
|
|
163
|
+
return true unless key.include?('.')
|
|
164
|
+
return true if @locales.present? && !@locales.member?(key.split('.').first)
|
|
165
|
+
|
|
166
|
+
@upload_disabled
|
|
167
|
+
end
|
|
168
|
+
|
|
166
169
|
# NOTE: 組み込みの Rails number.*.format キーは lookup 経路(Configuration#local_first_key?)と
|
|
167
170
|
# アップロード抑止経路(ここ)で同じ判定を共有する。判定本体は Configuration に集約し付け忘れの穴を防ぐ。
|
|
168
171
|
def local_first_key?(key_without_locale)
|
|
@@ -171,6 +174,12 @@ module CopyTunerClient
|
|
|
171
174
|
@local_first_key_regexp && key_without_locale.match?(@local_first_key_regexp)
|
|
172
175
|
end
|
|
173
176
|
|
|
177
|
+
def handle_ignored_key(key_without_locale)
|
|
178
|
+
return unless @ignored_keys.include?(key_without_locale)
|
|
179
|
+
|
|
180
|
+
@ignored_key_handler.call(IgnoredKey.new("Ignored key: #{key_without_locale}"))
|
|
181
|
+
end
|
|
182
|
+
|
|
174
183
|
def with_queued_changes
|
|
175
184
|
changes_to_push = nil
|
|
176
185
|
|
|
@@ -181,9 +190,7 @@ module CopyTunerClient
|
|
|
181
190
|
end
|
|
182
191
|
end
|
|
183
192
|
|
|
184
|
-
if changes_to_push
|
|
185
|
-
yield nil_value_to_empty(changes_to_push)
|
|
186
|
-
end
|
|
193
|
+
yield(nil_value_to_empty(changes_to_push)) if changes_to_push
|
|
187
194
|
end
|
|
188
195
|
|
|
189
196
|
def nil_value_to_empty(hash)
|
|
@@ -197,8 +204,8 @@ module CopyTunerClient
|
|
|
197
204
|
hash
|
|
198
205
|
end
|
|
199
206
|
|
|
200
|
-
def lock(&
|
|
201
|
-
@mutex.synchronize
|
|
207
|
+
def lock(&)
|
|
208
|
+
@mutex.synchronize(&)
|
|
202
209
|
end
|
|
203
210
|
end
|
|
204
211
|
end
|
|
@@ -9,14 +9,16 @@ module CopyTunerClient
|
|
|
9
9
|
#
|
|
10
10
|
# A client is usually instantiated when {Configuration#apply} is called, and
|
|
11
11
|
# the application will not need to interact with it directly.
|
|
12
|
-
class Client
|
|
12
|
+
class Client # rubocop:disable Metrics/ClassLength
|
|
13
13
|
# These errors will be rescued when connecting CopyTuner.
|
|
14
|
-
HTTP_ERRORS = [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
HTTP_ERRORS = [
|
|
15
|
+
Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
|
|
16
|
+
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
|
17
|
+
Net::ProtocolError, SocketError, OpenSSL::SSL::SSLError,
|
|
18
|
+
Errno::ECONNREFUSED
|
|
19
|
+
].freeze
|
|
18
20
|
|
|
19
|
-
USER_AGENT = "copy_tuner_client #{CopyTunerClient::VERSION}"
|
|
21
|
+
USER_AGENT = "copy_tuner_client #{CopyTunerClient::VERSION}".freeze
|
|
20
22
|
|
|
21
23
|
# ETags を外部から取得可能にする
|
|
22
24
|
# @return [String, nil] 現在のETag値
|
|
@@ -36,9 +38,11 @@ module CopyTunerClient
|
|
|
36
38
|
@etag = nil
|
|
37
39
|
@downloaded_blurbs = {}
|
|
38
40
|
|
|
39
|
-
[
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
%i[
|
|
42
|
+
api_key host port public http_read_timeout
|
|
43
|
+
http_open_timeout secure logger ca_file s3_host download_cache_dir
|
|
44
|
+
].each do |option|
|
|
45
|
+
instance_variable_set("@#{option}", options[option])
|
|
42
46
|
end
|
|
43
47
|
|
|
44
48
|
@download_cache_dir.mkpath
|
|
@@ -59,19 +63,19 @@ module CopyTunerClient
|
|
|
59
63
|
connect(s3_host) do |http|
|
|
60
64
|
request = Net::HTTP::Get.new(uri(download_resource))
|
|
61
65
|
request['If-None-Match'] = @etag
|
|
62
|
-
log
|
|
66
|
+
log('Start downloading translations')
|
|
63
67
|
t = Time.now
|
|
64
68
|
response = http.request(request)
|
|
65
69
|
t_ms = ((Time.now - t) * 1000).to_i
|
|
66
70
|
downloaded = check(response)
|
|
67
71
|
if downloaded
|
|
68
72
|
# NOTE: Net::HTTPではgzipが透過的に扱われるため正確なファイルサイズや速度をログに出すのは難しい
|
|
69
|
-
log
|
|
73
|
+
log("Downloaded translations (#{t_ms}ms)")
|
|
70
74
|
@downloaded_blurbs = JSON.parse(response.body)
|
|
71
75
|
@etag = response['ETag']
|
|
72
76
|
last_download_path.write(JSON.pretty_generate(etag: @etag, downloaded_blurbs: @downloaded_blurbs))
|
|
73
77
|
else
|
|
74
|
-
log
|
|
78
|
+
log("No new translations (#{t_ms}ms)")
|
|
75
79
|
end
|
|
76
80
|
|
|
77
81
|
yield(@downloaded_blurbs) if downloaded || cache_fallback
|
|
@@ -83,9 +87,10 @@ module CopyTunerClient
|
|
|
83
87
|
# @raise [ConnectionError] if the connection fails
|
|
84
88
|
def upload(data)
|
|
85
89
|
connect(host) do |http|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
headers = { 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT }
|
|
91
|
+
response = http.post(uri('draft_blurbs'), data.to_json, headers)
|
|
92
|
+
check(response)
|
|
93
|
+
log('Uploaded missing translations')
|
|
89
94
|
end
|
|
90
95
|
end
|
|
91
96
|
|
|
@@ -94,15 +99,22 @@ module CopyTunerClient
|
|
|
94
99
|
def deploy
|
|
95
100
|
connect(host) do |http|
|
|
96
101
|
response = http.post(uri('deploys'), '', 'User-Agent' => USER_AGENT)
|
|
97
|
-
check
|
|
98
|
-
log
|
|
102
|
+
check(response)
|
|
103
|
+
log('Deployed')
|
|
99
104
|
end
|
|
100
105
|
end
|
|
101
106
|
|
|
102
107
|
private
|
|
103
108
|
|
|
104
|
-
attr_reader :host,
|
|
105
|
-
|
|
109
|
+
attr_reader :host,
|
|
110
|
+
:port,
|
|
111
|
+
:api_key,
|
|
112
|
+
:http_read_timeout,
|
|
113
|
+
:http_open_timeout,
|
|
114
|
+
:secure,
|
|
115
|
+
:logger,
|
|
116
|
+
:ca_file,
|
|
117
|
+
:s3_host
|
|
106
118
|
|
|
107
119
|
def public?
|
|
108
120
|
@public
|
|
@@ -130,7 +142,7 @@ module CopyTunerClient
|
|
|
130
142
|
cache = JSON.parse(pathname.read.to_s).transform_keys(&:to_sym)
|
|
131
143
|
@etag = cache[:etag]
|
|
132
144
|
@downloaded_blurbs = cache[:downloaded_blurbs]
|
|
133
|
-
log
|
|
145
|
+
log("Loaded cache data from #{pathname}")
|
|
134
146
|
rescue JSON::JSONError, Errno::ENOENT, Errno::ENOTDIR
|
|
135
147
|
nil
|
|
136
148
|
end
|
|
@@ -144,9 +156,9 @@ module CopyTunerClient
|
|
|
144
156
|
http.ca_file = ca_file
|
|
145
157
|
|
|
146
158
|
begin
|
|
147
|
-
yield
|
|
148
|
-
rescue *HTTP_ERRORS =>
|
|
149
|
-
raise ConnectionError, "#{
|
|
159
|
+
yield(http)
|
|
160
|
+
rescue *HTTP_ERRORS => e
|
|
161
|
+
raise ConnectionError, "#{e.class.name}: #{e.message}"
|
|
150
162
|
end
|
|
151
163
|
end
|
|
152
164
|
|
|
@@ -12,14 +12,16 @@ module CopyTunerClient
|
|
|
12
12
|
# Used to set up and modify settings for the client.
|
|
13
13
|
class Configuration # rubocop:disable Metrics/ClassLength
|
|
14
14
|
# These options will be present in the Hash returned by {#to_hash}.
|
|
15
|
-
OPTIONS = %i[
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
OPTIONS = %i[
|
|
16
|
+
api_key development_environments environment_name host
|
|
17
|
+
http_open_timeout http_read_timeout client_name client_url
|
|
18
|
+
client_version port protocol proxy_host proxy_pass
|
|
19
|
+
proxy_port proxy_user secure polling_delay sync_interval
|
|
20
|
+
sync_interval_staging sync_ignore_path_regex logger
|
|
21
|
+
framework middleware disable_middleware disable_test_translation
|
|
22
|
+
ca_file local_first_key_regexp s3_host locales ignored_keys ignored_key_handler
|
|
23
|
+
download_cache_dir
|
|
24
|
+
].freeze
|
|
23
25
|
|
|
24
26
|
# NOTE: Rails 標準ロケールで非文字列値(precision: Integer, significant: Boolean,
|
|
25
27
|
# strip_insignificant_zeros: Boolean)を含むのは number.*.format 配下のみ。store_item が文字列しか
|
|
@@ -200,7 +202,7 @@ module CopyTunerClient
|
|
|
200
202
|
base_options = { public: public?, upload_disabled: upload_disabled? }
|
|
201
203
|
|
|
202
204
|
OPTIONS.inject(base_options) do |hash, option|
|
|
203
|
-
hash.merge
|
|
205
|
+
hash.merge(option.to_sym => public_send(option))
|
|
204
206
|
end
|
|
205
207
|
end
|
|
206
208
|
|
|
@@ -209,7 +211,7 @@ module CopyTunerClient
|
|
|
209
211
|
# @param [Hash] hash A set of configuration options that will take precedence over the defaults
|
|
210
212
|
# @return [Hash] the merged configuration hash
|
|
211
213
|
def merge(hash)
|
|
212
|
-
to_hash.merge
|
|
214
|
+
to_hash.merge(hash)
|
|
213
215
|
end
|
|
214
216
|
|
|
215
217
|
# Determines if the published or draft content will be used
|
|
@@ -222,7 +224,7 @@ module CopyTunerClient
|
|
|
222
224
|
# Determines if the content will be editable
|
|
223
225
|
# @return [Boolean] Returns +true+ if in a development environment, +false+ otherwise.
|
|
224
226
|
def development?
|
|
225
|
-
development_environments.include?
|
|
227
|
+
development_environments.include?(environment_name)
|
|
226
228
|
end
|
|
227
229
|
|
|
228
230
|
def enable_middleware?
|
|
@@ -252,15 +254,11 @@ module CopyTunerClient
|
|
|
252
254
|
# This creates the {I18nBackend} and puts them together.
|
|
253
255
|
#
|
|
254
256
|
# When {#test?} returns +false+, the poller will be started.
|
|
255
|
-
def apply # rubocop:disable Metrics/AbcSize
|
|
257
|
+
def apply # rubocop:disable Metrics/AbcSize
|
|
256
258
|
# NOTE: project_id は必須。未設定なら apply 時点で明示的に失敗させる
|
|
257
259
|
validate_project_id!
|
|
258
260
|
|
|
259
|
-
self.locales ||=
|
|
260
|
-
::Rails.application.config.i18n.available_locales.presence || Array(::Rails.application.config.i18n.default_locale)
|
|
261
|
-
else
|
|
262
|
-
[:en]
|
|
263
|
-
end
|
|
261
|
+
self.locales ||= default_locales
|
|
264
262
|
|
|
265
263
|
self.client ||= Client.new(to_hash)
|
|
266
264
|
self.cache ||= Cache.new(client, to_hash)
|
|
@@ -268,31 +266,12 @@ module CopyTunerClient
|
|
|
268
266
|
process_guard = ProcessGuard.new(cache, @poller, to_hash)
|
|
269
267
|
I18n.backend = I18nBackend.new(cache)
|
|
270
268
|
|
|
271
|
-
|
|
272
|
-
logger.info 'Using copytuner sync middleware'
|
|
273
|
-
request_sync_options = { poller: @poller, cache:, interval: sync_interval, ignore_regex: sync_ignore_path_regex }
|
|
274
|
-
if middleware_position.is_a?(Hash) && middleware_position[:before]
|
|
275
|
-
middleware.insert_before middleware_position[:before], RequestSync, request_sync_options
|
|
276
|
-
middleware.insert_before middleware_position[:before], CopyTunerClient::CopyrayMiddleware
|
|
277
|
-
elsif middleware_position.is_a?(Hash) && middleware_position[:after]
|
|
278
|
-
middleware.insert_after middleware_position[:after], RequestSync, request_sync_options
|
|
279
|
-
middleware.insert_after middleware_position[:after], CopyTunerClient::CopyrayMiddleware
|
|
280
|
-
else
|
|
281
|
-
middleware.use RequestSync, request_sync_options
|
|
282
|
-
middleware.use CopyTunerClient::CopyrayMiddleware
|
|
283
|
-
end
|
|
284
|
-
else
|
|
285
|
-
logger.info '[[[Warn]]] Not using copytuner sync middleware' unless middleware
|
|
286
|
-
end
|
|
269
|
+
setup_middleware
|
|
287
270
|
|
|
288
271
|
@applied = true
|
|
289
|
-
|
|
290
|
-
logger.info "Environment Info: #{environment_info}"
|
|
291
|
-
logger.info "Available locales: #{self.locales.join(' ')}"
|
|
272
|
+
log_applied
|
|
292
273
|
|
|
293
|
-
unless test?
|
|
294
|
-
process_guard.start
|
|
295
|
-
end
|
|
274
|
+
process_guard.start unless test?
|
|
296
275
|
|
|
297
276
|
unless test? && disable_test_translation
|
|
298
277
|
logger.info 'Download translation now'
|
|
@@ -348,7 +327,7 @@ module CopyTunerClient
|
|
|
348
327
|
validate_project_id!
|
|
349
328
|
|
|
350
329
|
path = "/projects/#{project_id}"
|
|
351
|
-
URI::Generic.build(scheme:
|
|
330
|
+
URI::Generic.build(scheme: protocol, host:, port: port.to_i, path:).to_s
|
|
352
331
|
end
|
|
353
332
|
|
|
354
333
|
# locale を除いたキーが local_first_key_regexp にマッチするかを返す。
|
|
@@ -369,6 +348,49 @@ module CopyTunerClient
|
|
|
369
348
|
|
|
370
349
|
private
|
|
371
350
|
|
|
351
|
+
def default_locales
|
|
352
|
+
if defined?(::Rails)
|
|
353
|
+
rails_i18n = ::Rails.application.config.i18n
|
|
354
|
+
rails_i18n.available_locales.presence || Array(rails_i18n.default_locale)
|
|
355
|
+
else
|
|
356
|
+
[:en]
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def setup_middleware
|
|
361
|
+
if enable_middleware?
|
|
362
|
+
logger.info 'Using copytuner sync middleware'
|
|
363
|
+
insert_middleware
|
|
364
|
+
else
|
|
365
|
+
logger.info '[[[Warn]]] Not using copytuner sync middleware' unless middleware
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def log_applied
|
|
370
|
+
logger.info "Client #{VERSION} ready (s3_download)"
|
|
371
|
+
logger.info "Environment Info: #{environment_info}"
|
|
372
|
+
logger.info "Available locales: #{locales.join(' ')}"
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def insert_middleware # rubocop:disable Metrics/AbcSize
|
|
376
|
+
request_sync_options = {
|
|
377
|
+
poller: @poller,
|
|
378
|
+
cache:,
|
|
379
|
+
interval: sync_interval,
|
|
380
|
+
ignore_regex: sync_ignore_path_regex,
|
|
381
|
+
}
|
|
382
|
+
if middleware_position.is_a?(Hash) && middleware_position[:before]
|
|
383
|
+
middleware.insert_before(middleware_position[:before], RequestSync, request_sync_options)
|
|
384
|
+
middleware.insert_before(middleware_position[:before], CopyTunerClient::CopyrayMiddleware)
|
|
385
|
+
elsif middleware_position.is_a?(Hash) && middleware_position[:after]
|
|
386
|
+
middleware.insert_after(middleware_position[:after], RequestSync, request_sync_options)
|
|
387
|
+
middleware.insert_after(middleware_position[:after], CopyTunerClient::CopyrayMiddleware)
|
|
388
|
+
else
|
|
389
|
+
middleware.use(RequestSync, request_sync_options)
|
|
390
|
+
middleware.use(CopyTunerClient::CopyrayMiddleware)
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
372
394
|
# project_id は必須。未設定なら明示的に失敗させる。
|
|
373
395
|
# apply(起動時の全体検証)と project_url(apply を経ない経路へのセーフネット)の両方から呼ぶ。
|
|
374
396
|
def validate_project_id!
|
|
@@ -38,7 +38,7 @@ module CopyTunerClient
|
|
|
38
38
|
# NOTE: 閾値超は Nokogiri を通さず可視トークン除去のみ。skipped=true で編集導線を諦めた旨を伝える。
|
|
39
39
|
return [strip_markers(scannable), true] if scannable.bytesize > MAX_REWRITE_BYTESIZE
|
|
40
40
|
|
|
41
|
-
[rewrite_with_nokogiri(scannable, fragment:
|
|
41
|
+
[rewrite_with_nokogiri(scannable, fragment:), false]
|
|
42
42
|
rescue StandardError => e
|
|
43
43
|
# NOTE: Copyray は開発支援機能なので、壊れた HTML 等で Nokogiri 処理が落ちても
|
|
44
44
|
# ページを 500 にしない。data-copyray-key 付与(編集導線)は諦め、最低限可視トークンだけ除去する。
|