lapis-minecraft-versioning 0.5.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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +18 -0
  3. data/.gitignore +151 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +1156 -0
  6. data/.travis.yml +4 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.md +16 -0
  9. data/README.md +83 -0
  10. data/Rakefile +28 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +7 -0
  13. data/lapis-minecraft-versioning.gemspec +35 -0
  14. data/lib/lapis/minecraft/version.rb +89 -0
  15. data/lib/lapis/minecraft/versioning.rb +26 -0
  16. data/lib/lapis/minecraft/versioning/asset.rb +44 -0
  17. data/lib/lapis/minecraft/versioning/asset_index.rb +61 -0
  18. data/lib/lapis/minecraft/versioning/basic.rb +56 -0
  19. data/lib/lapis/minecraft/versioning/detailed.rb +69 -0
  20. data/lib/lapis/minecraft/versioning/launcher_properties.rb +48 -0
  21. data/lib/lapis/minecraft/versioning/library.rb +51 -0
  22. data/lib/lapis/minecraft/versioning/manifest.rb +49 -0
  23. data/lib/lapis/minecraft/versioning/marshalling.rb +15 -0
  24. data/lib/lapis/minecraft/versioning/marshalling/asset_index_parser.rb +41 -0
  25. data/lib/lapis/minecraft/versioning/marshalling/manifest_parser.rb +66 -0
  26. data/lib/lapis/minecraft/versioning/marshalling/version_parser.rb +204 -0
  27. data/lib/lapis/minecraft/versioning/meta_server.rb +52 -0
  28. data/lib/lapis/minecraft/versioning/os_rule.rb +45 -0
  29. data/lib/lapis/minecraft/versioning/resource.rb +44 -0
  30. data/lib/lapis/minecraft/versioning/resource_set.rb +61 -0
  31. data/lib/lapis/minecraft/versioning/rule.rb +32 -0
  32. data/lib/lapis/minecraft/versioning/version.rb +7 -0
  33. data/lib/lapis/minecraft/versioning/version_list.rb +64 -0
  34. data/spec/factories/asset_factory.rb +11 -0
  35. data/spec/factories/asset_index_document_factory.rb +25 -0
  36. data/spec/factories/asset_index_factory.rb +15 -0
  37. data/spec/factories/basic_factory.rb +28 -0
  38. data/spec/factories/detailed_factory.rb +16 -0
  39. data/spec/factories/launcher_properties_factory.rb +11 -0
  40. data/spec/factories/library_factory.rb +21 -0
  41. data/spec/factories/manifest_document_factory.rb +48 -0
  42. data/spec/factories/manifest_factory.rb +12 -0
  43. data/spec/factories/meta_server_mock_factory.rb +33 -0
  44. data/spec/factories/os_rule_factory.rb +30 -0
  45. data/spec/factories/resource_factory.rb +32 -0
  46. data/spec/factories/resource_set_factory.rb +16 -0
  47. data/spec/factories/rule_factory.rb +17 -0
  48. data/spec/factories/version_document_factory.rb +176 -0
  49. data/spec/factories/version_factory.rb +18 -0
  50. data/spec/lapis/minecraft/version_spec.rb +181 -0
  51. data/spec/lapis/minecraft/versioning/asset_index_spec.rb +89 -0
  52. data/spec/lapis/minecraft/versioning/asset_spec.rb +65 -0
  53. data/spec/lapis/minecraft/versioning/basic_spec.rb +75 -0
  54. data/spec/lapis/minecraft/versioning/detailed_spec.rb +175 -0
  55. data/spec/lapis/minecraft/versioning/launcher_properties_spec.rb +73 -0
  56. data/spec/lapis/minecraft/versioning/library_spec.rb +91 -0
  57. data/spec/lapis/minecraft/versioning/manifest_spec.rb +71 -0
  58. data/spec/lapis/minecraft/versioning/marshalling/asset_index_parser_spec.rb +27 -0
  59. data/spec/lapis/minecraft/versioning/marshalling/manifest_parser_spec.rb +74 -0
  60. data/spec/lapis/minecraft/versioning/marshalling/version_parser_spec.rb +101 -0
  61. data/spec/lapis/minecraft/versioning/meta_server_spec.rb +59 -0
  62. data/spec/lapis/minecraft/versioning/os_rule_spec.rb +73 -0
  63. data/spec/lapis/minecraft/versioning/resource_set_spec.rb +87 -0
  64. data/spec/lapis/minecraft/versioning/resource_spec.rb +55 -0
  65. data/spec/lapis/minecraft/versioning/rule_spec.rb +36 -0
  66. data/spec/lapis/minecraft/versioning/version_list_spec.rb +66 -0
  67. data/spec/spec_helper.rb +90 -0
  68. data/spec/time_helper.rb +39 -0
  69. metadata +289 -0
@@ -0,0 +1,52 @@
1
+ require_relative 'marshalling'
2
+
3
+ module Lapis
4
+ module Minecraft
5
+ module Versioning
6
+
7
+ # Provides functionality for translating version information from a meta-data server.
8
+ # A meta-data server is a server that responds to requests about Minecraft versions.
9
+ # @todo Add more checks to response data.
10
+ class MetaServer
11
+
12
+ # Creates a reference to a Minecraft meta-data server.
13
+ # @param client [HTTPClient] Client used to connect to the meta-data server.
14
+ def initialize(client)
15
+ @client = client
16
+ @manifest_parser = Marshalling::ManifestParser.new
17
+ @version_parser = Marshalling::VersionParser.new
18
+ @asset_index_parser = Marshalling::AssetIndexParser.new
19
+ end
20
+
21
+ # Retrieves the manifest from the meta-data server.
22
+ # @param url [String] URL of the version manifest.
23
+ # @return [Manifest] Information about all Minecraft versions.
24
+ def get_manifest(url)
25
+ response = @client.get(url)
26
+ fail "Failed to retrieve manifest - #{response.status} (#{response.reason})" if response.status != 200
27
+ @manifest_parser.parse(response.content)
28
+ end
29
+
30
+ # Retrieves additional information about a Minecraft version.
31
+ # @param url [String] URL of the version document.
32
+ # @return [Detailed] Minecraft version information.
33
+ def get_details(url)
34
+ response = @client.get(url)
35
+ fail "Failed to retrieve version - #{response.status} (#{response.reason})" if response.status != 200
36
+ @version_parser.parse(response.content, url)
37
+ end
38
+
39
+ # Retrieves a listing of assets for a Minecraft version.
40
+ # @param url [String] URL of the asset index document.
41
+ # @return [Array<Asset>] List of assets in the index.
42
+ def get_assets(url)
43
+ response = @client.get(url)
44
+ fail "Failed to retrieve assets - #{response.status} (#{response.reason})" if response.status != 200
45
+ @asset_index_parser.parse(response.content)
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'rule'
2
+
3
+ module Lapis
4
+ module Minecraft
5
+ module Versioning
6
+
7
+ # Description of how resources can be chosen for operating systems.
8
+ class OSRule < Rule
9
+
10
+ # Type of operating system this rule applies to.
11
+ # @return [Symbol] Can be one of: +:windows+, +:linux+, or +:osx+.
12
+ attr_reader :os_type
13
+
14
+ # Operating system version regex.
15
+ # This rule should apply if the OS version matches this regex.
16
+ # @return [Regexp]
17
+ attr_reader :os_version
18
+
19
+ # Creates an OS rule.
20
+ # @param is_allowed [Boolean] Indicates whether the resource should be included.
21
+ # @param os_type [Symbol] Type of OS this rule applies to.
22
+ # Can be one of: +:windows+, +:linux+, or +:osx+.
23
+ # @param os_version [String, nil] OS version regex.
24
+ # Can be +nil+ to apply to all versions of the OS.
25
+ def initialize(is_allowed, os_type, os_version = nil)
26
+ super(is_allowed)
27
+ @os_type = os_type
28
+ @os_version = os_version ? Regexp.new(os_version) : // # Use empty regex if no version specified.
29
+ end
30
+
31
+ # Compares one rule to another.
32
+ # @param other [OSRule] Rule to compare against.
33
+ # @return [true] The rules are the same.
34
+ # @return [false] The rules are different.
35
+ def ==(other)
36
+ super(other) &&
37
+ other.os_type == @os_type &&
38
+ other.os_version == @os_version
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'asset'
2
+
3
+ module Lapis
4
+ module Minecraft
5
+ module Versioning
6
+
7
+ # Information about a resource (file) to download as part of the client or server.
8
+ class Resource < Asset
9
+
10
+ # URL where the resource can be found and downloaded from.
11
+ # @return [String] Download URL.
12
+ attr_reader :url
13
+
14
+ # Logical category the resource falls under.
15
+ # @return [String, nil] Name of the category or +nil+ if the resource doesn't have one.
16
+ attr_reader :classifier
17
+
18
+ # Creates information about a resource.
19
+ # @param url [String] URL where the resource can be found and downloaded from.
20
+ # @param size [Fixnum] Size of the resource in bytes.
21
+ # @param sha1 [String] SHA1 hash of the resource's contents in hexadecimal.
22
+ # @param path [String, nil] Path, relative to the installation directory, to store the resource.
23
+ # @param classifier [String, nil] Logical category the resource falls under.
24
+ def initialize(url, size, sha1, path = nil, classifier = nil)
25
+ super(size, sha1, path)
26
+ @url = url.dup.freeze
27
+ @classifier = classifier.dup.freeze
28
+ end
29
+
30
+ # Compares one resource to another.
31
+ # @param other [Resource] Resource to compare against.
32
+ # @return [true] The resources are the same.
33
+ # @return [false] The resources are different.
34
+ def ==(other)
35
+ super(other) &&
36
+ other.url == @url &&
37
+ other.classifier == @classifier
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ module Lapis
2
+ module Minecraft
3
+ module Versioning
4
+
5
+ # Information about the archives and natives needed for a library.
6
+ # @see Resource
7
+ class ResourceSet
8
+
9
+ # Classifier for the Windows native.
10
+ # @return [String] Classifier for Windows.
11
+ # @return [nil] No Windows native for this library.
12
+ # @note This value can contain variables.
13
+ attr_reader :windows_classifier
14
+
15
+ # Classifier for the Linux native.
16
+ # @return [String] Classifier for Linux.
17
+ # @return [nil] No Linux native for this library.
18
+ # @note This value can contain variables.
19
+ attr_reader :linux_classifier
20
+
21
+ # Classifier for the OSX native.
22
+ # @return [String] Classifier for OSX.
23
+ # @return [nil] No OSX native for this library.
24
+ # @note This value can contain variables.
25
+ attr_reader :osx_classifier
26
+
27
+ # List of all resources (including natives) the library uses.
28
+ # @return [Array<Resource>]
29
+ attr_reader :resources
30
+
31
+ # Creates a new resource set.
32
+ # @param resources [Array<Resource>] List of all resources (including natives).
33
+ # @param windows_classifier [String, nil] Classifier for the Windows native.
34
+ # Specify +nil+ if there is no native for Windows.
35
+ # @param linux_classifier [String, nil] Classifier for the Linux native.
36
+ # Specify +nil+ if there is no native for Linux.
37
+ # @param osx_classifier [String, nil] Classifier for the OSX native.
38
+ # Specify +nil+ if there is no native for OSX.
39
+ def initialize(resources, windows_classifier = nil, linux_classifier = nil, osx_classifier = nil)
40
+ @windows_classifier = windows_classifier ? windows_classifier.dup.freeze : nil
41
+ @linux_classifier = linux_classifier ? linux_classifier.dup.freeze : nil
42
+ @osx_classifier = osx_classifier ? osx_classifier.dup.freeze : nil
43
+ @resources = resources.dup.freeze
44
+ end
45
+
46
+ # Compares one resource set to another.
47
+ # @param other [ResourceSet] Resource set to compare against.
48
+ # @return [true] The resource sets are the same.
49
+ # @return [false] The resource sets are different.
50
+ def ==(other)
51
+ other.windows_classifier == @windows_classifier &&
52
+ other.linux_classifier == @linux_classifier &&
53
+ other.osx_classifier == @osx_classifier &&
54
+ other.resources == @resources
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,32 @@
1
+ module Lapis
2
+ module Minecraft
3
+ module Versioning
4
+
5
+ # Description of how resources can be chosen.
6
+ class Rule
7
+
8
+ # @!attribute [r] allowed?
9
+ # Indicates whether the resource should be included.
10
+ def allowed?
11
+ @is_allowed
12
+ end
13
+
14
+ # Creates a basic rule.
15
+ # @param is_allowed [Boolean] Indicates whether the resource should be included.
16
+ def initialize(is_allowed)
17
+ @is_allowed = !!is_allowed
18
+ end
19
+
20
+ # Compares one rule to another.
21
+ # @param other [Rule] Rule to compare against.
22
+ # @return [true] The rules are the same.
23
+ # @return [false] The rules are different.
24
+ def ==(other)
25
+ other.allowed? == @is_allowed
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module Lapis
2
+ module Minecraft
3
+ module Versioning
4
+ VERSION = '0.5.0'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,64 @@
1
+ require 'httpclient'
2
+ require_relative 'meta_server'
3
+ require_relative '../version'
4
+
5
+ module Lapis
6
+ module Minecraft
7
+ module Versioning
8
+
9
+ # Complete listing of Minecraft versions and detailed information about them.
10
+ class VersionList
11
+ include Enumerable
12
+
13
+ # URL of the official Mojang Minecraft version list.
14
+ OFFICIAL_MANIFEST_URL = 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
15
+
16
+ # Singleton for retrieving information about official Minecraft versions.
17
+ # @return [VersionList] Access to official version information.
18
+ def self.official
19
+ @official ||= new(OFFICIAL_MANIFEST_URL)
20
+ end
21
+
22
+ # Creates a version list.
23
+ # @param manifest_url [String] URL of the document listing all versions.
24
+ def initialize(manifest_url)
25
+ @manifest_url = manifest_url.dup.freeze
26
+ @meta_server = MetaServer.new(HTTPClient.new)
27
+ end
28
+
29
+ # Iterates over all versions.
30
+ # @yieldparam version [Version] Next version in the list.
31
+ # @return [void]
32
+ def each
33
+ return enum_for(:each) unless block_given?
34
+
35
+ manifest.each do |basic|
36
+ yield Version.new(basic, @meta_server)
37
+ end
38
+ end
39
+
40
+ # Retrieves the latest released version.
41
+ # @return [Version] Version information.
42
+ def latest_release
43
+ Version.new(manifest.latest_release, @meta_server)
44
+ end
45
+
46
+ # Information about the latest snapshot version.
47
+ # @return [Version] Version information.
48
+ def latest_snapshot
49
+ Version.new(manifest.latest_snapshot, @meta_server)
50
+ end
51
+
52
+ private
53
+
54
+ # Retrieves and caches the manifest data.
55
+ # @return [Manifest]
56
+ def manifest
57
+ @manifest ||= @meta_server.get_manifest(@manifest_url)
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :asset, class: Lapis::Minecraft::Versioning::Asset do
3
+ transient do
4
+ sequence(:path) { |n| "foo/bar/baz/asset-#{n}" }
5
+ size { Random.rand(16777216).to_i }
6
+ sha1 { Digest::SHA1.hexdigest path.to_s }
7
+ end
8
+
9
+ initialize_with { new(size, sha1, path) }
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ require 'json'
2
+
3
+ FactoryGirl.define do
4
+ factory :asset_document_entry, class: Array do
5
+ transient do
6
+ asset { build(:asset) }
7
+ end
8
+
9
+ initialize_with { [asset.path, {:hash => asset.sha1, :size => asset.size}] }
10
+ end
11
+
12
+ IndexStruct = Struct.new(:assets, :document)
13
+
14
+ factory :asset_index_document, class: IndexStruct do
15
+ transient do
16
+ asset_count 10
17
+ assets { build_list(:asset, asset_count) }
18
+ asset_list { assets.map { |asset| build(:asset_document_entry, :asset => asset) } }
19
+ structure { { :objects => Hash[asset_list] } }
20
+ json { structure.to_json }
21
+ end
22
+
23
+ initialize_with { new(asset_list, json) }
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ FactoryGirl.define do
2
+ factory :asset_index, class: Lapis::Minecraft::Versioning::AssetIndex do
3
+ transient do
4
+ sequence(:id) { |n| "Assets-#{n}" }
5
+ asset_count 20
6
+ assets { build_list(:asset, asset_count) }
7
+ size 500
8
+ url { "http://example.com/minecraft/assets/#{id}.json" }
9
+ total_size { assets.lazy.map { |asset| asset.size }.inject(:+) }
10
+ sha1 { Digest::SHA1.hexdigest assets.lazy.map { |asset| asset.path }.inject(:+) }
11
+ end
12
+
13
+ initialize_with { new(id, sha1, size, url, total_size) }
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ FactoryGirl.define do
2
+ factory :basic, class: Lapis::Minecraft::Versioning::Basic do
3
+ transient do
4
+ sequence(:id) { |n| "Version-1.0.#{n}" }
5
+ sequence(:url) { |n| "https://example.com/minecraft/versions/1.0.#{n}.json" }
6
+ type :release
7
+ time { 10.days.ago.round }
8
+ end
9
+
10
+ trait :alpha do
11
+ type :alpha
12
+ end
13
+
14
+ trait :beta do
15
+ type :beta
16
+ end
17
+
18
+ trait :snapshot do
19
+ type :snapshot
20
+ end
21
+
22
+ trait :release do
23
+ type :release
24
+ end
25
+
26
+ initialize_with { new(id, type, time, url) }
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ FactoryGirl.define do
2
+ factory :detailed, parent: :basic, class: Lapis::Minecraft::Versioning::Detailed do
3
+ transient do
4
+ assets { build_list(:asset, 20) }
5
+ asset_index { build(:asset_index, :assets => assets) }
6
+ downloads { [build(:download, :client), build(:download, :server), build(:resource)] }
7
+ libraries { build_list(:library, 5) }
8
+ launcher_properties { build(:launcher) }
9
+ end
10
+
11
+ initialize_with do
12
+ basic = Lapis::Minecraft::Versioning::Basic.new(id, type, time, url)
13
+ new(basic, asset_index, downloads, libraries, launcher_properties)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :launcher, class: Lapis::Minecraft::Versioning::LauncherProperties do
3
+ transient do
4
+ main_class 'com.example.minecraft.client'
5
+ arguments %w(-user ${user} -key ${key})
6
+ minimum_version 7
7
+ end
8
+
9
+ initialize_with { new(main_class, arguments, minimum_version) }
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ FactoryGirl.define do
2
+ factory :library_path, class: String do
3
+ transient do
4
+ sequence(:path) { |n| "exclude-path-#{n}" }
5
+ end
6
+
7
+ initialize_with { path }
8
+ end
9
+
10
+ factory :library, class: Lapis::Minecraft::Versioning::Library do
11
+ transient do
12
+ sequence(:name) { |n| "mc-library-#{n}" }
13
+ exclude_path_count 1
14
+ resources { build(:resource_set) }
15
+ rules { [build(:rule), build(:os_rule)] }
16
+ paths { build_list(:library_path, exclude_path_count) }
17
+ end
18
+
19
+ initialize_with { new(name, resources, rules, paths) }
20
+ end
21
+ end