irpack 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/irpack CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ir
2
2
 
3
3
  =begin
4
- Copyright (c) 2010 Ryuichi Sakamoto.
4
+ Copyright (c) 2010-2011 Ryuichi Sakamoto.
5
5
 
6
6
  This software is provided 'as-is', without any express or implied
7
7
  warranty. In no event will the authors be held liable for any damages
@@ -23,34 +23,8 @@ freely, subject to the following restrictions:
23
23
  distribution.
24
24
  =end
25
25
 
26
- require 'irpack'
27
- require 'optparse'
28
-
29
- packdir = nil
30
- output_file = nil
31
- target = :exe
32
- compress = false
33
- stdlib = true
34
- opt = OptionParser.new
35
- opt.on('-d SOURCEDIR', 'Specify pack directory. [base of ENTRYFILE]') {|v| packdir = v }
36
- opt.on('-o OUTPUTFILE', 'Specify output file name.') {|v| output_file = v }
37
- opt.on('-w', 'Generate window app.') { target = :winexe }
38
- opt.on('-W', 'Generate console app.[default]') { target = :exe }
39
- opt.on('--compress', 'Compress package.') { compress = true }
40
- opt.on('--no-stdlib', 'Do not include IronRuby assemblies.') {|v| stdlib = v }
41
- opt.banner = "Usage: #{$0} [options] ENTRYFILE"
42
- opt.parse!(ARGV)
43
-
44
- if ARGV.size<1 then
45
- $stderr.puts opt.help
46
- exit 1
47
- end
48
-
49
- entry_file = ARGV[0]
50
- packdir ||= File.dirname(entry_file)
51
- output_file ||= File.join(File.dirname(entry_file), File.basename(entry_file, '.*')+'.exe')
52
- IRPack.pack_dir(packdir, entry_file, output_file,
53
- :target => target,
54
- :compress => compress,
55
- :stdlib => stdlib)
26
+ require 'irpack/application'
27
+
28
+ args = IRPack::Application::Arguments.parse!(ARGV)
29
+ exit(IRPack::Application.run(args))
56
30
 
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright (c) 2010 Ryuichi Sakamoto.
2
+ Copyright (c) 2010-2011 Ryuichi Sakamoto.
3
3
 
4
4
  This software is provided 'as-is', without any express or implied
5
5
  warranty. In no event will the authors be held liable for any damages
@@ -21,484 +21,72 @@ freely, subject to the following restrictions:
21
21
  distribution.
22
22
  =end
23
23
 
24
- require 'erb'
25
- require 'fileutils'
24
+ require 'irpack/cscompiler'
25
+ require 'irpack/bootloader'
26
+ require 'irpack/entrypoint'
27
+ require 'irpack/packager'
28
+ require 'irpack/missing'
26
29
  require 'tmpdir'
27
- require 'pathname'
28
- require 'WindowsBase'
29
-
30
- unless Dir.respond_to?(:mktmpdir) then
31
- def Dir.mktmpdir(prefix_suffix=['d',''], tmpdir=Dir.tmpdir, &block)
32
- if prefix_suffix.kind_of?(String) then
33
- prefix = prefix_suffix
34
- suffix = ''
35
- else
36
- prefix = prefix_suffix[0]
37
- suffix = prefix_suffix[1]
38
- end
39
- n = 0
40
- begin
41
- path = File.join(tmpdir, "#{prefix}-#{Time.now.to_i}-#{$$}-#{rand(0x100000000).to_s(36)}-#{suffix}-#{n}")
42
- Dir.mkdir(path, 0700)
43
- rescue Errno::EEXIST
44
- n += 1
45
- retry
46
- end
47
-
48
- if block then
49
- begin
50
- block.call(path)
51
- ensure
52
- FileUtils.remove_entry_secure(path)
53
- end
54
- else
55
- path
56
- end
57
- end
58
- end
59
-
60
- module IRPack
61
- include System
62
- include System::Reflection
63
-
64
- module CSCompiler
65
- include Microsoft::CSharp
66
- include System::CodeDom::Compiler
67
- include System::Reflection
68
-
69
- module_function
70
- def compiler_version
71
- case System::Environment.version.major
72
- when 4
73
- 'v4.0'
74
- when 2
75
- 'v3.5'
76
- end
77
- end
78
-
79
- def system_assemblies
80
- case compiler_version
81
- when 'v4.0'
82
- [
83
- 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
84
- 'WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
85
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
86
- ]
87
- when 'v3.5'
88
- [
89
- 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
90
- 'WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
91
- 'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
92
- ]
93
- end
94
- end
95
-
96
- def system_assembly_files
97
- system_assemblies.collect {|name|
98
- Assembly.reflection_only_load(name.to_clr_string).location
99
- }
100
- end
101
-
102
- def find_assembly(paths, file)
103
- path = paths.find {|path| File.exist?(File.join(path, file)) }
104
- if path then
105
- File.join(path, file)
106
- else
107
- file
108
- end
109
- end
110
-
111
- class CompileError < RuntimeError; end
112
- def compile(target, srcs, references, resources, output_name)
113
- opts = System::Collections::Generic::Dictionary[System::String,System::String].new
114
- opts['CompilerVersion'] = compiler_version
115
- @compiler = CSharpCodeProvider.new(opts)
116
- srcs = srcs.kind_of?(Array) ? srcs : [srcs]
117
- refs = system_assembly_files + references
118
- refs = System::Array[System::String].new(refs.size) {|i| refs[i] }
119
- icon = resources.find {|rc| File.extname(rc)=='.ico' }
120
-
121
- params = CompilerParameters.new(refs, output_name, false)
122
- params.generate_in_memory = false
123
- compiler_options = ['/optimize+']
124
- case target
125
- when :exe, 'exe'
126
- params.generate_executable = true
127
- compiler_options << '/target:exe'
128
- compiler_options << "/win32icon:#{icon}" if icon
129
- when :winexe, 'winexe'
130
- params.generate_executable = true
131
- compiler_options << '/target:winexe'
132
- compiler_options << "/win32icon:#{icon}" if icon
133
- else
134
- params.generate_executable = false
135
- compiler_options << '/target:library'
136
- end
137
- params.compiler_options = compiler_options.join(' ')
138
- resources.each do |rc|
139
- params.embedded_resources.add(rc)
140
- end
141
- srcs = System::Array[System::String].new(srcs.size) {|i| srcs[i] }
142
- result = @compiler.compile_assembly_from_source(params, srcs)
143
- result.errors.each do |err|
144
- if err.is_warning then
145
- $stderr.puts(err.to_s)
146
- else
147
- raise CompileError, err.to_s
148
- end
149
- end
150
- result.path_to_assembly
151
- end
152
- end
153
- end
154
30
 
155
31
  module IRPack
156
- BootLoaderSource = <<CS
157
- using System;
158
- using System.IO;
159
- using System.IO.Packaging;
160
- using System.Reflection;
161
-
162
- namespace <%= module_name %> {
163
- public class BootLoader
164
- {
165
- private static Assembly LoadAssemblyFromPackage(AppDomain domain, Package package, string file)
166
- {
167
- var uri = PackUriHelper.CreatePartUri(new Uri(file, UriKind.Relative));
168
- if (package.PartExists(uri)) {
169
- var stream = package.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
170
- var raw = new byte[stream.Length];
171
- stream.Read(raw, 0, (int)stream.Length);
172
- stream.Close();
173
- return domain.Load(raw);
174
- }
175
- else {
176
- return null;
177
- }
178
- }
179
-
180
- private static Assembly LoadAssembly(AppDomain domain, Package package, string file)
181
- {
182
- try {
183
- return domain.Load(file);
184
- }
185
- catch (FileNotFoundException)
186
- {
187
- return LoadAssemblyFromPackage(domain, package, file);
188
- }
189
- }
190
-
191
- public static int Main(string[] args)
192
- {
193
- AppDomain domain = AppDomain.CurrentDomain;
194
- domain.AssemblyResolve += new ResolveEventHandler(delegate (object sender, ResolveEventArgs e) {
195
- foreach (var asm in domain.GetAssemblies()) {
196
- if (e.Name==asm.FullName) {
197
- return asm;
198
- }
199
- }
200
- throw new FileNotFoundException(e.Name);
201
- });
202
- var stream = Assembly.GetEntryAssembly().GetManifestResourceStream(@"<%= package_file %>");
203
- var package = Package.Open(stream, FileMode.Open, FileAccess.Read);
204
- <% preload_assemblies.each do |asm| %>
205
- LoadAssembly(domain, package, @"<%= asm %>");
206
- <% end %>
207
- var entry_point = LoadAssemblyFromPackage(domain, package, @"<%= module_name %>.EntryPoint.dll");
208
- var main = entry_point.GetType(@"<%= module_name %>.EntryPoint").GetMethod("Main");
209
- int result = (int)(main.Invoke(null, new object[] { package, args }));
210
- package.Close();
211
- return result;
212
- }
213
- }
214
- }
215
- CS
216
-
217
- EntryPointSource = <<CS
218
- using System;
219
- using System.IO;
220
- using System.IO.Packaging;
221
- using System.Reflection;
222
- using Microsoft.Scripting;
223
- using Microsoft.Scripting.Hosting;
224
-
225
- namespace <%= module_name %> {
226
- public class EntryPoint
227
- {
228
- public class PackagePAL : PlatformAdaptationLayer
229
- {
230
- public Package CurrentPackage { get; set; }
231
- public PackagePAL(Package pkg)
232
- {
233
- CurrentPackage = pkg;
234
- }
235
-
236
- private Uri ToPackageLoadPath(string path)
237
- {
238
- var domain = AppDomain.CurrentDomain;
239
- var fullpath = Path.GetFullPath(path);
240
- var searchpath = Path.GetFullPath(
241
- domain.RelativeSearchPath!=null ?
242
- Path.Combine(domain.BaseDirectory, domain.RelativeSearchPath) :
243
- domain.BaseDirectory);
244
- if (fullpath.StartsWith(searchpath)) {
245
- var relpath = fullpath.Substring(searchpath.Length, fullpath.Length-searchpath.Length);
246
- return PackUriHelper.CreatePartUri(new Uri(relpath, UriKind.Relative));
247
- }
248
- else {
249
- return PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
250
- }
251
- }
252
-
253
- private Uri ToPackagePath(string path)
254
- {
255
- var fullpath = Path.GetFullPath(path);
256
- var searchpath = Path.GetDirectoryName(Path.GetFullPath(Assembly.GetEntryAssembly().Location));
257
- if (fullpath.StartsWith(searchpath)) {
258
- var relpath = fullpath.Substring(searchpath.Length, fullpath.Length-searchpath.Length);
259
- return PackUriHelper.CreatePartUri(new Uri(relpath, UriKind.Relative));
260
- }
261
- else {
262
- return PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
263
- }
264
- }
265
-
266
- public override Assembly LoadAssembly(string name)
267
- {
268
- foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
269
- if (asm.FullName==name) {
270
- return asm;
271
- }
272
- }
273
- return Assembly.Load(name);
274
- }
275
-
276
- public override Assembly LoadAssemblyFromPath(string path)
277
- {
278
- try {
279
- return Assembly.LoadFile(path);
280
- }
281
- catch (FileNotFoundException e) {
282
- var uri = ToPackageLoadPath(path);
283
- if (CurrentPackage.PartExists(uri)) {
284
- var stream = CurrentPackage.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
285
- var raw = new byte[stream.Length];
286
- stream.Read(raw, 0, (int)stream.Length);
287
- stream.Close();
288
- return Assembly.Load(raw);
289
- }
290
- else {
291
- throw e;
292
- }
293
- }
294
- }
295
-
296
- public override bool FileExists(string path)
297
- {
298
- if (File.Exists(path)) {
299
- return true;
300
- }
301
- else {
302
- var uri = ToPackagePath(path);
303
- return CurrentPackage.PartExists(uri);
304
- }
305
- }
306
-
307
- public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share)
308
- {
309
- if (mode==FileMode.Open && access==FileAccess.Read) {
310
- var uri = ToPackagePath(path);
311
- if (CurrentPackage.PartExists(uri)) {
312
- return CurrentPackage.GetPart(uri).GetStream(mode, access);
313
- }
314
- else {
315
- return new FileStream(path, mode, access, share);
316
- }
317
- }
318
- else {
319
- return new FileStream(path, mode, access, share);
320
- }
321
- }
322
-
323
- public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
324
- {
325
- if (mode==FileMode.Open && access==FileAccess.Read) {
326
- var uri = ToPackagePath(path);
327
- if (CurrentPackage.PartExists(uri)) {
328
- return CurrentPackage.GetPart(uri).GetStream(mode, access);
329
- }
330
- else {
331
- return new FileStream(path, mode, access, share, bufferSize);
332
- }
333
- }
334
- else {
335
- return new FileStream(path, mode, access, share, bufferSize);
336
- }
337
- }
338
-
339
- public override Stream OpenInputFileStream(string path)
340
- {
341
- var uri = ToPackagePath(path);
342
- if (CurrentPackage.PartExists(uri)) {
343
- return CurrentPackage.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
344
- }
345
- else {
346
- return new FileStream(path, FileMode.Open, FileAccess.Read);
347
- }
348
- }
349
- }
350
-
351
- public class IRHost : ScriptHost
352
- {
353
- private PlatformAdaptationLayer PAL_;
354
- public override PlatformAdaptationLayer PlatformAdaptationLayer { get { return PAL_; } }
355
- public IRHost(Package pkg)
356
- {
357
- PAL_ = new PackagePAL(pkg);
358
- }
359
- }
360
-
361
- public static int Main(Package package, string[] args)
362
- {
363
- var runtime_setup = new ScriptRuntimeSetup();
364
- runtime_setup.LanguageSetups.Add(IronRuby.Ruby.CreateRubySetup());
365
- runtime_setup.Options["MainFile"] = "<%= entry_file %>";
366
- runtime_setup.Options["Arguments"] = args;
367
- runtime_setup.HostType = typeof(IRHost);
368
- runtime_setup.HostArguments = new object[] { package };
369
- var engine = IronRuby.Ruby.GetEngine(IronRuby.Ruby.CreateRuntime(runtime_setup));
370
- try {
371
- engine.ExecuteFile("<%= entry_file %>");
372
- return 0;
373
- }
374
- catch (IronRuby.Builtins.SystemExit e) {
375
- return e.Status;
376
- }
377
- }
378
- }
379
- }
380
- CS
381
- module_function
382
- def bootloader_source(module_name, package_file, preload_assemblies)
383
- ERB.new(BootLoaderSource).result(binding)
384
- end
385
-
386
- def entrypoint_source(module_name, entry_file)
387
- ERB.new(EntryPointSource).result(binding)
388
- end
389
- end
390
-
391
- module IRPack
392
- module Packager
393
- include System
394
- include System::IO::Packaging
395
-
396
- RelType = 'http://schemas.openxmlformats.org/package/2006/relationships/meta data/core-properties'
397
- module_function
398
- def pack(files, package_file, compress=false)
399
- compress_option = compress ? CompressionOption.normal : CompressionOption.not_compressed
400
- package = Package.open(package_file, System::IO::FileMode.create)
401
- files.each do |src, dest|
402
- uri = PackUriHelper.create_part_uri(Uri.new(dest, UriKind.relative))
403
- part = package.create_part(uri, 'application/octet-stream', compress_option)
404
- stream = part.get_stream
405
- File.open(src, 'rb') do |f|
406
- data = f.read
407
- stream.write(data, 0, data.size)
408
- end
409
- stream.close
410
- package.create_relationship(uri, TargetMode.internal, RelType)
411
- end
412
- package.close
413
- end
414
-
415
- def pack_dir(dir_name, package_file)
416
- files = {}
417
- base = Pathname.new(dir_name)
418
- Dir.glob(base.join('**', '*')) do |fn|
419
- files[fn] = Pathname.new(fn).relative_path_from(base)
420
- end
421
- pack(files, package_file)
422
- end
423
- end
424
-
425
- AssemblyPath = ::File.dirname(Assembly.get_entry_assembly.location.to_s)
426
- PreloadAssemblies = %w[
427
- Microsoft.Dynamic.dll
428
- Microsoft.Scripting.dll
429
- Microsoft.Scripting.Core.dll
430
- IronRuby.dll
431
- IronRuby.Libraries.dll
432
- IronRuby.Libraries.Yaml.dll
32
+ IronRubyAssemblies = %w[
33
+ Microsoft.Dynamic
34
+ Microsoft.Scripting
35
+ Microsoft.Scripting.Core
36
+ IronRuby
37
+ IronRuby.Libraries
38
+ IronRuby.Libraries.Yaml
433
39
  ]
434
40
 
435
41
  module_function
436
42
  def path_to_module_name(filename)
437
43
  name = File.basename(filename, '.*')
438
44
  name.gsub!(/[^A-Za-z0-9_]/, '_')
439
- /^[A-Za-z]/=~name ? name : ('M'+name)
45
+ (/^[A-Za-z]/=~name ? name : ('M'+name)).upcase
46
+ end
47
+
48
+ def ironruby_assemblies
49
+ IronRubyAssemblies.each do |name|
50
+ begin
51
+ load_assembly name
52
+ rescue LoadError
53
+ end
54
+ end
55
+ System::AppDomain.current_domain.get_assemblies.select {|asm|
56
+ IronRubyAssemblies.include?(asm.get_name.name)
57
+ }.collect {|asm| asm.location }
440
58
  end
441
59
 
442
- def pack(files, entry_file, output_file, options={})
443
- preload_assemblies = PreloadAssemblies.collect {|fn|
444
- File.join(AssemblyPath, fn)
445
- }.select {|fn|
446
- File.exist?(fn)
447
- }
60
+ def pack(output_file, files, entry_file, opts={})
61
+ opts = {
62
+ :target => :exe,
63
+ :compress => false,
64
+ :embed_references => true,
65
+ :module_name => path_to_module_name(output_file)
66
+ }.update(opts)
448
67
  basename = File.basename(output_file, '.*')
449
- module_name = path_to_module_name(output_file)
450
- resources = options[:resources] || []
451
- target = options[:target] || :exe
452
- stdlib = options.include?(:stdlib) ? options[:stdlib] : true
453
- compress = options.include?(:compress) ? options[:compress] : false
454
- pack_files = files.dup
68
+ module_name = opts[:module_name]
69
+ target = opts[:target]
70
+ references = opts[:references] || ironruby_assemblies
71
+ compress = opts[:compress]
72
+ pack_files = {}.merge(files)
73
+ if opts[:embed_references] then
74
+ references.each do |asm|
75
+ pack_files[asm] = File.basename(asm)
76
+ end
77
+ end
455
78
 
456
79
  Dir.mktmpdir(File.basename($0,'.*')) do |tmp_path|
457
- entry_src = entrypoint_source(module_name, entry_file)
458
80
  entry_dll = File.join(tmp_path, module_name+'.EntryPoint.dll')
459
- CSCompiler.compile(:dll, entry_src, preload_assemblies, [], entry_dll)
81
+ EntryPoint.compile(entry_dll, module_name, entry_file, references)
460
82
  pack_files[entry_dll] = File.basename(entry_dll)
461
- if stdlib then
462
- preload_assemblies.each do |asm|
463
- pack_files[asm] = File.basename(asm)
464
- end
465
- end
83
+
466
84
  package_file = File.join(tmp_path, basename+'.pkg')
467
85
  Packager.pack(pack_files, package_file, compress)
468
86
 
469
- target_src = bootloader_source(
470
- module_name,
471
- File.basename(package_file),
472
- preload_assemblies.collect {|fn| File.basename(fn) }
473
- )
474
- Dir.chdir(tmp_path) do
475
- CSCompiler.compile(target, target_src, [], [File.basename(package_file)], output_file)
476
- end
477
- end
478
- end
479
-
480
- def pack_dir(pack_dir, entry_file, output_file, options={})
481
- output_file = File.expand_path(output_file)
482
- entry_packed = nil
483
- pack_files = {}
484
- resources = []
485
- base = Pathname.new(pack_dir).expand_path
486
- Dir.glob(base.join('**', '*')) do |fn|
487
- path = Pathname.new(File.expand_path(fn))
488
- next if path==output_file
489
- relpath = path.relative_path_from(base)
490
- pack_files[path] = relpath
491
- if not entry_packed and
492
- (path.to_s==File.expand_path(entry_file) or
493
- path.basename.to_s==entry_file or
494
- relpath.to_s==entry_file) then
495
- entry_packed = relpath
496
- end
497
- resources << path.to_s if path.extname=='.ico'
87
+ BootLoader.compile(target, output_file, module_name, references, package_file)
498
88
  end
499
- raise ArgumentError, "Entry file `#{entry_file}' is not in packed directory."unless entry_packed
500
- options = options.merge(:resources => resources)
501
- pack(pack_files, entry_packed, output_file, options)
89
+ output_file
502
90
  end
503
91
  end
504
92