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