rake-delphi 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile.rb +12 -0
  6. data/lib/rake/common/chdirtask.rb +21 -0
  7. data/lib/rake/common/classes.rb +15 -0
  8. data/lib/rake/common/dsl.rb +10 -0
  9. data/lib/rake/common/echotask.rb +34 -0
  10. data/lib/rake/common/exectask.rb +20 -0
  11. data/lib/rake/common/git.rb +102 -0
  12. data/lib/rake/common/hashtask.rb +43 -0
  13. data/lib/rake/common/initask.rb +31 -0
  14. data/lib/rake/common/libstask.rb +35 -0
  15. data/lib/rake/common/sendmailtask.rb +45 -0
  16. data/lib/rake/common/ziptask.rb +98 -0
  17. data/lib/rake/delphi/dcc32.rb +260 -0
  18. data/lib/rake/delphi/envvariables.rb +41 -0
  19. data/lib/rake/delphi/liblist.rb +29 -0
  20. data/lib/rake/delphi/project.rb +68 -0
  21. data/lib/rake/delphi/projectinfo.rb +76 -0
  22. data/lib/rake/delphi/rc.rb +25 -0
  23. data/lib/rake/delphi/resources.rb +126 -0
  24. data/lib/rake/delphi/tool.rb +140 -0
  25. data/lib/rake/delphi/version.rb +7 -0
  26. data/lib/rake/delphi.rb +4 -0
  27. data/lib/rake/helpers/digest.rb +28 -0
  28. data/lib/rake/helpers/file.rb +35 -0
  29. data/lib/rake/helpers/filelist.rb +12 -0
  30. data/lib/rake/helpers/gemversion.rb +42 -0
  31. data/lib/rake/helpers/logger.rb +15 -0
  32. data/lib/rake/helpers/rake.rb +29 -0
  33. data/lib/rake/helpers/raketask.rb +39 -0
  34. data/lib/rake/helpers/string.rb +10 -0
  35. data/lib/rake/helpers/unittest.rb +17 -0
  36. data/lib/rake/templates/project.erb +60 -0
  37. data/rake-delphi.gemspec +23 -0
  38. data/test/helpers/consts.rb +4 -0
  39. data/test/resources/FakeDelphi/dcc32.exe +0 -0
  40. data/test/resources/FakeDelphi/rc.exe +0 -0
  41. data/test/resources/echo/file.in +1 -0
  42. data/test/resources/echo/file.out +1 -0
  43. data/test/resources/hashes/hash.2.file +1 -0
  44. data/test/resources/hashes/hash.file +1 -0
  45. data/test/resources/ini/file.ini +7 -0
  46. data/test/resources/libstask/lib/level-1/level-2-1/level-3-1/.gitkeep +0 -0
  47. data/test/resources/libstask/lib/level-1/level-2-1/level-3-2/.gitkeep +0 -0
  48. data/test/resources/libstask/lib/level-1/level-2-2/.gitkeep +0 -0
  49. data/test/resources/testproject/.gitignore +8 -0
  50. data/test/resources/testproject/ExplicitLib/ExplicitLibUnit.pas +17 -0
  51. data/test/resources/testproject/Rakefile.rb +54 -0
  52. data/test/resources/testproject/lib/AnyLib/LibUnit.pas +17 -0
  53. data/test/resources/testproject/local.resources.txt +1 -0
  54. data/test/resources/testproject/release.dcc.cfg +1 -0
  55. data/test/resources/testproject/resources.rc +1 -0
  56. data/test/resources/testproject/testproject.bdsproj +175 -0
  57. data/test/resources/testproject/testproject.cfg +39 -0
  58. data/test/resources/testproject/testproject.dpr +78 -0
  59. data/test/resources/testproject/testproject.dproj +77 -0
  60. data/test/resources/testproject/testproject.ico +0 -0
  61. data/test/test-delphi.rb +166 -0
  62. data/test/test-echo.rb +33 -0
  63. data/test/test-gemversion.rb +61 -0
  64. data/test/test-git.rb +144 -0
  65. data/test/test-hashes.rb +57 -0
  66. data/test/test-ini.rb +18 -0
  67. data/test/test-libstask.rb +54 -0
  68. data/test/test-projectinfo.rb +66 -0
  69. data/test/test-zip.rb +43 -0
  70. metadata +179 -0
@@ -0,0 +1,260 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake'
4
+ require 'rake/common/chdirtask'
5
+ require 'rake/delphi/envvariables'
6
+ require 'rake/delphi/resources'
7
+ require 'rake/delphi/tool'
8
+ require 'rake/helpers/rake'
9
+ require 'rake/helpers/raketask'
10
+
11
+ module Rake
12
+ module Delphi
13
+ class Dcc32Tool < CustomDelphiTool
14
+ def self.toolName
15
+ 'bin/dcc32.exe'
16
+ end
17
+
18
+ def readLibraryPaths
19
+ libpaths = self.class.readUserOption('Library', 'Search Path', self.version).split(';') \
20
+ | self.class.readUserOption('Library', 'SearchPath', self.version).split(';')
21
+ dev = EnvVariables.new(self.class.rootForVersion(self.version) + '\Environment Variables', self.delphidir)
22
+ libpaths.map! do |lp|
23
+ if !lp.nil? && !lp.empty?
24
+ lp = dev.expand(lp)
25
+ end
26
+ lp
27
+ end
28
+ return libpaths
29
+ end
30
+ end
31
+
32
+ class Dcc32Task < Rake::Task
33
+ attr_accessor :systempath, :mainicon, :_source, :exeoutput, :bin
34
+
35
+ private
36
+ @@symbols = [:quiet, :assertions, :build, :optimization, :debug, :defines,
37
+ :debuginfo, :localsymbols, :console, :warnings, :hints, :altercfg,
38
+ :includepaths, :writeableconst,
39
+ :map, :dcuoutput, :bploutput,
40
+ :dcpoutput, :dcu, :uselibrarypath, :uselibrarypath, :usecfg]
41
+ public
42
+ @@symbols.map do |sym|
43
+ attr_accessor sym
44
+ end
45
+
46
+ def initialize(name, application)
47
+ super
48
+ initvars
49
+ @arg_names = [:verbose]
50
+ @rc_template_task = application.define_task(RCTemplateTask, shortname + ':rc:template')
51
+ @rc_task = application.define_task(RCTask, shortname + ':rc')
52
+ enhance([@rc_template_task, @rc_task])
53
+ @dcc32Tool = Dcc32Tool.new
54
+ end
55
+
56
+ def versionInfoClass
57
+ @dcc32Tool.versionInfoClass
58
+ end
59
+
60
+ private
61
+ def initvars
62
+ @exeoutput = nil
63
+ @@symbols.map do |sym|
64
+ instance_variable_set("@#{sym.to_s}", nil)
65
+ end
66
+ end
67
+
68
+ def delphilibs
69
+ return [@dcc32Tool.delphidir + 'Lib'] | @dcc32Tool.readLibraryPaths
70
+ end
71
+
72
+ def _paths(ppaths)
73
+ ppaths.map! do |p|
74
+ a = []
75
+ ['U', 'I', 'R', 'O'].each do |s|
76
+ a << Rake.quotepath("-#{s}", p)
77
+ end
78
+ a
79
+ end
80
+ # unique paths only
81
+ ppaths.flatten!.uniq!
82
+ ppaths
83
+ end
84
+
85
+ def implicitpaths
86
+ ipaths = ['.', '..']
87
+ ipaths |= delphilibs if @uselibrarypath
88
+ _paths(ipaths)
89
+ end
90
+
91
+ def paths
92
+ @includepaths ||= []
93
+ _paths(@includepaths)
94
+ end
95
+
96
+ def debug?
97
+ return @debug ? '-$D+ -$L+ -$YD -$C+ -$Q+ -$R+ -$O- -GD' : ''
98
+ end
99
+
100
+ def build?
101
+ return @build ? '-B' : '-M'
102
+ end
103
+
104
+ def warnings?
105
+ return @warnings ? '-W-' : '-W+'
106
+ end
107
+
108
+ def hints?
109
+ return @hints ? '-H-' : '-H+'
110
+ end
111
+
112
+ def quiet?
113
+ return @quiet ? '-Q' : ''
114
+ end
115
+
116
+ def exeoutput
117
+ return @exeoutput || @bin
118
+ end
119
+
120
+ def dcuoutput
121
+ return @dcuoutput || @dcu || @_source.pathmap('%d%sdcu')
122
+ end
123
+
124
+ def map
125
+ # segments -> -GS
126
+ # publics -> -GP
127
+ # detailed -> -GD
128
+ return unless @map
129
+ segments = @map.to_s[0..0].upcase
130
+ return '-G' + segments
131
+ end
132
+
133
+ def alldebuginfo
134
+ return @debuginfo ? '-$D+ -$L+ -$YD' : '-$D- -$L- -$Y-'
135
+ end
136
+
137
+ def outputs
138
+ os = []
139
+ os << Rake.quotepath('-E', exeoutput)
140
+ os << Rake.quotepath('-N', dcuoutput)
141
+ os << Rake.quotepath('-LE', @bploutput)
142
+ return os
143
+ end
144
+
145
+ def _source
146
+ return Rake.quotepath('', @_source)
147
+ end
148
+
149
+ def defines
150
+ '-D' + @defines if @defines
151
+ end
152
+
153
+ def writeableconst
154
+ return '-$J' + (@writeableconst ? '+' : '-')
155
+ end
156
+
157
+ def build_args
158
+ args = []
159
+ args << build? << warnings? << hints? << quiet? << debug? << alldebuginfo << map
160
+ args << defines << writeableconst
161
+ args << _source << outputs << implicitpaths
162
+ args.flatten
163
+ end
164
+
165
+ public
166
+ def init(properties)
167
+ pp properties if trace?
168
+ properties.map do |key, value|
169
+ instance_variable_set("@#{key}", value)
170
+ end
171
+ @_source = properties[:projectfile].pathmap('%X.dpr')
172
+ src = @_source.gsub('\\', '/')
173
+ dcu = src.pathmap('%d%sdcu')
174
+ # make sure to create dir for output dcu
175
+ # for now default is <PROJECTDIR>/dcu
176
+ directory dcu
177
+ enhance([dcu])
178
+ # mainicon is usually requested by RCTemplate
179
+ @mainicon ||= Rake.quotepath('', src.pathmap('%X.ico'))
180
+ @rc_template_task.output = src
181
+ @rc_template_task[:version] = properties[:version]
182
+ @rc_template_task[:releaseCandidate] = properties[:releaseCandidate]
183
+ @rc_task.input = src
184
+ @rc_task.is_rc = properties[:releaseCandidate]
185
+ return unless properties[:resources_additional]
186
+ res_add = properties[:resources_additional]
187
+ if res_add.kind_of?(String)
188
+ res_add = res_add.split(';')
189
+ end
190
+ c = 0
191
+ res_add.each do |res|
192
+ if res.kind_of?(Symbol)
193
+ rc_task_add = res
194
+ else
195
+ c = c.next
196
+ rc_task_add = application.define_task(RCTask, shortname + ':rc:add' + c.to_s)
197
+ rc_task_add.input = src.pathmap('%d%s') + res
198
+ end
199
+ enhance([rc_task_add])
200
+ end
201
+ end
202
+
203
+ def init_libs(libs = nil)
204
+ unless libs
205
+ # call parent to find libs
206
+ application[name.gsub(/:dcc32$/, '')].init_libs
207
+ else
208
+ # called from parent
209
+ # set libs
210
+ @includepaths = libs
211
+ end
212
+ end
213
+
214
+ def execute(opts=nil)
215
+ @dcc32Tool.class.checkToolFailure(@dcc32Tool.toolpath)
216
+ fail "Could not find #{_source} to compile" unless @_source && File.exists?(@_source)
217
+ init_libs
218
+ args = build_args
219
+ # on cygwin $D is assumed as shell var
220
+ # so escape $
221
+ args.map! { |a| a.gsub('$', '\$') if a.kind_of?(String) } unless application.windows?
222
+ args.compact!
223
+ cmd = Rake.quotepath('', @dcc32Tool.toolpath)
224
+ cmd << ([''] | args).join(' ')
225
+ ChDir.new(self, File.dirname(@_source)) do |dir|
226
+ RakeFileUtils.verbose(trace?) do
227
+ begin
228
+ unless @usecfg
229
+ cfg = @systempath.pathmap('%X.cfg')
230
+ bak_cfg = @systempath.pathmap('%X.rake.cfg')
231
+ mv cfg, bak_cfg
232
+ if @altercfg
233
+ cp @altercfg, cfg
234
+ end
235
+ # on Windows there is some limit on command line parameters length
236
+ # so we just append path parameters to config file
237
+ File.open(cfg, 'a+') do |f|
238
+ paths.each do |p|
239
+ f.write(p + "\n")
240
+ end
241
+ f.close
242
+ end
243
+ end
244
+ sh cmd
245
+ ensure
246
+ unless @usecfg
247
+ begin
248
+ cp cfg, cfg + '.1' if trace?
249
+ ensure
250
+ mv bak_cfg, cfg
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ puts '' # make one empty string to separate from further lines
257
+ end
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module Rake
4
+ module Delphi
5
+ class EnvVariable
6
+ attr_reader :name
7
+ attr_accessor :value
8
+
9
+ def initialize(name, value)
10
+ @name, @value = name, value
11
+ end
12
+ end
13
+
14
+ class EnvVariables < ::Array
15
+ def initialize(regpath, delphidir)
16
+ _dir = delphidir.gsub(/\/$/, '')
17
+ add('DELPHI', _dir)
18
+ add('BDS', _dir)
19
+ expand_vars
20
+ end
21
+
22
+ def add(var, value)
23
+ self << EnvVariable.new(var, value)
24
+ end
25
+
26
+ def expand(value)
27
+ self.each do |ev|
28
+ value.gsub!("$(#{ev.name})", ev.value)
29
+ end
30
+ value
31
+ end
32
+
33
+ def expand_vars
34
+ self.map! do |v|
35
+ v.value = expand(v.value)
36
+ v
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake/helpers/filelist'
4
+
5
+ module Rake
6
+ module Delphi
7
+ class LibList < FileList
8
+ def read_ignored_libs
9
+ libs = []
10
+ file = (ENV['RAKE_DIR'] || Rake.original_dir) + '/.rake.ignored.libs'
11
+ return libs unless File.exists?(file)
12
+ IO.readlines(file).each do |line|
13
+ # skip comment lines (started with # or ;)
14
+ next if /^\s*[#;]/.match(line)
15
+ libs << FileList.get_ignored_dir_pattern(line.chomp)
16
+ end
17
+ libs
18
+ end
19
+
20
+ alias_method :initialize_base, :initialize
21
+
22
+ def initialize(*patterns)
23
+ initialize_base(patterns)
24
+ @exclude_patterns |= read_ignored_libs
25
+ @exclude_procs << proc { |fn| File.file?(fn) }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake'
4
+ require 'rake/common/classes'
5
+ require 'rake/common/libstask'
6
+ require 'rake/delphi/dcc32'
7
+ require 'rake/helpers/file'
8
+ require 'rake/helpers/raketask'
9
+ require 'rake/helpers/string'
10
+ require 'pp'
11
+
12
+ module Rake
13
+ module Delphi
14
+ class Project < Rake::Task
15
+ attr_accessor :properties
16
+
17
+ def initialize(name, app)
18
+ super
19
+ initvars
20
+ @dcc = application.define_task(Dcc32Task, shortname + ':dcc32')
21
+ @libs = LibsTask.define('all-delphi-libs', application)
22
+ @level = 1
23
+ enhance([@libs, @dcc])
24
+ end
25
+
26
+ def initvars
27
+ @properties = {
28
+ :build => true,
29
+ :warnings => false,
30
+ :hints => false,
31
+ :includepaths => nil
32
+ }
33
+ @cdir = ''
34
+ end
35
+
36
+ def init_libs
37
+ self[:includepaths] = ['.'] unless self[:includepaths]
38
+ self[:includepaths] |= @libs.libs_relative(@level)
39
+ @dcc.init_libs(self[:includepaths])
40
+ end
41
+
42
+ def init(module_name, rake_file, vars, level = 1)
43
+ @level = level
44
+ module_name = module_name.dup.pop.to_s
45
+ self[:projectlabel] = eval("#{module_name}::PROJECT_NAME")
46
+ projectfile = eval("#{module_name}::PROJECT_FILE")
47
+ self[:projectfile] = File.dirname2(rake_file) + File.separator + projectfile
48
+ self[:sourcename] = File.dirname2(rake_file)
49
+ @cdir = File.dirname(rake_file)
50
+ self[:systempath] = @cdir + '/' + projectfile
51
+ self[:altercfg].prepend(self[:sourcename] + '/') if self[:altercfg]
52
+ [:version, :bin, :build, :dcu, :alldebuginfo, :map, :defines, :releaseCandidate].each do |k|
53
+ self[k] = vars[k] if vars.has_key?(k)
54
+ end if vars
55
+
56
+ @dcc.init(@properties)
57
+ end
58
+
59
+ def []=(key, value)
60
+ @properties[key.to_sym] = value
61
+ end
62
+
63
+ def [](key)
64
+ return @properties[key]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ require 'xmlsimple'
4
+ require 'rake/helpers/rake'
5
+
6
+ module Rake
7
+ module Delphi
8
+ class ProjectVersionInfo
9
+ def initialize(task)
10
+ @info = Hash.new
11
+ @file = task.systempath.pathmap('%X.' + self._ext)
12
+ do_getcontent
13
+ end
14
+
15
+ def do_getcontent
16
+ @content = nil
17
+ end
18
+
19
+ def _ext
20
+ ''
21
+ end
22
+
23
+ def [](key)
24
+ @info[key.to_sym]
25
+ end
26
+
27
+ def method_missing(name, *args, &block)
28
+ @info[name]
29
+ end
30
+ end
31
+
32
+ class BDSVersionInfo < ProjectVersionInfo
33
+ def initialize(task)
34
+ super(task)
35
+ content = @content['Delphi.Personality']['VersionInfoKeys']['VersionInfoKeys']
36
+ use_encode = String.new.respond_to?(:encode)
37
+ encoding = self.class.encoding
38
+ if encoding && ! use_encode
39
+ require 'iconv'
40
+ iconv = Iconv.new(encoding, 'UTF-8')
41
+ end
42
+ content.each do |v|
43
+ cv = v['content']
44
+ cv = (use_encode ? cv.encode(encoding, 'UTF-8') : iconv.iconv(cv)) if encoding
45
+ @info[v['Name'].to_sym] = cv
46
+ end
47
+ end
48
+
49
+ def self.encoding
50
+ # override to set your own encoding
51
+ nil
52
+ end
53
+
54
+ def do_getcontent
55
+ @content = XmlSimple.xml_in(@file, :ForceArray => false)
56
+ end
57
+
58
+ def _ext
59
+ return 'bdsproj'
60
+ end
61
+ end
62
+
63
+ class RAD2007VersionInfo < BDSVersionInfo
64
+ def _ext
65
+ return 'dproj'
66
+ end
67
+
68
+ def do_getcontent
69
+ super
70
+ # .dproj file has more nesting levels
71
+ @content = @content['ProjectExtensions']['BorlandProject']['BorlandProject']
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake/delphi/tool'
4
+
5
+ module Rake
6
+ module Delphi
7
+ class RCResourceCompiler < CustomDelphiTool
8
+ def self.toolName
9
+ 'bin/rc.exe'
10
+ end
11
+ end
12
+
13
+ class BorlandResourceCompiler < RCResourceCompiler
14
+ def self.toolName
15
+ 'bin/brcc32.exe'
16
+ end
17
+ end
18
+
19
+ class GOResourceCompiler < RCResourceCompiler
20
+ def self.toolName
21
+ 'bin/gorc.exe'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,126 @@
1
+ # encoding: utf-8
2
+
3
+ require 'erb'
4
+ require 'rake/common/classes'
5
+ require 'rake/delphi/rc'
6
+ require 'rake/helpers/gemversion'
7
+ require 'rake/helpers/rake'
8
+
9
+ module Rake
10
+ module Delphi
11
+ class RCTemplate
12
+ attr_reader :language, :sublanguage, :lang, :codepage, :filetype
13
+ alias :method_missing_base :method_missing
14
+
15
+ def initialize(owner)
16
+ @owner = owner
17
+ # English
18
+ @language = '0x19'
19
+ @sublanguage = '0x01'
20
+ # Russian
21
+ @lang = '0419'
22
+ # Russian
23
+ @codepage = '04E3'
24
+ # exe
25
+ @filetype = '0x1'
26
+ @versioninfo = nil
27
+ @extra = {}
28
+ @main_owner_task_name = @owner.name.gsub(/:rc:template$/, '')
29
+ @main_owner_task = nil
30
+ end
31
+
32
+ def get_binding
33
+ binding
34
+ end
35
+
36
+ def main_owner_task
37
+ @main_owner_task ||= @owner.application[@main_owner_task_name]
38
+ end
39
+
40
+ def mainicon
41
+ # take dcc33 task
42
+ icon = main_owner_task.mainicon
43
+ end
44
+
45
+ def version
46
+ Gem::VersionImproved.new(@extra[:version])
47
+ end
48
+
49
+ def versioninfo
50
+ @versioninfo ||= main_owner_task.versionInfoClass.new(main_owner_task)
51
+ end
52
+
53
+ def product
54
+ Gem::VersionImproved.new(self.versioninfo['ProductVersion'])
55
+ end
56
+
57
+ def []=(key, value)
58
+ @extra[key] = value || ''
59
+ end
60
+
61
+ def method_missing(name, *args, &block)
62
+ if args.empty? && @extra[name]
63
+ @extra[name]
64
+ elsif
65
+ @source.name
66
+ end
67
+ end
68
+ end
69
+
70
+ class RCTemplateTask < Rake::Task
71
+ def initialize(name, app)
72
+ super
73
+ @output = nil
74
+ @template_file = File.expand_path('../../templates/project.erb', __FILE__)
75
+ @template_obj = RCTemplate.new(self)
76
+ end
77
+
78
+ def output=(value)
79
+ @output = value.pathmap('%X.rc')
80
+ end
81
+
82
+ def []=(key, value)
83
+ @template_obj[key] = value
84
+ end
85
+
86
+ def execute(args=nil)
87
+ erb = ERB.new(IO.read(@template_file))
88
+ text = erb.result(@template_obj.get_binding)
89
+ File.open(@output, 'w') do |f|
90
+ f.write(text)
91
+ end
92
+ end
93
+ end
94
+
95
+ class RCTask < Rake::Task
96
+ attr_accessor :output, :input
97
+ def initialize(name, app)
98
+ super
99
+ @output = nil
100
+ @is_rc = false
101
+ end
102
+
103
+ def input=(value)
104
+ @input = value.pathmap('%X.rc')
105
+ @output = @input.pathmap('%X.res')
106
+ end
107
+
108
+ def is_rc=(value)
109
+ @is_rc = ! value.to_s.empty?
110
+ end
111
+
112
+ def execute(args=nil)
113
+ v, path, tool = RCResourceCompiler.find(true)
114
+ a = []
115
+ a << '/dRC' if @is_rc
116
+ a |= ['/fo', Rake.quotepath('', output), '/r', Rake.quotepath('', input) ]
117
+ opts = { :args => a }
118
+ opts.merge!(args)
119
+ cmd = ([Rake.quotepath('', tool)] | opts[:args]).join(' ')
120
+ RakeFileUtils.verbose(trace?) do
121
+ sh cmd
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end