nauvisian 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +29 -0
  4. data/.rubocop_todo.yml +26 -0
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +26 -0
  7. data/Gemfile.lock +141 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +55 -0
  10. data/Rakefile +15 -0
  11. data/exe/nvsn +7 -0
  12. data/lib/nauvisian/api.rb +68 -0
  13. data/lib/nauvisian/cache/file_system.rb +55 -0
  14. data/lib/nauvisian/cache.rb +3 -0
  15. data/lib/nauvisian/cli/commands/mod/disable.rb +32 -0
  16. data/lib/nauvisian/cli/commands/mod/download.rb +34 -0
  17. data/lib/nauvisian/cli/commands/mod/enable.rb +32 -0
  18. data/lib/nauvisian/cli/commands/mod/info.rb +39 -0
  19. data/lib/nauvisian/cli/commands/mod/installed.rb +33 -0
  20. data/lib/nauvisian/cli/commands/mod/latest.rb +30 -0
  21. data/lib/nauvisian/cli/commands/mod/settings/dump.rb +30 -0
  22. data/lib/nauvisian/cli/commands/mod/versions.rb +31 -0
  23. data/lib/nauvisian/cli/commands/save/mod/list.rb +35 -0
  24. data/lib/nauvisian/cli/commands/save/mod/sync.rb +99 -0
  25. data/lib/nauvisian/cli/download_helper.rb +35 -0
  26. data/lib/nauvisian/cli/lister.rb +66 -0
  27. data/lib/nauvisian/cli/message_helper.rb +18 -0
  28. data/lib/nauvisian/cli.rb +36 -0
  29. data/lib/nauvisian/credential.rb +23 -0
  30. data/lib/nauvisian/deserializer.rb +96 -0
  31. data/lib/nauvisian/downloader.rb +57 -0
  32. data/lib/nauvisian/error.rb +16 -0
  33. data/lib/nauvisian/mod/detail.rb +15 -0
  34. data/lib/nauvisian/mod/release.rb +13 -0
  35. data/lib/nauvisian/mod.rb +20 -0
  36. data/lib/nauvisian/mod_list.rb +71 -0
  37. data/lib/nauvisian/mod_settings.rb +46 -0
  38. data/lib/nauvisian/platform.rb +78 -0
  39. data/lib/nauvisian/progress/bar.rb +24 -0
  40. data/lib/nauvisian/progress/null.rb +19 -0
  41. data/lib/nauvisian/progress.rb +4 -0
  42. data/lib/nauvisian/save.rb +89 -0
  43. data/lib/nauvisian/serializer.rb +111 -0
  44. data/lib/nauvisian/uri/s3.rb +22 -0
  45. data/lib/nauvisian/version.rb +6 -0
  46. data/lib/nauvisian/version24.rb +33 -0
  47. data/lib/nauvisian/version64.rb +33 -0
  48. data/lib/nauvisian.rb +33 -0
  49. data/nauvisian.gemspec +45 -0
  50. metadata +184 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e928d3061730068999c84496aec1c8eb57ccc08e143e0fc33bfbd10f5b16c92d
4
+ data.tar.gz: 5f0a59c8c77bc0d09ac5a34b8661d34f487898183c9e6fe0b5f1f7fb4a5243ba
5
+ SHA512:
6
+ metadata.gz: 040d1375254e5d5d7d594cb3071c13b28c18ea945b9244c49ca0bb692c7cd4c05199f5be85bb88c67926636e126870d7cd237769b5d1cd56de95c05e758b9e8f
7
+ data.tar.gz: 61e66892b9b1e54d5a12567b61f205e637c9108fece1c3de80fc08d1140538da67eab97c537810b26f7b547bcface784b7f15d72d5cd01d12164639bbfc17eef
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,29 @@
1
+ inherit_from:
2
+ - .rubocop/bundler.yml
3
+ - .rubocop/gemspec.yml
4
+ - .rubocop/layout.yml
5
+ - .rubocop/lint.yml
6
+ - .rubocop/metrics.yml
7
+ - .rubocop/naming.yml
8
+ - .rubocop/performance.yml
9
+ - .rubocop/rspec.yml
10
+ - .rubocop/security.yml
11
+ - .rubocop/style.yml
12
+ - .rubocop_todo.yml
13
+
14
+ require:
15
+ - rubocop-performance
16
+ - rubocop-rake
17
+ - rubocop-rspec
18
+
19
+ AllCops:
20
+ DisplayCopNames: true
21
+ DisplayStyleGuide: true
22
+ EnabledByDefault: true
23
+ Exclude:
24
+ - bin/**/*
25
+ - vendor/**/*
26
+ ExtraDetails: true
27
+ NewCops: enable
28
+ TargetRubyVersion: 3.2
29
+ UseCache: true
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,26 @@
1
+ Layout/LineLength:
2
+ Enabled: false
3
+
4
+ Metrics/AbcSize:
5
+ Enabled: false
6
+
7
+ Metrics/MethodLength:
8
+ Enabled: false
9
+
10
+ RSpec/NestedGroups:
11
+ Enabled: false
12
+
13
+ RSpec/ExampleLength:
14
+ Enabled: false
15
+
16
+ RSpec/MultipleExpectations:
17
+ Enabled: false
18
+
19
+ RSpec/PendingWithoutReason:
20
+ Enabled: false
21
+
22
+ Style/Documentation:
23
+ Enabled: false
24
+
25
+ Style/DocumentationMethod:
26
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-01-13
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ group :development do
8
+ gem "typeprof"
9
+ end
10
+
11
+ group :development, :test do
12
+ gem "debug"
13
+ gem "rake"
14
+ end
15
+
16
+ group :test do
17
+ gem "fabrication", require: false
18
+ gem "faker", require: false
19
+ gem "rspec", require: false
20
+ gem "rubocop", require: false
21
+ gem "rubocop-performance", require: false
22
+ gem "rubocop-rake", require: false
23
+ gem "rubocop-rspec", require: false
24
+ gem "simplecov", require: false
25
+ gem "webmock", require: false
26
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,141 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nauvisian (0.1.0)
5
+ aws-sdk-s3 (~> 1.0)
6
+ dry-cli (~> 1.0)
7
+ dry-inflector (~> 1.0)
8
+ rack (~> 3.0)
9
+ ruby-progressbar (~> 1.11)
10
+ rubyzip (~> 2.3)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ addressable (2.8.4)
16
+ public_suffix (>= 2.0.2, < 6.0)
17
+ ast (2.4.2)
18
+ aws-eventstream (1.2.0)
19
+ aws-partitions (1.765.0)
20
+ aws-sdk-core (3.172.0)
21
+ aws-eventstream (~> 1, >= 1.0.2)
22
+ aws-partitions (~> 1, >= 1.651.0)
23
+ aws-sigv4 (~> 1.5)
24
+ jmespath (~> 1, >= 1.6.1)
25
+ aws-sdk-kms (1.64.0)
26
+ aws-sdk-core (~> 3, >= 3.165.0)
27
+ aws-sigv4 (~> 1.1)
28
+ aws-sdk-s3 (1.122.0)
29
+ aws-sdk-core (~> 3, >= 3.165.0)
30
+ aws-sdk-kms (~> 1)
31
+ aws-sigv4 (~> 1.4)
32
+ aws-sigv4 (1.5.2)
33
+ aws-eventstream (~> 1, >= 1.0.2)
34
+ concurrent-ruby (1.2.2)
35
+ crack (0.4.5)
36
+ rexml
37
+ debug (1.8.0)
38
+ irb (>= 1.5.0)
39
+ reline (>= 0.3.1)
40
+ diff-lcs (1.5.0)
41
+ docile (1.4.0)
42
+ dry-cli (1.0.0)
43
+ dry-inflector (1.0.0)
44
+ fabrication (2.30.0)
45
+ faker (3.2.0)
46
+ i18n (>= 1.8.11, < 2)
47
+ hashdiff (1.0.1)
48
+ i18n (1.13.0)
49
+ concurrent-ruby (~> 1.0)
50
+ io-console (0.6.0)
51
+ irb (1.6.4)
52
+ reline (>= 0.3.0)
53
+ jmespath (1.6.2)
54
+ json (2.6.3)
55
+ parallel (1.23.0)
56
+ parser (3.2.2.1)
57
+ ast (~> 2.4.1)
58
+ public_suffix (5.0.1)
59
+ rack (3.0.7)
60
+ rainbow (3.1.1)
61
+ rake (13.0.6)
62
+ rbs (3.1.0)
63
+ regexp_parser (2.8.0)
64
+ reline (0.3.3)
65
+ io-console (~> 0.5)
66
+ rexml (3.2.5)
67
+ rspec (3.12.0)
68
+ rspec-core (~> 3.12.0)
69
+ rspec-expectations (~> 3.12.0)
70
+ rspec-mocks (~> 3.12.0)
71
+ rspec-core (3.12.2)
72
+ rspec-support (~> 3.12.0)
73
+ rspec-expectations (3.12.3)
74
+ diff-lcs (>= 1.2.0, < 2.0)
75
+ rspec-support (~> 3.12.0)
76
+ rspec-mocks (3.12.5)
77
+ diff-lcs (>= 1.2.0, < 2.0)
78
+ rspec-support (~> 3.12.0)
79
+ rspec-support (3.12.0)
80
+ rubocop (1.51.0)
81
+ json (~> 2.3)
82
+ parallel (~> 1.10)
83
+ parser (>= 3.2.0.0)
84
+ rainbow (>= 2.2.2, < 4.0)
85
+ regexp_parser (>= 1.8, < 3.0)
86
+ rexml (>= 3.2.5, < 4.0)
87
+ rubocop-ast (>= 1.28.0, < 2.0)
88
+ ruby-progressbar (~> 1.7)
89
+ unicode-display_width (>= 2.4.0, < 3.0)
90
+ rubocop-ast (1.28.1)
91
+ parser (>= 3.2.1.0)
92
+ rubocop-capybara (2.18.0)
93
+ rubocop (~> 1.41)
94
+ rubocop-factory_bot (2.22.0)
95
+ rubocop (~> 1.33)
96
+ rubocop-performance (1.17.1)
97
+ rubocop (>= 1.7.0, < 2.0)
98
+ rubocop-ast (>= 0.4.0)
99
+ rubocop-rake (0.6.0)
100
+ rubocop (~> 1.0)
101
+ rubocop-rspec (2.22.0)
102
+ rubocop (~> 1.33)
103
+ rubocop-capybara (~> 2.17)
104
+ rubocop-factory_bot (~> 2.22)
105
+ ruby-progressbar (1.13.0)
106
+ rubyzip (2.3.2)
107
+ simplecov (0.22.0)
108
+ docile (~> 1.1)
109
+ simplecov-html (~> 0.11)
110
+ simplecov_json_formatter (~> 0.1)
111
+ simplecov-html (0.12.3)
112
+ simplecov_json_formatter (0.1.4)
113
+ typeprof (0.21.7)
114
+ rbs (>= 1.8.1)
115
+ unicode-display_width (2.4.2)
116
+ webmock (3.18.1)
117
+ addressable (>= 2.8.0)
118
+ crack (>= 0.3.2)
119
+ hashdiff (>= 0.4.0, < 2.0.0)
120
+
121
+ PLATFORMS
122
+ arm64-darwin-21
123
+ x86_64-linux
124
+
125
+ DEPENDENCIES
126
+ debug
127
+ fabrication
128
+ faker
129
+ nauvisian!
130
+ rake
131
+ rspec
132
+ rubocop
133
+ rubocop-performance
134
+ rubocop-rake
135
+ rubocop-rspec
136
+ simplecov
137
+ typeprof
138
+ webmock
139
+
140
+ BUNDLED WITH
141
+ 2.4.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 OZAWA Sakuro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # Nauvisian
2
+
3
+ A library and CLI tool for the management of [Factorio](https://factorio.com) MODs and saves.
4
+
5
+ It eases downloading MODs, enabling/disabling locally installed MODs and synchroning MODs and settings with save files.
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add nauvisian
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install nauvisian
16
+
17
+ ## CLI Usage
18
+
19
+ - `nvsn mod disable MOD`
20
+ Disable an installed MOD
21
+ - `nvsn mod download MOD` 🔐
22
+ Download a MOD to the current directory
23
+ - `nvsn mod enable MOD`
24
+ Enable an installed MOD
25
+ - `nvsn mod info MOD` 🖧
26
+ Show info of MOD
27
+ - `nvsn mod installed`
28
+ List installed MODs
29
+ - `nvsn mod latest MOD` 🖧
30
+ Show the latest version of MOD
31
+ - `nvsn mod versions MOD` 🖧
32
+ List available versions of MOD
33
+ - `nvsn mod settings dump`
34
+ Dump MOD settings
35
+ - `nvsn save mod list SAVE`
36
+ List MODs used in the given SAVE
37
+ - `nvsn save mod sync SAVE` 🔐
38
+ Synchronize MODs and startup settings with the given SAVE
39
+
40
+ For options recognized by the commands above, try the command with `--help`.
41
+
42
+ - Commands with 🔐 requires the credenail information generally found in your `player-data.json`
43
+ - Commands with 🖧 accesses MOD portal's public API
44
+
45
+ ## Development
46
+
47
+ After checking out the repo, run `bin/setup` to install dependencies. It also copies currently installed MODs and saves into the workspace.
48
+
49
+ ## Contributing
50
+
51
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sakuro/nauvisian.
52
+
53
+ ## License
54
+
55
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/clean"
5
+ require "rspec/core/rake_task"
6
+ require "rubocop/rake_task"
7
+
8
+ CLEAN.add("coverage")
9
+ CLEAN.add(".rspec_status")
10
+ CLOBBER.add("*.zip")
11
+
12
+ RSpec::Core::RakeTask.new(:spec)
13
+ RuboCop::RakeTask.new
14
+
15
+ task default: %i[spec rubocop]
data/exe/nvsn ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "nauvisian/cli"
5
+
6
+ Zip.warn_invalid_date = false
7
+ Dry::CLI.new(Nauvisian::CLI::Commands).call
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "open-uri"
5
+
6
+ require "rack/utils"
7
+
8
+ require "nauvisian/error"
9
+
10
+ module Nauvisian
11
+ # Mod Portal API
12
+ # https://wiki.factorio.com/Mod_portal_API
13
+ class API
14
+ class Error < Nauvisian::Error; end
15
+
16
+ MOD_PORTAL_ENDPOINT_URI = URI("https://mods.factorio.com").freeze
17
+ private_constant :MOD_PORTAL_ENDPOINT_URI
18
+
19
+ def initialize
20
+ @cache = Nauvisian::Cache::FileSystem.new(name: "api")
21
+ end
22
+
23
+ def detail(mod)
24
+ with_error_handling(mod) do
25
+ path = "/api/mods/#{mod.name}/full"
26
+ raw_data = get(path)
27
+ data = raw_data.slice(:downloads_count, :name, :owner, :summary, :title, :category, :description)
28
+ Nauvisian::Mod::Detail[created_at: Time.parse(raw_data[:created_at]), **data]
29
+ end
30
+ end
31
+
32
+ def releases(mod)
33
+ with_error_handling(mod) do
34
+ path = "/api/mods/#{mod.name}"
35
+ raw_data = get(path)
36
+ parse_releases(raw_data[:releases], mod:)
37
+ end
38
+ end
39
+
40
+ private def with_error_handling(mod)
41
+ yield
42
+ rescue OpenURI::HTTPError => e
43
+ case e.io.status
44
+ in ["404", _]
45
+ raise Nauvisian::ModNotFound, mod
46
+ else
47
+ raise Nauvisian::API::Error, e.io.status
48
+ end
49
+ end
50
+
51
+ private def parse_releases(raw_releases, mod:)
52
+ raw_releases.map do |raw_release|
53
+ data = raw_release.slice(:file_name, :sha1)
54
+ data[:download_url] = MOD_PORTAL_ENDPOINT_URI + raw_release[:download_url]
55
+ data[:version] = Nauvisian::Version24[raw_release[:version]]
56
+ data[:released_at] = Time.parse(raw_release[:released_at])
57
+ Nauvisian::Mod::Release[mod:, **data]
58
+ end
59
+ end
60
+
61
+ private def get(path, **params)
62
+ request_url = MOD_PORTAL_ENDPOINT_URI + path
63
+ request_url.query = Rack::Utils.build_nested_query(params)
64
+ data = @cache.fetch(request_url) { request_url.read }
65
+ JSON.parse(data, symbolize_names: true)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/md5"
4
+ require "pathname"
5
+
6
+ module Nauvisian
7
+ module Cache
8
+ class FileSystem
9
+ MINIMUM_TTL = 5 * 60 # 5 minutes
10
+ private_constant :MINIMUM_TTL
11
+
12
+ def self.cache_root
13
+ Pathname(ENV.fetch("XDG_CACHE_HOME", Nauvisian.platform.home_directory / ".cache")) / "nauvisian"
14
+ end
15
+
16
+ def initialize(name:, ttl: MINIMUM_TTL)
17
+ raise ArgumentError, "ttl is too small (must be >= #{MINIMUM_TTL})" if ttl < MINIMUM_TTL
18
+
19
+ @cache_directory = self.class.cache_root / name
20
+ @ttl = ttl
21
+ end
22
+
23
+ private attr_reader :root
24
+
25
+ def fetch(key)
26
+ path = generate_path(key)
27
+ return path.binread if path.exist? && !stale?(path, Time.now)
28
+
29
+ yield.tap {|content| store(path, content) }
30
+ end
31
+
32
+ private def generate_path(key)
33
+ digest = Digest::MD5.hexdigest(key.to_s)
34
+ @cache_directory.join(digest[0..1], digest[2..3], digest[4..])
35
+ end
36
+
37
+ private def stale?(path, time)
38
+ time - path.mtime > @ttl
39
+ end
40
+
41
+ private def store(path, content)
42
+ dir = path.dirname
43
+ dir.mkpath
44
+
45
+ # Store into a temporary file
46
+ tmp = Tempfile.create(".cache-", dir, mode: IO::BINARY | IO::CREAT)
47
+ tmp.write(content)
48
+ tmp.close
49
+
50
+ # Rename to the desired path
51
+ File.rename(tmp.path, path)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "cache/file_system"
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../message_helper"
4
+
5
+ module Nauvisian
6
+ module CLI
7
+ module Commands
8
+ module Mod
9
+ class Disable < Dry::CLI::Command
10
+ include MessageHelper
11
+
12
+ desc "Disable an installed MOD"
13
+ argument :mod, desc: "Target MOD", required: true
14
+
15
+ option :mod_directory, desc: "Directory where MODs are installed", required: false, default: Nauvisian.platform.mod_directory.to_s
16
+
17
+ def call(mod:, **options)
18
+ mod_directory = Pathname(options[:mod_directory])
19
+ mod_list_path = mod_directory / "mod-list.json"
20
+ list = Nauvisian::ModList.load(mod_list_path)
21
+ mod = Nauvisian::Mod[name: mod]
22
+ list.disable(mod)
23
+ list.save(mod_list_path)
24
+ rescue Nauvisian::ModNotFound
25
+ message "❌ You can't disable a MOD which is not in the MOD list (#{mod.name})"
26
+ exit 1
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../download_helper"
4
+ require_relative "../../message_helper"
5
+
6
+ module Nauvisian
7
+ module CLI
8
+ module Commands
9
+ module Mod
10
+ class Download < Dry::CLI::Command
11
+ include DownloadHelper
12
+ include MessageHelper
13
+
14
+ desc "Download a MOD to the current directory"
15
+ argument :mod, desc: "Target MOD", required: true
16
+ option :version, desc: "Version to download (default: latest)"
17
+ option :user, desc: "The user at MOD Portal"
18
+ option :token, desc: "The token at MOD Portal"
19
+
20
+ def call(mod:, **options)
21
+ credential = find_credential(**options.slice(:user, :token))
22
+ release = find_release(Nauvisian::Mod[name: mod], version: options.key?(:version) ? Nauvisian::Version24[options[:version]] : nil)
23
+
24
+ downloader = Nauvisian::Downloader.new(credential:, progress: Nauvisian::Progress::Bar)
25
+ downloader.download(release, release.file_name)
26
+ rescue => e
27
+ message(e)
28
+ exit 1
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../message_helper"
4
+
5
+ module Nauvisian
6
+ module CLI
7
+ module Commands
8
+ module Mod
9
+ class Enable < Dry::CLI::Command
10
+ include MessageHelper
11
+
12
+ desc "Enable an installed MOD"
13
+ argument :mod, desc: "Target MOD", required: true
14
+
15
+ option :mod_directory, desc: "Directory where MODs are installed", required: false, default: Nauvisian.platform.mod_directory.to_s
16
+
17
+ def call(mod:, **options)
18
+ mod_directory = Pathname(options[:mod_directory])
19
+ mod_list_path = mod_directory / "mod-list.json"
20
+ list = Nauvisian::ModList.load(mod_list_path)
21
+ mod = Nauvisian::Mod[name: mod]
22
+ list.enable(mod)
23
+ list.save(mod_list_path)
24
+ rescue Nauvisian::ModNotFound
25
+ message "❌ You can't enable a MOD which is not in the MOD list (#{mod.name})"
26
+ exit 1
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../message_helper"
4
+
5
+ module Nauvisian
6
+ module CLI
7
+ module Commands
8
+ module Mod
9
+ class Info < Dry::CLI::Command
10
+ include MessageHelper
11
+
12
+ desc "Show info of MOD"
13
+ argument :mod, desc: "Target MOD", required: true
14
+
15
+ def call(mod:, **)
16
+ api = Nauvisian::API.new
17
+ mod = Nauvisian::Mod[name: mod]
18
+ detail = api.detail(mod)
19
+
20
+ puts <<~DETAIL
21
+ Name: #{detail.name}
22
+ Category: #{detail.category}
23
+ Downloads: #{detail.downloads_count}
24
+ URL: #{detail.url}
25
+ Title: #{detail.title}
26
+ Summary: #{detail.summary}
27
+ Owner: #{detail.owner}
28
+ Created at: #{detail.created_at}
29
+ Description: #{detail.description}
30
+ DETAIL
31
+ rescue => e
32
+ message(e)
33
+ exit 1
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../lister"
4
+ require_relative "../../message_helper"
5
+
6
+ module Nauvisian
7
+ module CLI
8
+ module Commands
9
+ module Mod
10
+ class Installed < Dry::CLI::Command
11
+ include MessageHelper
12
+
13
+ desc "List installed MODs"
14
+ option :format, default: "plain", values: Nauvisian::CLI::Lister.all, desc: "Output format"
15
+ option :mod_directory, desc: "Directory where MODs are installed", required: false, default: Nauvisian.platform.mod_directory.to_s
16
+
17
+ def call(*, **options)
18
+ mod_directory = Pathname(options[:mod_directory])
19
+ mod_list_path = mod_directory / "mod-list.json"
20
+ mods = Nauvisian::ModList.load(mod_list_path).sort
21
+ rows = mods.map {|mod, enabled| {"Name" => mod.name, "Enabled" => enabled} }
22
+
23
+ lister = Nauvisian::CLI::Lister.for(options[:format].to_sym).new(%w(Name Enabled))
24
+ lister.list(rows)
25
+ rescue => e
26
+ message(e)
27
+ exit 1
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../message_helper"
4
+
5
+ module Nauvisian
6
+ module CLI
7
+ module Commands
8
+ module Mod
9
+ class Latest < Dry::CLI::Command
10
+ include MessageHelper
11
+
12
+ desc "Show the latest version of MOD"
13
+ argument :mod, desc: "Target MOD", required: true
14
+
15
+ def call(mod:, **)
16
+ api = Nauvisian::API.new
17
+ mod = Nauvisian::Mod[name: mod]
18
+ releases = api.releases(mod)
19
+ latest = releases.max_by(&:released_at)
20
+
21
+ puts latest.version
22
+ rescue => e
23
+ message(e)
24
+ exit 1
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end