9e892db7bb3f0ff4302c82dec63d62d316afb72f
[redact.git] / lib / redact / app.rb
1 #--
2 # $Id: app.rb 48 2005-06-08 21:38:34Z 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 class OpenStruct
36         def clear
37                 @table = {}
38         end
39 end
40
41 module Redact
42         OPTIONS = OpenStruct.new
43
44         class App
45                 attr_reader :options
46
47                 def initialize(args)
48                         @filename = nil
49                         OPTIONS.clear
50                         @option_parser = parse_args(args)
51
52                         OPTIONS.input = args.first
53                         if OPTIONS.input.nil?
54                                 puts @option_parser.help
55                                 exit
56                         end
57
58                         OPTIONS.output ||= @options.input.sub(/.[^.]+$/, ".edj")
59                 end
60
61                 def run
62                         EDJE.clear
63                         SCRIPT_LINES__.clear
64
65                         begin
66                                 load OPTIONS.input
67                         rescue LoadError
68                                 raise("Cannot load '#{OPTIONS.input}'")
69                         end
70
71                         @filename = Pathname.new(OPTIONS.input).cleanpath.to_s
72
73                         if EDJE.collections.empty?
74                                 raise("No collections found")
75                         end
76
77                         amx = compile_embryo
78
79                         begin
80                                 Eet::File.open(OPTIONS.output, "w") do |ef|
81                                         dump_amx(amx, ef)
82
83                                         dump_header(ef)
84                                         dump_collections(ef)
85                                         dump_fonts(ef)
86                                         dump_images(ef)
87                                         dump_source(ef)
88                                         dump_fontmap(ef)
89                                 end
90                         rescue Exception
91                                 File.rm_f(OPTIONS.output)
92                                 raise
93                         end
94                 end
95
96                 private
97                 def parse_args(args)
98                         OptionParser.new do |o|
99                                 o.banner = "Usage: redact [options] INPUT_FILE"
100
101                                 o.separator ""
102                                 o.separator "Specific options:"
103
104                                 o.on("-o", "--output OUTPUT_FILE",
105                                      "Write Edje to OUTPUT_FILE") do |file|
106                                         OPTIONS.output = file
107                                 end
108
109                                 o.on("--image_dir IMAGE_DIR",
110                                      "Add IMAGE_DIR to the image lookup path") do |dir|
111                                         OPTIONS.image_dir = dir
112                                 end
113
114                                 o.on("--font_dir FONT_DIR",
115                                      "Add FONT_DIR to the font lookup path") do |dir|
116                                         OPTIONS.font_dir = dir
117                                 end
118
119                                 o.separator ""
120                                 o.separator "Common options:"
121
122                                 o.on_tail("-h", "--help", "Show this message") do
123                                         puts o
124                                         exit
125                                 end
126
127                                 o.on_tail("--version", "Show version") do
128                                         puts "Redact #{Redact::VERSION}"
129                                         exit
130                                 end
131
132                                 o.parse!(args)
133                         end
134                 end
135
136                 def compile_embryo
137                         ret = {}
138
139                         EDJE.collections.each_value do |col|
140                                 next unless col.has_embryo?
141
142                                 Tempfile.open("redact_col#{col.id}.sma") do |tf_in|
143                                         tf_in.puts "#include <edje>"
144                                         dump_sma(tf_in, col)
145                                         tf_in.flush
146
147                                         Tempfile.open("redact_col#{col.id}.amx") do |tf_out|
148                                                 incl = `edje-config --datadir`.strip
149
150                                                 c = "embryo_cc " +
151                                                     "-i #{incl}/include " +
152                                                     "-o #{tf_out.path} #{tf_in.path}"
153                                                 system(c)
154                                                 unless (0..1).include?($?.exitstatus)
155                                                         raise("Cannot compile Embryo code")
156                                                 end
157
158                                                 ret[col.id] = tf_out.read
159                                         end
160                                 end
161                         end
162
163                         ret
164                 end
165
166                 def dump_sma(tf, col)
167                         if col.has_embryo?(false)
168                                 tf.puts col.script.to_embryo(col)
169                         end
170
171                         col.programs.each_value do |p|
172                                 next unless p.is_a?(ExecScriptProgram)
173
174                                 s = p.script.to_embryo(col).gsub(/^(.+)$/, "\t\\1")
175
176                                 tf.puts <<EOT
177 public _p#{p.id}(sig[], src[])
178 {
179 #{s}
180 }
181 EOT
182                         end
183                 end
184
185                 def dump_amx(amx, ef)
186                         amx.each do |id, code|
187                                 ef.write("scripts/#{id}", code)
188                         end
189                 end
190
191                 def dump_header(ef)
192                         ef.write("edje_file", EDJE.to_eet)
193                 end
194
195                 def dump_collections(ef)
196                         EDJE.collections.each_value do |col|
197                                 ef.write("collections/#{col.id}", col.to_eet)
198                         end
199                 end
200
201                 def dump_fonts(ef)
202                         EDJE.font_dir.each do |entry|
203                                 ef.write("fonts/#{entry.alias}",
204                                          File.read(entry.filename))
205                         end
206                 end
207
208                 def dump_images(ef)
209                         EDJE.image_dir.each do |entry|
210                                 ef.write_image("images/#{entry.id}",
211                                                entry.image.data_for_reading_only,
212                                                entry.image.width, entry.image.height,
213                                                entry.image.has_alpha?)
214                         end
215                 end
216
217                 def dump_source(ef)
218                         s = SourceFiles.new
219
220                         SCRIPT_LINES__.each do |file, value|
221                                 sane = Pathname.new(file).cleanpath.to_s
222                                 method = (sane == @filename) ? :unshift : :push
223                                 s.send(method, SourceFile.new(sane, value.join))
224
225                                 # include files that are read with File.read, too
226                                 value.join.grep(/File\.read\(\"(.+)\"\)/) do
227                                         sane = Pathname.new($1).cleanpath.to_s
228                                         s << SourceFile.new(sane, File.read(sane))
229                                 end
230                         end
231
232                         ef.write("edje_sources", s.to_eet)
233                 end
234
235                 def dump_fontmap(ef)
236                         fm = EDJE.font_dir.inject(FontMap.new) do |a, entry|
237                                 a << FontMapEntry.new(entry)
238                         end
239
240                         ef.write("edje_source_fontmap", fm.to_eet)
241                 end
242         end
243 end