shoes-package 4.0.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e85a08b46b6fcdaa86a5b1609c14fb2e58c08677
4
+ data.tar.gz: b655bde5a2d94c020ed7a99a7eed8337cbb36d2f
5
+ SHA512:
6
+ metadata.gz: d425a176814a1adfb819ed1296ad7d5f4308ce13b5928bdbbe933ad99a87c82714f179e37a2b2f5c22abcb43d052ef00d01e153d3f4ccdb54481b99351a4707c
7
+ data.tar.gz: 31d06640d06a1932e8826727d62720d499b9a1ae391a611818d98607d6aada43dc98b7fd4f4b6b7d903c2753bfeb7472b5a578b47d92a61afb0609e83a2e4ff1
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,156 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+ require 'furoshiki/configuration'
4
+ require 'furoshiki/validator'
5
+ require 'furoshiki/warbler_extensions'
6
+ require 'warbler/traits/shoes'
7
+
8
+ class Shoes
9
+ module Package
10
+ # Configuration for Shoes packagers.
11
+ #
12
+ # @example
13
+ # config_file = '/path/to/app.yaml'
14
+ # config = Shoes::Package::Configuration.load(config_file)
15
+ #
16
+ module Configuration
17
+ extend ::Furoshiki::Util
18
+
19
+ JAR_APP_TEMPLATE_URL = 'https://s3.amazonaws.com/net.wasnotrice.shoes/wrappers/shoes-app-template-0.0.1.zip'
20
+
21
+ # Convenience method for loading config from a file. Note that you
22
+ # can pass four kinds of paths to the loader. Given the following
23
+ # file structure:
24
+ #
25
+ # ├── a
26
+ # │   ├── app.yaml
27
+ # │   └── shoes-app-a.rb
28
+ # └── b
29
+ # └── shoes-app-b.rb
30
+ #
31
+ # To package an app that has an `app.yaml`, like `shoes-app-a.rb`,
32
+ # you can call the loader with any of:
33
+ #
34
+ # - a/app.yaml
35
+ # - a
36
+ # - a/shoes-app-a.rb
37
+ #
38
+ # These will all find and use your configuration in `a/app.yaml`.
39
+ # To package an app that does not have an `app.yaml`, like
40
+ # `b/shoes-app-b.rb`, you must call the loader with the path of
41
+ # the script itself. Note that without an `app.yaml`, you will
42
+ # only bundle a single file, and your app will simply use the
43
+ # Shoes app icon.
44
+ #
45
+ # @overload load(path, base_config)
46
+ # @param [String] path location of the app's 'app.yaml'
47
+ # @param [Hash] base_config default values
48
+ # @overload load(path)
49
+ # @param [String] path location of the directory that
50
+ # contains the app's 'app.yaml'
51
+ # @param [Hash] base_config default values
52
+ # @overload load(path)
53
+ # @param [String] path location of the app
54
+ # @param [Hash] base_config default values
55
+ def self.load(path, base_config = {})
56
+ pathname = Pathname.new(path)
57
+ app_yaml = Pathname.new('app.yaml')
58
+
59
+ if pathname.basename == app_yaml
60
+ file, dir = pathname, pathname.dirname
61
+ elsif pathname.directory?
62
+ file, dir = pathname.join(app_yaml), pathname
63
+ elsif pathname.file? && pathname.parent.children.include?(pathname.parent.join app_yaml)
64
+ file, dir = pathname.parent.join(app_yaml), pathname.parent
65
+ else
66
+ file, dir = config_for_single_file_app(pathname)
67
+ end
68
+
69
+ config = YAML.load(file.read)
70
+ config[:working_dir] = dir
71
+ config[:gems] = merge_gems(base_config, config)
72
+ create(config)
73
+ end
74
+
75
+ # @param [Hash] config user options
76
+ def self.create(config = {})
77
+ defaults = {
78
+ name: 'Shoes App',
79
+ version: '0.0.0',
80
+ release: 'Rookie',
81
+ run: nil,
82
+ ignore: 'pkg',
83
+ # TODO: Add actual paths. Keep these keys for compatibility with Shoes 3
84
+ icons: {
85
+ #osx: 'path/to/default/App.icns',
86
+ #gtk: 'path/to/default/app.png',
87
+ #win32: 'path/to/default/App.ico',
88
+ },
89
+ # TODO: Add actual paths. Keep these keys for compatibility with Shoes 3
90
+ dmg: {
91
+ #ds_store: 'path/to/default/.DS_Store',
92
+ #background: 'path/to/default/background.png'
93
+ },
94
+ working_dir: Dir.pwd,
95
+ gems: ['shoes-core'],
96
+ validator: Validator,
97
+ warbler_extensions: WarblerExtensions
98
+ }
99
+
100
+ symbolized_config = deep_symbolize_keys(config)
101
+ symbolized_config[:gems] = merge_gems(defaults, symbolized_config)
102
+ Furoshiki::Configuration.new defaults.merge(symbolized_config)
103
+ end
104
+
105
+ private
106
+ # If it exists, load default options. If not, let the filesystem raise an
107
+ # error.
108
+ def self.config_for_single_file_app(pathname)
109
+ default_options = {
110
+ run: pathname.basename.to_s,
111
+ name: pathname.basename(pathname.extname).to_s.gsub(/\W/, '-')
112
+ }.to_yaml
113
+ options = pathname.exist? ? default_options : pathname
114
+ dummy_file = Struct.new(:read)
115
+ [dummy_file.new(options), pathname.parent]
116
+ end
117
+
118
+ # We want to retain all of the gems, but simply merging the hash will
119
+ # replace the whole array, so we handle the gems separately. Note that
120
+ # keys may not have been symbolized yet
121
+ def self.merge_gems(base, additional)
122
+ base_gems = base.fetch(:gems) rescue base['gems']
123
+ additional_gems = additional.fetch(:gems) rescue additional['gems']
124
+ Array(base_gems).concat(Array(additional_gems)).uniq
125
+ end
126
+ end
127
+
128
+ class Validator < Furoshiki::Validator
129
+ def validate
130
+ unless config.run && config.working_dir.join(config.run).exist?
131
+ add_missing_file_error(config.run, "Run file")
132
+ end
133
+
134
+ if config.icons[:osx] && !config.working_dir.join(config.icons[:osx]).exist?
135
+ add_missing_file_error(config.icons[:osx], "OS X icon file")
136
+ end
137
+ end
138
+ end
139
+
140
+ class WarblerExtensions < Furoshiki::WarblerExtensions
141
+ def customize(warbler_config)
142
+ warbler_config.tap do |warbler|
143
+ warbler.pathmaps.application = ['shoes-app/%p']
144
+ warbler.extend ShoesWarblerConfig
145
+ warbler.run = @config.run.split(/\s/).first
146
+ end
147
+ end
148
+
149
+ private
150
+ # Adds Shoes-specific functionality to the Warbler Config
151
+ module ShoesWarblerConfig
152
+ attr_accessor :run
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,17 @@
1
+ require 'forwardable'
2
+ require 'furoshiki/jar'
3
+
4
+ class Shoes
5
+ module Package
6
+ class Jar
7
+ extend Forwardable
8
+
9
+ def_delegators :@packager, :package, :default_dir, :filename
10
+
11
+ def initialize(config)
12
+ config.gems << 'shoes-swt'
13
+ @packager = Furoshiki::Jar.new(config)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'forwardable'
2
+ require 'furoshiki/jar_app'
3
+
4
+ class Shoes
5
+ module Package
6
+ class JarApp
7
+ extend Forwardable
8
+
9
+ def_delegators :@packager, :package, :default_package_dir, :cache_dir,
10
+ :remote_template_url, :template_path
11
+
12
+ def initialize(config)
13
+ config.gems << 'shoes-swt'
14
+ @packager = Furoshiki::JarApp.new(config)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ class Shoes
2
+ module Package
3
+ VERSION = "4.0.0.pre3"
4
+ end
5
+ end
@@ -0,0 +1,53 @@
1
+ require 'warbler'
2
+ require 'warbler/traits'
3
+ require 'warbler/traits/furoshiki'
4
+
5
+ module Warbler
6
+ module Traits
7
+ # Hack to control the executable
8
+ class NoGemspec
9
+ def update_archive(jar); end
10
+ end
11
+
12
+ # Disable this trait, since we are subclassing it (don't run twice)
13
+ class Furoshiki
14
+ def self.detect?; false; end
15
+ end
16
+
17
+ class Shoes < Furoshiki
18
+ def self.detect?
19
+ true
20
+ end
21
+
22
+ def self.requires?(trait)
23
+ # Actually, it would be better to dump the NoGemspec trait, but since
24
+ # we can't do that, we can at least make sure that this trait gets
25
+ # processed later by declaring that it requires NoGemspec.
26
+ [Traits::Jar, Traits::NoGemspec].include? trait
27
+ end
28
+
29
+ def after_configure
30
+ config.init_contents << StringIO.new("require 'shoes'\nShoes.configuration.backend = :swt\n")
31
+ end
32
+
33
+ def update_archive(jar)
34
+ super
35
+ add_main_rb(jar, apply_pathmaps(config, default_executable, :application))
36
+ end
37
+
38
+ # Uses the `@config.run` if it exists. Otherwise, looks in the
39
+ # application's `bin` directory for an executable with the same name as
40
+ # the jar. If this also fails, defaults to the first executable (alphabetically) in the
41
+ # applications `bin` directory.
42
+ #
43
+ # @return [String] filename of the executable to run
44
+ def default_executable
45
+ return @config.run if @config.run
46
+ exes = Dir['bin/*'].sort
47
+ exe = exes.grep(/#{config.jar_name}/).first || exes.first
48
+ raise "No executable script found" unless exe
49
+ exe
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('lib/shoes/package/version')
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "shoes-package"
6
+ s.version = Shoes::Package::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Team Shoes"]
9
+ s.email = ["shoes@librelist.com"]
10
+ s.homepage = "https://github.com/shoes/shoes4"
11
+ s.summary = %q{Application packaging for Shoes, the best little GUI toolkit for Ruby.}
12
+ s.description = %q{Application packaging for Shoes, the best little GUI toolkit for Ruby. Shoes makes building for Mac, Windows, and Linux super simple.}
13
+ s.license = 'MIT'
14
+
15
+ s.files = `git ls-files`.split($/)
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "shoes-core", Shoes::Package::VERSION
20
+ s.add_dependency "furoshiki", "~> 0.3.0"
21
+ end
@@ -0,0 +1,207 @@
1
+ require_relative 'spec_helper'
2
+ require 'shoes/package/configuration'
3
+
4
+ describe Shoes::Package::Configuration do
5
+ context "defaults" do
6
+ subject { Shoes::Package::Configuration.create }
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-core') }
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
+ its(:working_dir) { should eq(Pathname.new(Dir.pwd)) }
18
+ it { is_expected.not_to be_valid } # no :run
19
+
20
+ # TODO: Implement
21
+ describe "#icons" do
22
+ it 'osx is nil' do
23
+ expect(subject.icons[:osx]).to be_nil
24
+ end
25
+
26
+ it 'gtk is nil' do
27
+ expect(subject.icons[:gtk]).to be_nil
28
+ end
29
+
30
+ it 'win32 is nil' do
31
+ expect(subject.icons[:win32]).to be_nil
32
+ end
33
+ end
34
+
35
+ # TODO: Implement
36
+ describe "#dmg" do
37
+ it "ds_store is nil" do
38
+ expect(subject.dmg[:ds_store]).to be_nil
39
+ end
40
+
41
+ it "background is nil" do
42
+ expect(subject.dmg[:background]).to be_nil
43
+ end
44
+ end
45
+
46
+ describe "#to_hash" do
47
+ it "round-trips" do
48
+ expect(Shoes::Package::Configuration.create(subject.to_hash)).to eq(subject)
49
+ end
50
+ end
51
+ end
52
+
53
+ context "with options" do
54
+ include_context 'config'
55
+ subject { Shoes::Package::Configuration.load(@config_filename) }
56
+
57
+ its(:name) { should eq('Sugar Clouds') }
58
+ its(:shortname) { should eq('sweet-nebulae') }
59
+ its(:ignore) { should include('pkg') }
60
+ its(:run) { should eq('bin/hello_world') }
61
+ its(:gems) { should include('rspec') }
62
+ its(:gems) { should include('shoes-core') }
63
+ its(:version) { should eq('0.0.1') }
64
+ its(:release) { should eq('Mindfully') }
65
+ its(:icons) { should be_an_instance_of(Hash) }
66
+ its(:dmg) { should be_an_instance_of(Hash) }
67
+ its(:working_dir) { should eq(@config_filename.dirname) }
68
+ it { is_expected.to be_valid }
69
+
70
+ describe "#icons" do
71
+ it 'has osx' do
72
+ expect(subject.icons[:osx]).to eq('img/boots.icns')
73
+ end
74
+
75
+ it 'has gtk' do
76
+ expect(subject.icons[:gtk]).to eq('img/boots_512x512x32.png')
77
+ end
78
+
79
+ it 'has win32' do
80
+ expect(subject.icons[:win32]).to eq('img/boots.ico')
81
+ end
82
+ end
83
+
84
+ describe "#dmg" do
85
+ it "has ds_store" do
86
+ expect(subject.dmg[:ds_store]).to eq('path/to/custom/.DS_Store')
87
+ end
88
+
89
+ it "has background" do
90
+ expect(subject.dmg[:background]).to eq('path/to/custom/background.png')
91
+ end
92
+ end
93
+
94
+ it "incorporates custom features" do
95
+ expect(subject.custom).to eq('my custom feature')
96
+ end
97
+
98
+ it "round-trips" do
99
+ expect(Shoes::Package::Configuration.create(subject.to_hash)).to eq(subject)
100
+ end
101
+ end
102
+
103
+ context "with name, but without explicit shortname" do
104
+ let(:options) { {:name => "Sugar Clouds"} }
105
+ subject { Shoes::Package::Configuration.create options }
106
+
107
+ its(:name) { should eq("Sugar Clouds") }
108
+ its(:shortname) { should eq("sugarclouds") }
109
+ end
110
+
111
+ context "when the file to run doens't exist" do
112
+ let(:options) { {:run => "path/to/non-existent/file"} }
113
+ subject { Shoes::Package::Configuration.create options }
114
+
115
+ it { is_expected.not_to be_valid }
116
+ end
117
+
118
+ context "when osx icon is not specified" do
119
+ include_context 'config'
120
+ let(:valid_config) { Shoes::Package::Configuration.load(@config_filename) }
121
+ let(:options) { valid_config.to_hash.merge(:icons => {}) }
122
+ subject { Shoes::Package::Configuration.create(options) }
123
+
124
+ it "sets osx icon path to nil" do
125
+ expect(subject.icons[:osx]).to be_nil
126
+ end
127
+
128
+ it "is valid" do
129
+ expect(subject).to be_valid
130
+ end
131
+ end
132
+
133
+ context "when osx icon is specified, but doesn't exist" do
134
+ let(:options) { ({:icons => {:osx => "path/to/non-existent/file"}}) }
135
+ subject { Shoes::Package::Configuration.create options }
136
+
137
+ it "sets osx icon path" do
138
+ expect(subject.icons[:osx]).to eq("path/to/non-existent/file")
139
+ end
140
+
141
+ it { is_expected.not_to be_valid }
142
+ end
143
+
144
+ context "auto-loading" do
145
+ include_context 'config'
146
+
147
+ shared_examples "config with path" do
148
+ it "finds the config" do
149
+ Dir.chdir File.dirname(__FILE__) do
150
+ config = Shoes::Package::Configuration.load(path)
151
+ expect(config.shortname).to eq('sweet-nebulae')
152
+ end
153
+ end
154
+ end
155
+
156
+ context "with an 'app.yaml'" do
157
+ let(:path) { @config_filename }
158
+ it_behaves_like "config with path"
159
+ end
160
+
161
+ context "with a path to a directory containing an 'app.yaml'" do
162
+ let(:path) { @config_filename.parent }
163
+ it_behaves_like "config with path"
164
+ end
165
+
166
+ context "with a path to a file that is siblings with an 'app.yaml'" do
167
+ let(:path) { @config_filename.parent.join('sibling.rb') }
168
+ it_behaves_like "config with path"
169
+ end
170
+
171
+ context "with a path that exists, but no 'app.yaml'" do
172
+ let(:path) { @config_filename.parent.join('bin/hello_world') }
173
+ subject { Shoes::Package::Configuration.load(path) }
174
+
175
+ its(:name) { should eq('hello_world') }
176
+ its(:shortname) { should eq('hello_world') }
177
+ end
178
+
179
+ context "when the file doesn't exist" do
180
+ it "blows up" do
181
+ expect { Shoes::Package::Configuration.load('some/bogus/path') }.to raise_error
182
+ end
183
+ end
184
+
185
+ context "with additional gems" do
186
+ let(:path) { @config_filename }
187
+ let(:additional_config) { { gems: gems } }
188
+ let(:config) { config = Shoes::Package::Configuration.load(path, additional_config) }
189
+
190
+ context "one gem" do
191
+ let(:gems) { 'shoes-swt' }
192
+
193
+ it "adds one additional" do
194
+ expect(config.gems).to include('shoes-swt')
195
+ end
196
+ end
197
+
198
+ context "multiple gems" do
199
+ let(:gems) { ['shoes-swt', 'shoes-extras'] }
200
+
201
+ it "adds multiple additional gems" do
202
+ expect(config.gems & gems).to eq(gems)
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,69 @@
1
+ # Packaging caches files in $HOME/.furoshiki/cache by default.
2
+ # For testing, we override $HOME using $FUROSHIKI_HOME
3
+ FUROSHIKI_SPEC_DIR = Pathname.new(__FILE__).dirname.expand_path.to_s
4
+ ENV['FUROSHIKI_HOME'] = FUROSHIKI_SPEC_DIR
5
+
6
+ SHOES_PACKAGE_SPEC_ROOT= File.expand_path('..', __FILE__)
7
+
8
+ $LOAD_PATH << File.expand_path(SHOES_PACKAGE_SPEC_ROOT)
9
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
10
+ $LOAD_PATH << File.expand_path('../../../shoes-core/lib', __FILE__)
11
+
12
+ require 'pathname'
13
+ require 'rspec/its'
14
+
15
+ Dir["#{SHOES_PACKAGE_SPEC_ROOT}/support/**/*.rb"].each {|f| require f}
16
+
17
+ module PackageHelpers
18
+ # need these values from a context block, so let doesn't work
19
+ def spec_dir
20
+ Pathname.new(__FILE__).join('..').cleanpath
21
+ end
22
+
23
+ def input_dir
24
+ spec_dir.join 'support', 'zip'
25
+ end
26
+ end
27
+
28
+ # Guards for running or not running specs. Specs in the guarded block only
29
+ # run if the guard conditions are met.
30
+ #
31
+ module Guard
32
+ # Runs specs only if platform matches
33
+ #
34
+ # @example
35
+ # platform_is :windows do
36
+ # it "does something only on windows" do
37
+ # # specification
38
+ # end
39
+ # end
40
+ def platform_is(platform)
41
+ yield if self.send "platform_is_#{platform.to_s}"
42
+ end
43
+
44
+ # Runs specs only if platform does not match
45
+ #
46
+ # @example
47
+ # platform_is_not :windows do
48
+ # it "does something only on posix systems" do
49
+ # # specification
50
+ # end
51
+ # end
52
+ def platform_is_not(platform)
53
+ yield unless self.send "platform_is_#{platform.to_s}"
54
+ end
55
+
56
+ def platform_is_windows
57
+ return RbConfig::CONFIG['host_os'] =~ /windows|mswin/i
58
+ end
59
+
60
+ def platform_is_linux
61
+ return RbConfig::CONFIG['host_os'] =~ /linux/i
62
+ end
63
+
64
+ def platform_is_osx
65
+ return RbConfig::CONFIG['host_os'] =~ /darwin/i
66
+ end
67
+ end
68
+
69
+ include Guard
@@ -0,0 +1,15 @@
1
+ require 'yaml'
2
+ require 'pathname'
3
+
4
+ shared_context 'config' do
5
+ before :all do
6
+ @config_filename = Pathname.new(__FILE__).join('../../test_app/app.yaml').cleanpath
7
+ end
8
+ end
9
+
10
+ shared_context 'package' do
11
+ before :all do
12
+ @app_dir = Pathname.new(__FILE__).join '../../test_app'
13
+ @output_dir = @app_dir.join 'pkg'
14
+ end
15
+ end
@@ -0,0 +1,131 @@
1
+ require_relative 'spec_helper'
2
+ require 'shoes/package/configuration'
3
+ require 'shoes/package/jar_app'
4
+
5
+ include PackageHelpers
6
+
7
+ describe Shoes::Package::JarApp do
8
+ include_context 'config'
9
+ include_context 'package'
10
+
11
+ let(:config) { Shoes::Package::Configuration.load @config_filename }
12
+ subject { Shoes::Package::JarApp.new config }
13
+
14
+ let(:launcher) { @output_file.join('Contents/MacOS/JavaAppLauncher') }
15
+ let(:icon) { @output_file.join('Contents/Resources/boots.icns') }
16
+ let(:jar) { @output_file.join('Contents/Java/sweet-nebulae.jar') }
17
+
18
+ # $FUROSHIKI_HOME is set in spec_helper.rb for testing purposes,
19
+ # but should default to $HOME
20
+ context "when not setting $FUROSHIKI_HOME" do
21
+ before do
22
+ @old_furoshiki_home = ENV['FUROSHIKI_HOME']
23
+ ENV['FUROSHIKI_HOME'] = nil
24
+ end
25
+
26
+
27
+ its(:cache_dir) { should eq(Pathname.new(Dir.home).join('.furoshiki', 'cache')) }
28
+
29
+ after do
30
+ ENV['FUROSHIKI_HOME'] = @old_furoshiki_home
31
+ end
32
+ end
33
+
34
+ context "default" do
35
+ let(:cache_dir) { Pathname.new(SHOES_PACKAGE_SPEC_ROOT).join('.furoshiki', 'cache') }
36
+ its(:cache_dir) { should eq(cache_dir) }
37
+
38
+ it "sets package dir to {pwd}/pkg" do
39
+ Dir.chdir @app_dir do
40
+ expect(subject.default_package_dir).to eq(@app_dir.join 'pkg')
41
+ end
42
+ end
43
+
44
+ its(:template_path) { should eq(cache_dir.join('shoes-app-template.zip')) }
45
+ its(:remote_template_url) { should eq(Shoes::Package::Configuration::JAR_APP_TEMPLATE_URL) }
46
+ end
47
+
48
+ context "when creating a .app" do
49
+ before :all do
50
+ @output_dir.rmtree if @output_dir.exist?
51
+ @output_dir.mkpath
52
+ app_name = 'Sugar Clouds.app'
53
+ @output_file = @output_dir.join app_name
54
+ config = Shoes::Package::Configuration.load @config_filename
55
+ @subject = Shoes::Package::JarApp.new config
56
+ @subject.package
57
+ end
58
+
59
+ subject { @subject }
60
+
61
+ its(:template_path) { should exist }
62
+
63
+ it "creates a .app" do
64
+ expect(@output_file).to exist
65
+ end
66
+
67
+ it "includes launcher" do
68
+ expect(launcher).to exist
69
+ end
70
+
71
+ # Windows can't test this
72
+ platform_is_not :windows do
73
+ it "makes launcher executable" do
74
+ expect(launcher).to be_executable
75
+ end
76
+ end
77
+
78
+ it "deletes generic icon" do
79
+ expect(icon.parent.join('GenericApp.icns')).not_to exist
80
+ end
81
+
82
+ it "injects icon" do
83
+ expect(icon).to exist
84
+ end
85
+
86
+ it "injects jar" do
87
+ expect(jar).to exist
88
+ end
89
+
90
+ it "removes any extraneous jars" do
91
+ jar_dir_contents = @output_file.join("Contents/Java").children
92
+ expect(jar_dir_contents.reject {|f| f == jar }).to be_empty
93
+ end
94
+
95
+ describe "Info.plist" do
96
+ require 'plist'
97
+ before :all do
98
+ @plist = Plist.parse_xml(@output_file.join 'Contents/Info.plist')
99
+ end
100
+
101
+ it "sets identifier" do
102
+ expect(@plist['CFBundleIdentifier']).to eq('com.hackety.shoes.sweet-nebulae')
103
+ end
104
+
105
+ it "sets display name" do
106
+ expect(@plist['CFBundleDisplayName']).to eq('Sugar Clouds')
107
+ end
108
+
109
+ it "sets bundle name" do
110
+ expect(@plist['CFBundleName']).to eq('Sugar Clouds')
111
+ end
112
+
113
+ it "sets icon" do
114
+ expect(@plist['CFBundleIconFile']).to eq('boots.icns')
115
+ end
116
+
117
+ it "sets version" do
118
+ expect(@plist['CFBundleVersion']).to eq('0.0.1')
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "with an invalid configuration" do
124
+ let(:config) { Shoes::Package::Configuration.create }
125
+ subject { Shoes::Package::JarApp.new config }
126
+
127
+ it "fails to initialize" do
128
+ expect { subject }.to raise_error(Furoshiki::ConfigurationError)
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,66 @@
1
+ require_relative 'spec_helper'
2
+ require 'shoes/package/configuration'
3
+ require 'shoes/package/jar'
4
+
5
+ include PackageHelpers
6
+
7
+ describe Furoshiki::Jar 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
+ config = Shoes::Package::Configuration.load(@config_filename)
16
+ @subject = Shoes::Package::Jar.new(config)
17
+ @jar_path = @subject.package
18
+ end
19
+
20
+ let(:jar_name) { 'sweet-nebulae.jar' }
21
+ let(:output_file) { Pathname.new(@output_dir.join jar_name) }
22
+ subject { @subject }
23
+
24
+ it "creates a .jar" do
25
+ expect(output_file).to exist
26
+ end
27
+
28
+ it "returns path to .jar" do
29
+ expect(@jar_path).to eq(output_file.to_s)
30
+ end
31
+
32
+ it "creates .jar smaller than 60MB" do
33
+ expect(File.size(output_file)).to be < 60 * 1024 * 1024
34
+ end
35
+
36
+ context "inspecting contents" do
37
+ let (:jar) { Zip::File.new(output_file) }
38
+
39
+ it "includes shoes-core" do
40
+ shoes_core = jar.glob "gems/shoes-core*"
41
+ expect(shoes_core.length).to equal(1)
42
+ end
43
+
44
+ it "includes shoes-swt" do
45
+ shoes_swt = jar.glob "gems/shoes-swt*"
46
+ expect(shoes_swt.length).to equal(1)
47
+ end
48
+
49
+ it "excludes directories recursively" do
50
+ expect(jar.entries).not_to include("dir_to_ignore/file_to_ignore")
51
+ end
52
+ end
53
+
54
+ its(:default_dir) { should eq(@output_dir) }
55
+ its(:filename) { should eq(jar_name) }
56
+ end
57
+
58
+ describe "with an invalid configuration" do
59
+ let(:config) { Shoes::Package::Configuration.create}
60
+ subject { Shoes::Package::Jar.new(config) }
61
+
62
+ it "fails to initialize" do
63
+ expect { subject }.to raise_error(Furoshiki::ConfigurationError)
64
+ end
65
+ end
66
+ 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,3 @@
1
+ Shoes.app do
2
+ banner "Hello world"
3
+ end
@@ -0,0 +1 @@
1
+ should be ignored
Binary file
Binary file
@@ -0,0 +1 @@
1
+ # Just a sibling of 'app.yaml'
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shoes-package
3
+ version: !ruby/object:Gem::Version
4
+ version: 4.0.0.pre3
5
+ platform: ruby
6
+ authors:
7
+ - Team Shoes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '='
17
+ - !ruby/object:Gem::Version
18
+ version: 4.0.0.pre3
19
+ name: shoes-core
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0.pre3
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.3.0
33
+ name: furoshiki
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.0
41
+ description: Application packaging for Shoes, the best little GUI toolkit for Ruby. Shoes makes building for Mac, Windows, and Linux super simple.
42
+ email:
43
+ - shoes@librelist.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - Rakefile
49
+ - lib/shoes/package/configuration.rb
50
+ - lib/shoes/package/jar.rb
51
+ - lib/shoes/package/jar_app.rb
52
+ - lib/shoes/package/version.rb
53
+ - lib/warbler/traits/shoes.rb
54
+ - shoes-package.gemspec
55
+ - spec/.furoshiki/cache/shoes-app-template.zip
56
+ - spec/configuration_spec.rb
57
+ - spec/spec_helper.rb
58
+ - spec/support/shared_config.rb
59
+ - spec/swt_app_spec.rb
60
+ - spec/swt_jar_spec.rb
61
+ - spec/test_app/app.yaml
62
+ - spec/test_app/bin/hello_world
63
+ - spec/test_app/dir_to_ignore/file_to_ignore.txt
64
+ - spec/test_app/img/boots.icns
65
+ - spec/test_app/img/boots.ico
66
+ - spec/test_app/img/boots_512x512x32.png
67
+ - spec/test_app/sibling.rb
68
+ homepage: https://github.com/shoes/shoes4
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '>'
84
+ - !ruby/object:Gem::Version
85
+ version: 1.3.1
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.4.2
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Application packaging for Shoes, the best little GUI toolkit for Ruby.
92
+ test_files:
93
+ - spec/.furoshiki/cache/shoes-app-template.zip
94
+ - spec/configuration_spec.rb
95
+ - spec/spec_helper.rb
96
+ - spec/support/shared_config.rb
97
+ - spec/swt_app_spec.rb
98
+ - spec/swt_jar_spec.rb
99
+ - spec/test_app/app.yaml
100
+ - spec/test_app/bin/hello_world
101
+ - spec/test_app/dir_to_ignore/file_to_ignore.txt
102
+ - spec/test_app/img/boots.icns
103
+ - spec/test_app/img/boots.ico
104
+ - spec/test_app/img/boots_512x512x32.png
105
+ - spec/test_app/sibling.rb
106
+ has_rdoc: