rake-delphi 0.0.9 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/2 +336 -0
  2. data/Gemfile +2 -1
  3. data/lib/rake/common/logger.rb +1 -1
  4. data/lib/rake/delphi/androidmanifest.rb +57 -0
  5. data/lib/rake/delphi/dcc32.rb +58 -59
  6. data/lib/rake/delphi/dcc32tool.rb +51 -0
  7. data/lib/rake/delphi/dccaarmtool.rb +29 -0
  8. data/lib/rake/delphi/envvariables.rb +19 -22
  9. data/lib/rake/delphi/paclient.rb +251 -0
  10. data/lib/rake/delphi/paclienttool.rb +20 -0
  11. data/lib/rake/delphi/project.rb +4 -2
  12. data/lib/rake/delphi/projectinfo.rb +73 -1
  13. data/lib/rake/delphi/resources.rb +1 -1
  14. data/lib/rake/delphi/tool.rb +8 -1
  15. data/lib/rake/delphi/version.rb +1 -1
  16. data/lib/rake/helpers/gemversion.rb +11 -0
  17. data/lib/rake/helpers/raketask.rb +16 -0
  18. data/lib/rake/helpers/string.rb +13 -0
  19. data/rake-delphi-cygwin.env.cmd +11 -0
  20. data/rake-delphi-cygwin.env.sh +12 -0
  21. data/rake-delphi.gemspec +4 -1
  22. data/test/helpers/consts.rb +6 -1
  23. data/test/helpers/verinfo.rb +22 -3
  24. data/test/resources/testproject-android/AndroidManifest.erb +35 -0
  25. data/test/resources/testproject-android/AndroidManifest.xml +35 -0
  26. data/test/resources/testproject-android/Rakefile.rb +55 -0
  27. data/test/resources/testproject-android/TestProject.cfg +4 -0
  28. data/test/resources/testproject-android/TestProject.dpr +15 -0
  29. data/test/resources/testproject-android/TestProject.rc +62 -0
  30. data/test/resources/testproject-android/TestProject.res +0 -0
  31. data/test/resources/testproject-android/TestProject.xe5.dproj +373 -0
  32. data/test/resources/testproject-android/fmTest.fmx +26 -0
  33. data/test/resources/testproject-android/fmTest.pas +31 -0
  34. data/test/resources/testproject-android/local.resources.txt +1 -0
  35. data/test/resources/testproject-android/release.dcc.cfg +1 -0
  36. data/test/resources/testproject-android/resources.rc +1 -0
  37. data/test/resources/testproject-android/resources.res +0 -0
  38. data/test/resources/testproject/Rakefile.rb +1 -1
  39. data/test/test-delphi-android.rb +192 -0
  40. data/test/test-delphi.rb +3 -11
  41. data/test/test-envvariables.rb +7 -0
  42. data/test/test-gemversion.rb +11 -0
  43. data/test/test-projectinfo-android.rb +81 -0
  44. data/test/test-projectinfo.rb +0 -11
  45. data/test/test-string.rb +41 -0
  46. metadata +92 -6
  47. data/test/resources/testproject/testproject.cfg.1 +0 -8
  48. data/test/resources/testproject/testproject.drc +0 -210
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake/common/logger'
4
+ require 'rake/delphi/tool'
5
+
6
+ module Rake
7
+ module Delphi
8
+ class Dcc32Tool < CustomDelphiTool
9
+ attr_reader :env
10
+
11
+ def self.toolName
12
+ 'bin/dcc32.exe'
13
+ end
14
+
15
+ def delphidir
16
+ @@delphidir
17
+ end
18
+
19
+ def delphilib
20
+ ENV['BDSLIB']
21
+ end
22
+
23
+ def init_env
24
+ @env ||= EnvVariables.new(self.class.rootForVersion(self.version) + '\Environment Variables', self.delphidir)
25
+ end
26
+
27
+ def readLibraryPaths(platform, platform_stripped)
28
+ Logger.trace(Logger::TRACE, 'Reading library paths for platform: ' + platform.to_s)
29
+ warn "WARNING! You are using Delphi XE or above but no platform defined!" if ENV['DELPHI_VERSION'].to_i >= 14 && ! platform
30
+
31
+ platform = platform.to_s != '' ? '\\' + platform : ''
32
+ # platform not used for old Delphis 'SearchPath'
33
+ libpaths = self.class.readUserOption('Library' + platform, 'Search Path', self.version).split(';') \
34
+ | self.class.readUserOption('Library', 'SearchPath', self.version).split(';')
35
+ Logger.trace(Logger::TRACE, 'Library paths read:')
36
+ Logger.trace(Logger::TRACE, libpaths)
37
+ dev = init_env
38
+ dev['PLATFORM'] = platform_stripped if platform_stripped
39
+ libpaths.map! do |lp|
40
+ unless lp.to_s.empty?
41
+ lp = dev.expand(lp)
42
+ end
43
+ lp
44
+ end
45
+ Logger.trace(Logger::TRACE, 'Library paths expanded:')
46
+ Logger.trace(Logger::TRACE, libpaths)
47
+ return libpaths
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,29 @@
1
+ # vim: set shiftwidth=2 tabstop=2 expandtab:
2
+ # encoding: utf-8
3
+
4
+ require 'rake/delphi/dcc32tool'
5
+
6
+ module Rake
7
+ module Delphi
8
+ class DccARMTool < Dcc32Tool
9
+ def self.toolName
10
+ 'bin/dccaarm.exe'
11
+ end
12
+
13
+ def options
14
+ opts = []
15
+ linker_path = ENV['DELPHI_ANDROID_SDK_LINKER']
16
+ warn "Please, define DELPHI_ANDROID_SDK_LINKER environment variable.\n Otherwise you may get 'File not found: ldandroid.exe' error" unless linker_path
17
+ lib_path = ENV['DELPHI_ANDROID_SDK_LIBPATH']
18
+ warn 'Please, define DELPHI_ANDROID_SDK_LIBPATH environment variable' unless lib_path
19
+ linker_option = ENV['DELPHI_ANDROID_SDK_LINKER_OPTION']
20
+ warn 'Please, define DELPHI_ANDROID_SDK_LINKER_OPTION environment variable' unless linker_option
21
+ opts << '-TX.so'
22
+ opts << "--linker:\"#{linker_path}\""
23
+ opts << "--libpath:\"#{lib_path}\""
24
+ opts << "--linker-option:\"#{linker_option}\""
25
+ return opts
26
+ end
27
+ end
28
+ end
29
+ end
@@ -8,6 +8,22 @@ module Rake
8
8
  ENV['DELPHI_VERSION']
9
9
  end
10
10
 
11
+ def initialize(regpath, delphidir)
12
+ readreg(regpath)
13
+ _dir = delphidir.gsub(/\/$/, '')
14
+ add('DELPHI', _dir)
15
+ add('BDS', _dir)
16
+ add('BDSLIB', _dir + '/Lib')
17
+ expand_vars
18
+ Logger.trace(Logger::TRACE, self)
19
+ end
20
+
21
+ def expand(value)
22
+ value = expand_value(value, self)
23
+ value = expand_value(value, ENV)
24
+ end
25
+
26
+ private
11
27
  def readreg(regpath)
12
28
  return unless regpath
13
29
  begin
@@ -29,34 +45,15 @@ module Rake
29
45
  end
30
46
  end
31
47
 
32
- def initialize(regpath, delphidir)
33
- readreg(regpath)
34
- _dir = delphidir.gsub(/\/$/, '')
35
- add('DELPHI', _dir)
36
- add('BDS', _dir)
37
- add('BDSLIB', _dir + '/Lib')
38
- expand_vars
39
- Logger.trace(Logger::TRACE, self)
40
- end
41
-
42
48
  def add(var, value)
43
49
  self[var] = value
44
50
  end
45
51
 
46
- def expand_global(value)
47
- value.gsub!(/\$\((?'env_name'\w+)\)/) do |match|
52
+ def expand_value(value, values)
53
+ value.gsub(/\$\((?'env_name'\w+)\)/) do |match|
48
54
  name = Regexp.last_match[:env_name].upcase
49
- ENV[name] || match
50
- end
51
- value
52
- end
53
-
54
- def expand(value)
55
- self.each do |name, val|
56
- value.gsub!("$(#{name})", val)
57
- value = expand_global(value)
55
+ values[name] || match
58
56
  end
59
- value
60
57
  end
61
58
 
62
59
  def expand_vars
@@ -0,0 +1,251 @@
1
+ # vim: set shiftwidth=2 tabstop=2 expandtab:
2
+ # encoding: utf-8
3
+
4
+ require 'fileutils'
5
+ require 'tempfile'
6
+ require 'rake'
7
+ require 'rake/helpers/rake'
8
+ require 'rake/helpers/raketask'
9
+ require 'rake/helpers/string'
10
+ require 'rake/common/chdirtask'
11
+ require 'rake/delphi/paclienttool'
12
+ require 'rake/delphi/androidmanifest'
13
+
14
+ module Rake
15
+ module Delphi
16
+ class PAClientTask < Rake::Task
17
+ public
18
+ attr_reader :dccTask
19
+ attr_accessor :suffix
20
+ attr_reader :deploymentfiles
21
+ attr_accessor :noclean # for debugging
22
+
23
+ def initialize(name, application)
24
+ super
25
+ @last_put_arg_index = 0
26
+ @suffix = 'AndroidPackage'
27
+ @manifest = application.define_task(AndroidManifestTask, shortname + ':manifest')
28
+ enhance([@manifest])
29
+ self.needed = false
30
+ dccTaskName = name.gsub(/:post$/, '')
31
+ @dccTask = application[dccTaskName]
32
+ @deploymentfiles = nil
33
+ end
34
+
35
+ def needed=(value)
36
+ super
37
+ @manifest.needed = value
38
+ end
39
+
40
+ private
41
+ def expand_vars(deploymentfiles)
42
+ @dccTask.dccTool.init_env
43
+ deploymentfiles.collect! do |value|
44
+ file, dfile = [value.keys.first, value.values.first]
45
+ if file.kind_of?(String)
46
+ file = @dccTask.dccTool.env.expand(file)
47
+ end
48
+ # return expanded path
49
+ { file => dfile }
50
+ end
51
+ return deploymentfiles
52
+ end
53
+
54
+ def put_args
55
+ @deploymentfiles ||= @dccTask.createVersionInfo.deploymentfiles('Android')
56
+ r = expand_vars(@deploymentfiles)
57
+ @manifest_hash ||= { :manifest => ['.\\', '1'] }
58
+ # add unless already added before
59
+ r << @manifest_hash unless r.include?(@manifest_hash)
60
+ return r
61
+ end
62
+
63
+ def steps
64
+ r = [:Clean]
65
+ # add appropriate 'put' commands count
66
+ put_args.each do |arg|
67
+ r << :put
68
+ end
69
+ r << [:stripdebug, :aaptpackage, :jarsign, :zipalign]
70
+ r.flatten!
71
+ return r
72
+ end
73
+
74
+ def get_Clean_arg(paclientTool)
75
+ return '' if @noclean
76
+ tempfile = Tempfile.new('paclient')
77
+ tempfile.close
78
+ tempfile = File.expand_path2(tempfile.path)
79
+ tempfile.double_delimiters!
80
+ output = @dccTask.exeoutput
81
+ output += '\\' + @suffix
82
+ output.double_delimiters!
83
+ output = Rake.quotepath('', output)
84
+ return [output, tempfile].join(',')
85
+ end
86
+
87
+ def get_put_arg(paclientTool)
88
+ output = @dccTask.exeoutput
89
+ next_put_arg = put_args[@last_put_arg_index]
90
+ if next_put_arg.kind_of?(Hash)
91
+ src, out = next_put_arg.to_a.first
92
+ out = out.dup
93
+ if src == :project_so
94
+ src = out.last
95
+ src = output + '\\' + src
96
+ elsif src.kind_of?(Symbol)
97
+ src = self.send(src)
98
+ out << src
99
+ end
100
+ out = output + '\\' + @suffix + '\\' + out.join(',')
101
+ arg = src + ',' + out
102
+ else
103
+ arg = next_put_arg
104
+ end
105
+ arg.double_delimiters!
106
+ arg = Rake.quotepath('', arg)
107
+ @last_put_arg_index += 1
108
+ return arg
109
+ end
110
+
111
+ def find_project_so(deploymentfiles)
112
+ deploymentfiles.each do |file|
113
+ return file[:project_so] if file[:project_so]
114
+ end
115
+ fail 'Cannot find :project_so in files'
116
+ end
117
+
118
+ def get_stripdebug_arg(paclientTool)
119
+ stripdebug_path = ENV['DELPHI_ANDROID_SDK_STRIPDEBUG']
120
+ warn 'Please, set DELPHI_ANDROID_SDK_STRIPDEBUG to path where arm-linux-androideabi-strip.exe is located' unless stripdebug_path
121
+ stripdebug_path = Rake.quotepath('', stripdebug_path.to_s)
122
+ output_dest = find_project_so(@deploymentfiles).dup
123
+ output = @dccTask.exeoutput + '\\' + output_dest.last
124
+ # remove '1' string
125
+ output_dest.delete_at(1)
126
+ output_dest.unshift @dccTask.exeoutput + '\\' + @suffix + '\\'
127
+ args = [stripdebug_path.double_delimiters, output.double_delimiters, output_dest.join.double_delimiters]
128
+ return args.join(',')
129
+ end
130
+
131
+ def aapt_args
132
+ r = ['library', 'classes', 'res', 'assets', :manifest, :jar, :output]
133
+ return r
134
+ end
135
+
136
+ def manifest
137
+ 'AndroidManifest.xml'
138
+ end
139
+
140
+ def unsigned_path(full = false)
141
+ r = @dccTask.dpr.pathmap('%n-unsigned.apk')
142
+ r = @dccTask.exeoutput + '/' + @suffix + '/' + r if full
143
+ return r
144
+ end
145
+
146
+ def get_aaptpackage_arg(paclientTool)
147
+ output = @dccTask.exeoutput
148
+ output_platform = File.expand_path2(output, '-u')
149
+ apt_path = ENV['DELPHI_ANDROID_SDK_BUILD_TOOLS_PATH']
150
+ warn 'Please, set DELPHI_ANDROID_SDK_BUILD_TOOLS_PATH to path where aapt.exe is located' unless apt_path
151
+ apt_path = apt_path.to_s + '\\aapt.exe'
152
+ apt_path = Rake.quotepath('', apt_path)
153
+ args = [apt_path.double_delimiters]
154
+ args += aapt_args.map do |a|
155
+ to_mkdir = false
156
+ out = true
157
+ if a == :output
158
+ a = unsigned_path
159
+ elsif a == :jar
160
+ platform = ENV['DELPHI_ANDROID_SDK_PLATFORM_PATH']
161
+ warn 'Please, set DELPHI_ANDROID_SDK_PLATFORM_PATH to the path where android.jar is located' unless platform
162
+ a = platform.to_s + '\\android.jar'
163
+ a = Rake.quotepath('', a)
164
+ out = false
165
+ else
166
+ if a.kind_of?(Symbol)
167
+ a = self.send(a)
168
+ else
169
+ # mkdir dirs represented by strings
170
+ to_mkdir = true
171
+ end
172
+ end
173
+ if out
174
+ a = '/' + @suffix + '/' + a
175
+ a_platform = output_platform + a
176
+ a = output + a
177
+ if to_mkdir
178
+ mkdir a_platform unless File.exists?(a_platform)
179
+ end
180
+ end
181
+ a.gsub!('/', '\\')
182
+ a.double_delimiters!
183
+ a
184
+ end
185
+ return args.join(',')
186
+ end
187
+
188
+ def get_jarsign_arg(paclientTool)
189
+ jdk_path = ENV['JAVA_SDK_PATH']
190
+ warn 'Please, set JAVA_SDK_PATH to the path where jarsigner.exe is located' unless jdk_path
191
+ args = [Rake.quotepath('', jdk_path.to_s + '\\jarsigner.exe')]
192
+ args << unsigned_path(true).double_delimiters
193
+ key_store = ENV['DELPHI_ANDROID_KEYSTORE']
194
+ warn 'Please, set DELPHI_ANDROID_KEYSTORE to the path where keystore (to sign application) located' unless key_store
195
+ key_store = Rake.quotepath('', key_store.double_delimiters)
196
+ key_store_params = ENV['DELPHI_ANDROID_KEYSTORE_PARAMS']
197
+ warn 'Please, set DELPHI_ANDROID_KEYSTORE_PARAMS to alias,method,keystore_password,key_password' unless key_store_params
198
+ key_alias, key_params = key_store_params.split(',', 2)
199
+ args << key_alias << key_store << key_params
200
+ return args.join(',')
201
+ end
202
+
203
+ def get_zipalign_arg(paclientTool)
204
+ zip_align = ENV['DELPHI_ANDROID_SDK_PLATFORM_TOOLS']
205
+ warn 'Please, set DELPHI_ANDROID_SDK_PLATFORM_TOOLS to the path where zipalign.exe is located' unless zip_align
206
+ args = [Rake.quotepath('', zip_align.to_s + '\\zipalign.exe')]
207
+ args << unsigned_path(true).double_delimiters
208
+ zip_aligned_out = @dccTask.exeoutput + '\\' + @suffix + '\\' + @dccTask.dpr.pathmap('%n.apk')
209
+ zip_aligned_out_platform = File.expand_path2(zip_aligned_out, '-u')
210
+ FileUtils.rm zip_aligned_out_platform if File.exists?(zip_aligned_out_platform)
211
+ zip_aligned_out.double_delimiters!
212
+ args << zip_aligned_out
213
+ args << '4'
214
+ return args.join(',')
215
+ end
216
+
217
+ def build_args(paclientTool, step)
218
+ r = ['']
219
+ arg = ''
220
+ if step.kind_of?(Symbol)
221
+ arg = self.send("get_#{step.to_s}_arg", paclientTool)
222
+ else
223
+ arg = ''
224
+ end
225
+ r << "--#{step.to_s}=#{arg}"
226
+ return r
227
+ end
228
+
229
+ public
230
+ def execute(args = nil)
231
+ super
232
+ paclientTool = PAClientTool.new
233
+ paclientTool.class.checkToolFailure(paclientTool.toolpath)
234
+ exe_cmd = Rake.quotepath('', paclientTool.toolpath)
235
+ _source = @dccTask.dpr
236
+ ChDir.new(self, File.dirname(_source)) do |dir|
237
+ RakeFileUtils.verbose(Logger.debug?) do
238
+ @last_put_arg_index = 0
239
+ steps.each do |step|
240
+ args = build_args(paclientTool, step)
241
+ args.compact!
242
+ sh exe_cmd + args.join(' ')
243
+ end
244
+ output_platform = File.expand_path2(@dccTask.exeoutput, '-u')
245
+ mv output_platform.pathmap('%p%s') + @suffix + _source.pathmap('%s%n.apk'), output_platform
246
+ end
247
+ end
248
+ end
249
+ end # class PAClientTask
250
+ end
251
+ end
@@ -0,0 +1,20 @@
1
+ # vim: set shiftwidth=2 tabstop=2 expandtab:
2
+ # encoding: utf-8
3
+
4
+ require 'rake/common/logger'
5
+ require 'rake/delphi/tool'
6
+
7
+ module Rake
8
+ module Delphi
9
+ class PAClientTool < CustomDelphiTool
10
+ def initialize(checkExistance = false)
11
+ self.class.reinit
12
+ super
13
+ end
14
+
15
+ def self.toolName
16
+ 'bin/paclient.exe'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -4,6 +4,7 @@ require 'rake'
4
4
  require 'rake/common/classes'
5
5
  require 'rake/common/libstask'
6
6
  require 'rake/delphi/dcc32'
7
+ require 'rake/delphi/paclient'
7
8
  require 'rake/helpers/file'
8
9
  require 'rake/helpers/raketask'
9
10
  require 'rake/helpers/string'
@@ -17,9 +18,10 @@ module Rake
17
18
  super
18
19
  initvars
19
20
  @dcc = application.define_task(Dcc32Task, shortname + ':dcc32')
20
- @libs = LibsTask.define('all-delphi-libs', application)
21
+ @libs = LibsTask.define(name + ':all-delphi-libs', application)
22
+ @post = application.define_task(PAClientTask, @dcc.shortname + ':post')
21
23
  @level = 1
22
- enhance([@libs, @dcc])
24
+ enhance([@libs, @dcc, @post])
23
25
  end
24
26
 
25
27
  def initvars
@@ -68,7 +68,7 @@ module Rake
68
68
  @content = XmlSimple.xml_in(@file, :ForceArray => false)
69
69
  else
70
70
  warn "WARNING! Version info file #{@file} does not exists"
71
- @content = nil
71
+ super
72
72
  end
73
73
  end
74
74
 
@@ -96,6 +96,78 @@ module Rake
96
96
  end
97
97
 
98
98
  class XEVersionInfo < RAD2010VersionInfo
99
+ private
100
+ def read_file_class(platform, node, hash, key)
101
+ platforms = node['Platform']
102
+ unless platforms.kind_of?(Array)
103
+ platforms = [platforms]
104
+ end
105
+ platforms.each do |plat|
106
+ if plat['Name'].casecmp(platform) == 0
107
+ # take filename from hash by key
108
+ value = node.delete(key)
109
+ # delete Name (it is a filtered platform)
110
+ plat.delete('Name')
111
+ # update Platform
112
+ node['Platform'] = plat
113
+ node.delete('Platform') if plat.empty?
114
+ hash.merge!({ value => node })
115
+ end
116
+ end
117
+ end
118
+
119
+ def read_files_and_classes(deployment_content, platform)
120
+ files = {}
121
+ classes = {}
122
+ deployment_content.each do |k, v|
123
+ if k == 'DeployFile'
124
+ v.each do |file|
125
+ read_file_class(platform, file, files, 'LocalName')
126
+ end
127
+ elsif k == 'DeployClass'
128
+ v.each do |_class|
129
+ read_file_class(platform, _class, classes, 'Name')
130
+ end
131
+ end
132
+ end
133
+ return files, classes
134
+ end
135
+
136
+ def make_deployment(files, classes)
137
+ r = []
138
+ files.each do |file, value|
139
+ value_class = value['Class']
140
+ _class = classes[value_class]
141
+ next if ['AndroidGDBServer', 'ProjectAndroidManifest'].include?(value_class)
142
+ if value_class == 'AndroidClassesDexFile'
143
+ # dirty hack for 'classes.dex'
144
+ # usually .dproj has full path to it
145
+ # but we may have another path
146
+ # so remove 'first' part
147
+ file = file.gsub(/^.+(\\lib\\android\\)/, '$(BDS)\1')
148
+ end
149
+ remote_name = value['Platform'] ? value['Platform']['RemoteName'] : file.pathmap('%f')
150
+ if value_class == 'ProjectOutput'
151
+ file = :project_so
152
+ end
153
+ r << { file => [_class['Platform']['RemoteDir'] + '\\', '1', remote_name] }
154
+ end
155
+ return r
156
+ end
157
+
158
+ public
159
+ def deploymentfiles(platform)
160
+ deployment = @content
161
+ raise 'There is no deployment info! Cannot continue.' unless deployment
162
+ ['ProjectExtensions', 'BorlandProject', 'Deployment'].each do |section|
163
+ deployment = deployment[section]
164
+ break unless deployment
165
+ end
166
+ warn "#{@file} have no deployment info" unless deployment
167
+ files, classes = read_files_and_classes(deployment, platform)
168
+ r = make_deployment(files, classes)
169
+ return r
170
+ end
99
171
  end
100
172
 
101
173
  end