box-release 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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ log/*
2
+ coverage/*
3
+ *~
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in box-release.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ box-release (0.0.1)
5
+ activesupport
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activesupport (3.0.7)
11
+ diff-lcs (1.1.2)
12
+ rcov (0.9.9)
13
+ rspec (2.5.0)
14
+ rspec-core (~> 2.5.0)
15
+ rspec-expectations (~> 2.5.0)
16
+ rspec-mocks (~> 2.5.0)
17
+ rspec-core (2.5.1)
18
+ rspec-expectations (2.5.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.5.0)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ box-release!
27
+ rcov
28
+ rspec
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ Dir['tasks/**/*.rake'].each { |t| load t }
5
+
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/bin/box-release ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'box/release'
4
+ require 'box/release/cli'
5
+
6
+ begin
7
+ Box::Release::CLI.new(ARGV).validate!.upgrade
8
+ rescue => e
9
+ Box::Release.logger.error e.to_s
10
+ raise e
11
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "box/release/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "box-release"
7
+ s.version = Box::Release::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Alban Peignier", "Florent Peyraud"]
10
+ s.email = ["alban@tryphon.eu", "florent@tryphon.eu"]
11
+ s.homepage = "http://projects.tryphon.eu/box-release"
12
+ s.summary = %q{Check, download and install Tryphon boxes releases}
13
+ s.description = %q{}
14
+
15
+ s.rubyforge_project = "box-release"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency("activesupport")
23
+
24
+ s.add_development_dependency('rspec')
25
+ s.add_development_dependency('rcov')
26
+ end
@@ -0,0 +1,195 @@
1
+ require 'box/release/downloader'
2
+ require 'digest'
3
+ require 'tempfile'
4
+
5
+ module Box
6
+ module Release
7
+ module Base
8
+
9
+ # after_save :change_current
10
+
11
+ # def after_initialize
12
+ # self.status_updated_at ||= Time.now
13
+ # self.status ||= :available
14
+ # end
15
+
16
+ # @@latest_url = nil
17
+ # cattr_accessor :latest_url
18
+
19
+ # def self.check_latest
20
+ # Loader.save_release_at(latest_url) do |release|
21
+ # release.status = :available
22
+ # release.newer?(last)
23
+ # end
24
+ # end
25
+
26
+ # @@current_url = nil
27
+ # cattr_accessor :current_url
28
+
29
+ # def self.check_current
30
+ # Loader.save_release_at(current_url) do |release|
31
+ # release.status = :installed
32
+ # true
33
+ # end
34
+ # end
35
+
36
+ # def self.check
37
+ # check_current
38
+ # check_latest
39
+ # end
40
+
41
+ # def self.latest
42
+ # latest = last
43
+ # latest.reset_download_status if latest and latest.newer?(current)
44
+ # end
45
+
46
+ # def self.current
47
+ # find_by_status("installed")
48
+ # end
49
+
50
+ # def human_name
51
+ # name.gsub("_"," ").capitalize.gsub("box","Box")
52
+ # end
53
+
54
+ # def status
55
+ # status = read_attribute :status
56
+ # status ? ActiveSupport::StringInquirer.new(status) : nil
57
+ # end
58
+
59
+ # def status=(status, update_timestamp = true)
60
+ # write_attribute :status, status ? status.to_s : nil
61
+ # self.status_updated_at = Time.now unless new_record?
62
+ # end
63
+
64
+ def file
65
+ "/tmp/release.tar"
66
+ end
67
+
68
+ def newer?(other)
69
+ other.nil? or (self.name and self.name > other.name)
70
+ end
71
+
72
+ # def presenter
73
+ # @presenter ||= ReleasePresenter.new self
74
+ # end
75
+
76
+ def download
77
+ logger.info "Download #{url} into #{file}"
78
+ # return if self.status.downloaded?
79
+
80
+ # update_attribute :status, :download_pending
81
+
82
+ File.open(file, "w") do |file|
83
+ Box::Release::Downloader.open(url) do |data, download_size, url_size|
84
+ file.write data
85
+
86
+ # self.url_size ||= url_size
87
+ # self.download_size = download_size
88
+ # save! if 10.seconds.ago > self.updated_at
89
+ end
90
+ end
91
+
92
+ raise "Invalid checksum after download" unless valid_checksum?
93
+ # self.status = :downloaded
94
+ ensure
95
+ # self.status = :download_failed unless self.status.downloaded?
96
+ # save!
97
+ end
98
+
99
+ # def reset_download_status
100
+ # if %w{download_pending downloaded}.include?(status) and
101
+ # status_updated_at < 30.seconds.ago and
102
+ # not file_exists?
103
+
104
+ # update_attributes :status => :download_failed, :url_size => nil, :download_size => nil
105
+ # end
106
+
107
+ # self
108
+ # end
109
+
110
+ def install(options = {})
111
+ options = {
112
+ :install_command => install_command
113
+ }.merge(options)
114
+
115
+ logger.info "Install #{name}"
116
+ Box::Release.execute! "#{options[:install_command]} #{file} #{yaml_file}"
117
+ end
118
+
119
+ def yaml_file
120
+ @yaml_file ||= Tempfile.new("release").tap do |yaml_file|
121
+ begin
122
+ yaml_file.write to_yaml
123
+ ensure
124
+ yaml_file.close
125
+ end
126
+ end
127
+
128
+ @yaml_file.path
129
+ end
130
+
131
+ def valid_checksum?
132
+ checksum.nil? or checksum == file_checksum
133
+ end
134
+
135
+ def file_checksum
136
+ Digest::SHA256.file(file).hexdigest if file_exists?
137
+ end
138
+
139
+ def file_exists?
140
+ File.exists?(file)
141
+ end
142
+
143
+ def to_yaml
144
+ { "name" => name, "description_url" => description_url, "status_updated_at" => status_updated_at }.to_yaml
145
+ end
146
+
147
+ # def change_current
148
+ # return unless status.installed?
149
+
150
+ # (Release.find_all_by_status("installed") - [self]).each do |old_release|
151
+ # old_release.update_attribute :status, :old
152
+ # end
153
+ # end
154
+
155
+ # class Loader
156
+
157
+ # attr_reader :url
158
+
159
+ # def initialize(url)
160
+ # @url = url
161
+ # end
162
+
163
+ # def self.release_at(url)
164
+ # new(url).release if url
165
+ # end
166
+
167
+ # def self.save_release_at(url)
168
+ # if release = release_at(url)
169
+ # release.save unless block_given? and not yield release
170
+ # end
171
+ # end
172
+
173
+ # def attributes
174
+ # @attributes ||= YAML.load open(url,&:read)
175
+ # rescue => e
176
+ # Rails.logger.error "Can't load attributes from #{url} : #{e}"
177
+ # {}
178
+ # end
179
+
180
+ # def supported_attributes
181
+ # attributes.reject do |attribute, _|
182
+ # not Release.column_names.include? attribute.to_s
183
+ # end
184
+ # end
185
+
186
+ # def release
187
+ # Release.find_or_create_by_name supported_attributes["name"], supported_attributes
188
+ # end
189
+
190
+ # end
191
+
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,89 @@
1
+ require 'optparse'
2
+
3
+ module Box
4
+ module Release
5
+ class CLI
6
+
7
+ attr_accessor :url, :current_definition, :install_command, :before_download_command
8
+
9
+ def initialize(arguments = [])
10
+ @install_command = "/usr/local/sbin/box-upgrade"
11
+
12
+ parse_options(arguments)
13
+ end
14
+
15
+ def usage(output = $stdout)
16
+ output.puts option_parser
17
+ end
18
+
19
+ def option_parser
20
+ @option_parser ||= OptionParser.new do |options|
21
+ options.banner = <<-BANNER.gsub(/^ /,'')
22
+ Box Release CLI : update your box in command line
23
+
24
+ Usage: #{File.basename($0)} [options]
25
+
26
+ Options are:
27
+ BANNER
28
+ options.separator ""
29
+ options.on("-c", "--current=file/name", String,
30
+ "The current.yml file or the current name") { |arg| self.current_definition = arg }
31
+ options.on("-i", "--install=command", String,
32
+ "The install command used to install the release") { |arg| self.install_command = arg }
33
+ options.on("-b", "--before-download=command", String,
34
+ "The command executed before download starts") { |arg| self.before_download_command = arg }
35
+ end
36
+ end
37
+
38
+ def parse_options(arguments)
39
+ option_parser.parse!(arguments)
40
+ @url = arguments.shift
41
+ end
42
+
43
+ def latest
44
+ @latest ||= Box::Release::Loader.release_at url
45
+ end
46
+
47
+ def current
48
+ @current ||=
49
+ if File.exists?(current_definition)
50
+ Box::Release::Loader.release_at current_definition
51
+ else
52
+ Box::Release::Memory.new :name => current_definition
53
+ end
54
+ end
55
+
56
+ def valid?
57
+ current_definition
58
+ end
59
+
60
+ def validate!(output = $stdout)
61
+ unless valid?
62
+ usage(output)
63
+ exit 1
64
+ end
65
+
66
+ self
67
+ end
68
+
69
+ def before_download
70
+ Box::Release.execute! before_download_command if before_download_command
71
+ end
72
+
73
+ def upgrade
74
+ if latest and latest.newer?(current)
75
+ Box::Release.logger.info "New release : #{latest}"
76
+ before_download
77
+ latest.download
78
+ Box::Release.logger.info "Replace #{current} with #{latest}"
79
+ latest.install :install_command => install_command
80
+ Box::Release.logger.info "Successfully installed #{latest}"
81
+ else
82
+ Box::Release.logger.info "Keep current release : #{current} (latest is #{latest})"
83
+ false
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,74 @@
1
+ require 'net/http'
2
+
3
+ module Box
4
+ module Release
5
+ class Downloader
6
+
7
+ attr_reader :url
8
+
9
+ def initialize(url)
10
+ @url = URI.parse url
11
+ end
12
+
13
+ def self.open(url, &block)
14
+ new(url).open(&block)
15
+ end
16
+
17
+ def open(&block)
18
+ if url.scheme == "http"
19
+ open_http &block
20
+ else
21
+ open_file &block
22
+ end
23
+ end
24
+
25
+ def open_file(&block)
26
+ content_length = File.size(url.path)
27
+ File.open(url.path, "r") do |file|
28
+ downloaded_size = 0
29
+ while data = file.read(1024)
30
+ downloaded_size += data.size
31
+ yield data, downloaded_size, content_length
32
+ end
33
+ end
34
+ end
35
+
36
+ def open_http(&block)
37
+ send_request do |response|
38
+ content_length = nil
39
+ if response.key?('Content-Length')
40
+ content_length = response['Content-Length'].to_i
41
+ end
42
+
43
+ downloaded_size = 0
44
+ response.read_body do |data|
45
+ downloaded_size += data.size
46
+ yield data, downloaded_size, content_length
47
+ end
48
+ end
49
+ end
50
+
51
+ def send_request(target = url, redirection_count = 0, &block)
52
+ raise "Too many redirections, last one was #{target}" if redirection_count > 10
53
+
54
+ Net::HTTP.start(target.host, target.port) do |http|
55
+ request = Net::HTTP::Get.new target.path
56
+ http.request(request) do |response|
57
+ case response
58
+ when Net::HTTPSuccess
59
+ yield response
60
+ when Net::HTTPMovedPermanently, # 301
61
+ Net::HTTPFound, # 302
62
+ Net::HTTPSeeOther, # 303
63
+ Net::HTTPTemporaryRedirect # 307
64
+ send_request URI.parse(response['location']), redirection_count+1, &block
65
+ else
66
+ response.error!
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,31 @@
1
+ require 'yaml'
2
+ require 'open-uri'
3
+
4
+ module Box
5
+ module Release
6
+ class Loader
7
+
8
+ attr_reader :url
9
+
10
+ def initialize(url)
11
+ @url = url
12
+ end
13
+
14
+ def self.release_at(url)
15
+ new(url).release if url
16
+ end
17
+
18
+ def attributes
19
+ @attributes ||= YAML.load open(url,&:read)
20
+ rescue => e
21
+ Box::Release.logger.error "Can't load attributes from #{url} : #{e}"
22
+ {}
23
+ end
24
+
25
+ def release
26
+ Box::Release::Memory.new attributes
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'box/release/base'
2
+ #require 'active_support/string_inquirer'
3
+
4
+ module Box
5
+ module Release
6
+ class Memory
7
+ include Box::Release::Base
8
+
9
+ def initialize(attributes = {})
10
+ attributes.each_pair do |k,v|
11
+ send "#{k}=", v
12
+ end
13
+ end
14
+
15
+ attr_accessor :name, :description_url, :status_updated_at
16
+ attr_accessor :url, :checksum
17
+
18
+ def to_s
19
+ name
20
+ end
21
+
22
+ def logger
23
+ Box::Release.logger
24
+ end
25
+
26
+ def install_command
27
+ Box::Release.install_command
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module Box
2
+ module Release
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,48 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'logger'
3
+
4
+ begin
5
+ require 'syslog_logger'
6
+ rescue LoadError
7
+ $stderr.puts "SyslogLogger isn't available"
8
+ end
9
+
10
+ module Box
11
+ module Release
12
+
13
+ def self.default_logger
14
+ if defined?(SyslogLogger)
15
+ SyslogLogger.new("box-release")
16
+ else
17
+ Logger.new($stdout)
18
+ end
19
+ end
20
+
21
+ @@logger = default_logger
22
+ mattr_accessor :logger
23
+
24
+ @@install_command = nil
25
+ mattr_accessor :install_command
26
+
27
+ class ExecutionError < StandardError; end
28
+
29
+ def self.execute!(command)
30
+ logger.debug "execute '#{command}'"
31
+ output = `#{command} 2>&1`
32
+ logger.debug output unless output.empty?
33
+
34
+ if $? != 0
35
+ raise ExecutionError.new("Command failed: #{command} (error code #{$?})")
36
+ end
37
+
38
+ true
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ require 'box/release/loader'
45
+ require 'box/release/downloader'
46
+ require 'box/release/base'
47
+ require 'box/release/memory'
48
+
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ require 'fileutils'
4
+
5
+ describe Box::Release::Base do
6
+
7
+ let(:update_tar) { File.expand_path "../../../fixtures/box-update-20100421-0846.tar", __FILE__ }
8
+
9
+ subject { Box::Release::Memory.new }
10
+
11
+ its(:file) { should == "/tmp/release.tar" }
12
+
13
+ describe "download" do
14
+
15
+ before(:each) do
16
+ FileUtils.rm_f(subject.file)
17
+ end
18
+
19
+ it "should download a local file" do
20
+ subject.url = __FILE__
21
+ subject.download
22
+ IO.read(subject.file).should == IO.read(__FILE__)
23
+ end
24
+
25
+ it "should raise an error if checksum is invalid" do
26
+ subject.stub :valid_checksum? => false
27
+ lambda { subject.download }.should raise_error
28
+ end
29
+
30
+ end
31
+
32
+ describe "valid_checksum? " do
33
+
34
+ before(:each) do
35
+ subject.stub :file => update_tar
36
+ end
37
+
38
+ it "should return true if checksum is SHA256 digest of downloaded file" do
39
+ subject.checksum = "9eeb495a5b273c7dd88aa8dd741df8ecf10b5a34c422b0fe6b7a1b053a518369"
40
+ subject.should be_valid_checksum
41
+ end
42
+
43
+ it "should return false if checksum is not the SHA256 digest of downloaded file" do
44
+ subject.checksum = "dummy"
45
+ subject.should_not be_valid_checksum
46
+ end
47
+
48
+ it "should return true if checksum is nil" do
49
+ subject.checksum = nil
50
+ subject.should be_valid_checksum
51
+ end
52
+
53
+ it "should return false if download file isn't found" do
54
+ subject.checksum = "dummy"
55
+ subject.stub!(:file_checksum)
56
+ subject.should_not be_valid_checksum
57
+ end
58
+
59
+ end
60
+
61
+ describe "to_yaml" do
62
+
63
+ def self.it_shoud_include(attribute)
64
+ attribute = attribute.to_s
65
+ it "should the Release #{attribute}" do
66
+ subject.send("#{attribute}=", "dummy")
67
+ YAML.load(subject.to_yaml).should include(attribute => "dummy")
68
+ end
69
+ end
70
+
71
+ it_shoud_include :name
72
+ it_shoud_include :description_url
73
+ it_shoud_include :status_updated_at
74
+
75
+ end
76
+
77
+ describe "yaml_file" do
78
+
79
+ it "should return the path of a file which contains Release#to_yaml" do
80
+ subject.stub :to_yaml => "to_yaml"
81
+ IO.read(subject.yaml_file).should == "to_yaml"
82
+ end
83
+
84
+ end
85
+
86
+ describe "#install" do
87
+
88
+ before(:each) do
89
+ subject.stub :yaml_file => "/path/to/tempfile"
90
+ end
91
+
92
+ it "should execute install command with release file and temp file (with attributes) in argument" do
93
+ subject.stub :install_command => "/usr/bin/dummy", :file => "/tmp/test.tar"
94
+ Box::Release.should_receive(:execute!).with("/usr/bin/dummy /tmp/test.tar /path/to/tempfile").and_return(true)
95
+ subject.install
96
+ end
97
+
98
+ end
99
+
100
+ describe '#newer? ' do
101
+
102
+ it "should be true when other release is nil" do
103
+ subject.should be_newer(nil)
104
+ end
105
+
106
+ it "should be true when name is greather than the other one" do
107
+ subject.name = "version-2"
108
+ subject.should be_newer(stub(:name => "version-1"))
109
+ end
110
+
111
+ it "should be false when name is nil" do
112
+ subject.name = nil
113
+ subject.should_not be_newer(stub(:name => "version-1"))
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,235 @@
1
+ require 'spec_helper'
2
+
3
+ require 'box/release/cli'
4
+
5
+ describe Box::Release::CLI do
6
+
7
+ describe "#current_definition" do
8
+
9
+ it "should be nil by default" do
10
+ subject.current_definition.should be_nil
11
+ end
12
+
13
+ it "should be the value specified with --current" do
14
+ subject.parse_options %w{--current dummy}
15
+ subject.current_definition.should == "dummy"
16
+ end
17
+
18
+ end
19
+
20
+ describe "#install_command" do
21
+
22
+ it "should be /usr/local/sbin/box-upgrade by default" do
23
+ subject.install_command.should == "/usr/local/sbin/box-upgrade"
24
+ end
25
+
26
+ it "should use the value specified with --install" do
27
+ subject.parse_options %w{--install dummy}
28
+ subject.install_command.should == "dummy"
29
+ end
30
+
31
+ end
32
+
33
+ describe "#url" do
34
+
35
+ it "should be nil by default" do
36
+ subject.url.should be_nil
37
+ end
38
+
39
+ it "should use the valud specified in argument (after options)" do
40
+ subject.parse_options %w{dummy}
41
+ subject.url.should == "dummy"
42
+ end
43
+
44
+ end
45
+
46
+ describe "#before_download_command" do
47
+
48
+ it "should be nil by default" do
49
+ subject.before_download_command.should be_nil
50
+ end
51
+
52
+ it "should use the valud specified with --before-download" do
53
+ subject.parse_options %w{--before-download dummy}
54
+ subject.before_download_command.should == "dummy"
55
+ end
56
+
57
+ end
58
+
59
+ describe "#valid?" do
60
+
61
+ subject {
62
+ Box::Release::CLI.new.tap do |cli|
63
+ cli.current_definition = "dummy"
64
+ end
65
+ }
66
+
67
+ it "should be true when current_definition is nil" do
68
+ subject.current_definition = nil
69
+ subject.should_not be_valid
70
+ end
71
+
72
+ end
73
+
74
+ describe "validate!" do
75
+
76
+ before(:each) do
77
+ subject.stub :exit => true
78
+ end
79
+
80
+ context "when valid" do
81
+
82
+ before(:each) do
83
+ subject.stub :valid? => true
84
+ end
85
+
86
+ it "should return the CLI instance" do
87
+ subject.validate!.should == subject
88
+ end
89
+
90
+ end
91
+
92
+ context "when invalid" do
93
+
94
+ before(:each) do
95
+ subject.stub :valid? => false
96
+ end
97
+
98
+ it "should display usage" do
99
+ subject.should_receive(:usage)
100
+ subject.validate!
101
+ end
102
+
103
+ it "should exit with code 1" do
104
+ subject.should_receive(:exit).with(1)
105
+ subject.validate!(StringIO.new)
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+
112
+ describe "#latest" do
113
+
114
+ before(:each) do
115
+ subject.url = given_url
116
+ end
117
+
118
+ let(:given_url) { "given_url" }
119
+ let(:loaded_release) { mock(Box::Release::Memory) }
120
+
121
+ it "should load release described by the given url" do
122
+ Box::Release::Loader.should_receive(:release_at).with(given_url).and_return(loaded_release)
123
+ subject.latest.should == loaded_release
124
+ end
125
+
126
+ end
127
+
128
+ describe "current" do
129
+
130
+ context "when current_defintion is a existing file" do
131
+
132
+ before(:each) do
133
+ subject.current_definition = existing_file
134
+ end
135
+
136
+ let(:existing_file) { File.expand_path("../../../fixtures/current.yml", __FILE__) }
137
+ let(:loaded_release) { mock(Box::Release::Memory) }
138
+
139
+ it "should load release described by the given file" do
140
+ Box::Release::Loader.should_receive(:release_at).with(subject.current_definition).and_return(loaded_release)
141
+ subject.current.should == loaded_release
142
+ end
143
+
144
+ end
145
+
146
+ context "when current_definition is an existing file" do
147
+
148
+ before(:each) do
149
+ subject.current_definition = "dummy"
150
+ end
151
+
152
+ it "should create a Box::Release with the given name" do
153
+ subject.current.name.should == "dummy"
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+
160
+ describe "upgrade" do
161
+
162
+ before(:each) do
163
+ subject.current_definition = "dummy"
164
+ end
165
+
166
+ context "when latest release can't be loaded" do
167
+
168
+ before(:each) do
169
+ subject.stub :latest => nil
170
+ end
171
+
172
+ it "should return false" do
173
+ subject.upgrade.should be_false
174
+ end
175
+
176
+ end
177
+
178
+ context "when latest release isn't newer than current" do
179
+
180
+ before(:each) do
181
+ subject.stub :latest => mock(:newer? => false)
182
+ end
183
+
184
+ it "should return false" do
185
+ subject.upgrade.should be_false
186
+ end
187
+
188
+ end
189
+
190
+ context "when latest release is new than current" do
191
+
192
+ before(:each) do
193
+ subject.stub :latest => latest
194
+ end
195
+
196
+ let(:latest) { mock :name => "latest", :newer? => true, :download => true, :install => true }
197
+
198
+ it "should invoke before_download ... before downloading latest release" do
199
+ subject.should_receive(:before_download).ordered
200
+ subject.latest.should_receive(:download).ordered
201
+ subject.upgrade
202
+ end
203
+
204
+ it "should download the latest release" do
205
+ subject.latest.should_receive(:download)
206
+ subject.upgrade
207
+ end
208
+
209
+ it "should install the latest release (after downloading it ...)" do
210
+ subject.latest.should_receive(:download).ordered
211
+ subject.latest.should_receive(:install).ordered
212
+ subject.upgrade
213
+ end
214
+
215
+ it "should install by using the given install_command" do
216
+ subject.install_command = "dummy"
217
+ subject.latest.should_receive(:install).with(:install_command => subject.install_command)
218
+ subject.upgrade
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+
225
+ describe "before_download" do
226
+
227
+ it "should execute the before_download_command if given" do
228
+ subject.before_download_command = "dummy"
229
+ Box::Release.should_receive(:execute!).with("dummy")
230
+ subject.before_download
231
+ end
232
+
233
+ end
234
+
235
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ require 'box/release/loader'
4
+
5
+ describe Box::Release::Loader do
6
+
7
+ describe "#attributes" do
8
+
9
+ let(:loader) { Box::Release::Loader.new("dummy") }
10
+
11
+ it "should load attributes found in url" do
12
+ Tempfile.open("release-loader") do |file|
13
+ file.puts "dummy: true"
14
+ file.close
15
+
16
+ Box::Release::Loader.new(file.path).attributes.should == { "dummy" => true }
17
+ end
18
+ end
19
+
20
+ it "should be empty if url isn't reachable" do
21
+ loader.stub(:open).and_raise(SocketError)
22
+ loader.attributes.should be_empty
23
+ end
24
+
25
+ end
26
+
27
+ describe "#release" do
28
+
29
+ let(:loader) { Box::Release::Loader.new("dummy") }
30
+
31
+ it "should create a new Release with attributes" do
32
+ loader.stub :attributes => { "checksum" => "dummy" }
33
+ loader.release.checksum.should == "dummy"
34
+ end
35
+
36
+ end
37
+
38
+ describe ".release_at" do
39
+
40
+ let(:url) { "dummy://url" }
41
+ let(:loaded_release) { Box::Release::Memory.new }
42
+
43
+ it "should create a new Loader and load release" do
44
+ Box::Release::Loader.should_receive(:new).with(url).and_return(stub(:release => loaded_release))
45
+ Box::Release::Loader.release_at(url).should == loaded_release
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Box::Release::Memory do
4
+
5
+
6
+
7
+
8
+ end
@@ -0,0 +1,3 @@
1
+ name: playbox-20100414-1224
2
+ status_updated_at: 2010-04-15 08:25:34
3
+ description_url: http://www.tryphon.eu/blog/playbox-20100414-1224
@@ -0,0 +1,5 @@
1
+ name: playbox-20110424-1616
2
+ url: spec/fixtures/box-update-20100421-0846.tar
3
+ checksum: 9eeb495a5b273c7dd88aa8dd741df8ecf10b5a34c422b0fe6b7a1b053a518369
4
+ status_updated_at: Sun Apr 24 16:19:08 +0200 2011
5
+ description_url: http://www.tryphon.eu/release/playbox-20110424-1616
data/spec/rcov.opts ADDED
@@ -0,0 +1,2 @@
1
+ --exclude "spec/*,gems/*"
2
+ --rails
@@ -0,0 +1,14 @@
1
+ require 'rspec'
2
+
3
+ require 'box/release'
4
+
5
+ RSpec.configure do |config|
6
+
7
+ config.before(:suite) do
8
+ FileUtils.mkdir_p "log"
9
+ Box::Release.logger = Logger.new("log/test.log")
10
+ end
11
+
12
+ end
13
+
14
+
data/tasks/rspec.rake ADDED
@@ -0,0 +1,36 @@
1
+ begin
2
+ require 'rspec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ require 'rspec'
6
+ end
7
+
8
+ begin
9
+ require 'rspec/core/rake_task'
10
+ rescue LoadError
11
+ puts <<-EOS
12
+ To use rspec for testing you must install rspec gem:
13
+ gem install rspec
14
+ EOS
15
+ exit(0)
16
+ end
17
+
18
+ desc "Run the specs under spec"
19
+ RSpec::Core::RakeTask.new do |t|
20
+ t.pattern = 'spec/**/*_spec.rb'
21
+ end
22
+
23
+ namespace :spec do
24
+ desc "Run all specs in spec directory with RCov (excluding plugin specs)"
25
+ RSpec::Core::RakeTask.new(:rcov) do |t|
26
+ t.rcov = true
27
+ t.pattern = "./spec/**/*_spec.rb"
28
+ t.rcov_opts = '--exclude /gems/,/Library/,/usr/,lib/tasks,.bundle,config,/lib/rspec/,/lib/rspec-,spec/*'
29
+ end
30
+
31
+ desc "Print Specdoc for all specs (excluding plugin specs)"
32
+ RSpec::Core::RakeTask.new(:doc) do |t|
33
+ t.rspec_opts = ["--format", "specdoc", "--dry-run"]
34
+ t.pattern = "./spec/**/*_spec.rb"
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: box-release
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Alban Peignier
14
+ - Florent Peyraud
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-05-10 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rcov
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ description: ""
64
+ email:
65
+ - alban@tryphon.eu
66
+ - florent@tryphon.eu
67
+ executables:
68
+ - box-release
69
+ extensions: []
70
+
71
+ extra_rdoc_files: []
72
+
73
+ files:
74
+ - .gitignore
75
+ - Gemfile
76
+ - Gemfile.lock
77
+ - Rakefile
78
+ - autotest/discover.rb
79
+ - bin/box-release
80
+ - box-release.gemspec
81
+ - lib/box/release.rb
82
+ - lib/box/release/base.rb
83
+ - lib/box/release/cli.rb
84
+ - lib/box/release/downloader.rb
85
+ - lib/box/release/loader.rb
86
+ - lib/box/release/memory.rb
87
+ - lib/box/release/version.rb
88
+ - spec/box/release/base_spec.rb
89
+ - spec/box/release/cli_spec.rb
90
+ - spec/box/release/loader_spec.rb
91
+ - spec/box/release/memory_spec.rb
92
+ - spec/fixtures/box-update-20100421-0846.tar
93
+ - spec/fixtures/current.yml
94
+ - spec/fixtures/latest.yml
95
+ - spec/rcov.opts
96
+ - spec/spec_helper.rb
97
+ - tasks/rspec.rake
98
+ homepage: http://projects.tryphon.eu/box-release
99
+ licenses: []
100
+
101
+ post_install_message:
102
+ rdoc_options: []
103
+
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ hash: 3
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ requirements: []
125
+
126
+ rubyforge_project: box-release
127
+ rubygems_version: 1.7.2
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: Check, download and install Tryphon boxes releases
131
+ test_files:
132
+ - spec/box/release/base_spec.rb
133
+ - spec/box/release/cli_spec.rb
134
+ - spec/box/release/loader_spec.rb
135
+ - spec/box/release/memory_spec.rb
136
+ - spec/fixtures/box-update-20100421-0846.tar
137
+ - spec/fixtures/current.yml
138
+ - spec/fixtures/latest.yml
139
+ - spec/rcov.opts
140
+ - spec/spec_helper.rb