sekt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []