box-release 0.0.1

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