sekt 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9cbee1dac31486242ac182ee86e8b6c0e1f81d02
4
+ data.tar.gz: fd27a7f8dfce7cfffb5a291659075546f59d8b8f
5
+ SHA512:
6
+ metadata.gz: 90dabe9775be4bfd21d15dc88d8276d5e5473ab9827d7a68d9de04c25f14683959666801a0d9228e21b3b5046226a06bc3a2dcc089c02d0ab97ce1b14c9dac53
7
+ data.tar.gz: 37d9f1c05ad085fd2dc45674fb5766961f6607d49519ec65e42cbcca19dbbf65fdadeb41487a9171e9efac589fd538177ed6fc35c58c68842c890d465138d32b
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gemspec
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require 'sekt'
3
+
4
+ begin
5
+ Sekt::CLI::CLI.start(ARGV)
6
+ rescue
7
+ $stderr.puts "\t|Error| #{$!.message}"
8
+ end
9
+
10
+
@@ -0,0 +1,2 @@
1
+ cellar_location: ~/.cellar # Location where wine prefixes will be stored
2
+ logging_level: debug # debug, info, warn, error ...
@@ -0,0 +1,13 @@
1
+ name: World of Tanks
2
+ description: World of Tanks DX11 EU servers
3
+ source: https://redirect.wargaming.net/WoT/launcher_install_eu
4
+ architecture: win32
5
+ executable: C:\Games\World_of_Tanks\WoTLauncher.exe
6
+ dependencies:
7
+ - corefonts
8
+ - mfc40
9
+ - mfc42
10
+ - msxml3
11
+ - msxml4
12
+ - msxml6
13
+ - dxvk
@@ -0,0 +1,12 @@
1
+ module Sekt
2
+ autoload :CLI, 'sekt/cli'
3
+ autoload :Cellar, 'sekt/cellar'
4
+ autoload :Bottle, 'sekt/bottle'
5
+ autoload :Bottler, 'sekt/bottler'
6
+ autoload :Wine, 'sekt/wine'
7
+ autoload :WineTricks, 'sekt/wine_tricks'
8
+ autoload :Download, 'sekt/download'
9
+ autoload :Settings, 'sekt/settings'
10
+ end
11
+
12
+ require 'sekt/version'
@@ -0,0 +1,80 @@
1
+ require 'sekt/cellar'
2
+ require 'sekt/wine'
3
+ require 'sekt/wine_tricks'
4
+
5
+ module Sekt
6
+ class Bottle
7
+ WINE_PREFIX_NAME = 'windows'.freeze
8
+ REQUIRED_ATTRIBUTES = %w{id name source}.freeze
9
+ OPTIONAL_ATTRIBUTES = %w{architecture description dependencies executable}.freeze
10
+ ATTRIBUTES = REQUIRED_ATTRIBUTES + OPTIONAL_ATTRIBUTES
11
+
12
+ attr_reader(*ATTRIBUTES)
13
+ attr_reader :path, :wine_prefix
14
+
15
+ def check_args!(hash)
16
+ diff = REQUIRED_ATTRIBUTES - hash.keys
17
+ raise "Some required bottle attributes are missing: #{diff}" unless diff.empty?
18
+ end
19
+
20
+ def initialize(hash)
21
+ check_args!(hash)
22
+
23
+ ATTRIBUTES.each { |attr| instance_variable_set("@#{attr}", hash[attr]) }
24
+
25
+ @path = File.join(Cellar::CELLAR_PATH, @id)
26
+ @wine_prefix = File.join(@path, WINE_PREFIX_NAME)
27
+ end
28
+
29
+ def self.load(id, hash)
30
+ hash['id'] = id
31
+ Bottle.new(hash)
32
+ end
33
+
34
+ def wine
35
+ Wine.new(wine_prefix, architecture)
36
+ end
37
+
38
+ def wine_tricks
39
+ WineTricks.new(wine_prefix, architecture)
40
+ end
41
+
42
+ def inside(&block)
43
+ Dir.chdir(path, &block)
44
+ end
45
+
46
+ def inside_wine(&block)
47
+ Dir.chdir(File.join(wine_prefix, 'drive_c'), &block)
48
+ end
49
+
50
+ def start
51
+ wine.execute(executable)
52
+ end
53
+
54
+ def install_libs(libs)
55
+ wine_tricks.install(libs)
56
+ @dependencies + libs
57
+ end
58
+
59
+ def to_h
60
+ ATTRIBUTES.each_with_object({}) { |attr, hash| hash[attr] = instance_variable_get("@#{attr}") }
61
+ end
62
+
63
+ def pp
64
+ %(
65
+ Bottle___________________________________________________
66
+ |NAME: #{name}
67
+ |ID: #{id}
68
+ |PATH: #{path}
69
+ |WINE_PREFIX: #{wine_prefix}
70
+ |________________________________________________________
71
+
72
+ Description:
73
+ #{description}
74
+ Source: #{source}
75
+ Executable: #{executable}
76
+ Architecture: #{architecture}
77
+ )
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,36 @@
1
+ require 'zip'
2
+
3
+ module Sekt
4
+ class Bottler
5
+ def initialize(bottle, outputFile=nil)
6
+ @inputDir = bottle.path
7
+ @outputFile = outputFile || "#{bottle.id}.bottle"
8
+ end
9
+
10
+ def write()
11
+ entries = Dir.entries(@inputDir); entries.delete("."); entries.delete("..")
12
+ io = Zip::File.open(@outputFile, Zip::File::CREATE);
13
+
14
+ writeEntries(entries, "", io)
15
+ io.close();
16
+ end
17
+
18
+ private
19
+
20
+ def writeEntries(entries, path, io)
21
+
22
+ entries.each { |e|
23
+ zipFilePath = path == "" ? e : File.join(path, e)
24
+ diskFilePath = File.join(@inputDir, zipFilePath)
25
+ puts "Deflating " + diskFilePath
26
+ if File.directory?(diskFilePath)
27
+ io.mkdir(zipFilePath)
28
+ subdir =Dir.entries(diskFilePath); subdir.delete("."); subdir.delete("..")
29
+ writeEntries(subdir, zipFilePath, io)
30
+ else
31
+ io.get_output_stream(zipFilePath) { |f| f.puts(File.open(diskFilePath, "rb").read())}
32
+ end
33
+ }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,53 @@
1
+ require 'yaml'
2
+ require 'securerandom'
3
+ require 'fileutils'
4
+ require 'sekt/bottle'
5
+
6
+ module Sekt
7
+ class Cellar
8
+ CELLAR_PATH = File.expand_path(Sekt::Settings.cellar_location).freeze
9
+
10
+ attr_reader :bottles
11
+
12
+ def self.inside(&block)
13
+ Dir.chdir(CELLAR_PATH, &block)
14
+ end
15
+
16
+ def initialize
17
+ Dir.mkdir(CELLAR_PATH) unless Dir.exists?(CELLAR_PATH)
18
+ bottle_dirs = Dir.glob(File.join(CELLAR_PATH, '*')).select { |f| File.directory? f }
19
+ @bottles = bottle_dirs.map { |bd| Bottle.load(File.basename(bd), YAML.load_file(File.join(bd, 'bottle.yml'))) }
20
+ logger.debug('Cellar loaded')
21
+ end
22
+
23
+ def create_bottle(hash, id=SecureRandom.urlsafe_base64(6))
24
+ bottle_path = File.join(CELLAR_PATH, id)
25
+ Dir.mkdir(bottle_path)
26
+ File.write(File.join(bottle_path, 'bottle.yml'), hash.to_yaml)
27
+ bottle = Bottle.load(id, hash)
28
+ @bottles << bottle
29
+ bottle
30
+ end
31
+
32
+ def update_bottle(bottle)
33
+ File.write(File.join(bottle.path, 'bottle.yml'), bottle.to_h.to_yaml)
34
+ end
35
+
36
+ def remove(id)
37
+ bottle = get_bottle(id)
38
+ remove_bottle(bottle)
39
+ end
40
+
41
+ def remove_bottle(bottle)
42
+ FileUtils.rm_rf(bottle.path) if bottle
43
+ end
44
+
45
+ def get_bottle(id)
46
+ bottles.find { |b| b.id == id }
47
+ end
48
+
49
+ def clean
50
+ bottles.each { |b| remove_bottle(b) }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ module Sekt
2
+ module CLI
3
+ autoload :CLI, 'sekt/cli/cli'
4
+ autoload :Recipe, 'sekt/cli/recipe'
5
+ autoload :Bottle, 'sekt/cli/bottle'
6
+ autoload :GetBottle, 'sekt/cli/get_bottle'
7
+ end
8
+ end
@@ -0,0 +1,69 @@
1
+ require 'thor'
2
+
3
+ module Sekt
4
+ module CLI
5
+ class Bottle < Thor
6
+ include GetBottle
7
+
8
+ desc 'start ID', 'Start default bottle executable'
9
+ def start(id)
10
+ get_bottle!(id).start
11
+ end
12
+
13
+ desc 'execute ID EXECUTABLE', 'Execute program inside bottle'
14
+ def execute(id, executable)
15
+ get_bottle!(id).wine.start(executable)
16
+ end
17
+
18
+ desc 'rename OLD NEW', 'Rename bottle'
19
+ def rename(old, new)
20
+ get_bottle!(old)
21
+ Cellar.inside { File.rename(old, new) }
22
+ end
23
+
24
+ desc 'remove ID', 'Remove bottle with given id'
25
+ def remove(id)
26
+ get_bottle!(id)
27
+ return unless yes?("Are you sure you want to delete bottle #{id}?")
28
+ Cellar.new.remove(id)
29
+ end
30
+
31
+ desc 'clean', 'Delete all bottles'
32
+ def clean
33
+ return unless yes?("Are you sure you want to delete all bottles?")
34
+ Cellar.new.clean
35
+ end
36
+
37
+ desc 'list', 'List installed bottles'
38
+ def list
39
+ Cellar.new.bottles.each { |b| puts b.pp }
40
+ end
41
+
42
+ desc 'print ID', 'Print detailed info about bottle'
43
+ def print(id)
44
+ bottle = get_bottle!(id)
45
+ puts bottle.pp
46
+ puts "\tDependencies:"
47
+ bottle.dependencies.each { |d| puts "\t\t- #{d}"}
48
+ end
49
+
50
+ desc 'install-lib ID *LIBS', 'Install libraries from winetricks'
51
+ def install_lib(id, *libs)
52
+ bottle = get_bottle!(id)
53
+
54
+ bottle.install_libs(libs)
55
+
56
+ cellar.update_bottle(bottle)
57
+ end
58
+
59
+ # TODO: Implement in future
60
+ #desc 'import FILE', 'Import bottle'
61
+ #def import(file) # *.bottle file
62
+ #end
63
+ #
64
+ #desc 'export ID [FILE]', 'Export bottle'
65
+ #def export(id, file="#{id}.bottle")
66
+ #end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,31 @@
1
+ require 'thor'
2
+ require 'yell'
3
+
4
+ module Sekt
5
+ module CLI
6
+ class CLI < Thor
7
+ def initialize(*args)
8
+ super
9
+ init_logger
10
+ end
11
+
12
+ desc 'version', 'Print Sekt version'
13
+ def version
14
+ puts Sekt::VERSION
15
+ end
16
+
17
+ desc 'bottle SUBCOMMAND ...ARGS', 'Manage bottles'
18
+ subcommand 'bottle', Bottle
19
+
20
+ desc 'recipe SUBCOMMAND ...ARGS', 'Manage recipes'
21
+ subcommand 'recipe', Recipe
22
+
23
+ private
24
+
25
+ def init_logger
26
+ Yell.new :stdout, name: Object, level: Settings.logging_level
27
+ Object.send :include, Yell::Loggable
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ module Sekt
2
+ module CLI
3
+ module GetBottle
4
+ def get_bottle!(id)
5
+ @cellar ||= Cellar.new
6
+ bottle = @cellar.get_bottle(id)
7
+ raise "Failed to find bottle: #{id}" unless bottle
8
+ return bottle
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,49 @@
1
+ require 'thor'
2
+
3
+ module Sekt
4
+ module CLI
5
+ class Recipe < Thor
6
+ include GetBottle
7
+
8
+ desc 'install [FILE]', 'Install wine program from recipe into bottle'
9
+ def install(file='bottle.yml')
10
+ @cellar = Cellar.new
11
+
12
+ bottle_yaml = YAML.load_file(file)
13
+ bottle = @cellar.create_bottle(bottle_yaml)
14
+
15
+ wine_tricks = bottle.wine_tricks
16
+ wine_tricks.sandbox
17
+ wine_tricks.install(bottle.dependencies)
18
+
19
+ wine = bottle.wine
20
+ bottle.inside_wine do
21
+ wine.execute("C:\\#{get_source(bottle)}")
22
+ end
23
+
24
+ @cellar.update_bottle(bottle)
25
+ end
26
+
27
+ desc 'export ID', 'Export recipe from bottle'
28
+ def export(id)
29
+ File.write("#{id}.yml", get_bottle!(id).to_h.to_yaml)
30
+ end
31
+
32
+ private
33
+
34
+ def get_source(bottle)
35
+ if bottle.source =~ URI::regexp
36
+ return Download.new(bottle.source).start
37
+ end
38
+
39
+ source_path = Pathname.new(bottle.source)
40
+ if source_path
41
+ FileUtils.cp(source_path, '.')
42
+ return source_path.basename
43
+ end
44
+
45
+ raise 'Failed to retrieve bottle.source'
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ require 'open-uri'
2
+
3
+ module Sekt
4
+ class Download
5
+ def initialize(uri, folder='.')
6
+ @uri = uri
7
+ @folder = folder
8
+ end
9
+
10
+ def start
11
+ download = open(@uri)
12
+ @name = "#{download.base_uri.to_s.split('/')[-1]}"
13
+ IO.copy_stream(download, File.join(@folder, @name))
14
+ @name
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ require 'settingslogic'
2
+
3
+ module Sekt
4
+ class Settings < Settingslogic
5
+ CONFIG_FILE = 'sekt.yml'.freeze
6
+
7
+ source "#{ENV['HOME']}/.sekt/#{CONFIG_FILE}" \
8
+ if File.exist?("#{ENV['HOME']}/.sekt/#{CONFIG_FILE}")
9
+
10
+ source "/etc/sekt/#{CONFIG_FILE}" \
11
+ if File.exist?("/etc/sekt/#{CONFIG_FILE}")
12
+
13
+ source "#{File.dirname(__FILE__)}/../../config/#{CONFIG_FILE}"
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Sekt
2
+ VERSION = '0.0.1'.freeze
3
+ end
@@ -0,0 +1,20 @@
1
+ require 'open3'
2
+
3
+ module Sekt
4
+ class Wine
5
+ def initialize(prefix='', architecture='win32')
6
+ @prefix = prefix
7
+ @architecture = architecture
8
+ @version = `wine --version`.strip
9
+ raise '\'wine\' is not installed' unless $?.success?
10
+ logger.debug { "'wine' found, version: #{@version}" }
11
+ end
12
+
13
+ def execute(file)
14
+ command = "WINEPREFIX=#{@prefix} WINEDLLOVERRIDES=winemenubuilder.exe=d WINEARCH=#{@architecture} wine '#{file}'"
15
+ logger.debug { "Executing command: `#{command}`" }
16
+ stdout, stderr, status = Open3.capture3(command)
17
+ raise '\'wine.execute\' failed' unless status.success?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ require 'open3'
2
+
3
+ module Sekt
4
+ class WineTricks
5
+ def initialize(prefix, architecture='win32')
6
+ @prefix = prefix
7
+ @architecture = architecture
8
+ @version = `winetricks --version`.strip
9
+ raise '\'winetricks\' is not installed' unless $?.success?
10
+ logger.debug { "'winetricks' found, version: #{@version}" }
11
+ end
12
+
13
+ def install(dependencies)
14
+ return if dependencies.nil? || dependencies.empty?
15
+ command = "WINEPREFIX=#{@prefix} WINEARCH=#{@architecture} winetricks #{dependencies.join(' ')}"
16
+ logger.debug { "Executing command: `#{command}`" }
17
+ stdout, stderr, status = Open3.capture3(command)
18
+ raise '\'wine_tricks.install\' failed' unless status.success?
19
+ end
20
+
21
+ def sandbox
22
+ command = "WINEPREFIX=#{@prefix} WINEARCH=#{@architecture} winetricks sandbox"
23
+ logger.debug { "Executing command: `#{command}`" }
24
+ stdout, stderr, status = Open3.capture3(command)
25
+ raise '\'wine_tricks.sandbox\' failed' unless status.success?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'sekt/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'sekt'
7
+ spec.version = Sekt::VERSION
8
+ spec.authors = ['Dušan Baran']
9
+ spec.email = ['work.dusanbaran@gmail.com']
10
+
11
+ spec.summary = 'WINE prefix manager'
12
+ spec.description = 'WINE prefix manager'
13
+ spec.homepage = 'https://github.com/dudoslav/sekt'
14
+ spec.license = 'GPL-3.0'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject \
17
+ { |f| f.match(%r{^(test|spec|features)/}) }
18
+ gem_dir = __dir__ + '/'
19
+ `git submodule --quiet foreach --recursive pwd`.split($OUTPUT_RECORD_SEPARATOR).each do |submodule_path|
20
+ Dir.chdir(submodule_path) do
21
+ submodule_relative_path = submodule_path.sub gem_dir, ''
22
+ `git ls-files`.split($OUTPUT_RECORD_SEPARATOR).each do |filename|
23
+ spec.files << "#{submodule_relative_path}/#{filename}"
24
+ end
25
+ end
26
+ end
27
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.16'
31
+
32
+ spec.add_runtime_dependency 'thor', '~> 0.20'
33
+ spec.add_runtime_dependency 'yell', '~> 2.0'
34
+ spec.add_runtime_dependency 'settingslogic', '~> 2.0'
35
+ # spec.add_runtime_dependency 'rubyzip', '~> 1.2'
36
+ end
37
+
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sekt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dušan Baran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.20'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.20'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yell
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: settingslogic
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ description: WINE prefix manager
70
+ email:
71
+ - work.dusanbaran@gmail.com
72
+ executables:
73
+ - sekt
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - Gemfile
78
+ - bin/sekt
79
+ - config/sekt.yml
80
+ - examples/wot_x32_dx11.yml
81
+ - lib/sekt.rb
82
+ - lib/sekt/bottle.rb
83
+ - lib/sekt/bottler.rb
84
+ - lib/sekt/cellar.rb
85
+ - lib/sekt/cli.rb
86
+ - lib/sekt/cli/bottle.rb
87
+ - lib/sekt/cli/cli.rb
88
+ - lib/sekt/cli/get_bottle.rb
89
+ - lib/sekt/cli/recipe.rb
90
+ - lib/sekt/download.rb
91
+ - lib/sekt/settings.rb
92
+ - lib/sekt/version.rb
93
+ - lib/sekt/wine.rb
94
+ - lib/sekt/wine_tricks.rb
95
+ - sekt.gemspec
96
+ homepage: https://github.com/dudoslav/sekt
97
+ licenses:
98
+ - GPL-3.0
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.6.14
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: WINE prefix manager
120
+ test_files: []