releasy 0.2.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +17 -0
  2. data/.yardopts +4 -0
  3. data/CHANGELOG.md +24 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +165 -0
  7. data/Rakefile +31 -0
  8. data/bin/7z.sfx +0 -0
  9. data/bin/releasy +7 -0
  10. data/lib/releasy.rb +18 -0
  11. data/lib/releasy/archivers.rb +12 -0
  12. data/lib/releasy/archivers/archiver.rb +74 -0
  13. data/lib/releasy/archivers/dmg.rb +18 -0
  14. data/lib/releasy/archivers/exe.rb +23 -0
  15. data/lib/releasy/archivers/seven_zip.rb +12 -0
  16. data/lib/releasy/archivers/tar_archiver.rb +14 -0
  17. data/lib/releasy/archivers/tar_bzip2.rb +13 -0
  18. data/lib/releasy/archivers/tar_gzip.rb +13 -0
  19. data/lib/releasy/archivers/zip.rb +12 -0
  20. data/lib/releasy/builders.rb +12 -0
  21. data/lib/releasy/builders/builder.rb +52 -0
  22. data/lib/releasy/builders/ocra_builder.rb +43 -0
  23. data/lib/releasy/builders/osx_app.rb +158 -0
  24. data/lib/releasy/builders/source.rb +27 -0
  25. data/lib/releasy/builders/windows_builder.rb +65 -0
  26. data/lib/releasy/builders/windows_folder.rb +47 -0
  27. data/lib/releasy/builders/windows_folder_from_ruby_dist.rb +150 -0
  28. data/lib/releasy/builders/windows_installer.rb +117 -0
  29. data/lib/releasy/builders/windows_standalone.rb +37 -0
  30. data/lib/releasy/cli.rb +12 -0
  31. data/lib/releasy/cli/install_sfx.rb +66 -0
  32. data/lib/releasy/dsl_wrapper.rb +71 -0
  33. data/lib/releasy/mixins/exec.rb +14 -0
  34. data/lib/releasy/mixins/has_archivers.rb +37 -0
  35. data/lib/releasy/mixins/has_gemspecs.rb +42 -0
  36. data/lib/releasy/mixins/register.rb +47 -0
  37. data/lib/releasy/project.rb +300 -0
  38. data/lib/releasy/version.rb +3 -0
  39. data/lib/releasy/windows_wrapper_maker.rb +90 -0
  40. data/lib/releasy/windows_wrapper_maker/Gemfile +8 -0
  41. data/media/releasy.png +0 -0
  42. data/releasy.gemspec +37 -0
  43. data/test/releasy/archivers_test.rb +65 -0
  44. data/test/releasy/builders/data/Info.plist +51 -0
  45. data/test/releasy/builders/data/Main.rb +12 -0
  46. data/test/releasy/builders/data/relapse_runner.rb +1 -0
  47. data/test/releasy/builders/data/set_app_executable.sh +3 -0
  48. data/test/releasy/builders/helpers/helper.rb +47 -0
  49. data/test/releasy/builders/ocra_builder_test.rb +37 -0
  50. data/test/releasy/builders/osx_app_test.rb +107 -0
  51. data/test/releasy/builders/source_test.rb +43 -0
  52. data/test/releasy/builders/windows_builder_test.rb +26 -0
  53. data/test/releasy/builders/windows_folder_from_ruby_dist_test.rb +105 -0
  54. data/test/releasy/builders/windows_folder_test.rb +56 -0
  55. data/test/releasy/builders/windows_installer_test.rb +62 -0
  56. data/test/releasy/builders/windows_standalone_test.rb +58 -0
  57. data/test/releasy/cli/install_sfx_test.rb +90 -0
  58. data/test/releasy/dsl_wrapper_test.rb +79 -0
  59. data/test/releasy/integration/source_test.rb +122 -0
  60. data/test/releasy/mixins/register_test.rb +52 -0
  61. data/test/releasy/project_test.rb +198 -0
  62. data/test/releasy/windows_wrapper_maker_test.rb +61 -0
  63. data/test/teststrap.rb +52 -0
  64. data/test/yard_test.rb +61 -0
  65. data/test_project/Gemfile +9 -0
  66. data/test_project/LICENSE.txt +1 -0
  67. data/test_project/README.txt +2 -0
  68. data/test_project/bin/test_app +3 -0
  69. data/test_project/lib/test_app.rb +6 -0
  70. data/test_project/lib/test_app/stuff.rb +1 -0
  71. data/test_project/test_app.icns +0 -0
  72. data/test_project/test_app.ico +0 -0
  73. data/wrappers/put_wrappers_here_for_testing.txt +17 -0
  74. metadata +236 -0
@@ -0,0 +1,14 @@
1
+ require "releasy/archivers/archiver"
2
+
3
+ module Releasy
4
+ module Archivers
5
+ # An archiver that tars and then compresses the folder.
6
+ # @abstract
7
+ class TarArchiver < Archiver
8
+ protected
9
+ def command(folder)
10
+ %[7z a -so -mmt -bd -ttar "#{folder}.tar" "#{folder}" | 7z a -si -bd -t#{self.class::FORMAT} -mx9 "#{folder}#{extension}"]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require "releasy/archivers/tar_archiver"
2
+
3
+ module Releasy
4
+ module Archivers
5
+ # Archives with tar and Bzip2 formats.
6
+ class TarBzip2 < TarArchiver
7
+ TYPE = :tar_bz2
8
+ DEFAULT_EXTENSION = ".tar.bz2"
9
+ FORMAT = "bzip2"
10
+ Archivers.register self
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require "releasy/archivers/tar_archiver"
2
+
3
+ module Releasy
4
+ module Archivers
5
+ # Archives with tar and Gzip formats.
6
+ class TarGzip < TarArchiver
7
+ TYPE = :tar_gz
8
+ DEFAULT_EXTENSION = ".tar.gz"
9
+ FORMAT = "gzip"
10
+ Archivers.register self
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require "releasy/archivers/archiver"
2
+
3
+ module Releasy
4
+ module Archivers
5
+ # Archives with zip format. This isn't efficient, but can be decompressed on Windows Vista or later without requiring a 3rd party tool.
6
+ class Zip < Archiver
7
+ TYPE = :zip
8
+ DEFAULT_EXTENSION = ".zip"
9
+ Archivers.register self
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'releasy/mixins/register'
2
+
3
+ module Releasy
4
+ # Contains all {Builder} types.
5
+ module Builders
6
+ extend Mixins::Register
7
+ end
8
+ end
9
+
10
+ %w[osx_app source windows_folder windows_folder_from_ruby_dist windows_installer windows_standalone].each do |builder|
11
+ require "releasy/builders/#{builder}"
12
+ end
@@ -0,0 +1,52 @@
1
+ require "releasy/mixins/has_archivers"
2
+ require "releasy/mixins/exec"
3
+
4
+ module Releasy
5
+ module Builders
6
+ # Builds release folders.
7
+ # @abstract
8
+ class Builder
9
+ include Rake::DSL
10
+ include Mixins::HasArchivers
11
+ include Mixins::Exec
12
+
13
+ # @return [Project] that this Builder belongs to.
14
+ attr_reader :project
15
+ # @return [String] Suffix on the folder generated, after name and version.
16
+ attr_accessor :folder_suffix
17
+
18
+ # @return [Symbol] Type of builder.
19
+ def type; self.class::TYPE; end
20
+
21
+ # Is the builder valid for the current platform (OS)?
22
+ def valid_for_platform?; true; end
23
+
24
+ def initialize(project)
25
+ super()
26
+ @project = project
27
+ @folder_suffix = self.class::DEFAULT_FOLDER_SUFFIX
28
+ setup
29
+ end
30
+
31
+ protected
32
+ # @return [String] Called from the project, but users don't need to know about it.
33
+ def task_group; type.to_s.split(/_/).first; end
34
+ # @return [String] Output folder.
35
+ def folder; "#{project.folder_base}#{folder_suffix.empty? ? '' : '_'}#{folder_suffix}"; end
36
+
37
+ protected
38
+ # Called by {#initalize}
39
+ def setup; end
40
+
41
+ protected
42
+ # Copy a number of files into a folder, maintaining relative paths.
43
+ def copy_files_relative(files, folder)
44
+ files.each do |file|
45
+ destination = File.join(folder, File.dirname(file))
46
+ mkdir_p destination unless File.exists? destination
47
+ cp file, destination
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ require "releasy/builders/windows_builder"
2
+
3
+ module Releasy
4
+ module Builders
5
+ # Functionality for a {WindowsBuilder} that use Ocra and runs on Windows.
6
+ # @attr icon [String] Optional filename of icon to show on executable/installer (.ico).
7
+ # @abstract
8
+ class OcraBuilder < WindowsBuilder
9
+ OCRA_COMMAND = "ocra"
10
+ ICON_EXTENSION = ".ico"
11
+
12
+ # @return [String] Extra options to send to Ocra (Windows outputs only).
13
+ attr_accessor :ocra_parameters
14
+
15
+ def valid_for_platform?; Releasy.win_platform?; end
16
+
17
+ attr_reader :icon
18
+ def icon=(icon)
19
+ raise ArgumentError, "icon must be a #{ICON_EXTENSION} file" unless File.extname(icon) == ICON_EXTENSION
20
+ @icon = icon
21
+ end
22
+
23
+ protected
24
+ def setup
25
+ @icon = nil
26
+ @ocra_parameters = ""
27
+ super
28
+ end
29
+
30
+ protected
31
+ def ocra_command
32
+ command = defined?(Bundler) ? 'bundle exec ' : ''
33
+ command += %[#{OCRA_COMMAND} "#{project.executable}" ]
34
+ command += "--#{effective_executable_type} "
35
+ command += "--no-enc " if encoding_excluded?
36
+ command += "#{ocra_parameters} " if ocra_parameters
37
+ command += %[--icon "#{icon}" ] if icon
38
+ command += (project.files - [project.executable]).map {|f| %["#{f}"]}.join(" ")
39
+ command
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,158 @@
1
+ require "releasy/builders/builder"
2
+ require "releasy/mixins/has_gemspecs"
3
+
4
+ module Releasy
5
+ module Builders
6
+ # Builds an OS X application bundle.
7
+ #
8
+ # @attr icon [String] Optional filename of icon to show on executable/installer (.icns).
9
+ class OsxApp < Builder
10
+ include Mixins::HasGemspecs
11
+
12
+ TYPE = :osx_app
13
+
14
+ DEFAULT_FOLDER_SUFFIX = "OSX"
15
+
16
+ # Binary gems included in app.
17
+ BINARY_GEMS = %w[gosu texplay chipmunk]
18
+ # Icon type used in the app.
19
+ ICON_EXTENSION = ".icns"
20
+ # Source gems included in app that we should remove.
21
+ SOURCE_GEMS_TO_REMOVE = %w[chingu]
22
+
23
+ Builders.register self
24
+
25
+ # @return [String] Name of .app directory used as the framework for osx app release.
26
+ attr_accessor :wrapper
27
+ # @return [String] Inverse url of application (e.g. 'org.supergames.blasterbotsfrommars')
28
+ attr_accessor :url
29
+
30
+ # @return [String] Optional filename of icon to show on app (.icns).
31
+ attr_reader :icon
32
+
33
+ def icon=(icon)
34
+ raise ConfigError, "icon must be a #{ICON_EXTENSION} file" unless File.extname(icon) == ICON_EXTENSION
35
+ @icon = icon
36
+ end
37
+
38
+ protected
39
+ def generate_tasks
40
+ raise ConfigError, "#url not set" unless url
41
+ raise ConfigError, "#wrapper not set" unless wrapper
42
+ raise ConfigError, "#wrapper not valid wrapper: #{wrapper}" unless File.basename(wrapper) =~ /gosu-mac-wrapper-[\d\.]+.tar.gz/
43
+
44
+ new_app = File.join folder, app_name
45
+
46
+ directory folder
47
+
48
+ desc "Build OS X app"
49
+ task "build:osx:app" => folder
50
+
51
+ file folder => project.files + [wrapper] do
52
+ Rake::FileUtilsExt.verbose project.verbose?
53
+
54
+ # Copy the app files.
55
+ exec %[7z x -so -bd "#{wrapper}" | 7z x -si -mmt -bd -ttar -o"#{folder}"]
56
+ mv File.join(folder, "RubyGosu App.app"), new_app
57
+
58
+ ## Copy my source files.
59
+ copy_files_relative project.files, File.join(new_app, 'Contents/Resources/application')
60
+
61
+ # Copy accompanying files.
62
+ project.exposed_files.each {|file| cp file, folder }
63
+
64
+ copy_gems vendored_gem_names(BINARY_GEMS), File.join(new_app, 'Contents/Resources/vendor')
65
+ create_main new_app
66
+ edit_init new_app
67
+ remove_gems new_app
68
+ rename_executable new_app
69
+ update_icon new_app
70
+ create_executable_setter
71
+ end
72
+ end
73
+
74
+ protected
75
+ def setup
76
+ @icon = nil
77
+ @url = nil
78
+ @wrapper = nil
79
+ super
80
+ end
81
+
82
+ protected
83
+ def app_name; "#{project.name}.app"; end
84
+
85
+ protected
86
+ def create_executable_setter
87
+ if Releasy.win_platform?
88
+ # Ensure that we have a Unixy file by setting binary ("wb") mode on Windows.
89
+ File.open(File.join(folder, "set_app_executable.sh"), "wb") do |file|
90
+ file.puts <<END
91
+ #!/bin/sh
92
+ chmod a+x "./#{app_name}/Contents/MacOS/#{project.name}"
93
+ echo "Made #{app_name} executable"
94
+ END
95
+
96
+ end
97
+ end
98
+ end
99
+
100
+ protected
101
+ def rename_executable(app)
102
+ new_executable = "#{app}/Contents/MacOS/#{project.name}"
103
+ mv "#{app}/Contents/MacOS/RubyGosu App" , new_executable
104
+ chmod 0755, new_executable
105
+ end
106
+
107
+ protected
108
+ # Remove unnecessary gems from the distribution.
109
+ def remove_gems(app)
110
+ SOURCE_GEMS_TO_REMOVE.each do |gem|
111
+ rm_r "#{app}/Contents/Resources/lib/#{gem}"
112
+ end
113
+ end
114
+
115
+ protected
116
+ def update_icon(app)
117
+ if icon
118
+ rm "#{app}/Contents/Resources/Gosu.icns"
119
+ cp icon, "#{app}/Contents/Resources"
120
+ end
121
+ end
122
+
123
+ protected
124
+ def create_main(app)
125
+ # Something for the .app to run -> just a little redirection file.
126
+ puts "--- Creating Main.rb" if project.verbose?
127
+ File.open("#{app}/Contents/Resources/Main.rb", "w") do |file|
128
+ file.puts <<END_TEXT
129
+ Dir[File.expand_path("../vendor/gems/*/lib", __FILE__)].each do |lib|
130
+ $LOAD_PATH.unshift lib
131
+ end
132
+
133
+ OSX_EXECUTABLE_FOLDER = File.expand_path("../../..", __FILE__)
134
+
135
+ # Really hacky fudge-fix for something oddly missing in the .app.
136
+ class Encoding
137
+ UTF_7 = UTF_16BE = UTF_16LE = UTF_32BE = UTF_32LE = Encoding.list.first
138
+ end
139
+
140
+ load 'application/#{project.executable}'
141
+ END_TEXT
142
+ end
143
+ end
144
+
145
+ protected
146
+ def edit_init(app)
147
+ file = "#{app}/Contents/Info.plist"
148
+ # Edit the info file to be specific for my game.
149
+ puts "--- Editing init" if project.verbose?
150
+ info = File.read(file)
151
+ info.sub!('<string>Gosu</string>', "<string>#{File.basename(icon).chomp(File.extname(icon))}</string>") if icon
152
+ info.sub!('<string>RubyGosu App</string>', "<string>#{project.name}</string>")
153
+ info.sub!('<string>org.libgosu.UntitledGame</string>', "<string>#{url}</string>")
154
+ File.open(file, "w") {|f| f.puts info }
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,27 @@
1
+ require "releasy/builders/builder"
2
+
3
+ module Releasy
4
+ module Builders
5
+ # Creates a folder containing the application source.
6
+ class Source < Builder
7
+ TYPE = :source
8
+ Builders.register self
9
+
10
+ DEFAULT_FOLDER_SUFFIX = "SOURCE"
11
+
12
+ protected
13
+ def generate_tasks
14
+ desc "Build source folder"
15
+ task "build:source" => folder
16
+
17
+ directory folder
18
+
19
+ file folder => project.files do
20
+ Rake::FileUtilsExt.verbose project.verbose?
21
+
22
+ copy_files_relative project.files, folder
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,65 @@
1
+ require "releasy/builders/builder"
2
+
3
+ module Releasy
4
+ module Builders
5
+ # General functionality for Windows builders.
6
+ # @abstract
7
+ # @attr icon [String] Optional filename of icon to show on executable/installer (.ico).
8
+ class WindowsBuilder < Builder
9
+ EXECUTABLE_TYPES = [:auto, :windows, :console]
10
+
11
+ # @return [:auto, :windows, :console] Type of ruby to run executable with. :console means run with 'ruby.exe', :windows means run with 'rubyw.exe', :auto means determine type from executable extension (.rb => :console or .rbw => :windows).
12
+ attr_accessor :executable_type
13
+
14
+ # Excludes encoding files from 1.9 releases (equivalent to using '--no-enc' in Ocra).
15
+ def exclude_encoding
16
+ @exclude_encoding = true
17
+ end
18
+
19
+ # Should encoding files be excluded?
20
+ def encoding_excluded?; @exclude_encoding; end
21
+ protected :encoding_excluded?
22
+
23
+ # Executable type, resolving :auto if possible.
24
+ # @return [:windows, :console]
25
+ def effective_executable_type
26
+ if executable_type == :auto
27
+ case File.extname(project.executable)
28
+ when '.rbw'
29
+ :windows
30
+ when '.rb'
31
+ :console
32
+ else
33
+ raise ConfigError, "Unless the executable file extension is .rbw or .rb, then #executable_type must be explicitly :windows or :console"
34
+ end
35
+ else
36
+ executable_type
37
+ end
38
+ end
39
+
40
+ protected
41
+ def setup
42
+ @exclude_encoding = false
43
+ @executable_type = :auto
44
+ super
45
+ end
46
+
47
+ protected
48
+ def create_link_files(dir)
49
+ project.send(:links).each_pair do |url, title|
50
+ create_link_file url, File.join(dir, title)
51
+ end
52
+ end
53
+
54
+ protected
55
+ def create_link_file(url, title)
56
+ File.open("#{title}.url", "w") do |file|
57
+ file.puts <<END
58
+ [InternetShortcut]
59
+ URL=#{url}
60
+ END
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,47 @@
1
+ require "releasy/builders/ocra_builder"
2
+ require 'releasy/windows_wrapper_maker'
3
+
4
+ module Releasy
5
+ module Builders
6
+ # Builds a folder containing Ruby + your source + a small Windows executable to run your executable script.
7
+ class WindowsFolder < OcraBuilder
8
+ TYPE = :windows_folder
9
+ DEFAULT_FOLDER_SUFFIX = "WIN32"
10
+
11
+ Builders.register self
12
+
13
+ protected
14
+ # FOLDER containing EXE, Ruby + source.
15
+ def generate_tasks
16
+ directory project.output_path
17
+
18
+ file folder => project.files do
19
+ Rake::FileUtilsExt.verbose project.verbose?
20
+
21
+ tmp_ocra_executable = "#{folder}.exe"
22
+
23
+ exec %[#{ocra_command} --output "#{tmp_ocra_executable}" --debug-extract]
24
+
25
+ # Extract the files from the executable.
26
+ system tmp_ocra_executable
27
+ rm tmp_ocra_executable
28
+
29
+ mv Dir["#{File.dirname(folder)}/ocr*\.tmp"].first, folder
30
+
31
+ maker = Releasy::WindowsWrapperMaker.new
32
+ maker.build_executable("#{folder}/#{executable_name}", "src/#{project.executable}",
33
+ :icon => icon, :windows => (effective_executable_type == :windows))
34
+
35
+ create_link_files folder
36
+ project.exposed_files.each {|file| cp file, folder }
37
+ end
38
+
39
+ desc "Build source/exe folder #{project.version}"
40
+ task "build:windows:folder" => folder
41
+ end
42
+
43
+ protected
44
+ def executable_name; "#{project.underscored_name}.exe"; end
45
+ end
46
+ end
47
+ end