wonko_the_sane 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cc57f86a647b80182858a1980048fe31dde2dbc6
4
- data.tar.gz: 7ddb8818395ea2e823cf61ac94aa26d362453f79
3
+ metadata.gz: 40c75f8cc35f2cedea382f8b22f0373f9199ab60
4
+ data.tar.gz: 419906fc73b134f8ddc6d994d2bab5ec8d277840
5
5
  SHA512:
6
- metadata.gz: 48502a7dfd108e92d4cae999c99fa87ab236334ef771aec8f9cb6c942dc25a4ae9fc43ee0d81c79fed334415256d95e8cf2d47884767be965b23d25c96dfd678
7
- data.tar.gz: 7addb60be6a1876d40cc473367916d4a406937cc9d492baa43b01a2c6d73e81ec9222329a245a0f6d110eb724e74d3efc920fe5babfc0c2a86284ebea90a1000
6
+ metadata.gz: bcba25e623bf105bc2aa37d9572e3a542ffc58c4eaa30f50d8dc576aa6af10a9472175736e4460687d24564e977070de45935b037001b39be6b7f2ea972f3a25
7
+ data.tar.gz: 52fd86ab7abd1262bf6b2096ef67e89a83641157b8fb9106787a2d71d4916d17bf85f1d0cecf369b64e0c8b6baa126c51302a84f281549851f32179744553e0c
data/bin/wonko_the_sane CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env ruby
1
2
  require 'wonko_the_sane'
2
3
  require 'optparse'
3
4
 
@@ -21,7 +22,7 @@ Logging.logger['General'].info 'Welcome to WonkoTheSane!'.yellow
21
22
 
22
23
  WonkoTheSane.configure do |config|
23
24
  config.data_path = File.dirname(__FILE__) + '/../data'
24
- config.register_lists_from 'data/sources.json'
25
+ config.register_lists_from_sources
25
26
  config.register_list VanillaVersionList
26
27
  config.register_list VanillaLegacyVersionList
27
28
  config.register_list LiteLoaderVersionList
@@ -82,6 +83,15 @@ OptionParser.new do |opts|
82
83
  opts.on '--update-nem', 'Updates sources.json with data from NEM' do
83
84
  update_nem
84
85
  end
86
+ opts.on '--set-config=VAL', 'Sets a configuration value' do |val|
87
+ parts = val.match /([^:=]*)([:=](.*))?/
88
+ if parts.length == 4 && !parts[3].nil?
89
+ Settings[parts[1]] = parts[3]
90
+ else
91
+ Settings.delete parts[1]
92
+ end
93
+ Settings.save! WonkoTheSane.settings_file
94
+ end
85
95
  opts.on '-h', '--help', 'Prints this help' do
86
96
  puts opts
87
97
  exit
@@ -89,3 +99,4 @@ OptionParser.new do |opts|
89
99
  end.parse!
90
100
 
91
101
  TaskStack.pop_all
102
+ WonkoTheSane.wonkoweb_uploader.upload_changes!
data/data/minecraft.json CHANGED
@@ -1,4 +1,4 @@
1
- {
1
+ {
2
2
  "versions": [
3
3
  {
4
4
  "id": "1.5.2",
@@ -4,9 +4,19 @@ require 'yajl/json_gem'
4
4
  require 'fileutils'
5
5
  require 'zip'
6
6
  require 'set'
7
+ require 'uri'
8
+ require 'net/http'
9
+ require 'digest'
10
+ require 'date'
11
+ require 'time'
12
+ require 'oga'
13
+ require 'configliere'
14
+ require 'httparty'
15
+ require 'active_support/core_ext/hash/indifferent_access'
7
16
 
8
17
  require 'wonko_the_sane/version'
9
18
  require 'wonko_the_sane/tools/update_nem'
19
+ require 'wonko_the_sane/util/benchmark'
10
20
  require 'wonko_the_sane/util/configuration'
11
21
  require 'wonko_the_sane/util/extraction_cache'
12
22
  require 'wonko_the_sane/util/deep_storage_cache'
@@ -30,6 +40,7 @@ require 'wonko_the_sane/versionlists/liteloader_version_list'
30
40
  require 'wonko_the_sane/versionlists/vanilla_legacy_version_list'
31
41
  require 'wonko_the_sane/versionlists/vanilla_version_list'
32
42
 
43
+ require 'wonko_the_sane/wonkoweb_uploader'
33
44
  require 'wonko_the_sane/reader_writer'
34
45
  require 'wonko_the_sane/registry'
35
46
  require 'wonko_the_sane/rules'
@@ -39,16 +50,25 @@ require 'wonko_the_sane/version_parser'
39
50
  require 'wonko_the_sane/wonko_version'
40
51
 
41
52
  module WonkoTheSane
53
+ def self.wonkoweb_uploader
54
+ @uploader ||= WonkoWebUploader.new
55
+ end
56
+
42
57
  def self.lists
43
58
  configuration.lists
44
59
  end
45
60
 
61
+ def self.settings_file
62
+ File.dirname(__FILE__) + '/../wonko_the_sane.yml'
63
+ end
64
+
46
65
  def self.data(file)
47
66
  configuration.data_path + '/' + file
48
67
  end
49
68
 
50
69
  def self.data_json(file)
51
- JSON.parse File.open(data(file), 'r'), symbolize_keys: true
70
+ res = JSON.parse File.read data file
71
+ res.is_a?(Hash) ? HashWithIndifferentAccess.new(res) : res
52
72
  end
53
73
 
54
74
  def self.set_data_json(file, obj)
@@ -64,3 +84,24 @@ module WonkoTheSane
64
84
  end
65
85
  private_class_method :configuration
66
86
  end
87
+
88
+ Settings.use :config_block, :encrypted, :prompt, :define
89
+ Settings({
90
+ aws: {
91
+ client_id: nil,
92
+ client_secret: nil
93
+ },
94
+ wonkoweb: {
95
+ host: nil,
96
+ email: nil,
97
+ token: nil
98
+ }
99
+ })
100
+ Settings.define 'aws.client_id', encrypted: true
101
+ Settings.define 'aws.client_secret', encrypted: true
102
+ Settings.define 'wonkoweb.host'
103
+ Settings.define 'wonkoweb.name'
104
+ Settings.define 'wonkoweb.token', encrypted: true
105
+ Settings.read WonkoTheSane.settings_file
106
+ Settings[:encrypt_pass] = ENV['ENCRYPT_PASS'] || (print 'Password: '; pwd = STDIN.noecho(&:gets).chomp; puts; pwd)
107
+ Settings.resolve!
@@ -114,16 +114,16 @@ class MojangInput
114
114
  file.client.downloads = object[:libraries].map do |obj|
115
115
  MojangInput.sanetize_mojang_library obj
116
116
  end.flatten 1
117
- mainLib = VersionLibrary.new
118
- mainLib.name = "net.minecraft:minecraft:#{file.version}"
119
- mainLib.url = 'http://s3.amazonaws.com/Minecraft.Download/versions/' + file.version + '/' + file.version + '.jar'
120
- file.client.downloads << mainLib
117
+ main_lib = VersionLibrary.new
118
+ main_lib.name = "net.minecraft:minecraft:#{file.version}"
119
+ main_lib.url = 'http://s3.amazonaws.com/Minecraft.Download/versions/' + file.version + '/' + file.version + '.jar'
120
+ file.client.downloads << main_lib
121
121
  file.client.launchMethod = 'minecraft'
122
122
 
123
- serverLib = VersionLibrary.new
124
- serverLib.name = "net.minecraft:minecraft_server:#{file.version}"
125
- serverLib.url = 'http://s3.amazonaws.com/Minecraft.Download/versions/' + file.version + '/minecraft_server.' + file.version + '.jar'
126
- file.server.downloads << serverLib
123
+ server_lib = VersionLibrary.new
124
+ server_lib.name = "net.minecraft:minecraft_server:#{file.version}"
125
+ server_lib.url = 'http://s3.amazonaws.com/Minecraft.Download/versions/' + file.version + '/minecraft_server.' + file.version + '.jar'
126
+ file.server.downloads << server_lib
127
127
  file.server.jarModTarget = "net.minecraft:minecraft_server:#{file.version}"
128
128
  file.server.launchMethod = 'java.jar'
129
129
 
@@ -2,7 +2,7 @@ require 'hashie'
2
2
 
3
3
  module Reader
4
4
  def read_version_index(data)
5
- json = Hashie::Mash.new JSON.parse(data, symbolize_names: true)
5
+ json = Hashie::Mash.new data
6
6
 
7
7
  index = VersionIndex.new json.uid
8
8
  index.name = json.name
@@ -21,11 +21,11 @@ module Reader
21
21
 
22
22
  def read_download(data, key)
23
23
  if data[key.to_sym]
24
- return data[key.to_sym].map do |dl|
24
+ data[key.to_sym].map do |dl|
25
25
  Download.from_json key, dl
26
26
  end
27
27
  else
28
- return []
28
+ []
29
29
  end
30
30
  end
31
31
 
@@ -49,7 +49,7 @@ module Reader
49
49
  end
50
50
 
51
51
  def read_version(data)
52
- json = Hashie::Mash.new JSON.parse(data)
52
+ json = Hashie::Mash.new data
53
53
 
54
54
  file = WonkoVersion.new
55
55
  file.is_complete = true
@@ -73,11 +73,11 @@ module Reader
73
73
  end
74
74
  end if json[:data]
75
75
 
76
- return file
76
+ file
77
77
  end
78
78
 
79
79
  def read_index(data)
80
- JSON.parse data, symbolize_names: true
80
+ data.with_indifferent_access
81
81
  end
82
82
  end
83
83
 
@@ -96,7 +96,7 @@ module Writer
96
96
  json[:versions] << obj
97
97
  end
98
98
 
99
- return JSON.pretty_generate json
99
+ json
100
100
  end
101
101
 
102
102
  def write_resource(side, resource, out)
@@ -134,25 +134,26 @@ module Writer
134
134
  formatVersion: 0,
135
135
  uid: version.uid,
136
136
  version: version.version,
137
- time: version.time
137
+ time: version.time.to_s,
138
+ type: version.type,
139
+ data: [],
140
+ requires: []
138
141
  }
139
- json[:type] = version.type if version.type and version.type != ''
140
142
  json[:requires] = version.requires.map do |req|
141
143
  obj = { uid: req.uid }
142
144
  obj[:version] = req.version if req.version
143
145
  obj
144
146
  end if version.requires and not version.requires.empty?
145
147
 
146
- json[:data] = []
147
148
  write_resource(:client, version.client, json[:data]) if version.is_complete
148
149
  write_resource(:server, version.server, json[:data]) if version.is_complete
149
150
  write_resource(:common, version.common, json[:data]) if version.is_complete
150
151
 
151
- JSON.pretty_generate json
152
+ json
152
153
  end
153
154
 
154
155
  def write_index(index)
155
- JSON.pretty_generate index
156
+ index
156
157
  end
157
158
  end
158
159
 
@@ -1,20 +1,17 @@
1
1
  class Registry
2
2
  def version_index(uid)
3
- if File.exist? VersionIndex.local_filename(uid)
4
- $rw.read_version_index File.read(VersionIndex.local_filename uid)
5
- else
6
- VersionIndex.new uid
7
- end
3
+ return VersionIndex.new uid unless File.exists? VersionIndex.local_filename uid
4
+ $rw.read_version_index JSON.parse File.read(VersionIndex.local_filename uid)
5
+ end
6
+
7
+ def store_version_index(index)
8
+ File.write index.local_filename, JSON.pretty_generate($rw.write_version_index index)
9
+ WonkoTheSane.wonkoweb_uploader.file_changed index.uid
8
10
  end
9
11
 
10
12
  def index
11
- if File.exists? 'files/index.json'
12
- $rw.read_index File.read('files/index.json')
13
- else
14
- {
15
- index: []
16
- }
17
- end
13
+ return { index: [] } unless File.exists? 'files/index.json'
14
+ $rw.read_index JSON.parse File.read 'files/index.json'
18
15
  end
19
16
 
20
17
  def store(version)
@@ -23,34 +20,30 @@ class Registry
23
20
  else
24
21
  BaseSanitizer.sanitize(version, DownloadsFixer).each do |version|
25
22
  Dir.mkdir 'files/' + version.uid unless Dir.exist? 'files/' + version.uid
26
- File.write version.local_filename, $rw.write_version(version)
23
+ File.write version.local_filename, JSON.pretty_generate($rw.write_version version)
24
+ WonkoTheSane.wonkoweb_uploader.version_changed version.uid, version.version
27
25
 
28
26
  vindex = version_index version.uid
29
27
  vindex.add_version version
30
- File.write VersionIndex.local_filename(vindex.uid), $rw.write_version_index(vindex)
28
+ store_version_index vindex
31
29
 
32
30
  ind = index
31
+ next if ind[:index].find { |i| version.uid == i[:uid] } # early exit if the uid already exists in the index
33
32
  ind[:formatVersion] = 0
34
- ind[:index].each do |i|
35
- if version.uid == i[:uid]
36
- return
37
- end
38
- end
39
- ind[:index] << {
40
- uid: version.uid
41
- }
42
- File.write 'files/index.json', $rw.write_index(ind)
33
+ ind[:index] << { uid: version.uid }
34
+ File.write 'files/index.json', JSON.pretty_generate($rw.write_index ind)
43
35
  end
44
36
  end
45
37
  rescue Exception => e
46
38
  Logging.logger[version.uid].error 'Unable to store: ' + version.version
47
39
  raise e
48
40
  end
41
+
49
42
  def retrieve(id, version)
50
43
  if File.exist? WonkoVersion.local_filename(id, version)
51
- return $rw.read_version File.read(WonkoVersion.local_filename id, version)
44
+ $rw.read_version JSON.parse File.read(WonkoVersion.local_filename id, version)
52
45
  else
53
- return nil
46
+ nil
54
47
  end
55
48
  end
56
49
 
@@ -0,0 +1,17 @@
1
+ module Util
2
+ def self.deep_map_keys(val, &block)
3
+ Util.deep_map_hash val do |k, v|
4
+ [yield(k), v]
5
+ end
6
+ end
7
+
8
+ def self.deep_map(val, &block)
9
+ if val.is_a? Array
10
+ val.map { |item| deep_map_hash item, &block }
11
+ elsif val.is_a? Hash
12
+ Hash[val.map { |k, v| yield k, deep_map_hash(v, &block) }]
13
+ else
14
+ yield nil, val
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'benchmark'
2
+
3
+ module WonkoTheSane
4
+ module Util
5
+ class Benchmark
6
+ def initialize
7
+ @timers = {}
8
+ @calls = {}
9
+ end
10
+
11
+ def benchmark(id, &block)
12
+ @timers[id.to_s] ||= ::Benchmark::Tms.new(0, 0, 0, 0, 0, id.to_s)
13
+ @calls[id.to_s] ||= 0
14
+ @calls[id.to_s] += 1
15
+ ret = nil
16
+ @timers[id.to_s].add! { ret = yield }
17
+ ret
18
+ end
19
+
20
+ def print_times(reset = false)
21
+ @timers.each do |id, timer|
22
+ puts "#{timer.label}: #{timer.real.round 2}s total, #{(timer.real / @calls[id]).round 2}s/call"
23
+ end
24
+ @timers = {} if reset
25
+ @calls = {} if reset
26
+ end
27
+ end
28
+ end
29
+ end
@@ -18,7 +18,7 @@ module WonkoTheSane
18
18
  end
19
19
  end
20
20
 
21
- def register_lists_from(file)
21
+ def register_lists_from_sources
22
22
  sources = WonkoTheSane.data_json 'sources.json'
23
23
  sources[:forgefiles].each do |uid, urlId|
24
24
  register_list ForgeFilesModsList.new(uid.to_s, urlId)
@@ -4,13 +4,14 @@ require 'wonko_the_sane/util/http_cache'
4
4
  module WonkoTheSane
5
5
  module Util
6
6
  class DeepStorageCache
7
- def initialize(manifest_file)
8
- lines = File.read('.aws-credentials').split "\n"
9
- @resource = Aws::S3::Resource.new region: 'eu-west-1', credentials: Aws::Credentials.new(lines[0], lines[1])
7
+ def initialize
8
+ @resource = Aws::S3::Resource.new region: 'eu-west-1',
9
+ credentials: Aws::Credentials.new(Settings[:aws][:client_id],
10
+ Settings[:aws][:client_secret])
10
11
  @bucket = @resource.bucket 'wonkoweb-02jandal-xyz'
11
12
 
12
13
  @manifest = @bucket.object 'manifest.json'
13
- @entries = @manifest.exists? ? JSON.parse(@manifest.get.body, symbolize_keys: true) : {}
14
+ @entries = @manifest.exists? ? JSON.parse(@manifest.get.body.read, symbolize_keys: true) : {}
14
15
  end
15
16
 
16
17
  def get_info(url, options = {})
@@ -19,7 +20,7 @@ module WonkoTheSane
19
20
  ctxt = options[:ctxt] || 'DeepStorageCache'
20
21
 
21
22
  file = HTTPCache.file url, check_stale: false, ctxt: options[:ctxt]
22
- info = info_for_file file, url
23
+ info = self.class.info_for_file file, url
23
24
 
24
25
  @entries[url] = info
25
26
  @manifest.put body: JSON.pretty_generate(@entries)
@@ -31,8 +32,18 @@ module WonkoTheSane
31
32
  # http://anthonylewis.com/2011/02/09/to-hex-and-back-with-ruby/
32
33
  md5 = [info[:md5].scan(/../).map { |x| x.hex.chr }.join].pack 'm0'
33
34
 
35
+ content_type = case url
36
+ when /\.zip$/, /\.jar$/
37
+ 'application/zip'
38
+ else
39
+ ''
40
+ end
41
+
34
42
  Logging.logger[ctxt].debug "Uploading backup of #{url} to S3..."
35
- object.put body: file, content_md5: md5, metadata: Hash[info.map { |k,v| [k.to_s, v.to_s]}]
43
+ object.put body: file,
44
+ content_md5: md5,
45
+ content_type: content_type,
46
+ metadata: Hash[info.map { |k,v| [k.to_s, v.to_s]}]
36
47
  Logging.logger[ctxt].debug 'Backup successfully uploaded to S3'
37
48
  end
38
49
  end
@@ -41,8 +52,8 @@ module WonkoTheSane
41
52
  end
42
53
 
43
54
  def self.get_info(url, options = {})
44
- if File.exists? '.aws-credentials'
45
- @@instance ||= DeepStorageCache.new 'cache/deep_storage.json'
55
+ if Settings[:aws][:client_id]
56
+ @@instance ||= DeepStorageCache.new
46
57
  @@instance.get_info url, options
47
58
  else
48
59
  info_for_file HTTPCache.file(url, check_stale: false, ctxt: options[:ctxt]), url
@@ -51,7 +62,7 @@ module WonkoTheSane
51
62
 
52
63
  private
53
64
 
54
- def info_for_file(file, url)
65
+ def self.info_for_file(file, url)
55
66
  {
56
67
  url: url,
57
68
  file: url.gsub(/[&:$@=+,?\\^`><\{\}\[\]#%'"~|]/, '_'),
@@ -16,7 +16,7 @@ class HTTPCache
16
16
 
17
17
  def file(ctxt, url, key, check_stale = true)
18
18
  fetch ctxt, url, key, check_stale
19
- File.new @basedir + '/' + key, 'r'
19
+ File.open @basedir + '/' + key, 'r'
20
20
  end
21
21
 
22
22
  private
@@ -1,3 +1,3 @@
1
1
  module WonkoTheSane
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -14,19 +14,25 @@ class VersionIndex
14
14
  @versions << version
15
15
  end
16
16
  end
17
+
17
18
  def remove_version(version)
18
19
  @versions.select! do |ver|
19
20
  version.version != ver.version
20
21
  end
21
22
  end
23
+
22
24
  def self.get_full_version(version)
23
25
  if File.exist? version.local_filename
24
- Reader.read_version File.read(version.local_filename)
26
+ Reader.read_version JSON.parse File.read(version.local_filename)
25
27
  else
26
28
  nil
27
29
  end
28
30
  end
29
31
 
32
+ def local_filename
33
+ VersionIndex.local_filename @uid
34
+ end
35
+
30
36
  def self.local_filename(uid)
31
37
  'files/' + uid + '.json'
32
38
  end
@@ -18,38 +18,36 @@ class BaseVersionList
18
18
 
19
19
  def refresh
20
20
  @lastError = nil
21
- begin
22
- versions = get_versions
21
+ versions = get_versions
23
22
 
24
- # check if some versions aren't in @processed (likely new ones) and fetch and process them
25
- versions.each do |version|
26
- begin
27
- next if not version
28
- id = version.is_a?(Array) ? version.first : version
29
- unless @processed.include? id
30
- files = get_version version
31
- next if files.nil? or (files.is_a? Array and files.empty?)
23
+ # check if some versions aren't in @processed (likely new ones) and fetch and process them
24
+ versions.each do |version|
25
+ begin
26
+ next if not version
27
+ id = version.is_a?(Array) ? version.first : version
28
+ unless @processed.include? id
29
+ files = get_version version
30
+ next if files.nil? or (files.is_a? Array and files.empty?)
32
31
 
33
- files.flatten.each do |file|
34
- file.is_complete = true
35
- Registry.instance.store file
36
- end if files and files.is_a? Array
37
- files.is_complete = true if files and files.is_a? WonkoVersion
38
- Registry.instance.store files if files and files.is_a? WonkoVersion
32
+ files.flatten.each do |file|
33
+ file.is_complete = true
34
+ Registry.instance.store file
35
+ end if files and files.is_a? Array
36
+ files.is_complete = true if files and files.is_a? WonkoVersion
37
+ Registry.instance.store files if files and files.is_a? WonkoVersion
39
38
 
40
- @processed << id
41
- write_cache_file
42
- end
43
- rescue => e
44
- logger.error e.message
45
- logger.warn e.backtrace.first
46
- binding.pry if $stdout.isatty && ENV['DEBUG_ON_ERROR']
47
- @lastError = e.message
39
+ @processed << id
40
+ write_cache_file
48
41
  end
49
42
  end
50
-
51
- FileUtils.touch cache_file
52
43
  end
44
+
45
+ FileUtils.touch cache_file
46
+ rescue => e
47
+ logger.error e.message
48
+ logger.warn e.backtrace.first
49
+ binding.pry if $stdout.isatty && ENV['DEBUG_ON_ERROR']
50
+ @lastError = e.message
53
51
  end
54
52
 
55
53
  def logger
@@ -93,11 +91,11 @@ class BaseVersionList
93
91
  end
94
92
 
95
93
  def get_json(url)
96
- JSON.parse HTTPCache.file(url, ctxt: @artifact, check_stale: true), symbolize_names: true
94
+ Yajl::Parser.parse HTTPCache.file(url, ctxt: @artifact, check_stale: true), symbolize_keys: true
97
95
  end
98
96
 
99
97
  def get_json_cached(url)
100
- JSON.parse HTTPCache.file(url, ctxt: @artifact, check_stale: false), symbolize_names: true
98
+ Yajl::Parser.parse HTTPCache.file(url, ctxt: @artifact, check_stale: false), symbolize_keys: true
101
99
  end
102
100
  end
103
101
  Dir.mkdir 'cache' unless Dir.exist? 'cache'
@@ -1,7 +1,3 @@
1
- require_relative 'base_version_list'
2
- require 'date'
3
- require 'time'
4
-
5
1
  class CurseVersionList < BaseVersionList
6
2
  def initialize(uid, curseId, fileRegex)
7
3
  super(uid)
@@ -95,7 +95,7 @@ class VersionLibrary < Download
95
95
  @mavenBaseUrl = json[:mavenBaseUrl]
96
96
 
97
97
  # if the absolute url is equal to the expected maven url we clear the absolute url
98
- if @url == url
98
+ if @mavenBaseUrl && @url == url
99
99
  @url = nil
100
100
  end
101
101
  end
@@ -134,7 +134,7 @@ class WonkoVersion
134
134
  attr_accessor :type
135
135
  attr_accessor :is_complete
136
136
 
137
- attr_accessor :requires # list of Referenced
137
+ attr_accessor :requires # [Referenced]
138
138
 
139
139
  class Resources
140
140
  attr_accessor :traits
@@ -0,0 +1,162 @@
1
+ module WonkoTheSane
2
+ class WonkoWeb
3
+ include HTTParty
4
+
5
+ class UploadError < ResponseError
6
+ attr_reader :errors
7
+
8
+ def initialize(errors)
9
+ @errors = errors
10
+ end
11
+ end
12
+
13
+ def initialize(benchmark)
14
+ self.class.base_uri Settings[:wonkoweb][:host]
15
+ self.class.headers 'X-Uploader-Name' => Settings[:wonkoweb][:name],
16
+ 'X-Uploader-Token' => Settings[:wonkoweb][:token],
17
+ 'X-WUR-Enabled' => 'true',
18
+ 'Content-Type' => 'application/json'
19
+
20
+ @benchmark = benchmark
21
+ end
22
+
23
+ def index
24
+ self.class.get(path 'index').with_indifferent_access
25
+ end
26
+
27
+ def file(uid)
28
+ self.class.get(path uid).with_indifferent_access
29
+ end
30
+
31
+ def version(uid, version)
32
+ self.class.get(path uid, version).with_indifferent_access
33
+ end
34
+
35
+ def upload_file(data)
36
+ return if data.nil?
37
+ uid = data[:uid]
38
+ theirs = @benchmark.benchmark('upload_file.theirs') { file uid rescue nil }
39
+
40
+ data.delete :versions # only stubs here
41
+ data[:name] ||= data[:uid]
42
+
43
+ upload_hash path, path(uid), data, theirs, false
44
+ end
45
+
46
+ def upload_version(data)
47
+ return if data.nil?
48
+ uid = data[:uid]
49
+ version = data[:version]
50
+ theirs = @benchmark.benchmark('upload_version.theirs') { version uid, version rescue nil }
51
+ upload_hash path(uid), path(uid, version), data, theirs, true
52
+ end
53
+
54
+ private
55
+
56
+ def upload_hash(create_path, update_path, ours, theirs, allow_overwrite)
57
+ caller = ours[:version] ? 'upload_version' : 'upload_file'
58
+ res = if theirs.nil? || (theirs[:errors] && theirs[:errors].size > 0)
59
+ # upload entire file
60
+ @benchmark.benchmark(caller + '.create') { self.class.post create_path, body: JSON.generate(ours) }
61
+ else
62
+ # upload changes
63
+
64
+ body = JSON.parse JSON.generate ours # round-trip to "normalize" things
65
+ # keep_if modifies in-place (why isn't it named keep_if! ????????)
66
+ body.keep_if { |k, v| !(theirs[k.to_sym] == v) }
67
+ body.keep_if { |k, v| theirs[k.to_sym].nil? || theirs[k.to_sym].to_s.empty? } unless allow_overwrite
68
+ @benchmark.benchmark(caller + '.update') { self.class.patch update_path, body: JSON.generate(body) } unless body.empty?
69
+ end
70
+
71
+ if !res.nil? && (res.code >= 300 || JSON.parse(res.body).key?('errors'))
72
+ binding.pry
73
+ fail UploadError.new res.body[:errors]
74
+ end
75
+ end
76
+
77
+ def path(*args)
78
+ return '/api/v1.json' if args.nil? || args.empty?
79
+ '/api/v1/' + args.map(&:to_s).join('/') + '.json'
80
+ end
81
+ end
82
+
83
+ class WonkoWebUploader
84
+ def initialize
85
+ data = JSON.parse File.read 'uploader_queue.json' if File.exists? 'uploader_queue.json'
86
+ data ||= {}
87
+ data = data.with_indifferent_access
88
+ @changed_files = data[:files] || []
89
+ @changed_versions = data[:versions] || {}
90
+
91
+ @benchmark = WonkoTheSane::Util::Benchmark.new
92
+ @client = WonkoWeb.new @benchmark
93
+ end
94
+
95
+ def file_changed(uid)
96
+ @changed_files << uid
97
+ save_changes!
98
+ end
99
+
100
+ def version_changed(uid, version)
101
+ @changed_versions[uid] ||= []
102
+ @changed_versions[uid] << version
103
+ save_changes!
104
+ end
105
+
106
+ def upload_changes!
107
+ @changed_files.uniq!
108
+ return if Settings[:wonkoweb][:host].nil?
109
+
110
+ existing_uids = @benchmark.benchmark('initial index') { @client.index }[:index].map { |obj| obj[:uid] }
111
+ logger.info "Uploading #{@changed_files.size} changed files to WonkoWeb at #{Settings[:wonkoweb][:host]}..."
112
+ @changed_files.dup.each do |uid|
113
+ begin
114
+ @client.upload_file $rw.write_version_index Registry.instance.version_index uid
115
+ existing_uids << uid
116
+ @changed_files.delete uid
117
+ rescue => e
118
+ logger.error "Unable to upload file for #{uid} to WonkoWeb: #{e.message}"
119
+ logger.warn e.backtrace.first
120
+ binding.pry if $stdout.isatty && ENV['DEBUG_ON_ERROR']
121
+ end
122
+ end
123
+ logger.info 'Done.'
124
+ @benchmark.print_times true
125
+
126
+ num_versions = @changed_versions.collect { |k, v| v.size }.inject :+
127
+ logger.info "Uploading #{num_versions} changed versions to WonkoWeb at #{Settings[:wonkoweb][:host]}..."
128
+ @changed_versions.dup.each do |uid, versions|
129
+ versions.dup.each do |version|
130
+ begin
131
+ @client.upload_file $rw.write_version_index Registry.instance.version_index uid unless existing_uids.include? uid
132
+ @client.upload_version $rw.write_version Registry.instance.retrieve uid, version
133
+ versions.delete version
134
+ rescue => e
135
+ logger.error "Unable to upload version #{version} of #{uid} to WonkoWeb: #{e.message}"
136
+ logger.warn e.backtrace.first
137
+ binding.pry if $stdout.isatty && ENV['DEBUG_ON_ERROR']
138
+ end
139
+ @changed_versions.delete uid if versions.empty?
140
+ end
141
+ end
142
+ logger.info 'Done.'
143
+ @benchmark.print_times true
144
+
145
+ save_changes!
146
+ end
147
+
148
+ private
149
+
150
+ def logger
151
+ Logging.logger[self]
152
+ end
153
+
154
+ def save_changes!
155
+ data = {
156
+ files: @changed_files,
157
+ versions: @changed_versions
158
+ }
159
+ File.write 'uploader_queue.json', JSON.pretty_generate(data)
160
+ end
161
+ end
162
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wonko_the_sane
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - 02JanDal
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-05-17 00:00:00.000000000 Z
13
+ date: 2015-05-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -250,6 +250,48 @@ dependencies:
250
250
  - - ">="
251
251
  - !ruby/object:Gem::Version
252
252
  version: '0'
253
+ - !ruby/object:Gem::Dependency
254
+ name: configliere
255
+ requirement: !ruby/object:Gem::Requirement
256
+ requirements:
257
+ - - ">="
258
+ - !ruby/object:Gem::Version
259
+ version: '0'
260
+ type: :runtime
261
+ prerelease: false
262
+ version_requirements: !ruby/object:Gem::Requirement
263
+ requirements:
264
+ - - ">="
265
+ - !ruby/object:Gem::Version
266
+ version: '0'
267
+ - !ruby/object:Gem::Dependency
268
+ name: httparty
269
+ requirement: !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - ">="
272
+ - !ruby/object:Gem::Version
273
+ version: '0'
274
+ type: :runtime
275
+ prerelease: false
276
+ version_requirements: !ruby/object:Gem::Requirement
277
+ requirements:
278
+ - - ">="
279
+ - !ruby/object:Gem::Version
280
+ version: '0'
281
+ - !ruby/object:Gem::Dependency
282
+ name: activesupport
283
+ requirement: !ruby/object:Gem::Requirement
284
+ requirements:
285
+ - - ">="
286
+ - !ruby/object:Gem::Version
287
+ version: '0'
288
+ type: :runtime
289
+ prerelease: false
290
+ version_requirements: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - ">="
293
+ - !ruby/object:Gem::Version
294
+ version: '0'
253
295
  description:
254
296
  email:
255
297
  - jan@dalheimer.de
@@ -276,6 +318,8 @@ files:
276
318
  - lib/wonko_the_sane/rules.rb
277
319
  - lib/wonko_the_sane/timestamps.rb
278
320
  - lib/wonko_the_sane/tools/update_nem.rb
321
+ - lib/wonko_the_sane/util.rb
322
+ - lib/wonko_the_sane/util/benchmark.rb
279
323
  - lib/wonko_the_sane/util/configuration.rb
280
324
  - lib/wonko_the_sane/util/deep_storage_cache.rb
281
325
  - lib/wonko_the_sane/util/extraction_cache.rb
@@ -295,6 +339,7 @@ files:
295
339
  - lib/wonko_the_sane/versionlists/vanilla_legacy_version_list.rb
296
340
  - lib/wonko_the_sane/versionlists/vanilla_version_list.rb
297
341
  - lib/wonko_the_sane/wonko_version.rb
342
+ - lib/wonko_the_sane/wonkoweb_uploader.rb
298
343
  homepage: https://github.com/MultiMC/WonkoTheSane
299
344
  licenses:
300
345
  - MIT
@@ -321,4 +366,3 @@ specification_version: 4
321
366
  summary: Pre-processing and format-unification of various resources mainly related
322
367
  to Minecraft
323
368
  test_files: []
324
- has_rdoc: