mmi 0.1.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 +7 -0
- data/README.adoc +91 -0
- data/exe/mmi +43 -0
- data/lib/mmi.rb +44 -0
- data/lib/mmi/assets_processor.rb +41 -0
- data/lib/mmi/interactive.rb +13 -0
- data/lib/mmi/interactive/updater.rb +168 -0
- data/lib/mmi/mod_file_processor.rb +58 -0
- data/lib/mmi/modloader/fabric.rb +98 -0
- data/lib/mmi/modloader/none.rb +11 -0
- data/lib/mmi/source/github.rb +91 -0
- data/lib/mmi/version.rb +3 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 013ded8588d84a0bae1c8220648116e88d5d3953047ccc31b239fd508ce4f4b4
|
4
|
+
data.tar.gz: 8a01d3a0fbada194c797f3b8f7f630853d6c964b7c5c05fbfdf7e51565fa9895
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e7774ec272fbf8cef3887bd3da36cc6f482dee216974996d69f9a2794e3a4a5622a4e8ef0375980073593dcc96f7f6ca0a290db91f43716ed8c6e15f1690f7e6
|
7
|
+
data.tar.gz: d375e06d6174bf417d4938b4136f33d5cacac67ab6c785a6bbf346f1c19b72f24fbeda611ebc7fa101116c662e4fdb812a7332759b765bbebf64dd806e557527
|
data/README.adoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
:toc:
|
2
|
+
:toc-placement!:
|
3
|
+
|
4
|
+
= MMI
|
5
|
+
|
6
|
+
MMI is some Ruby code that should make downloading and installing modloaders, mods, resource packs and other files for Minecraft easier.
|
7
|
+
Configuring the downloads/installs is done by reading a YAML file.
|
8
|
+
|
9
|
+
Ideally, a user would not need to know or write any YAML to create a configuration file.
|
10
|
+
This is still work in progress.
|
11
|
+
|
12
|
+
The application is currently CLI-only, but should work on Linux, MacOS and Windows.
|
13
|
+
|
14
|
+
toc::[]
|
15
|
+
|
16
|
+
= Installation
|
17
|
+
|
18
|
+
== Prerequisites
|
19
|
+
|
20
|
+
To run the application, Ruby version 2.5+ has to be installed.
|
21
|
+
For maximum compatibility, use version 3.0+.
|
22
|
+
|
23
|
+
== Steps
|
24
|
+
|
25
|
+
Clone the repository and navigate into its root directory.
|
26
|
+
|
27
|
+
[source,bash]
|
28
|
+
----
|
29
|
+
$ git clone https://github.com/expeehaa/mmi.git
|
30
|
+
# or
|
31
|
+
$ hg clone https://github.com/expeehaa/mmi.git
|
32
|
+
|
33
|
+
$ cd mmi
|
34
|
+
----
|
35
|
+
|
36
|
+
Install gem dependencies.
|
37
|
+
|
38
|
+
[source,bash]
|
39
|
+
----
|
40
|
+
$ bundle install
|
41
|
+
----
|
42
|
+
|
43
|
+
If you get an error that the lockfile requires `bundler` version 2.0+, install it first.
|
44
|
+
|
45
|
+
[source,bash]
|
46
|
+
----
|
47
|
+
$ gem install bundler
|
48
|
+
----
|
49
|
+
|
50
|
+
= Basic usage
|
51
|
+
|
52
|
+
In the repository root directory, run `exe/mmi`.
|
53
|
+
|
54
|
+
[source,text]
|
55
|
+
----
|
56
|
+
Syntax: exe/mmi <config file> [action=install]
|
57
|
+
|
58
|
+
where action is one of
|
59
|
+
install - Install the modloader and assets as specified in the config file.
|
60
|
+
validate - Validate the config file.
|
61
|
+
update - Update the config file interactively.
|
62
|
+
----
|
63
|
+
|
64
|
+
The script currently does not support any arguments besides the ones listed above.
|
65
|
+
Trying to get help by running `exe/mmi --help` or similar will not work.
|
66
|
+
|
67
|
+
= Example configs
|
68
|
+
|
69
|
+
Example configuration files can be found in `examples/`.
|
70
|
+
They are completely working and download and install files into `tmp/` so that your `.minecraft` folder will stay unharmed.
|
71
|
+
|
72
|
+
|
73
|
+
= TODOs
|
74
|
+
|
75
|
+
* Improve argument parsing.
|
76
|
+
* Write tests.
|
77
|
+
* Add command to interactively create a config file.
|
78
|
+
* Be able to update/change modloader interactively.
|
79
|
+
* Be able to remove assets interactively.
|
80
|
+
* Think about advising everyone to use another file extension than `.yaml` (e.g. `.mmi`, `.mmiconf`).
|
81
|
+
* Try to make a Java-executable `.jar` file using `warbler` and `JRuby`.
|
82
|
+
|
83
|
+
= Contributing
|
84
|
+
|
85
|
+
Contributions are very welcome.
|
86
|
+
If you intend to create a pull request, please choose a branch name describing its changes (i.e. not some generic term like `master` or `fix`, but e.g. `fix_typo` or `add_interactive_update_command`).
|
87
|
+
|
88
|
+
Please be aware that I have a very specific code style and am interested in keeping it in this repository.
|
89
|
+
Some basic rules are specified in the `.editorconfig` file, which your editor should support.
|
90
|
+
Other code style rules may have to be exactly specified in the future.
|
91
|
+
When in doubt, take a look at the existing code.
|
data/exe/mmi
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'psych'
|
5
|
+
|
6
|
+
require 'mmi'
|
7
|
+
require 'mmi/interactive'
|
8
|
+
|
9
|
+
CLI::UI::StdoutRouter.enable
|
10
|
+
|
11
|
+
def processor(file)
|
12
|
+
content = Psych.load_file(file)
|
13
|
+
|
14
|
+
begin
|
15
|
+
Mmi::ModFileProcessor.new(content)
|
16
|
+
rescue Mmi::ValidationError => e
|
17
|
+
puts e
|
18
|
+
Kernel.exit 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if ARGV.length>0
|
23
|
+
file = ARGV.shift
|
24
|
+
action_param = ARGV.shift
|
25
|
+
action = action_param.nil? ? :install : action_param.to_sym
|
26
|
+
|
27
|
+
case action
|
28
|
+
when :install
|
29
|
+
processor(file).install
|
30
|
+
when :validate
|
31
|
+
processor(file)
|
32
|
+
|
33
|
+
puts 'File is valid.'
|
34
|
+
when :update
|
35
|
+
Mmi::Interactive.update(processor(file), file)
|
36
|
+
else
|
37
|
+
STDERR.puts "Unknown action: #{action_param.inspect}."
|
38
|
+
Kernel.exit 1
|
39
|
+
end
|
40
|
+
else
|
41
|
+
puts 'No file given.'
|
42
|
+
Kernel.exit 1
|
43
|
+
end
|
data/lib/mmi.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'semver'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'digest'
|
5
|
+
require 'github_api'
|
6
|
+
|
7
|
+
require 'mmi/version'
|
8
|
+
require 'mmi/mod_file_processor'
|
9
|
+
|
10
|
+
module Mmi
|
11
|
+
MMI_CACHE_DIR = File.join(Dir.home, '.cache', 'mmi')
|
12
|
+
MINECRAFT_DIR = File.join(Dir.home, '.minecraft')
|
13
|
+
|
14
|
+
def self.cache_dir
|
15
|
+
MMI_CACHE_DIR
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.minecraft_dir
|
19
|
+
MINECRAFT_DIR
|
20
|
+
end
|
21
|
+
|
22
|
+
class ValidationError < StandardError; end
|
23
|
+
class MissingAttributeError < ValidationError; end
|
24
|
+
class InvalidAttributeError < ValidationError; end
|
25
|
+
|
26
|
+
def self.debug(text)
|
27
|
+
if ENV['MMI_ENV']=='dev'
|
28
|
+
puts text
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.info(text)
|
33
|
+
puts text
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.warn(text)
|
37
|
+
puts text
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.fail!(text)
|
41
|
+
STDERR.puts text
|
42
|
+
Kernel.exit 1
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mmi/source/github'
|
2
|
+
|
3
|
+
module Mmi
|
4
|
+
class AssetsProcessor
|
5
|
+
attr_reader :profile_dir
|
6
|
+
attr_reader :assets
|
7
|
+
|
8
|
+
def initialize(profile_dir, assets)
|
9
|
+
@profile_dir = profile_dir
|
10
|
+
|
11
|
+
assets ||= []
|
12
|
+
|
13
|
+
if assets.is_a?(Array)
|
14
|
+
@assets = assets.map.with_index do |asset, index|
|
15
|
+
source = asset['source']
|
16
|
+
|
17
|
+
if source
|
18
|
+
type = source['type']
|
19
|
+
|
20
|
+
case type
|
21
|
+
when 'github'
|
22
|
+
Source::Github.new(source)
|
23
|
+
else
|
24
|
+
raise Mmi::InvalidAttributeError, %Q{Invalid "source.type" in asset #{index.inspect}: #{type.inspect}}
|
25
|
+
end
|
26
|
+
else
|
27
|
+
raise Mmi::MissingAttributeError, %Q{Missing "source" in asset #{index.inspect}.}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise Mmi::InvalidAttributeError, %Q{Invalid "assets": expected Array or nothing, got #{self.assets.inspect}.}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def install
|
36
|
+
assets.each do |asset|
|
37
|
+
asset.install(self.profile_dir)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Mmi
|
2
|
+
module Interactive
|
3
|
+
class Updater
|
4
|
+
attr_accessor :processor
|
5
|
+
attr_accessor :file_path
|
6
|
+
|
7
|
+
def initialize(processor, file_path=nil)
|
8
|
+
self.processor = processor
|
9
|
+
self.file_path = file_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def run!
|
13
|
+
while true
|
14
|
+
to_update = CLI::UI::Prompt.ask('What do you want to update?') do |handler|
|
15
|
+
[
|
16
|
+
['assets' , :assets ],
|
17
|
+
['quit & save changes' , :quit_save ],
|
18
|
+
['quit & discard changes', :quit_discard],
|
19
|
+
].each do |name, result|
|
20
|
+
handler.option(name) do |s|
|
21
|
+
result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
case to_update
|
27
|
+
when :assets
|
28
|
+
update_assets
|
29
|
+
when :quit_save
|
30
|
+
file_path = CLI::UI::Prompt.ask('Filename', default: self.file_path, is_file: true)
|
31
|
+
yaml = self.processor.content.to_yaml
|
32
|
+
|
33
|
+
File.write(File.expand_path(file_path, Dir.pwd), yaml)
|
34
|
+
break
|
35
|
+
when :quit_discard
|
36
|
+
break
|
37
|
+
else
|
38
|
+
raise 'Consider yourself lucky, you found a bug.'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_assets
|
44
|
+
while true
|
45
|
+
assets = processor.assets.assets
|
46
|
+
|
47
|
+
choice = CLI::UI::Prompt.ask('Which asset do you want to change?') do |handler|
|
48
|
+
assets.each do |asset|
|
49
|
+
handler.option(asset.display_name) do |s|
|
50
|
+
asset
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
handler.option('add' , &:to_sym)
|
55
|
+
handler.option('quit', &:to_sym)
|
56
|
+
end
|
57
|
+
|
58
|
+
case choice
|
59
|
+
when :quit
|
60
|
+
break
|
61
|
+
when :add
|
62
|
+
add_asset
|
63
|
+
else
|
64
|
+
update_asset(choice)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_asset
|
70
|
+
source_type = CLI::UI::Prompt.ask('Choose a source type.') do |handler|
|
71
|
+
[
|
72
|
+
'github',
|
73
|
+
].each do |type|
|
74
|
+
handler.option(type, &:to_sym)
|
75
|
+
end
|
76
|
+
|
77
|
+
handler.option('quit', &:to_sym)
|
78
|
+
end
|
79
|
+
|
80
|
+
case source_type
|
81
|
+
when :quit
|
82
|
+
false
|
83
|
+
when :github
|
84
|
+
options = {
|
85
|
+
'source' => {
|
86
|
+
'type' => 'github',
|
87
|
+
'asset_id' => 0,
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
options['source']['owner' ] = CLI::UI::Prompt.ask('Who is the owner of the source repository?').strip
|
92
|
+
options['source']['repo' ] = CLI::UI::Prompt.ask('What is the name of the source repository?').strip
|
93
|
+
options['source']['install_dir'] = CLI::UI::Prompt.ask('In which directory should the asset be placed?', default: 'mods').strip
|
94
|
+
options['source']['filename' ] = CLI::UI::Prompt.ask('Under which filename should the asset be saved? (leave empty for release asset name)', allow_empty: true).strip.then do |filename|
|
95
|
+
filename == '' ? nil : filename
|
96
|
+
end
|
97
|
+
|
98
|
+
options['source'].compact!
|
99
|
+
|
100
|
+
source = Mmi::Source::Github.new(options['source'])
|
101
|
+
|
102
|
+
if update_asset(source)
|
103
|
+
self.processor.content['assets'] ||= []
|
104
|
+
|
105
|
+
self.processor.content['assets'].push(options)
|
106
|
+
self.processor.assets.assets.push(source)
|
107
|
+
|
108
|
+
true
|
109
|
+
else
|
110
|
+
CLI::UI.puts('Aborting asset addition. No change will be made.', color: CLI::UI::Color::RED)
|
111
|
+
|
112
|
+
false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def update_asset(asset)
|
118
|
+
case asset
|
119
|
+
when Mmi::Source::Github
|
120
|
+
releases = ::Github::Client::Repos::Releases.new.list(owner: asset.owner, repo: asset.repo, per_page: 100)
|
121
|
+
|
122
|
+
release = CLI::UI::Prompt.ask('Choose a release.') do |handler|
|
123
|
+
releases.select do |release|
|
124
|
+
release.assets.any?
|
125
|
+
end.each do |release|
|
126
|
+
handler.option(release.name) do |s|
|
127
|
+
release
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
handler.option('quit', &:to_sym)
|
132
|
+
end
|
133
|
+
|
134
|
+
case release
|
135
|
+
when :quit
|
136
|
+
false
|
137
|
+
else
|
138
|
+
release_asset = CLI::UI::Prompt.ask('Choose an asset.') do |handler|
|
139
|
+
release.assets.each do |a|
|
140
|
+
handler.option(a.name) do |s|
|
141
|
+
a
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
handler.option('quit', &:to_sym)
|
146
|
+
end
|
147
|
+
|
148
|
+
case release_asset
|
149
|
+
when :quit
|
150
|
+
false
|
151
|
+
else
|
152
|
+
asset.options.delete('release')
|
153
|
+
asset.options.delete('file' )
|
154
|
+
|
155
|
+
asset.options['asset_id'] = release_asset.id
|
156
|
+
|
157
|
+
true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
else
|
161
|
+
CLI::UI.puts('This asset cannot be updated.', color: CLI::UI::Color::RED)
|
162
|
+
|
163
|
+
false
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'mmi/modloader/none'
|
2
|
+
require 'mmi/modloader/fabric'
|
3
|
+
require 'mmi/assets_processor'
|
4
|
+
|
5
|
+
module Mmi
|
6
|
+
class ModFileProcessor
|
7
|
+
attr_reader :content
|
8
|
+
|
9
|
+
attr_reader :version
|
10
|
+
attr_reader :profile_dir
|
11
|
+
|
12
|
+
attr_reader :modloader
|
13
|
+
attr_reader :assets
|
14
|
+
|
15
|
+
def initialize(content)
|
16
|
+
@content = content
|
17
|
+
|
18
|
+
@version = content['version' ]
|
19
|
+
@profile_dir = content['profile_dir'] || Mmi.minecraft_dir
|
20
|
+
|
21
|
+
version = SemVer.parse(self.version)
|
22
|
+
lib_version = SemVer.parse(Mmi::VERSION)
|
23
|
+
|
24
|
+
if self.version
|
25
|
+
if version.major <= lib_version.major
|
26
|
+
if version.minor > lib_version.minor
|
27
|
+
Mmi.warn %Q{Config file specified "version" #{version}, but MMI is at #{lib_version}. Some features might not be supported.}
|
28
|
+
end
|
29
|
+
|
30
|
+
ml = content['modloader']
|
31
|
+
@modloader = if ml
|
32
|
+
case ml['name']
|
33
|
+
when 'none'
|
34
|
+
Modloader::None.new(ml)
|
35
|
+
when 'fabric'
|
36
|
+
Modloader::Fabric.new(ml)
|
37
|
+
else
|
38
|
+
raise Mmi::InvalidAttributeError, %Q{Unkown modloader #{ml['name'].inspect}.}
|
39
|
+
end
|
40
|
+
else
|
41
|
+
Modloader::None.new
|
42
|
+
end
|
43
|
+
|
44
|
+
@assets = AssetsProcessor.new(self.profile_dir, content['assets'])
|
45
|
+
else
|
46
|
+
raise Mmi::InvalidAttributeError, %Q{Config file specified "version" #{version}, but MMI is at #{lib_version}.}
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise Mmi::MissingAttributeError, 'Missing "version".'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def install
|
54
|
+
self.modloader.install
|
55
|
+
self.assets.install
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Mmi
|
2
|
+
module Modloader
|
3
|
+
class Fabric
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
attr_reader :version
|
7
|
+
attr_reader :install_type
|
8
|
+
attr_reader :mcversion
|
9
|
+
attr_reader :install_dir
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@options = options
|
13
|
+
|
14
|
+
@version = options['version' ]
|
15
|
+
@install_type = options['install_type' ]
|
16
|
+
@mcversion = options['minecraft_version']
|
17
|
+
@install_dir = options['install_dir' ] || Mmi.minecraft_dir
|
18
|
+
|
19
|
+
if self.version
|
20
|
+
if self.install_type
|
21
|
+
if ['client', 'server'].include?(self.install_type)
|
22
|
+
if self.mcversion
|
23
|
+
# Pass.
|
24
|
+
else
|
25
|
+
raise Mmi::MissingAttributeError, 'Missing "modloader.minecraft_version".'
|
26
|
+
end
|
27
|
+
else
|
28
|
+
raise Mmi::InvalidAttributeError, %Q{Invalid "modloader.install_type". Expecting "client" or "server", got #{self.install_type.inspect}.}
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise Mmi::MissingAttributeError, 'Missing "modloader.install_type".'
|
32
|
+
end
|
33
|
+
else
|
34
|
+
raise Mmi::MissingAttributeError, 'Missing "modloader.version".'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def installer_uri
|
39
|
+
"https://maven.fabricmc.net/net/fabricmc/fabric-installer/#{self.version}/fabric-installer-#{self.version}.jar"
|
40
|
+
end
|
41
|
+
|
42
|
+
def installer_sha512sum_uri
|
43
|
+
"#{installer_uri}.sha512"
|
44
|
+
end
|
45
|
+
|
46
|
+
def installer_path
|
47
|
+
File.join(Mmi.cache_dir, "fabric-installer-#{self.version}.jar")
|
48
|
+
end
|
49
|
+
|
50
|
+
def absolute_install_dir
|
51
|
+
File.expand_path(self.install_dir)
|
52
|
+
end
|
53
|
+
|
54
|
+
def download_installer
|
55
|
+
Mmi.info "Downloading fabric-installer version #{self.version.inspect}."
|
56
|
+
|
57
|
+
begin
|
58
|
+
FileUtils.mkdir_p(Mmi.cache_dir)
|
59
|
+
|
60
|
+
expected_hexdigest = URI.open(installer_sha512sum_uri).read
|
61
|
+
|
62
|
+
if !File.exists?(installer_path) || expected_hexdigest != Digest::SHA512.hexdigest(File.read(installer_path))
|
63
|
+
stream = URI.open(installer_uri)
|
64
|
+
|
65
|
+
IO.copy_stream(stream, installer_path)
|
66
|
+
|
67
|
+
actual_hexdigest = Digest::SHA512.hexdigest(File.read(installer_path))
|
68
|
+
|
69
|
+
if expected_hexdigest == actual_hexdigest
|
70
|
+
# Pass.
|
71
|
+
else
|
72
|
+
Mmi.fail! "Expected fabric installer to have SHA512 sum #{expected_hexdigest.inspect} but received #{actual_hexdigest.inspect}."
|
73
|
+
end
|
74
|
+
else
|
75
|
+
Mmi.info 'Using cached fabric-installer.'
|
76
|
+
end
|
77
|
+
rescue OpenURI::HTTPError => e
|
78
|
+
Mmi.fail! %Q{Error when requesting fabric installer. Maybe "modloader.version" == #{version.inspect} is invalid.\n#{e.inspect}}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def run_installer
|
83
|
+
FileUtils.mkdir_p(absolute_install_dir)
|
84
|
+
|
85
|
+
if system('java', '-jar', installer_path, 'client', '-dir', absolute_install_dir, '-noprofile', '-mcversion', self.mcversion)
|
86
|
+
# Pass.
|
87
|
+
else
|
88
|
+
Mmi.fail! 'Failed to install Fabric modloader.'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def install
|
93
|
+
download_installer
|
94
|
+
run_installer
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Mmi
|
2
|
+
module Source
|
3
|
+
class Github
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
attr_reader :owner
|
7
|
+
attr_reader :repo
|
8
|
+
attr_reader :install_dir
|
9
|
+
attr_reader :filename
|
10
|
+
|
11
|
+
attr_reader :asset_id
|
12
|
+
attr_reader :release
|
13
|
+
attr_reader :file
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
@options = options
|
17
|
+
|
18
|
+
@owner = options['owner' ]
|
19
|
+
@repo = options['repo' ]
|
20
|
+
@asset_id = options['asset_id' ]
|
21
|
+
@release = options['release' ]
|
22
|
+
@file = options['file' ]
|
23
|
+
@install_dir = options['install_dir']
|
24
|
+
@filename = options['filename' ]
|
25
|
+
|
26
|
+
if self.owner
|
27
|
+
if self.repo
|
28
|
+
if self.install_dir
|
29
|
+
if self.asset_id
|
30
|
+
# Pass.
|
31
|
+
else
|
32
|
+
if self.release
|
33
|
+
if self.file
|
34
|
+
# Pass.
|
35
|
+
else
|
36
|
+
raise Mmi::MissingAttributeError, 'Missing "source.file" from asset because "source.asset_id" is not provided.'
|
37
|
+
end
|
38
|
+
else
|
39
|
+
raise Mmi::MissingAttributeError, 'Missing "source.release" from asset because "source.asset_id" is not provided.'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
else
|
43
|
+
raise Mmi::MissingAttributeError, 'Missing "source.install_dir" from asset.'
|
44
|
+
end
|
45
|
+
else
|
46
|
+
raise Mmi::MissingAttributeError, 'Missing "source.repo" from asset.'
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise Mmi::MissingAttributeError, 'Missing "source.owner" from asset.'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def repository_url
|
54
|
+
"https://github.com/#{self.owner}/#{self.repo}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def cached_asset_response
|
58
|
+
@asset_get ||= ::Github::Client::Repos::Releases::Assets.new.get(owner: self.owner, repo: self.repo, id: self.asset_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
def download_url
|
62
|
+
if self.asset_id
|
63
|
+
cached_asset_response.browser_download_url
|
64
|
+
else
|
65
|
+
"#{repository_url}/releases/download/#{release}/#{file}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def install(dir)
|
70
|
+
install_dir = File.expand_path(self.install_dir, dir)
|
71
|
+
filepath = File.join(install_dir, self.filename || (self.asset_id ? cached_asset_response.name : self.file))
|
72
|
+
|
73
|
+
Mmi.info "Downloading #{download_url.inspect} into #{filepath.inspect}."
|
74
|
+
|
75
|
+
FileUtils.mkdir_p(install_dir)
|
76
|
+
|
77
|
+
begin
|
78
|
+
stream = URI.open(download_url)
|
79
|
+
|
80
|
+
IO.copy_stream(stream, filepath)
|
81
|
+
rescue OpenURI::HTTPError => e
|
82
|
+
Mmi.fail! %Q{Error when requesting asset.\n#{e.inspect}}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def display_name
|
87
|
+
repository_url
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/mmi/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mmi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- expeehaa
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: semver2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: github_api
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.19'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.19'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: cli-ui
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.13'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.13'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- expeehaa@outlook.com
|
100
|
+
executables:
|
101
|
+
- mmi
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- README.adoc
|
106
|
+
- exe/mmi
|
107
|
+
- lib/mmi.rb
|
108
|
+
- lib/mmi/assets_processor.rb
|
109
|
+
- lib/mmi/interactive.rb
|
110
|
+
- lib/mmi/interactive/updater.rb
|
111
|
+
- lib/mmi/mod_file_processor.rb
|
112
|
+
- lib/mmi/modloader/fabric.rb
|
113
|
+
- lib/mmi/modloader/none.rb
|
114
|
+
- lib/mmi/source/github.rb
|
115
|
+
- lib/mmi/version.rb
|
116
|
+
homepage: https://github.com/expeehaa/mmi
|
117
|
+
licenses: []
|
118
|
+
metadata: {}
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubygems_version: 3.2.3
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Program to install minecraft modloaders, mods and other assets through a
|
138
|
+
single config file.
|
139
|
+
test_files: []
|