Don't abort if embryo_cc's return code is 1.
[redact.git] / lib / redact / app.rb
1 #--
2 # $Id: app.rb 39 2005-04-28 21:08:11Z tilman $
3 #
4 # Copyright (c) 2005 Tilman Sauerbeck (tilman at code-monkey de)
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 require "redact/redact.rb"
26 require "redact/source.rb"
27 require "ftools"
28 require "tempfile"
29 require "pathname"
30 require "ostruct"
31 require "optparse"
32
33 SCRIPT_LINES__ = {}
34
35 module Redact
36         class App
37                 def initialize(args)
38                         @filename = nil
39                         @options = OpenStruct.new
40                         @option_parser = parse_args(args)
41
42                         @options.input = args.first
43                         if @options.input.nil?
44                                 puts @option_parser.help
45                                 exit
46                         end
47
48                         @options.output ||= @options.input.sub(/.[^.]+$/, ".edj")
49                 end
50
51                 def run
52                         EDJE.clear
53                         SCRIPT_LINES__.clear
54
55                         begin
56                                 load @options.input
57                         rescue LoadError
58                                 raise("Cannot load '#{@options.input}'")
59                         end
60
61                         @filename = Pathname.new(@options.input).cleanpath.to_s
62
63                         if EDJE.collections.empty?
64                                 raise("No collections found")
65                         end
66
67                         amx = compile_embryo
68
69                         Eet::File.open(@options.output, "w") do |ef|
70                                 dump_amx(amx, ef)
71
72                                 dump_header(ef)
73                                 dump_collections(ef)
74                                 dump_fonts(ef)
75                                 dump_images(ef)
76                                 dump_source(ef)
77                                 dump_fontmap(ef)
78                         end
79                 end
80
81                 private
82                 def parse_args(args)
83                         OptionParser.new do |o|
84                                 o.banner = "Usage: redact [options] INPUT_FILE"
85
86                                 o.separator ""
87                                 o.separator "Specific options:"
88
89                                 o.on("-o", "--output OUTPUT_FILE",
90                                      "Write Edje to OUTPUT_FILE") do |file|
91                                         @options.output = file
92                                 end
93
94                                 o.on("--image_dir IMAGE_DIR",
95                                      "Add IMAGE_DIR to the image lookup path") do |dir|
96                                         @options.image_dir = dir
97                                 end
98
99                                 o.on("--font_dir FONT_DIR",
100                                      "Add FONT_DIR to the font lookup path") do |dir|
101                                         @options.font_dir = dir
102                                 end
103
104                                 o.separator ""
105                                 o.separator "Common options:"
106
107                                 o.on_tail("-h", "--help", "Show this message") do
108                                         puts o
109                                         exit
110                                 end
111
112                                 o.on_tail("--version", "Show version") do
113                                         puts "Redact #{Redact::VERSION}"
114                                         exit
115                                 end
116
117                                 o.parse!(args)
118                         end
119                 end
120
121                 def compile_embryo
122                         ret = {}
123
124                         EDJE.collections.each_value do |col|
125                                 next unless col.has_embryo?
126
127                                 Tempfile.open("redact_col#{col.id}.sma") do |tf_in|
128                                         tf_in.puts "#include <edje>"
129                                         dump_sma(tf_in, col)
130                                         tf_in.flush
131
132                                         Tempfile.open("redact_col#{col.id}.amx") do |tf_out|
133                                                 incl = `edje-config --datadir`.strip
134
135                                                 c = "embryo_cc " +
136                                                     "-i #{incl}/include " +
137                                                     "-o #{tf_out.path} #{tf_in.path}"
138                                                 system(c)
139                                                 unless (0..1).include?($?.exitstatus)
140                                                         raise("Cannot compile Embryo code")
141                                                 end
142
143                                                 ret[col.id] = tf_out.read
144                                         end
145                                 end
146                         end
147
148                         ret
149                 end
150
151                 def dump_sma(tf, col)
152                         if col.has_embryo?(false)
153                                 tf.puts col.script.to_embryo(col)
154                         end
155
156                         col.programs.each_value do |p|
157                                 next unless p.is_a?(ExecScriptProgram)
158
159                                 s = p.script.to_embryo(col).gsub(/^(.+)$/, "\t\\1")
160
161                                 tf.puts <<EOT
162 public _p#{p.id}(sig[], src[])
163 {
164 #{s}
165 }
166 EOT
167                         end
168                 end
169
170                 def dump_amx(amx, ef)
171                         amx.each do |id, code|
172                                 ef.write("scripts/#{id}", code)
173                         end
174                 end
175
176                 def dump_header(ef)
177                         ef.write("edje_file", EDJE.to_eet)
178                 end
179
180                 def dump_collections(ef)
181                         EDJE.collections.each_value do |col|
182                                 ef.write("collections/#{col.id}", col.to_eet)
183                         end
184                 end
185
186                 def dump_fonts(ef)
187                         EDJE.font_dir.each do |entry|
188                                 ef.write("fonts/#{entry.filename}",
189                                          File.read(entry.filename))
190                         end
191                 end
192
193                 def dump_images(ef)
194                         EDJE.image_dir.each do |entry|
195                                 ef.write_image("images/#{entry.id}",
196                                                entry.image.data_for_reading_only,
197                                                entry.image.width, entry.image.height,
198                                                entry.image.has_alpha?)
199                         end
200                 end
201
202                 def dump_source(ef)
203                         s = SourceFiles.new
204
205                         SCRIPT_LINES__.each do |file, value|
206                                 sane = Pathname.new(file).cleanpath.to_s
207                                 method = (sane == @filename) ? :unshift : :push
208                                 s.send(method, SourceFile.new(sane, value.join))
209
210                                 # include files that are read with File.read, too
211                                 value.join.grep(/File\.read\(\"(.+)\"\)/) do
212                                         sane = Pathname.new($1).cleanpath.to_s
213                                         s << SourceFile.new(sane, File.read(sane))
214                                 end
215                         end
216
217                         ef.write("edje_sources", s.to_eet)
218                 end
219
220                 def dump_fontmap(ef)
221                         fm = EDJE.font_dir.inject(FontMap.new) do |a, entry|
222                                 a << FontMapEntry.new(entry)
223                         end
224
225                         ef.write("edje_source_fontmap", fm.to_eet)
226                 end
227         end
228 end