bukin 0.8.0 → 0.9.0

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