smartkiosk-server 0.10.4 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -19,6 +19,7 @@
19
19
  /public/uploads
20
20
  /public/builds
21
21
  /public/assets
22
+ /public/gems
22
23
 
23
24
  # Ignore the default SQLite database.
24
25
  /db/*.sqlite3*
data/Gemfile CHANGED
@@ -69,3 +69,5 @@ group :development do
69
69
  end
70
70
 
71
71
  gem 'iso8583-mkb', '0.0.2'
72
+
73
+ gem 'bundler', '~> 1.2.3'
@@ -385,6 +385,7 @@ DEPENDENCIES
385
385
  axlsx
386
386
  better_errors
387
387
  binding_of_caller
388
+ bundler (~> 1.2.3)
388
389
  capistrano
389
390
  carrierwave
390
391
  clockwork
@@ -7,7 +7,16 @@ ActiveAdmin.register TerminalBuild do
7
7
  index do
8
8
  selectable_column
9
9
  column :id
10
- column :version
10
+ column :version do |tb|
11
+ div tb.version
12
+
13
+ if tb.gems_ready
14
+ status_tag(I18n.t('smartkiosk.admin.terminal_build.gems_ready'), :ok)
15
+ else
16
+ status_tag(I18n.t('smartkiosk.admin.terminal_build.gems_not_ready'), :error)
17
+ end
18
+
19
+ end
11
20
  column :source do |tb|
12
21
  link_to File.basename(tb.source.path), tb.source.url
13
22
  end
@@ -23,6 +32,9 @@ ActiveAdmin.register TerminalBuild do
23
32
  row :source do |tb|
24
33
  link_to File.basename(tb.source.path), tb.source.url
25
34
  end
35
+ row :gems_ready do |tb|
36
+ status_boolean(self, tb.gems_ready)
37
+ end
26
38
  row :created_at
27
39
  row :updated_at
28
40
  end
@@ -35,5 +47,5 @@ ActiveAdmin.register TerminalBuild do
35
47
  end
36
48
  f.actions
37
49
  end
38
-
50
+
39
51
  end
@@ -2,8 +2,8 @@ ActiveAdmin.register Terminal do
2
2
 
3
3
  SIMPLE_ORDERS = Terminal::ORDERS.select{|x| x != 'upgrade'} unless defined?(SIMPLE_ORDERS)
4
4
 
5
- menu :parent => I18n.t('activerecord.models.terminal.other'),
6
- :label => I18n.t('smartkiosk.admin.menu.manage'),
5
+ menu :parent => I18n.t('activerecord.models.terminal.other'),
6
+ :label => I18n.t('smartkiosk.admin.menu.manage'),
7
7
  :priority => 1,
8
8
  :if => proc { can? :index, Terminal }
9
9
 
@@ -62,11 +62,16 @@ ActiveAdmin.register Terminal do
62
62
  member_action :upgrade, :method => :post do
63
63
  build = TerminalBuild.find(params[:build_id])
64
64
 
65
- Terminal.where(:id => params[:id].split(',')).each do |t|
66
- t.order! :upgrade, build.id, build.version, build.path, build.url
65
+ if build.gems_ready
66
+ Terminal.where(:id => params[:id].split(',')).each do |t|
67
+ t.order! :upgrade, build.id, build.version, build.path, build.url, URI.join(root_url, "/gems").to_s
68
+ end
69
+
70
+ redirect_to :action => :index
71
+ else
72
+ redirect_to :back, :flash => { :error => I18n.t('smartkiosk.admin.terminal_build.gems_not_ready_error') }
67
73
  end
68
74
 
69
- redirect_to :action => :index
70
75
  end
71
76
 
72
77
  SIMPLE_ORDERS.each do |order|
@@ -80,7 +85,7 @@ ActiveAdmin.register Terminal do
80
85
  # INDEX
81
86
  #
82
87
  batch_action(
83
- I18n.t('smartkiosk.admin.actions.terminals.upgrade'),
88
+ I18n.t('smartkiosk.admin.actions.terminals.upgrade'),
84
89
  :if => proc{current_user.priveleged?(:terminals, :upgrade)}
85
90
  ) do |selection|
86
91
  redirect_to upgrade_build_admin_terminal_path(Terminal.find(selection).map(&:id).join(','))
@@ -1,6 +1,11 @@
1
1
  require 'digest/md5'
2
2
 
3
3
  class TerminalBuild < ActiveRecord::Base
4
+ include Redis::Objects
5
+
6
+ lock :stash_worker, :global => true, :timeout => 0.1
7
+ counter :stash_counter, :global => true
8
+
4
9
  mount_uploader :source, ZipUploader
5
10
 
6
11
  validates :source, :presence => true
@@ -24,10 +29,12 @@ class TerminalBuild < ActiveRecord::Base
24
29
  end
25
30
 
26
31
  self.update_attributes :hashes => build_hashes
32
+ update_stash
27
33
  end
28
34
 
29
35
  after_destroy do
30
36
  FileUtils.rm_rf path
37
+ update_stash
31
38
  end
32
39
 
33
40
  def path
@@ -59,4 +66,12 @@ class TerminalBuild < ActiveRecord::Base
59
66
 
60
67
  hashes
61
68
  end
69
+
70
+ protected
71
+
72
+ def update_stash
73
+ TerminalBuild.stash_counter.incr
74
+
75
+ GemStashUpdateWorker.perform_async
76
+ end
62
77
  end
@@ -0,0 +1,43 @@
1
+ require "gem_stasher"
2
+
3
+ class GemStashUpdateWorker
4
+ include Sidekiq::Worker
5
+
6
+ sidekiq_options :retry => false
7
+
8
+ def perform
9
+ begin
10
+ TerminalBuild.stash_worker_lock.lock do
11
+ while TerminalBuild.stash_counter.getset(0) > 0
12
+ update_stash!
13
+ end
14
+ end
15
+ rescue Redis::Lock::LockTimeout => e
16
+ Sidekiq::Logging.logger.warn "Lock timeout."
17
+
18
+ # To avoid excessive cpu burning but still ensure robust updates
19
+ GemStashUpdateWorker.perform_in 1.minute
20
+ end
21
+ end
22
+
23
+ def update_stash!
24
+ builds = TerminalBuild.all
25
+
26
+ stasher = GemStasher.new Sidekiq::Logging.logger, Rails.root.join("public/gems")
27
+ stasher.maintain_cache builds.map(&:path)
28
+ stasher.update_index
29
+
30
+ TerminalBuild.transaction do
31
+ builds.each do |build|
32
+ begin
33
+ build.gems_ready = true
34
+
35
+ build.save!
36
+ rescue => e
37
+ Sidekiq::Logging.logger.warn "error occured during update of build #{build.id}: #{e}"
38
+ end
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -14,7 +14,7 @@ ru:
14
14
  not_a_hash: содержат неправильный формат
15
15
  rebate:
16
16
  attributes:
17
- start:
17
+ start:
18
18
  too_large: должна быть меньше даты окончания
19
19
  conditions_intersect: Условия выборки пересекаются
20
20
  requires_commission_intersects: Нельзя указать разные типы связи с комиссией в рамках одного шлюза
@@ -25,7 +25,7 @@ ru:
25
25
  too_large: должно быть меньше До
26
26
  commission:
27
27
  attributes:
28
- start:
28
+ start:
29
29
  too_large: должна быть меньше даты окончания
30
30
  conditions_intersect: Условия выборки пересекаются
31
31
  payment_type_intersects: Нельзя указать разные типы связи типа платежа в рамках одного провайдера
@@ -35,7 +35,7 @@ ru:
35
35
  too_large: должно быть меньше До
36
36
  limit:
37
37
  attributes:
38
- start:
38
+ start:
39
39
  too_large: должна быть меньше даты окончания
40
40
  conditions_intersect: Условия выборки пересекаются
41
41
  payment_type_intersects: Нельзя указать разные типы связи типа платежа в рамках одного провайдера
@@ -178,7 +178,7 @@ ru:
178
178
  many: Сверок
179
179
  one: Сверка
180
180
  other: Сверки
181
- terminal:
181
+ terminal:
182
182
  few: Терминала
183
183
  many: Терминалов
184
184
  one: Терминал
@@ -244,6 +244,7 @@ ru:
244
244
  terminal_build:
245
245
  version: Версия
246
246
  source: Источник (ZIP)
247
+ gems_ready: Готова к деплою
247
248
  created_at: Дата создания
248
249
  updated_at: Дата обновления
249
250
  provider_receipt_template:
@@ -1,6 +1,6 @@
1
1
  ru:
2
2
  smartkiosk:
3
- welcome:
3
+ welcome:
4
4
  header: Вы авторизованы как %{user}
5
5
  roles: Доступные роли
6
6
  properties: Свойства аккаунта
@@ -78,6 +78,10 @@ ru:
78
78
  upgrade: Обновление терминалов
79
79
  all_pings: Полная история связи
80
80
  pings: История связи
81
+ terminal_build:
82
+ gems_ready: Готова к деплою
83
+ gems_not_ready: Подготавливается
84
+ gems_not_ready_error: Сборка еще подготавливается
81
85
  role_priveleges:
82
86
  basic:
83
87
  create: Создание
@@ -4,6 +4,7 @@ class CreateTerminalBuilds < ActiveRecord::Migration
4
4
  t.string :version
5
5
  t.string :source
6
6
  t.text :hashes
7
+ t.boolean :gems_ready, :default => false
7
8
  t.timestamps
8
9
  end
9
10
  end
@@ -370,8 +370,9 @@ ActiveRecord::Schema.define(:version => 20130108091644) do
370
370
  t.string "version"
371
371
  t.string "source"
372
372
  t.text "hashes"
373
- t.datetime "created_at", :null => false
374
- t.datetime "updated_at", :null => false
373
+ t.boolean "gems_ready", :default => false
374
+ t.datetime "created_at", :null => false
375
+ t.datetime "updated_at", :null => false
375
376
  end
376
377
 
377
378
  create_table "terminal_orders", :force => true do |t|
@@ -0,0 +1,171 @@
1
+ require "bundler"
2
+ require "rubygems/user_interaction"
3
+ require "rubygems/package"
4
+ require "net/http"
5
+ require "set"
6
+ require "fileutils"
7
+
8
+ # Make LazySpecification Set-able
9
+ class Bundler::LazySpecification
10
+ alias :eql? :==
11
+
12
+ def hash
13
+ [ @name, @version, @dependencies, @platform, @source ].hash
14
+ end
15
+ end
16
+
17
+ class GemStasher
18
+ def initialize(logger, gempath)
19
+ @logger = logger
20
+ @gempath = gempath
21
+ end
22
+
23
+ def maintain_cache(builds)
24
+ sources = Set.new
25
+ required_gems = Set.new
26
+ existing_gems = Set.new
27
+
28
+ FileUtils.mkdir_p "#{@gempath}/gems"
29
+
30
+ @logger.info "Updating gem cache"
31
+
32
+ Dir["#{@gempath}/gems/*.gem"].each do |gempack|
33
+ begin
34
+ File.open(gempack) do |io|
35
+ Gem::Package.open(io, 'r', nil) do |gem|
36
+ spec = Bundler::LazySpecification.new(
37
+ gem.metadata.name,
38
+ gem.metadata.version,
39
+ gem.metadata.platform
40
+ )
41
+
42
+ existing_gems.add spec
43
+ end
44
+ end
45
+ rescue => e
46
+ @logger.warn "unable to read #{gempack}: #{e}"
47
+ File.delete gempack
48
+ end
49
+ end
50
+
51
+ builds.each do |build|
52
+ begin
53
+ gemfile = Bundler::Definition.build File.join(build, "Gemfile"),
54
+ File.join(build, "Gemfile.lock"), {}
55
+
56
+ gemfile.sources.each do |source|
57
+ next unless source.kind_of? Bundler::Source::Rubygems
58
+
59
+ source.remotes.each { |remote| sources.add remote }
60
+ end
61
+
62
+ gemfile.resolve.each do |spec|
63
+
64
+ required_gems.add Bundler::LazySpecification.new(
65
+ spec.name,
66
+ spec.version,
67
+ spec.platform
68
+ )
69
+ end
70
+ rescue => e
71
+ @logger.warn "unable to process #{build}: #{e}"
72
+ end
73
+ end
74
+
75
+ dead_gems = existing_gems - required_gems
76
+ missing_gems = required_gems - existing_gems
77
+
78
+ dead_gems.each do |spec|
79
+ @logger.info "- deleting dead #{spec.name} #{spec.version}"
80
+
81
+ filename = filename_for_spec spec
82
+
83
+ begin
84
+ File.delete "#{@gempath}/#{filename}"
85
+ rescue => e
86
+ @logger.warn "unable to delete #{filename}: #{e}"
87
+ end
88
+ end
89
+
90
+ if missing_gems.any?
91
+ sources.each do |uri|
92
+ fetcher = Bundler::Fetcher.new uri
93
+
94
+ names = missing_gems.map { |gem| gem.name }
95
+ specs = fetcher.specs names, uri
96
+
97
+ missing_gems.each do |gem|
98
+ found = specs.local_search gem
99
+
100
+ next unless found.any?
101
+
102
+ missing_gems.delete gem
103
+
104
+ spec, = found
105
+ filename = filename_for_spec spec
106
+ local_file_name = "#{@gempath}/#{filename}"
107
+
108
+ file_uri = uri.dup
109
+ file_uri.path = "#{uri.path}#{filename}"
110
+
111
+ @logger.info " - fetching #{spec.name} #{spec.version} from #{uri}"
112
+
113
+ io = File.open(local_file_name, "wb")
114
+ begin
115
+ fetch_file file_uri, io
116
+ rescue => e
117
+ File.delete io
118
+ warn "unable to download #{filename}: #{e}"
119
+ ensure
120
+ io.close
121
+ end
122
+ end
123
+ end
124
+
125
+ if missing_gems.any?
126
+ @logger.warn "unresolved dependencies:"
127
+ missing_gems.each do |spec|
128
+ @logger.warn " - #{spec}"
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def update_index
135
+ @logger.info "Updating gem index at #{@gempath}"
136
+ # unfortunately, it's not possible to use Gem::Index without breaking
137
+ # host application bundler.
138
+ Bundler.with_clean_env do
139
+ system "gem", "generate_index", "--directory", @gempath.to_s, "--quiet"
140
+ end
141
+ end
142
+
143
+ private
144
+
145
+ def filename_for_spec(spec)
146
+ "gems/#{spec.name}-#{spec.version}.gem"
147
+ end
148
+
149
+ def fetch_file(uri, io)
150
+ Net::HTTP.start(uri.host,
151
+ uri.port,
152
+ :use_ssl => uri.scheme == 'https',
153
+ :verify_mode => OpenSSL::SSL::VERIFY_NONE
154
+ ) do |http|
155
+ http.request_get(uri.path) do |response|
156
+ case response
157
+ when Net::HTTPSuccess
158
+ response.read_body { |chunk| io.write chunk }
159
+
160
+ when Net::HTTPRedirection
161
+ fetch_file URI.join(uri.to_s, response['location']), io
162
+
163
+ else
164
+ raise response.value
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ Bundler.settings[:frozen] = true
@@ -1,5 +1,5 @@
1
1
  module Smartkiosk
2
2
  module Server
3
- VERSION = '0.10.4'
3
+ VERSION = '0.10.5'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartkiosk-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.4
4
+ version: 0.10.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-06 00:00:00.000000000 Z
13
+ date: 2013-02-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -176,6 +176,7 @@ files:
176
176
  - app/views/admin/terminals/upgrade_build.html.arb
177
177
  - app/views/layouts/application.html.erb
178
178
  - app/views/welcome/index.html.erb
179
+ - app/workers/gem_stash_update_worker.rb
179
180
  - app/workers/pay_worker.rb
180
181
  - app/workers/report_worker.rb
181
182
  - app/workers/revise_worker.rb
@@ -272,6 +273,7 @@ files:
272
273
  - lib/date_expander.rb
273
274
  - lib/dav4rack/build_resource.rb
274
275
  - lib/formtastic/inputs/selectable_check_boxes.rb
276
+ - lib/gem_stasher.rb
275
277
  - lib/paper_trail/version_fix.rb
276
278
  - lib/report_builder.rb
277
279
  - lib/seeder.rb
@@ -321,7 +323,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
321
323
  version: '0'
322
324
  segments:
323
325
  - 0
324
- hash: 1639411805563885975
326
+ hash: -1133320975275850938
325
327
  required_rubygems_version: !ruby/object:Gem::Requirement
326
328
  none: false
327
329
  requirements: