furoshiki 0.0.2 → 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Gemfile +9 -0
- data/README.rdoc +33 -28
- data/Rakefile +3 -1
- data/furoshiki.gemspec +2 -1
- data/lib/furoshiki/exceptions.rb +3 -0
- data/lib/furoshiki/shoes/configuration.rb +146 -0
- data/lib/furoshiki/shoes/swt_app.rb +217 -0
- data/lib/furoshiki/shoes/swt_jar.rb +62 -0
- data/lib/furoshiki/shoes.rb +15 -0
- data/lib/furoshiki/version.rb +1 -1
- data/lib/furoshiki/zip/directory.rb +19 -0
- data/lib/furoshiki/zip/directory_contents.rb +20 -0
- data/lib/furoshiki/zip/recursive.rb +58 -0
- data/lib/furoshiki/zip.rb +2 -0
- data/lib/furoshiki.rb +3 -1
- data/lib/warbler/traits/shoes.rb +51 -0
- data/spec/shoes/configuration_spec.rb +156 -0
- data/spec/shoes/spec_helper.rb +68 -0
- data/spec/shoes/support/shared_config.rb +6 -0
- data/spec/shoes/swt_app_spec.rb +119 -0
- data/spec/shoes/swt_jar_spec.rb +45 -0
- data/spec/shoes/test_app/app.yaml +17 -0
- data/spec/shoes/test_app/bin/hello_world +3 -0
- data/spec/shoes/test_app/dir_to_ignore/file_to_ignore.txt +1 -0
- data/spec/shoes/test_app/img/boots.icns +0 -0
- data/spec/shoes/test_app/img/boots.ico +0 -0
- data/spec/shoes/test_app/img/boots_512x512x32.png +0 -0
- data/spec/shoes/test_app/sibling.rb +1 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/shared_zip.rb +21 -0
- data/spec/support/zip/a/a.rb +3 -0
- data/spec/support/zip/a/b/b.png +0 -0
- data/spec/support/zip/a/b/c/c.rb +3 -0
- data/spec/zip/directory_contents_spec.rb +25 -0
- data/spec/zip/directory_spec.rb +30 -0
- data/vendor/appbundler-1.0.jar +0 -0
- metadata +103 -47
- data/.rvmrc +0 -1
- data/Gemfile.lock +0 -7
- data/lib/furoshiki/rake_task.rb +0 -19
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'zip/zip'
|
3
|
+
|
4
|
+
module Furoshiki
|
5
|
+
module Zip
|
6
|
+
# Adapted from rubyzip's sample, ZipFileGenerator
|
7
|
+
#
|
8
|
+
# This is a utility class that uses rubyzip to recursively
|
9
|
+
# generate a zip file containing the given entries and all of
|
10
|
+
# their children.
|
11
|
+
#
|
12
|
+
# Best used through frontend classes Furoshiki::Zip::Directory or
|
13
|
+
# Furoshiki::Zip::DirectoryContents
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# To zip the directory "/tmp/input" so that unarchiving
|
17
|
+
# gives you a single directory "input":
|
18
|
+
#
|
19
|
+
# zip = Furoshiki::Zip::Recursive
|
20
|
+
# entries = Pathname.new("/tmp/input").entries
|
21
|
+
# zip_prefix = ''
|
22
|
+
# disk_prefix = '/tmp'
|
23
|
+
# output_file = '/tmp/out.zip'
|
24
|
+
# zf.write(entries, disk_prefix, zip_prefix, output_file)
|
25
|
+
class Recursive
|
26
|
+
def initialize(output_file)
|
27
|
+
@output_file = output_file.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [Array<Pathname>] entries the initial set of files to include
|
31
|
+
# @param [Pathname] disk_prefix a path prefix for existing entries
|
32
|
+
# @param [Pathname] zip_prefix a path prefix to add within archive
|
33
|
+
# @param [Pathname] output_file the location of the output archive
|
34
|
+
def write(entries, disk_prefix, zip_prefix)
|
35
|
+
io = ::Zip::ZipFile.open(@output_file, ::Zip::ZipFile::CREATE);
|
36
|
+
write_entries(entries, disk_prefix, zip_prefix, io)
|
37
|
+
io.close();
|
38
|
+
end
|
39
|
+
|
40
|
+
# A helper method to make the recursion work.
|
41
|
+
private
|
42
|
+
def write_entries(entries, disk_prefix, path, io)
|
43
|
+
entries.each do |e|
|
44
|
+
zip_path = path.to_s == "" ? e.basename : path.join(e.basename)
|
45
|
+
disk_path = disk_prefix.join(zip_path)
|
46
|
+
puts "Deflating #{disk_path}"
|
47
|
+
if disk_path.directory?
|
48
|
+
io.mkdir(zip_path)
|
49
|
+
subdir = disk_path.children(false)
|
50
|
+
write_entries(subdir, disk_prefix, zip_path, io)
|
51
|
+
else
|
52
|
+
io.get_output_stream(zip_path) { |f| f.puts(File.open(disk_path, "rb").read())}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/furoshiki.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'furoshiki/shoes/configuration'
|
2
|
+
|
3
|
+
module Warbler
|
4
|
+
module Traits
|
5
|
+
# Hack to control the executable
|
6
|
+
class NoGemspec
|
7
|
+
def update_archive(jar); end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Shoes
|
11
|
+
include Trait
|
12
|
+
include PathmapHelper
|
13
|
+
|
14
|
+
def self.detect?
|
15
|
+
#File.exist? "app.yaml"
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.requires?(trait)
|
20
|
+
# Actually, it would be better to dump the NoGemspec trait, but since
|
21
|
+
# we can't do that, we can at least make sure that this trait gets
|
22
|
+
# processed later by declaring that it requires NoGemspec.
|
23
|
+
[Traits::Jar, Traits::NoGemspec].include? trait
|
24
|
+
end
|
25
|
+
|
26
|
+
def after_configure
|
27
|
+
config.init_contents << StringIO.new("require 'shoes'\nShoes.configuration.backend = :swt\n")
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_archive(jar)
|
31
|
+
# Not sure why Warbler doesn't do this automatically
|
32
|
+
jar.files.delete_if { |k, v| @config.excludes.include? k }
|
33
|
+
add_main_rb(jar, apply_pathmaps(config, default_executable, :application))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Uses the `@config.run` if it exists. Otherwise, looks in the
|
37
|
+
# application's `bin` directory for an executable with the same name as
|
38
|
+
# the jar. If this also fails, defaults to the first executable (alphabetically) in the
|
39
|
+
# applications `bin` directory.
|
40
|
+
#
|
41
|
+
# @return [String] filename of the executable to run
|
42
|
+
def default_executable
|
43
|
+
return @config.run if @config.run
|
44
|
+
exes = Dir['bin/*'].sort
|
45
|
+
exe = exes.grep(/#{config.jar_name}/).first || exes.first
|
46
|
+
raise "No executable script found" unless exe
|
47
|
+
exe
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'furoshiki/shoes/configuration'
|
3
|
+
|
4
|
+
describe Furoshiki::Shoes::Configuration do
|
5
|
+
context "defaults" do
|
6
|
+
subject { Furoshiki::Shoes::Configuration.new }
|
7
|
+
|
8
|
+
its(:name) { should eq('Shoes App') }
|
9
|
+
its(:shortname) { should eq('shoesapp') }
|
10
|
+
its(:ignore) { should eq(['pkg']) }
|
11
|
+
its(:gems) { should include('shoes') }
|
12
|
+
its(:version) { should eq('0.0.0') }
|
13
|
+
its(:release) { should eq('Rookie') }
|
14
|
+
its(:icons) { should be_an_instance_of(Hash) }
|
15
|
+
its(:dmg) { should be_an_instance_of(Hash) }
|
16
|
+
its(:run) { should be_nil }
|
17
|
+
|
18
|
+
describe "#icon" do
|
19
|
+
it 'osx is nil' do
|
20
|
+
subject.icons[:osx].should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'gtk is nil' do
|
24
|
+
subject.icons[:gtk].should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'win32 is nil' do
|
28
|
+
subject.icons[:win32].should be_nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#dmg" do
|
33
|
+
it "has ds_store" do
|
34
|
+
subject.dmg[:ds_store].should eq('path/to/default/.DS_Store')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has background" do
|
38
|
+
subject.dmg[:background].should eq('path/to/default/background.png')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#to_hash" do
|
43
|
+
it "round-trips" do
|
44
|
+
Furoshiki::Shoes::Configuration.new(subject.to_hash).should eq(subject)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "with options" do
|
50
|
+
include_context 'config'
|
51
|
+
subject { Furoshiki::Shoes::Configuration.load(config_filename) }
|
52
|
+
|
53
|
+
its(:name) { should eq('Sugar Clouds') }
|
54
|
+
its(:shortname) { should eq('sweet-nebulae') }
|
55
|
+
its(:ignore) { should include('pkg') }
|
56
|
+
its(:gems) { should include('rspec') }
|
57
|
+
its(:gems) { should include('shoes') }
|
58
|
+
its(:version) { should eq('0.0.1') }
|
59
|
+
its(:release) { should eq('Mindfully') }
|
60
|
+
its(:icons) { should be_an_instance_of(Hash) }
|
61
|
+
its(:dmg) { should be_an_instance_of(Hash) }
|
62
|
+
|
63
|
+
describe "#icon" do
|
64
|
+
it 'has osx' do
|
65
|
+
subject.icons[:osx].should eq('img/boots.icns')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'has gtk' do
|
69
|
+
subject.icons[:gtk].should eq('img/boots_512x512x32.png')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'has win32' do
|
73
|
+
subject.icons[:win32].should eq('img/boots.ico')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#dmg" do
|
78
|
+
it "has ds_store" do
|
79
|
+
subject.dmg[:ds_store].should eq('path/to/custom/.DS_Store')
|
80
|
+
end
|
81
|
+
|
82
|
+
it "has background" do
|
83
|
+
subject.dmg[:background].should eq('path/to/custom/background.png')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "incorporates custom features" do
|
88
|
+
subject.custom.should eq('my custom feature')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with name, but without explicit shortname" do
|
93
|
+
let(:options) { {:name => "Sugar Clouds"} }
|
94
|
+
subject { Furoshiki::Shoes::Configuration.new options }
|
95
|
+
|
96
|
+
its(:name) { should eq("Sugar Clouds") }
|
97
|
+
its(:shortname) { should eq("sugarclouds") }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "auto-loading" do
|
101
|
+
include_context 'config'
|
102
|
+
|
103
|
+
context "without a path" do
|
104
|
+
it "looks for 'app.yaml' in current directory" do
|
105
|
+
Dir.chdir config_filename.parent do
|
106
|
+
config = Furoshiki::Shoes::Configuration.load
|
107
|
+
config.shortname.should eq('sweet-nebulae')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "blows up if it can't find the file" do
|
112
|
+
Dir.chdir File.dirname(__FILE__) do
|
113
|
+
lambda { config = Furoshiki::Shoes::Configuration.load }.should raise_error
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
shared_examples "config with path" do
|
119
|
+
it "finds the config" do
|
120
|
+
Dir.chdir File.dirname(__FILE__) do
|
121
|
+
config = Furoshiki::Shoes::Configuration.load(path)
|
122
|
+
config.shortname.should eq('sweet-nebulae')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "with an 'app.yaml'" do
|
128
|
+
let(:path) { config_filename }
|
129
|
+
it_behaves_like "config with path"
|
130
|
+
end
|
131
|
+
|
132
|
+
context "with a path to a directory containing an 'app.yaml'" do
|
133
|
+
let(:path) { config_filename.parent }
|
134
|
+
it_behaves_like "config with path"
|
135
|
+
end
|
136
|
+
|
137
|
+
context "with a path to a file that is siblings with an 'app.yaml'" do
|
138
|
+
let(:path) { config_filename.parent.join('sibling.rb') }
|
139
|
+
it_behaves_like "config with path"
|
140
|
+
end
|
141
|
+
|
142
|
+
context "with a path that exists, but no 'app.yaml'" do
|
143
|
+
let(:path) { config_filename.parent.join('bin/hello_world') }
|
144
|
+
subject { Furoshiki::Shoes::Configuration.load(path) }
|
145
|
+
|
146
|
+
its(:name) { should eq('hello_world') }
|
147
|
+
its(:shortname) { should eq('hello_world') }
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when the file doesn't exist" do
|
151
|
+
it "blows up" do
|
152
|
+
lambda { Furoshiki::Shoes::Configuration.load('some/bogus/path') }.should raise_error
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
SHOESSPEC_ROOT = File.expand_path('..', __FILE__)
|
2
|
+
|
3
|
+
# Packaging caches files in $HOME/.furoshiki/cache by default.
|
4
|
+
# For testing, we override $HOME using $FUROSHIKI_HOME
|
5
|
+
ENV['FUROSHIKI_HOME'] = SHOESSPEC_ROOT
|
6
|
+
|
7
|
+
require 'rspec'
|
8
|
+
require 'pathname'
|
9
|
+
require 'furoshiki/shoes'
|
10
|
+
|
11
|
+
# Guards for running or not running specs. Specs in the guarded block only
|
12
|
+
# run if the guard conditions are met.
|
13
|
+
#
|
14
|
+
# @see Guard#backend_is
|
15
|
+
module Guard
|
16
|
+
# Runs specs only if backend matches given name
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# backend_is :swt do
|
20
|
+
# specify "backend_name is :swt" do
|
21
|
+
# # body of spec
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
def backend_is(backend)
|
25
|
+
yield if Shoes.configuration.backend_name == backend && block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Runs specs only if platform matches
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# platform_is :windows do
|
32
|
+
# it "does something only on windows" do
|
33
|
+
# # specification
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
def platform_is(platform)
|
37
|
+
yield if self.send "platform_is_#{platform.to_s}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Runs specs only if platform does not match
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# platform_is_not :windows do
|
44
|
+
# it "does something only on posix systems" do
|
45
|
+
# # specification
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
def platform_is_not(platform)
|
49
|
+
yield unless self.send "platform_is_#{platform.to_s}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def platform_is_windows
|
53
|
+
return RbConfig::CONFIG['host_os'] =~ /windows|mswin/i
|
54
|
+
end
|
55
|
+
|
56
|
+
def platform_is_linux
|
57
|
+
return RbConfig::CONFIG['host_os'] =~ /linux/i
|
58
|
+
end
|
59
|
+
|
60
|
+
def platform_is_osx
|
61
|
+
return RbConfig::CONFIG['host_os'] =~ /darwin/i
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
include Guard
|
66
|
+
|
67
|
+
Dir["#{SHOESSPEC_ROOT}/support/**/*.rb"].each {|f| require f}
|
68
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
require 'pathname'
|
4
|
+
require 'furoshiki/shoes/swt_app'
|
5
|
+
|
6
|
+
include PackageHelpers
|
7
|
+
|
8
|
+
describe Furoshiki::Shoes::SwtApp do
|
9
|
+
include_context 'config'
|
10
|
+
include_context 'package'
|
11
|
+
|
12
|
+
let(:app_name) { 'Sugar Clouds.app' }
|
13
|
+
let(:output_file) { output_dir.join app_name }
|
14
|
+
let(:config) { Furoshiki::Shoes::Configuration.load config_filename}
|
15
|
+
let(:launcher) { output_file.join('Contents/MacOS/JavaAppLauncher') }
|
16
|
+
let(:icon) { output_file.join('Contents/Resources/boots.icns') }
|
17
|
+
let(:jar) { output_file.join('Contents/Java/sweet-nebulae.jar') }
|
18
|
+
subject { Furoshiki::Shoes::SwtApp.new config }
|
19
|
+
|
20
|
+
# $FUROSHIKI_HOME is set in spec_helper.rb for testing purposes,
|
21
|
+
# but should default to $HOME
|
22
|
+
context "when not setting $FUROSHIKI_HOME" do
|
23
|
+
before do
|
24
|
+
@old_furoshiki_home = ENV['FUROSHIKI_HOME']
|
25
|
+
ENV['FUROSHIKI_HOME'] = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
its(:cache_dir) { should eq(Pathname.new(Dir.home).join('.furoshiki', 'cache')) }
|
29
|
+
|
30
|
+
after do
|
31
|
+
ENV['FUROSHIKI_HOME'] = @old_furoshiki_home
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "default" do
|
36
|
+
let(:cache_dir) { Pathname.new(SHOESSPEC_ROOT).join('.furoshiki', 'cache') }
|
37
|
+
its(:cache_dir) { should eq(cache_dir) }
|
38
|
+
|
39
|
+
it "sets package dir to {pwd}/pkg" do
|
40
|
+
Dir.chdir app_dir do
|
41
|
+
subject.default_package_dir.should eq(app_dir.join 'pkg')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
its(:template_path) { should eq(cache_dir.join('shoes-app-template.zip')) }
|
46
|
+
its(:remote_template_url) { should eq('http://shoesrb.com/downloads/shoes-app-template-0.0.1.zip') }
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when creating a .app" do
|
50
|
+
before :all do
|
51
|
+
output_dir.rmtree if output_dir.exist?
|
52
|
+
output_dir.mkpath
|
53
|
+
Dir.chdir app_dir do
|
54
|
+
subject.package
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
its(:template_path) { should exist }
|
59
|
+
|
60
|
+
it "creates a .app" do
|
61
|
+
output_file.should exist
|
62
|
+
end
|
63
|
+
|
64
|
+
it "includes launcher" do
|
65
|
+
launcher.should exist
|
66
|
+
end
|
67
|
+
|
68
|
+
# Windows can't test this
|
69
|
+
platform_is_not :windows do
|
70
|
+
it "makes launcher executable" do
|
71
|
+
launcher.should be_executable
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "deletes generic icon" do
|
76
|
+
icon.parent.join('GenericApp.icns').should_not exist
|
77
|
+
end
|
78
|
+
|
79
|
+
it "injects icon" do
|
80
|
+
icon.should exist
|
81
|
+
end
|
82
|
+
|
83
|
+
it "injects jar" do
|
84
|
+
jar.should exist
|
85
|
+
end
|
86
|
+
|
87
|
+
it "removes any extraneous jars" do
|
88
|
+
jar_dir_contents = output_file.join("Contents/Java").children
|
89
|
+
jar_dir_contents.reject {|f| f == jar }.should be_empty
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "Info.plist" do
|
93
|
+
require 'plist'
|
94
|
+
before :all do
|
95
|
+
@plist = Plist.parse_xml(output_file.join 'Contents/Info.plist')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "sets identifier" do
|
99
|
+
@plist['CFBundleIdentifier'].should eq('com.hackety.shoes.sweet-nebulae')
|
100
|
+
end
|
101
|
+
|
102
|
+
it "sets display name" do
|
103
|
+
@plist['CFBundleDisplayName'].should eq('Sugar Clouds')
|
104
|
+
end
|
105
|
+
|
106
|
+
it "sets bundle name" do
|
107
|
+
@plist['CFBundleName'].should eq('Sugar Clouds')
|
108
|
+
end
|
109
|
+
|
110
|
+
it "sets icon" do
|
111
|
+
@plist['CFBundleIconFile'].should eq('boots.icns')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "sets version" do
|
115
|
+
@plist['CFBundleVersion'].should eq('0.0.1')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'pathname'
|
3
|
+
require 'furoshiki/shoes/swt_jar'
|
4
|
+
|
5
|
+
include PackageHelpers
|
6
|
+
|
7
|
+
describe Furoshiki::Shoes::SwtJar do
|
8
|
+
include_context 'config'
|
9
|
+
include_context 'package'
|
10
|
+
|
11
|
+
context "when creating a .jar" do
|
12
|
+
before :all do
|
13
|
+
output_dir.rmtree if output_dir.exist?
|
14
|
+
output_dir.mkpath
|
15
|
+
Dir.chdir app_dir do
|
16
|
+
@jar_path = subject.package(output_dir)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:jar_name) { 'sweet-nebulae.jar' }
|
21
|
+
let(:output_file) { Pathname.new(output_dir.join jar_name) }
|
22
|
+
let(:config) { Furoshiki::Shoes::Configuration.load(config_filename) }
|
23
|
+
subject { Furoshiki::Shoes::SwtJar.new(config) }
|
24
|
+
|
25
|
+
it "creates a .jar" do
|
26
|
+
output_file.should exist
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns path to .jar" do
|
30
|
+
@jar_path.should eq(output_file.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "creates .jar smaller than 50MB" do
|
34
|
+
File.size(output_file).should be < 50 * 1024 * 1024
|
35
|
+
end
|
36
|
+
|
37
|
+
it "excludes directories recursively" do
|
38
|
+
jar = Zip::ZipFile.new(output_file)
|
39
|
+
jar.entries.should_not include("dir_to_ignore/file_to_ignore")
|
40
|
+
end
|
41
|
+
|
42
|
+
its(:default_dir) { should eq(output_dir) }
|
43
|
+
its(:filename) { should eq(jar_name) }
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
name: Sugar Clouds
|
2
|
+
shortname: sweet-nebulae
|
3
|
+
ignore:
|
4
|
+
- pkg
|
5
|
+
- dir_to_ignore
|
6
|
+
run: bin/hello_world
|
7
|
+
gems: rspec
|
8
|
+
version: 0.0.1
|
9
|
+
release: Mindfully
|
10
|
+
icons:
|
11
|
+
osx: img/boots.icns
|
12
|
+
gtk: img/boots_512x512x32.png
|
13
|
+
win32: img/boots.ico
|
14
|
+
dmg:
|
15
|
+
ds_store: path/to/custom/.DS_Store
|
16
|
+
background: path/to/custom/background.png
|
17
|
+
custom: my custom feature
|
@@ -0,0 +1 @@
|
|
1
|
+
should be ignored
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
# Just a sibling of 'app.yaml'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module PackageHelpers
|
2
|
+
# need these values from a context block, so let doesn't work
|
3
|
+
def spec_dir
|
4
|
+
Pathname.new(__FILE__).join('..').cleanpath
|
5
|
+
end
|
6
|
+
|
7
|
+
def input_dir
|
8
|
+
spec_dir.join 'support', 'zip'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ZipHelpers
|
13
|
+
include PackageHelpers
|
14
|
+
# dir = Pathname.new('spec/support/zip')
|
15
|
+
# add_trailing_slash(dir) #=> '/path/to/spec/support/zip/'
|
16
|
+
def add_trailing_slash(dir)
|
17
|
+
dir.to_s + "/"
|
18
|
+
end
|
19
|
+
|
20
|
+
def relative_input_paths(from_dir)
|
21
|
+
Pathname.glob(input_dir + "**/*").map do |p|
|
22
|
+
directory = true if p.directory?
|
23
|
+
relative_path = p.relative_path_from(from_dir).to_s
|
24
|
+
relative_path = add_trailing_slash(relative_path) if directory
|
25
|
+
relative_path
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
spec_root = File.dirname(__FILE__)
|
31
|
+
Dir["#{spec_root}/support/**/*.rb"].each { |f| require f }
|
32
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
include ZipHelpers
|
2
|
+
|
3
|
+
shared_context 'package' do
|
4
|
+
let(:app_dir) { spec_dir.join 'shoes/test_app' }
|
5
|
+
let(:output_dir) { app_dir.join 'pkg' }
|
6
|
+
end
|
7
|
+
|
8
|
+
shared_context 'zip' do
|
9
|
+
include_context 'package'
|
10
|
+
let(:output_file) { output_dir.join 'zip_directory_spec.zip' }
|
11
|
+
let(:zip) { Zip::ZipFile.open output_file }
|
12
|
+
|
13
|
+
before :all do
|
14
|
+
output_dir.mkpath
|
15
|
+
subject.write
|
16
|
+
end
|
17
|
+
|
18
|
+
after :all do
|
19
|
+
FileUtils.rm_rf output_dir
|
20
|
+
end
|
21
|
+
end
|
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'furoshiki/zip'
|
4
|
+
|
5
|
+
describe Furoshiki::Zip::DirectoryContents do
|
6
|
+
subject { Furoshiki::Zip::DirectoryContents.new input_dir, output_file }
|
7
|
+
|
8
|
+
context "output file" do
|
9
|
+
include_context 'zip'
|
10
|
+
|
11
|
+
it "exists" do
|
12
|
+
output_file.should exist
|
13
|
+
end
|
14
|
+
|
15
|
+
it "does not include input directory without parents" do
|
16
|
+
zip.entries.map(&:name).should_not include(add_trailing_slash input_dir.basename)
|
17
|
+
end
|
18
|
+
|
19
|
+
relative_input_paths(input_dir).each do |path|
|
20
|
+
it "includes all children of input directory" do
|
21
|
+
zip.entries.map(&:name).should include(path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'furoshiki/zip'
|
4
|
+
|
5
|
+
describe Furoshiki::Zip::Directory do
|
6
|
+
subject { Furoshiki::Zip::Directory.new input_dir, output_file }
|
7
|
+
|
8
|
+
context "output file" do
|
9
|
+
include_context 'zip'
|
10
|
+
|
11
|
+
it "exists" do
|
12
|
+
output_file.should exist
|
13
|
+
end
|
14
|
+
|
15
|
+
it "includes input directory without parents" do
|
16
|
+
zip.entries.map(&:name).should include(add_trailing_slash input_dir.basename)
|
17
|
+
end
|
18
|
+
|
19
|
+
relative_input_paths(input_dir.parent).each do |path|
|
20
|
+
it "includes all children of input directory" do
|
21
|
+
zip.entries.map(&:name).should include(path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "doesn't include extra files" do
|
26
|
+
number_of_files = Dir.glob("#{input_dir}/**/*").push(input_dir).length
|
27
|
+
zip.entries.length.should eq(number_of_files)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
Binary file
|