tml 5.2.7 → 5.4.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 +4 -4
- data/LICENSE +1 -1
- data/README.md +2 -2
- data/lib/tml/api/client.rb +98 -43
- data/lib/tml/application.rb +22 -20
- data/lib/tml/cache.rb +111 -30
- data/lib/tml/cache_version.rb +135 -0
- data/lib/tml/config.rb +14 -10
- data/lib/tml/language.rb +5 -3
- data/lib/tml/language_case.rb +3 -3
- data/lib/tml/languages/en.json +643 -663
- data/lib/tml/session.rb +6 -3
- data/lib/tml/source.rb +1 -1
- data/lib/tml/utils.rb +30 -0
- data/lib/tml/version.rb +1 -1
- data/lib/tml.rb +1 -1
- metadata +3 -5
- data/lib/tml/api/post_office.rb +0 -71
- data/lib/tml/generators/base.rb +0 -122
- data/lib/tml/generators/file.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a84984e64ec22f712cec34434ceba677ccb757a
|
4
|
+
data.tar.gz: 91eaaef9c8621cc7459bb76b7e2abfaece3b702e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b82d16a5ed538b5c53e458d5c46a999eb80622812de47fb0e325a6b8e3123f564195c81a86e9741f694f7c1d9067a1b64e9241b3429f93db8485834a36d9ae24
|
7
|
+
data.tar.gz: 196079f8c475c04383978418e96dacf95d91d3ed7cf89266a147eefc7b6de0f714881ac7cc690f34359321729879f64db4bc141630695c45e626e520dc085979
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -209,7 +209,7 @@ Links
|
|
209
209
|
|
210
210
|
* Register on TranslationExchange.com: http://translationexchange.com
|
211
211
|
|
212
|
-
* Read TranslationExchange's documentation: http://translationexchange.com
|
212
|
+
* Read TranslationExchange's documentation: http://docs.translationexchange.com
|
213
213
|
|
214
214
|
* Follow TranslationExchange on Twitter: https://twitter.com/translationx
|
215
215
|
|
@@ -221,7 +221,7 @@ Links
|
|
221
221
|
Copyright and license
|
222
222
|
==================
|
223
223
|
|
224
|
-
Copyright (c)
|
224
|
+
Copyright (c) 2016 Translation Exchange, Inc
|
225
225
|
|
226
226
|
Permission is hereby granted, free of charge, to any person obtaining
|
227
227
|
a copy of this software and associated documentation files (the
|
data/lib/tml/api/client.rb
CHANGED
@@ -39,31 +39,37 @@ class Tml::Api::Client < Tml::Base
|
|
39
39
|
|
40
40
|
attributes :application
|
41
41
|
|
42
|
-
# get results from
|
42
|
+
# get results from API
|
43
43
|
def results(path, params = {}, opts = {})
|
44
44
|
get(path, params, opts)['results']
|
45
45
|
end
|
46
46
|
|
47
|
+
# get from API
|
47
48
|
def get(path, params = {}, opts = {})
|
48
49
|
api(path, params, opts.merge(:method => :get))
|
49
50
|
end
|
50
51
|
|
52
|
+
# post to API
|
51
53
|
def post(path, params = {}, opts = {})
|
52
54
|
api(path, params, opts.merge(:method => :post))
|
53
55
|
end
|
54
56
|
|
57
|
+
# put to API
|
55
58
|
def put(path, params = {}, opts = {})
|
56
59
|
api(path, params, opts.merge(:method => :put))
|
57
60
|
end
|
58
61
|
|
62
|
+
# delete from API
|
59
63
|
def delete(path, params = {}, opts = {})
|
60
64
|
api(path, params, opts.merge(:method => :delete))
|
61
65
|
end
|
62
66
|
|
67
|
+
# checks if there are any API errors
|
63
68
|
def self.error?(data)
|
64
69
|
not data['error'].nil?
|
65
70
|
end
|
66
71
|
|
72
|
+
# API connection
|
67
73
|
def connection
|
68
74
|
@connection ||= Faraday.new(:url => application.host) do |faraday|
|
69
75
|
faraday.request(:url_encoded) # form-encode POST params
|
@@ -72,22 +78,34 @@ class Tml::Api::Client < Tml::Base
|
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
81
|
+
# get cache version from CDN
|
75
82
|
def get_cache_version
|
76
|
-
|
83
|
+
data = get_from_cdn('version', {t: Time.now.to_i}, {public: true, uncompressed: true})
|
84
|
+
|
85
|
+
unless data
|
86
|
+
Tml.logger.debug('No releases have been published yet')
|
87
|
+
return '0'
|
88
|
+
end
|
89
|
+
|
90
|
+
data['version']
|
77
91
|
end
|
78
92
|
|
93
|
+
# verify cache version
|
79
94
|
def verify_cache_version
|
80
|
-
return if Tml.cache.version
|
95
|
+
return if Tml.cache.version.defined?
|
96
|
+
|
97
|
+
current_version = Tml.cache.version.fetch
|
81
98
|
|
82
|
-
current_version = Tml.cache.fetch_version
|
83
99
|
if current_version == 'undefined'
|
84
|
-
Tml.cache.
|
100
|
+
Tml.cache.version.store(get_cache_version)
|
85
101
|
else
|
86
|
-
Tml.cache.version
|
102
|
+
Tml.cache.version.set(current_version)
|
87
103
|
end
|
88
|
-
|
104
|
+
|
105
|
+
Tml.logger.info("Cache Version: #{Tml.cache.version}")
|
89
106
|
end
|
90
107
|
|
108
|
+
# cdn_connection
|
91
109
|
def cdn_connection
|
92
110
|
@cdn_connection ||= Faraday.new(:url => application.cdn_host) do |faraday|
|
93
111
|
faraday.request(:url_encoded) # form-encode POST params
|
@@ -95,11 +113,21 @@ class Tml::Api::Client < Tml::Base
|
|
95
113
|
end
|
96
114
|
end
|
97
115
|
|
116
|
+
# get from the CDN
|
98
117
|
def get_from_cdn(key, params = {}, opts = {})
|
99
|
-
|
118
|
+
if Tml.cache.version.invalid? and key != 'version'
|
119
|
+
return nil
|
120
|
+
end
|
100
121
|
|
101
122
|
response = nil
|
102
|
-
cdn_path = "/#{application.key}
|
123
|
+
cdn_path = "/#{application.key}"
|
124
|
+
|
125
|
+
if key == 'version'
|
126
|
+
cdn_path += "/#{key}.json"
|
127
|
+
else
|
128
|
+
cdn_path += "/#{Tml.cache.version.to_s}/#{key}.json#{opts[:uncompressed] ? '' : '.gz'}"
|
129
|
+
end
|
130
|
+
|
103
131
|
trace_api_call(cdn_path, params, opts.merge(:host => application.cdn_host)) do
|
104
132
|
begin
|
105
133
|
response = cdn_connection.get do |request|
|
@@ -116,8 +144,12 @@ class Tml::Api::Client < Tml::Base
|
|
116
144
|
compressed_data = response.body
|
117
145
|
return if compressed_data.nil? or compressed_data == ''
|
118
146
|
|
119
|
-
data =
|
120
|
-
|
147
|
+
data = compressed_data
|
148
|
+
|
149
|
+
unless opts[:uncompressed]
|
150
|
+
data = Zlib::GzipReader.new(StringIO.new(compressed_data.to_s)).read
|
151
|
+
Tml.logger.debug("Compressed: #{compressed_data.length} Uncompressed: #{data.length}")
|
152
|
+
end
|
121
153
|
|
122
154
|
begin
|
123
155
|
data = JSON.parse(data)
|
@@ -128,39 +160,52 @@ class Tml::Api::Client < Tml::Base
|
|
128
160
|
data
|
129
161
|
end
|
130
162
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
163
|
+
# access token
|
164
|
+
def access_token
|
165
|
+
application.token
|
166
|
+
end
|
167
|
+
|
168
|
+
# should the API go to live server
|
169
|
+
def live_api_request?
|
170
|
+
# if no access token, never use live mode
|
171
|
+
return false if access_token.blank?
|
172
|
+
|
173
|
+
# if block is specifically asking for it or inline mode is activated
|
174
|
+
Tml.session.inline_mode? or Tml.session.block_option(:live)
|
135
175
|
end
|
136
176
|
|
137
|
-
|
177
|
+
# checks if cache is enable
|
178
|
+
def cache_enabled?(opts)
|
179
|
+
# only gets ever get cached
|
138
180
|
return false unless opts[:method] == :get
|
139
181
|
return false if opts[:cache_key].nil?
|
140
182
|
return false unless Tml.cache.enabled?
|
141
|
-
return false if live_translations_request?(opts[:cache_key])
|
142
|
-
return false if Tml.session.inline_mode?
|
143
183
|
true
|
144
184
|
end
|
145
185
|
|
186
|
+
# checks mode and cache, and fetches data
|
146
187
|
def api(path, params = {}, opts = {})
|
147
|
-
# inline mode should always
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
188
|
+
# inline mode should always use API calls
|
189
|
+
if live_api_request?
|
190
|
+
return process_response(execute_request(path, params, opts), opts)
|
191
|
+
end
|
192
|
+
|
193
|
+
return unless cache_enabled?(opts)
|
194
|
+
|
195
|
+
# ensure the cache version is not outdated
|
196
|
+
verify_cache_version
|
197
|
+
|
198
|
+
return if Tml.cache.version.invalid?
|
199
|
+
|
200
|
+
# get request uses local cache, then CDN
|
201
|
+
data = Tml.cache.fetch(opts[:cache_key]) do
|
202
|
+
Tml.cache.read_only? ? nil : get_from_cdn(opts[:cache_key])
|
161
203
|
end
|
204
|
+
|
205
|
+
process_response(data, opts)
|
162
206
|
end
|
163
207
|
|
208
|
+
# paginates through API results
|
164
209
|
def paginate(path, params = {}, opts = {})
|
165
210
|
data = get(path, params, opts.merge({'raw' => true}))
|
166
211
|
|
@@ -181,31 +226,35 @@ class Tml::Api::Client < Tml::Base
|
|
181
226
|
end
|
182
227
|
end
|
183
228
|
|
229
|
+
# prepares API path
|
184
230
|
def prepare_api_path(path)
|
185
|
-
return path if path.index('oauth')
|
186
231
|
return path if path.match(/^https?:\/\//)
|
187
232
|
"#{API_PATH}#{path[0] == '/' ? '' : '/'}#{path}"
|
188
233
|
end
|
189
234
|
|
235
|
+
# prepares request
|
190
236
|
def prepare_request(request, path, params)
|
191
|
-
request.options.timeout
|
192
|
-
request.options.open_timeout
|
237
|
+
request.options.timeout = Tml.config.api_client[:timeout]
|
238
|
+
request.options.open_timeout = Tml.config.api_client[:open_timeout]
|
193
239
|
request.headers['User-Agent'] = "tml-ruby v#{Tml::VERSION} (Faraday v#{Faraday::VERSION})"
|
194
240
|
request.headers['Accept'] = 'application/json'
|
195
241
|
request.headers['Accept-Encoding'] = 'gzip, deflate'
|
196
242
|
request.url(path, params)
|
197
243
|
end
|
198
244
|
|
245
|
+
# execute API request
|
199
246
|
def execute_request(path, params = {}, opts = {})
|
200
247
|
response = nil
|
201
248
|
error = nil
|
202
249
|
|
203
|
-
# oauth path is separate from versioned APIs
|
204
250
|
path = prepare_api_path(path)
|
205
|
-
|
251
|
+
|
252
|
+
unless opts[:public]
|
253
|
+
params = params.merge(:access_token => access_token)
|
254
|
+
end
|
206
255
|
|
207
256
|
if opts[:method] == :post
|
208
|
-
params = params.merge(:
|
257
|
+
params = params.merge(:app_id => application.key)
|
209
258
|
end
|
210
259
|
|
211
260
|
@compressed = false
|
@@ -235,7 +284,7 @@ class Tml::Api::Client < Tml::Base
|
|
235
284
|
raise Tml::Exception.new("Error: #{response.body}")
|
236
285
|
end
|
237
286
|
|
238
|
-
if @compressed
|
287
|
+
if @compressed and (not opts[:uncompressed])
|
239
288
|
compressed_data = response.body
|
240
289
|
return if compressed_data.nil? or compressed_data == ''
|
241
290
|
|
@@ -260,11 +309,13 @@ class Tml::Api::Client < Tml::Base
|
|
260
309
|
data
|
261
310
|
end
|
262
311
|
|
312
|
+
# get object class from options
|
263
313
|
def object_class(opts)
|
264
314
|
return unless opts[:class]
|
265
315
|
opts[:class].is_a?(String) ? opts[:class].constantize : opts[:class]
|
266
316
|
end
|
267
317
|
|
318
|
+
# process API response
|
268
319
|
def process_response(data, opts)
|
269
320
|
return nil if data.nil?
|
270
321
|
return data if opts[:raw] or opts[:raw_json]
|
@@ -283,18 +334,22 @@ class Tml::Api::Client < Tml::Base
|
|
283
334
|
object_class(opts).new(data.merge(opts[:attributes] || {}))
|
284
335
|
end
|
285
336
|
|
337
|
+
# convert params to query
|
286
338
|
def to_query(hash)
|
287
339
|
query = []
|
288
340
|
hash.each do |key, value|
|
289
|
-
query << "#{key}=#{value}"
|
341
|
+
query << "#{key.to_s}=#{value.to_s}"
|
290
342
|
end
|
291
343
|
query.join('&')
|
292
344
|
end
|
293
345
|
|
346
|
+
# trace api call for logging
|
294
347
|
def trace_api_call(path, params, opts = {})
|
295
|
-
|
296
|
-
|
297
|
-
|
348
|
+
if Tml.config.logger[:secure]
|
349
|
+
[:access_token].each do |param|
|
350
|
+
params = params.merge(param => "##filtered##") if params[param]
|
351
|
+
end
|
352
|
+
end
|
298
353
|
|
299
354
|
path = "#{path[0] == '/' ? '' : '/'}#{path}"
|
300
355
|
|
data/lib/tml/application.rb
CHANGED
@@ -35,9 +35,10 @@ require 'faraday'
|
|
35
35
|
class Tml::Application < Tml::Base
|
36
36
|
|
37
37
|
CDN_HOST = 'https://cdn.translationexchange.com'
|
38
|
+
# CDN_HOST = 'https://trex-snapshots.s3-us-west-1.amazonaws.com'
|
38
39
|
API_HOST = 'https://api.translationexchange.com'
|
39
40
|
|
40
|
-
attributes :host, :id, :key, :access_token, :name, :description, :threshold, :default_locale, :default_level
|
41
|
+
attributes :host, :id, :key, :access_token, :name, :description, :threshold, :default_locale, :default_level
|
41
42
|
has_many :features, :languages, :languages_by_locale, :sources, :tokens, :css, :shortcuts, :translations, :extensions
|
42
43
|
has_many :ignored_keys
|
43
44
|
|
@@ -65,7 +66,7 @@ class Tml::Application < Tml::Base
|
|
65
66
|
|
66
67
|
# Fetches application definition from the service
|
67
68
|
def fetch
|
68
|
-
data = api_client.get(
|
69
|
+
data = api_client.get("projects/#{key}/definition",{
|
69
70
|
locale: Tml.session.current_locale,
|
70
71
|
source: Tml.session.current_source,
|
71
72
|
ignored: true
|
@@ -76,7 +77,8 @@ class Tml::Application < Tml::Base
|
|
76
77
|
if data
|
77
78
|
update_attributes(data)
|
78
79
|
else
|
79
|
-
Tml.
|
80
|
+
add_language(Tml.config.default_language)
|
81
|
+
Tml.logger.debug('Cache is disabled or no data has been cached.')
|
80
82
|
end
|
81
83
|
|
82
84
|
self
|
@@ -177,16 +179,6 @@ class Tml::Application < Tml::Base
|
|
177
179
|
@locales ||= languages.collect{|lang| lang.locale}
|
178
180
|
end
|
179
181
|
|
180
|
-
# Returns tools data
|
181
|
-
def tools
|
182
|
-
@attributes[:tools] || {}
|
183
|
-
end
|
184
|
-
|
185
|
-
# Returns asset url
|
186
|
-
def url_for(path)
|
187
|
-
"#{tools['assets']}#{path}"
|
188
|
-
end
|
189
|
-
|
190
182
|
# Returns source by key
|
191
183
|
def source(key, locale)
|
192
184
|
self.sources ||= {}
|
@@ -196,7 +188,7 @@ class Tml::Application < Tml::Base
|
|
196
188
|
).fetch_translations(locale)
|
197
189
|
end
|
198
190
|
|
199
|
-
#
|
191
|
+
# Verify current source path
|
200
192
|
def verify_source_path(source_key, source_path)
|
201
193
|
return if Tml.cache.enabled? and not Tml.session.inline_mode?
|
202
194
|
return if extensions.nil? or extensions['sources'].nil?
|
@@ -205,14 +197,17 @@ class Tml::Application < Tml::Base
|
|
205
197
|
@missing_keys_by_sources[source_path] ||= {}
|
206
198
|
end
|
207
199
|
|
200
|
+
# Register missing keys
|
208
201
|
def register_missing_key(source_key, tkey)
|
209
202
|
return if Tml.cache.enabled? and not Tml.session.inline_mode?
|
203
|
+
source_key = source_key.to_s
|
210
204
|
@missing_keys_by_sources ||= {}
|
211
205
|
@missing_keys_by_sources[source_key] ||= {}
|
212
206
|
@missing_keys_by_sources[source_key][tkey.key] ||= tkey
|
213
207
|
submit_missing_keys if Tml.config.submit_missing_keys_realtime
|
214
208
|
end
|
215
209
|
|
210
|
+
# Register keys
|
216
211
|
def register_keys(keys)
|
217
212
|
params = []
|
218
213
|
keys.each do |source_key, keys|
|
@@ -228,12 +223,14 @@ class Tml::Application < Tml::Base
|
|
228
223
|
Tml.logger.error(e.backtrace)
|
229
224
|
end
|
230
225
|
|
226
|
+
# Submit missing translation keys
|
231
227
|
def submit_missing_keys
|
232
228
|
return if @missing_keys_by_sources.nil? or @missing_keys_by_sources.empty?
|
233
229
|
register_keys(@missing_keys_by_sources)
|
234
230
|
@missing_keys_by_sources = nil
|
235
231
|
end
|
236
232
|
|
233
|
+
# Reset translation cache
|
237
234
|
def reset_translation_cache
|
238
235
|
self.sources = {}
|
239
236
|
self.translations = {}
|
@@ -241,18 +238,20 @@ class Tml::Application < Tml::Base
|
|
241
238
|
@missing_keys_by_sources = nil
|
242
239
|
end
|
243
240
|
|
241
|
+
# Check if a key is ignored
|
244
242
|
def ignored_key?(key)
|
245
243
|
return false if ignored_keys.nil?
|
246
244
|
not ignored_keys.index(key).nil?
|
247
245
|
end
|
248
246
|
|
247
|
+
# Fetch translations from API
|
249
248
|
def fetch_translations(locale)
|
250
249
|
self.translations ||= {}
|
251
250
|
self.translations[locale] ||= begin
|
252
251
|
results = Tml.cache.fetch(Tml::Application.translations_cache_key(locale)) do
|
253
252
|
data = {}
|
254
253
|
unless Tml.cache.read_only?
|
255
|
-
data = api_client.get(
|
254
|
+
data = api_client.get("projects/#{key}/translations", :all => true, :ignored => true, :raw_json => true)
|
256
255
|
end
|
257
256
|
data
|
258
257
|
end
|
@@ -280,6 +279,7 @@ class Tml::Application < Tml::Base
|
|
280
279
|
{}
|
281
280
|
end
|
282
281
|
|
282
|
+
# Cache translations within application object
|
283
283
|
def cache_translations(locale, key, new_translations)
|
284
284
|
self.translations ||= {}
|
285
285
|
self.translations[locale] ||= {}
|
@@ -292,11 +292,13 @@ class Tml::Application < Tml::Base
|
|
292
292
|
end
|
293
293
|
end
|
294
294
|
|
295
|
+
# Get application cached translations
|
295
296
|
def cached_translations(locale, key)
|
296
297
|
return unless self.translations and self.translations[locale]
|
297
298
|
self.translations[locale][key]
|
298
299
|
end
|
299
300
|
|
301
|
+
# Debug translations
|
300
302
|
def debug_translations
|
301
303
|
return 'no translations' unless self.translations
|
302
304
|
self.translations.each do |locale, keys|
|
@@ -308,24 +310,24 @@ class Tml::Application < Tml::Base
|
|
308
310
|
end
|
309
311
|
end
|
310
312
|
|
313
|
+
# Get default decoration token
|
311
314
|
def default_decoration_token(token)
|
312
315
|
hash_value(tokens, "decoration.#{token.to_s}")
|
313
316
|
end
|
314
317
|
|
318
|
+
# Get default data token
|
315
319
|
def default_data_token(token)
|
316
320
|
hash_value(tokens, "data.#{token.to_s}")
|
317
321
|
end
|
318
322
|
|
323
|
+
# Check if feature is enabled
|
319
324
|
def feature_enabled?(key)
|
320
325
|
hash_value(features, key.to_s)
|
321
326
|
end
|
322
327
|
|
328
|
+
# Create API client
|
323
329
|
def api_client
|
324
|
-
@api_client ||= Tml.config.
|
325
|
-
end
|
326
|
-
|
327
|
-
def postoffice
|
328
|
-
@postoffice ||= Tml::Api::PostOffice.new(application: self)
|
330
|
+
@api_client ||= Tml.config.api_client[:class].new(application: self)
|
329
331
|
end
|
330
332
|
|
331
333
|
end
|
data/lib/tml/cache.rb
CHANGED
@@ -30,9 +30,13 @@
|
|
30
30
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
31
|
#++
|
32
32
|
|
33
|
-
|
33
|
+
require 'rubygems'
|
34
|
+
require 'rubygems/package'
|
35
|
+
require 'open-uri'
|
36
|
+
require 'zlib'
|
37
|
+
require 'fileutils'
|
34
38
|
|
35
|
-
|
39
|
+
module Tml
|
36
40
|
|
37
41
|
def self.cache
|
38
42
|
@cache ||= begin
|
@@ -48,41 +52,19 @@ module Tml
|
|
48
52
|
|
49
53
|
class Cache
|
50
54
|
|
51
|
-
#
|
55
|
+
# version object
|
52
56
|
def version
|
53
|
-
@version
|
54
|
-
end
|
55
|
-
|
56
|
-
# sets the current version
|
57
|
-
def version=(new_version)
|
58
|
-
@version = new_version
|
57
|
+
@version ||= Tml::CacheVersion.new(self)
|
59
58
|
end
|
60
59
|
|
61
60
|
# resets current version
|
62
61
|
def reset_version
|
63
|
-
|
62
|
+
version.reset
|
64
63
|
end
|
65
64
|
|
66
65
|
# upgrade current version
|
67
66
|
def upgrade_version
|
68
|
-
|
69
|
-
reset_version
|
70
|
-
end
|
71
|
-
|
72
|
-
# fetches the version from the cache
|
73
|
-
def fetch_version
|
74
|
-
@version ||= begin
|
75
|
-
v = fetch(CACHE_VERSION_KEY) do
|
76
|
-
{'version' => Tml.config.cache[:version] || 'undefined'}
|
77
|
-
end
|
78
|
-
v.is_a?(Hash) ? v['version'] : v
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# stores the current version back in cache
|
83
|
-
def store_version(new_version)
|
84
|
-
@version = new_version
|
85
|
-
store(CACHE_VERSION_KEY, {'version' => new_version})
|
67
|
+
version.upgrade
|
86
68
|
end
|
87
69
|
|
88
70
|
# checks if Tml is enabled
|
@@ -114,12 +96,12 @@ module Tml
|
|
114
96
|
# namespace of each cache key
|
115
97
|
def namespace
|
116
98
|
return '#' if Tml.config.disabled?
|
117
|
-
Tml.config.cache[:namespace] || Tml.config.
|
99
|
+
Tml.config.cache[:namespace] || Tml.config.application[:key][0..5]
|
118
100
|
end
|
119
101
|
|
120
102
|
# versioned name of cache key
|
121
103
|
def versioned_key(key, opts = {})
|
122
|
-
|
104
|
+
version.versioned_key(key, namespace)
|
123
105
|
end
|
124
106
|
|
125
107
|
# fetches key from cache
|
@@ -148,6 +130,105 @@ module Tml
|
|
148
130
|
# do nothing
|
149
131
|
end
|
150
132
|
|
133
|
+
def extract_version(app, version = nil)
|
134
|
+
if version
|
135
|
+
Tml.cache.version.set(version.to_s)
|
136
|
+
else
|
137
|
+
version_data = app.api_client.get_from_cdn('version', {t: Time.now.to_i}, {uncompressed: true})
|
138
|
+
|
139
|
+
unless version_data
|
140
|
+
Tml.logger.debug('No releases have been generated yet. Please visit your Dashboard and publish translations.')
|
141
|
+
return
|
142
|
+
end
|
143
|
+
|
144
|
+
Tml.cache.version.set(version_data['version'])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# warmup cache
|
149
|
+
def warmup(version = nil)
|
150
|
+
t0 = Time.now
|
151
|
+
Tml.logger = Logger.new(STDOUT)
|
152
|
+
|
153
|
+
Tml.logger.debug('Starting cache warmup...')
|
154
|
+
app = Tml::Application.new(key: Tml.config.application[:key])
|
155
|
+
extract_version(app, version)
|
156
|
+
|
157
|
+
Tml.logger.debug("Warming Up Version: #{Tml.cache.version}")
|
158
|
+
|
159
|
+
application = app.api_client.get_from_cdn('application', {t: Time.now.to_i})
|
160
|
+
Tml.cache.store(Tml::Application.cache_key, application)
|
161
|
+
|
162
|
+
sources = app.api_client.get_from_cdn('sources', {t: Time.now.to_i}, {uncompressed: true})
|
163
|
+
|
164
|
+
application['languages'].each do |lang|
|
165
|
+
locale = lang['locale']
|
166
|
+
language = app.api_client.get_from_cdn("#{locale}/language", {t: Time.now.to_i})
|
167
|
+
Tml.cache.store(Tml::Language.cache_key(locale), language)
|
168
|
+
|
169
|
+
sources.each do |src|
|
170
|
+
source = app.api_client.get_from_cdn("#{locale}/sources/#{src}", {t: Time.now.to_i})
|
171
|
+
Tml.cache.store(Tml::Source.cache_key(locale, src), source)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
t1 = Time.now
|
176
|
+
Tml.logger.debug("Cache warmup took #{t1-t0}s")
|
177
|
+
end
|
178
|
+
|
179
|
+
# default cache path
|
180
|
+
def default_cache_path
|
181
|
+
@cache_path ||= begin
|
182
|
+
path = Tml.config.cache[:path]
|
183
|
+
path ||= 'config/tml'
|
184
|
+
FileUtils.mkdir_p(path)
|
185
|
+
FileUtils.chmod(0777, path)
|
186
|
+
path
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# downloads cache from the CDN
|
191
|
+
def download(cache_path = default_cache_path, version = nil)
|
192
|
+
t0 = Time.now
|
193
|
+
Tml.logger = Logger.new(STDOUT)
|
194
|
+
|
195
|
+
Tml.logger.debug('Starting cache download...')
|
196
|
+
app = Tml::Application.new(key: Tml.config.application[:key])
|
197
|
+
extract_version(app, version)
|
198
|
+
|
199
|
+
Tml.logger.debug("Downloading Version: #{Tml.cache.version}")
|
200
|
+
|
201
|
+
archive_name = "#{Tml.cache.version}.tar.gz"
|
202
|
+
path = "#{cache_path}/#{archive_name}"
|
203
|
+
url = "#{app.cdn_host}/#{Tml.config.application[:key]}/#{archive_name}"
|
204
|
+
|
205
|
+
Tml.logger.debug("Downloading cache file: #{url}")
|
206
|
+
open(path, 'wb') do |file|
|
207
|
+
file << open(url).read
|
208
|
+
end
|
209
|
+
|
210
|
+
Tml.logger.debug('Extracting cache file...')
|
211
|
+
version_path = "#{cache_path}/#{Tml.cache.version}"
|
212
|
+
Tml::Utils.untar(Tml::Utils.ungzip(File.new(path)), version_path)
|
213
|
+
Tml.logger.debug("Cache has been stored in #{version_path}")
|
214
|
+
|
215
|
+
File.unlink(path)
|
216
|
+
|
217
|
+
begin
|
218
|
+
current_path = 'current'
|
219
|
+
FileUtils.chdir(cache_path)
|
220
|
+
FileUtils.rm(current_path) if File.exist?(current_path)
|
221
|
+
FileUtils.ln_s(Tml.cache.version.to_s, current_path)
|
222
|
+
Tml.logger.debug("The new version #{Tml.cache.version} has been marked as current")
|
223
|
+
rescue Exception => ex
|
224
|
+
Tml.logger.debug("Could not generate current symlink to the cache path: #{ex.message}")
|
225
|
+
end
|
226
|
+
|
227
|
+
t1 = Time.now
|
228
|
+
Tml.logger.debug("Cache download took #{t1-t0}s")
|
229
|
+
end
|
230
|
+
|
231
|
+
# remove extensions
|
151
232
|
def strip_extensions(data)
|
152
233
|
if data.is_a?(Hash)
|
153
234
|
data = data.dup
|