bukin 0.8.0 → 0.9.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.
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.1.0
3
4
  - 2.0.0
4
5
  - 1.9.3
5
6
 
data/README.md CHANGED
@@ -40,12 +40,12 @@ Bukin is still a work in progress and is far from feature complete. Currently i
40
40
  * Auto selection if none specified
41
41
  * Automatic or user specified filtering of downloaded files
42
42
  * Automatic or user specified extraction of zip files
43
+ * Automatic detection of already installed plugins
43
44
  * Installation groups
44
45
 
45
46
  Eventually, I'd like to add some of the following:
46
47
 
47
48
  * A lockfile that tracks exactly what versions are installed
48
- * Automatic detection of already installed plugins
49
49
  * Dependency tracking and resolution
50
50
  * More complex version selectors
51
51
  * Modpack support
@@ -61,7 +61,7 @@ Usage
61
61
  Bukin works by reading a list of dependencies from a `Bukfile`. The most basic usage would be:
62
62
 
63
63
  ```bash
64
- echo "server 'craftbukkit'" > Bukfile
64
+ bukin init
65
65
  bukin install
66
66
  ```
67
67
 
@@ -48,7 +48,7 @@ module Bukin
48
48
 
49
49
  def self.with_friendly_errors
50
50
  yield
51
- rescue Bukin::BukinError => error
51
+ rescue BukinError => error
52
52
  abort error.message
53
53
  rescue SocketError => error
54
54
  abort "#{error.message}\nCheck that you have a stable connection and the service is online"
@@ -45,7 +45,7 @@ module Bukin
45
45
  private
46
46
  def add_resource(name, type, args)
47
47
  raise(
48
- Bukin::BukinError,
48
+ BukinError,
49
49
  "Error: The #{type} '#{name}' is declared "\
50
50
  "more than once in your #{FILE_NAME}"
51
51
  ) if resource_exists?(name, type)
@@ -7,6 +7,7 @@ require 'bukin/bukget'
7
7
  require 'bukin/bukkit_dl'
8
8
  require 'bukin/jenkins'
9
9
  require 'bukin/download'
10
+ require 'bukin/state'
10
11
 
11
12
  module Bukin
12
13
  class CLI < Thor
@@ -18,13 +19,30 @@ module Bukin
18
19
  without = options[:without].map(&:to_sym)
19
20
  raw_resources = parse_resources(names, without)
20
21
 
21
- # Get all the informatin needed to install
22
+ # Get all the information needed to install
22
23
  resources = prepare_resources(raw_resources)
23
24
 
24
25
  # Download and install all resources
25
26
  install_resources(resources)
26
27
  end
27
28
 
29
+ desc 'init', "Creates a new Bukfile with craftbukkit as a server and adds"\
30
+ "the .bukin directory to any existing .gitignore file."
31
+ def init
32
+ path = File.join(Dir.pwd, Bukfile::FILE_NAME)
33
+ if File.exist?(path)
34
+ say 'Bukfile already exists'
35
+ else
36
+ say 'Creating Bukfile'
37
+ File.open(path, 'w') {|file| file.write("server 'craftbukkit'")}
38
+ end
39
+
40
+ if File.exist?('.gitignore') && File.readlines('.gitignore').grep(/\.bukin/).empty?
41
+ say 'Writing .bukin to gitignore'
42
+ File.open('.gitignore', 'a') {|file| file.write('.bukin')}
43
+ end
44
+ end
45
+
28
46
  def help(*)
29
47
  shell.say "Bukin is a plugin and server package manager for Minecraft.\n"
30
48
  super
@@ -32,7 +50,7 @@ module Bukin
32
50
 
33
51
  private
34
52
  def parse_resources(names, without)
35
- resources = section('Parsing Bukfile') {Bukin::Bukfile.new.resources}
53
+ resources = section('Parsing Bukfile') {Bukfile.new.resources}
36
54
 
37
55
  # If name are specified, only install resources with those names
38
56
  resources.select! {|resource| names.include?(resource[:name])} if names.any?
@@ -43,7 +61,7 @@ module Bukin
43
61
  resource[:group].empty? || (resource[:group] - without).any?
44
62
  end
45
63
  end
46
- raise Bukin::BukinError, "Nothing to install" if resources.empty?
64
+ raise BukinError, "Nothing to install" if resources.empty?
47
65
 
48
66
  resources
49
67
  end
@@ -59,13 +77,13 @@ module Bukin
59
77
  end
60
78
 
61
79
  downloads.each do |provider, datas|
62
- fetching provider do
80
+ fetching_section provider do
63
81
  datas.each do |data|
64
82
  begin
65
83
  version, download = provider.find(data)
66
84
  final_resources << Resource.new(data, version, download)
67
85
  rescue OpenURI::HTTPError => ex
68
- raise Bukin::BukinError,
86
+ raise BukinError,
69
87
  "There was an error fetching information about "\
70
88
  "'#{data[:name]} (#{data[:version]})'.\n"\
71
89
  "#{ex.message}"
@@ -78,15 +96,24 @@ module Bukin
78
96
  end
79
97
 
80
98
  def install_resources(resources)
81
- installer = Bukin::Installer.new(Dir.pwd, true)
99
+ installer = Installer.new(Dir.pwd)
100
+ state = State.new(Dir.pwd)
82
101
 
102
+ # Install new resources
83
103
  resources.each do |resource|
84
- downloading resource.name, resource.version do
104
+ if state.files.installed?(resource.name, resource.version)
105
+ using_section(resource.name, resource.version)
106
+ next
107
+ else
108
+ state.files.delete(resource.name)
109
+ end
110
+
111
+ installing_section resource.name, resource.version do
85
112
  begin
86
113
  installer.install(resource)
87
114
  rescue OpenURI::HTTPError => ex
88
115
  raise(
89
- Bukin::BukinError,
116
+ BukinError,
90
117
  "There was an error installing "\
91
118
  "'#{resource[:name]} (#{resource[:version]})'.\n"\
92
119
  "#{ex.message}"
@@ -94,6 +121,12 @@ module Bukin
94
121
  end
95
122
  end
96
123
  end
124
+
125
+ # Remove old resources
126
+ names = resources.map(&:name)
127
+ state.files.names.each do |name|
128
+ state.files.delete(name) unless names.include?(name)
129
+ end
97
130
  end
98
131
 
99
132
  PROVIDERS = {
@@ -131,13 +164,19 @@ module Bukin
131
164
  raise ex
132
165
  end
133
166
 
134
- def downloading(name, version, &block)
135
- msg = "Downloading #{name}"
167
+ def installing_section(name, version, &block)
168
+ msg = "Installing #{name}"
136
169
  msg << " (#{version})" if version
137
170
  section(msg, &block)
138
171
  end
139
172
 
140
- def fetching(provider, &block)
173
+ def using_section(name, version)
174
+ msg = "Using #{name}"
175
+ msg << " (#{version})" if version
176
+ section(msg) {}
177
+ end
178
+
179
+ def fetching_section(provider, &block)
141
180
  if provider.is_a?(Download)
142
181
  yield
143
182
  else
@@ -1,27 +1,29 @@
1
- require 'bukin/lockfile'
1
+ require 'bukin/state'
2
2
  require 'zip'
3
3
 
4
4
  module Bukin
5
5
  class Installer
6
6
  PATHS = { :server => '.', :plugin => 'plugins' }
7
7
 
8
- def initialize(path, use_lockfile = false)
9
- @lockfile = Bukin::Lockfile.new if use_lockfile
8
+ def initialize(path)
9
+ @state = State.new(path)
10
10
  end
11
11
 
12
12
  def install(resource)
13
13
  path = PATHS[resource.type]
14
- file_names = []
14
+ files = []
15
15
  dl_data, dl_name = download_file(resource.download)
16
16
 
17
17
  if File.extname(dl_name) == '.zip'
18
18
  match = self.get_match(resource[:extract])
19
- file_names = extract_files(dl_data, path, match)
20
- raise Bukin::InstallError, "The resource #{resource.name} (#{resources.version}) has no jar files in it's download (zip file)." if file_names.empty?
19
+ files = extract_files(dl_data, path, match)
20
+ raise InstallError, "The resource #{resource.name} (#{resources.version}) has no jar files in it's download (zip file)." if files.empty?
21
21
  else
22
- save_download(dl_data, dl_name, path)
23
- file_names << dl_name
22
+ files = save_download(dl_data, dl_name, path)
24
23
  end
24
+
25
+ @state.files[resource.name, resource.version] = files
26
+ @state.save
25
27
  end
26
28
 
27
29
  def extract_files(file_data, path, match)
@@ -34,8 +36,9 @@ module Bukin
34
36
  Zip::File.open(tempfile.path) do |zipfile|
35
37
  files = zipfile.find_all {|file| file.name =~ match}
36
38
  files.each do |file|
37
- file.extract(File.join(path, file.name)) { true }
38
- file_names << file.name
39
+ full_path = File.join(path, file.name)
40
+ file.extract(full_path) { true }
41
+ file_names << full_path
39
42
  end
40
43
  end
41
44
  ensure
@@ -47,9 +50,11 @@ module Bukin
47
50
 
48
51
  def save_download(data, name, path)
49
52
  FileUtils.mkdir_p(path)
50
- open("#{path}/#{name}", "wb") do |file|
53
+ full_path = File.join(path, name)
54
+ open(full_path, 'wb') do |file|
51
55
  file.print data
52
56
  end
57
+ [full_path]
53
58
  end
54
59
 
55
60
  def download_file(url, content_disposition = false)
@@ -76,7 +81,7 @@ module Bukin
76
81
  when nil
77
82
  /\.jar$/
78
83
  else
79
- raise Bukin::InstallError, "The extract option #{match} is not valid. Please use a String, Regexp or :all"
84
+ raise InstallError, "The extract option #{match} is not valid. Please use a String, Regexp or :all"
80
85
  end
81
86
  end
82
87
 
@@ -0,0 +1,77 @@
1
+ require 'yaml'
2
+ require 'fileutils'
3
+
4
+ module Bukin
5
+ # State of the current install
6
+ class State
7
+ attr_reader :path, :files
8
+
9
+ def initialize(path = nil)
10
+ path ||= '.'
11
+ @path = File.join(path, '.bukin')
12
+ create_dir
13
+ @files = FileState.new(File.join(@path, 'files.yml'), path)
14
+ end
15
+
16
+ def save
17
+ create_dir
18
+ @files.save
19
+ end
20
+
21
+ private
22
+ def create_dir
23
+ FileUtils.mkdir_p(@path) unless Dir.exist?(@path)
24
+ end
25
+ end
26
+
27
+ class FileState
28
+ def initialize(path, base_path)
29
+ @path = path
30
+ @base_path = base_path
31
+ @files = (File.exist?(@path) ? YAML::load_file(@path) : {})
32
+ end
33
+
34
+ def [](name, version = nil)
35
+ if version
36
+ (@files[name] || {})[version]
37
+ else
38
+ @files[name]
39
+ end
40
+ end
41
+
42
+ def []=(name, version = nil, value)
43
+ if version
44
+ (@files[name] ||= {})[version] = value
45
+ else
46
+ @files[name] = value
47
+ end
48
+ end
49
+
50
+ def installed?(name, version)
51
+ files = self[name, version]
52
+ return false unless files
53
+
54
+ files.all? do |file|
55
+ File.exist?(File.join(@base_path, file))
56
+ end
57
+ end
58
+
59
+ def delete(name)
60
+ (self[name] || {}).each do |version, files|
61
+ files.each do |file|
62
+ FileUtils.rm_r(file) if File.exist?(file)
63
+ end
64
+ end
65
+
66
+ @files.delete(name)
67
+ end
68
+
69
+ def names
70
+ @files.keys
71
+ end
72
+
73
+ def save
74
+ File.open(@path, "w") {|file| file.write @files.to_yaml}
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module Bukin
2
- VERSION = '0.8.0'
2
+ VERSION = '0.9.0'
3
3
  end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'bukin/state'
3
+ require 'fakefs/safe'
4
+ require 'fileutils'
5
+ require 'yaml'
6
+
7
+ describe Bukin::State do
8
+ before(:all) do
9
+ FakeFS.activate!
10
+ @path = Bukin::State.new.path
11
+ end
12
+
13
+ before(:each) {FileUtils.rm_r(@path) if Dir.exist?(@path)}
14
+ after(:all) {FakeFS.deactivate!}
15
+
16
+ it 'assignes a default path if none is provided' do
17
+ state = Bukin::State.new
18
+ state.path.should == @path
19
+ end
20
+
21
+ it 'assignes the path provided in the constructor' do
22
+ state = Bukin::State.new('/test/path')
23
+ state.path.should == '/test/path/.bukin'
24
+ end
25
+
26
+ it 'stores files by their name and version' do
27
+ state = Bukin::State.new
28
+ state.files['worldguard', '1.0.0'] = ['plugins/WorldGuard.jar']
29
+
30
+ state.files['worldguard'].should == { '1.0.0' => ['plugins/WorldGuard.jar'] }
31
+ end
32
+
33
+ it 'saves files to a yaml file' do
34
+ state = Bukin::State.new
35
+ state.files['worldguard', '1.0.0'] = ['plugins/WorldGuard.jar']
36
+ state.save
37
+
38
+ data = YAML::load_file(File.join(state.path,'files.yml'))
39
+ data.should == { 'worldguard' => { '1.0.0' => ['plugins/WorldGuard.jar'] } }
40
+ end
41
+
42
+ it 'loads files from a yaml file' do
43
+ data = { 'worldguard' => { '1.0.0' => ['plugins/WorldGuard.jar'] } }
44
+ FileUtils.mkdir_p(@path)
45
+ File.open(File.join(@path, 'files.yml'), 'w') {|file| file.write data.to_yaml}
46
+
47
+ state = Bukin::State.new
48
+ state.files['worldguard', '1.0.0'].should == ['plugins/WorldGuard.jar']
49
+ end
50
+
51
+ it 'checks for already instaled files' do
52
+ FileUtils.mkdir_p('plugins')
53
+ FileUtils.touch('plugins/WorldGuard.jar')
54
+
55
+ state = Bukin::State.new
56
+ state.files['worldguard', '1.0.0'] = ['plugins/WorldGuard.jar']
57
+
58
+ state.files.installed?('worldguard', '1.0.0').should be_true
59
+ end
60
+
61
+ it 'removes old installed files' do
62
+ FileUtils.mkdir_p('plugins')
63
+ FileUtils.touch('plugins/WorldGuard.jar')
64
+
65
+ state = Bukin::State.new
66
+ state.files['worldguard', '1.0.0'] = ['plugins/WorldGuard.jar']
67
+ state.files.delete('worldguard')
68
+
69
+ File.exist?('plugins/WorldGuard.jar').should be_false
70
+ state.files['worldguard', '1.0.0'].should be_nil
71
+ end
72
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bukin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-23 00:00:00.000000000 Z
12
+ date: 2014-01-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -70,8 +70,8 @@ files:
70
70
  - lib/bukin/file_match.rb
71
71
  - lib/bukin/installer.rb
72
72
  - lib/bukin/jenkins.rb
73
- - lib/bukin/lockfile.rb
74
73
  - lib/bukin/resource.rb
74
+ - lib/bukin/state.rb
75
75
  - lib/bukin/version.rb
76
76
  - spec/bukfile_spec.rb
77
77
  - spec/bukget_spec.rb
@@ -97,8 +97,8 @@ files:
97
97
  - spec/file_match_spec.rb
98
98
  - spec/installer_spec.rb
99
99
  - spec/jenkins_spec.rb
100
- - spec/lockfile_spec.rb
101
100
  - spec/spec_helper.rb
101
+ - spec/state_spec.rb
102
102
  homepage: http://github.com/Nullreff/bukin
103
103
  licenses: []
104
104
  post_install_message:
@@ -148,6 +148,6 @@ test_files:
148
148
  - spec/file_match_spec.rb
149
149
  - spec/installer_spec.rb
150
150
  - spec/jenkins_spec.rb
151
- - spec/lockfile_spec.rb
152
151
  - spec/spec_helper.rb
152
+ - spec/state_spec.rb
153
153
  has_rdoc:
@@ -1,31 +0,0 @@
1
- require 'yaml'
2
-
3
- module Bukin
4
- class Lockfile
5
- FILE_NAME = 'Bukfile.lock'
6
- attr_reader :path
7
-
8
- def initialize(path = nil)
9
- @path = path || File.join(Dir.pwd, FILE_NAME)
10
- @resources = File.exist?(@path) ? YAML::load_file(@path) : {}
11
- @resources = { 'resources' => {} } if @resources['resources'].nil?
12
- end
13
-
14
- def add(data)
15
- name = data[:name]
16
- resources[name] = {
17
- 'version' => data[:version],
18
- 'files' => data[:files]
19
- }
20
- save
21
- end
22
-
23
- def resources
24
- @resources['resources']
25
- end
26
-
27
- def save
28
- File.open(@path, "w") {|file| file.write @resources.to_yaml}
29
- end
30
- end
31
- end
@@ -1,78 +0,0 @@
1
- require 'spec_helper'
2
- require 'bukin'
3
- require 'fakefs/safe'
4
- require 'yaml'
5
-
6
- describe Bukin::Lockfile do
7
- before(:all) do
8
- FakeFS.activate!
9
- @path = File.join(Dir.pwd, Bukin::Lockfile::FILE_NAME)
10
- end
11
-
12
- before(:each) {File.delete(@path) if File.exist?(@path)}
13
- after(:all) {FakeFS.deactivate!}
14
-
15
- it 'assignes a default path if none is provided' do
16
- lockfile = Bukin::Lockfile.new
17
- lockfile.path.should == @path
18
- end
19
-
20
- it 'assignes the path provided in the constructor' do
21
- lockfile = Bukin::Lockfile.new('/test/path')
22
- lockfile.path.should == '/test/path'
23
- end
24
-
25
- it 'loads no resources for an empty or missing file' do
26
- lockfile = Bukin::Lockfile.new('/non/existant/path')
27
- lockfile.resources.should == {}
28
- end
29
-
30
- it 'loads resources from an already existing lockfile' do
31
- resources = { 'resources' => 'value' }
32
-
33
- File.open(@path, 'w') {|file| file.write resources.to_yaml}
34
-
35
- lockfile = Bukin::Lockfile.new
36
- lockfile.resources.should == 'value'
37
- end
38
-
39
- it 'saves resources to a lockfile' do
40
- lockfile = Bukin::Lockfile.new
41
- lockfile.add({
42
- :name => 'resource_name',
43
- :version => '1.0.0',
44
- :files => ['file']
45
- })
46
- lockfile.save
47
-
48
- path = File.join
49
- data = YAML::load_file(@path)
50
- data.should == {
51
- 'resources' => {
52
- 'resource_name' => {
53
- 'version' => '1.0.0',
54
- 'files' => ['file']
55
- }
56
- }
57
- }
58
-
59
- File.delete(@path)
60
- lockfile = Bukin::Lockfile.new
61
- lockfile.resources.should == {}
62
- end
63
-
64
- it 'adds resources to the lockfile' do
65
- lockfile = Bukin::Lockfile.new
66
- lockfile.resources.count.should == 0
67
- lockfile.add({
68
- :name => 'resource_name',
69
- :version => '1.0.0',
70
- :files => ['file1', 'file2']
71
- })
72
- lockfile.resources.count.should == 1
73
- lockfile.resources['resource_name'].should == {
74
- 'version' => '1.0.0',
75
- 'files' => ['file1', 'file2']
76
- }
77
- end
78
- end