fcshd 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +14 -0
- data/bin/fcshc +116 -0
- data/bin/fcshd +24 -0
- data/fcshd.gemspec +19 -0
- data/lib/fcshd.rb +8 -0
- data/lib/fcshd/compiler-output-writer.rb +19 -0
- data/lib/fcshd/compiler-output.rb +91 -0
- data/lib/fcshd/compiler.rb +145 -0
- data/lib/fcshd/logger.rb +41 -0
- data/lib/fcshd/problem.rb +153 -0
- data/lib/fcshd/server.rb +34 -0
- data/lib/fcshd/source-location.rb +27 -0
- data/lib/fcshd/version.rb +5 -0
- metadata +85 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@fcshd --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/bin/fcshc
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "fcshd"
|
5
|
+
rescue LoadError
|
6
|
+
require "pathname"
|
7
|
+
$: << File.expand_path("../../lib", Pathname.new(__FILE__).realpath)
|
8
|
+
require "fcshd"
|
9
|
+
end
|
10
|
+
|
11
|
+
require "optparse"
|
12
|
+
require "socket"
|
13
|
+
|
14
|
+
def die(message)
|
15
|
+
puts "#{File.basename($0)}: #{message}"
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
$source_directories = []
|
20
|
+
$library_filenames = []
|
21
|
+
$extra_arguments = []
|
22
|
+
|
23
|
+
OptionParser.new do |parser|
|
24
|
+
parser.banner = "Usage: fcshc MAIN [SRCDIR|LIB]... -o OUTPUT"
|
25
|
+
|
26
|
+
parser.on("--halo", "Use the Halo theme") do
|
27
|
+
if ENV["FLEX_HOME"]
|
28
|
+
$extra_arguments << "-theme=" +
|
29
|
+
File.join(ENV["FLEX_HOME"], *%w(frameworks themes Halo halo.swc))
|
30
|
+
else
|
31
|
+
die "must set $FLEX_HOME to use --halo option"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
parser.on("-o", "--output FILENAME", "Write SWF to FILENAME") do |value|
|
36
|
+
$output_filename = File.expand_path(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
parser.on("-3", "Use -compatibility-version=3") do |value|
|
40
|
+
$extra_arguments << "-compatibility-version=3"
|
41
|
+
end
|
42
|
+
|
43
|
+
parser.on("-X EXTRA-ARGUMENT", "Pass EXTRA-ARGUMENT to mxmlc") do |value|
|
44
|
+
$extra_arguments << value
|
45
|
+
end
|
46
|
+
|
47
|
+
parser.on("-v", "--verbose", "Print mxmlc command line") do
|
48
|
+
$verbose = true
|
49
|
+
end
|
50
|
+
end.parse!
|
51
|
+
|
52
|
+
for name in ARGV
|
53
|
+
if not File.exists? name
|
54
|
+
die "no such file or directory: #{name}"
|
55
|
+
elsif File.directory? name
|
56
|
+
$source_directories << File.expand_path(name)
|
57
|
+
elsif %w(.as .mxml).include? File.extname(name)
|
58
|
+
die "multiple source files not allowed" if $source_filename
|
59
|
+
$source_filename = File.expand_path(name)
|
60
|
+
elsif %w(.swc).include? File.extname(name)
|
61
|
+
$library_filenames << File.expand_path(name)
|
62
|
+
else
|
63
|
+
die "don't know what to do with file: #{name}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
if $source_filename == nil
|
68
|
+
die "missing source file to compile"
|
69
|
+
end
|
70
|
+
|
71
|
+
if $output_filename == nil
|
72
|
+
$source_filename.sub(/\.(as|mxml)$/, ".swf").tap do |filename|
|
73
|
+
local_filename = File.basename(filename)
|
74
|
+
$output_filename = File.expand_path(local_filename)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
$fcshd_arguments = ["mxmlc #$source_filename -output=#$output_filename"]
|
79
|
+
|
80
|
+
for directory in $source_directories
|
81
|
+
$fcshd_arguments << "-compiler.source-path+=#{directory}"
|
82
|
+
end
|
83
|
+
|
84
|
+
for filename in $library_filenames
|
85
|
+
$fcshd_arguments << "-compiler.library-path+=#{filename}"
|
86
|
+
end
|
87
|
+
|
88
|
+
$fcshd_arguments.concat($extra_arguments)
|
89
|
+
|
90
|
+
begin
|
91
|
+
host, port = "localhost", 34345
|
92
|
+
socket = TCPSocket.new(host, port)
|
93
|
+
rescue Errno::ECONNREFUSED
|
94
|
+
die "Could not connect to fcshd at #{host}:#{port}."
|
95
|
+
end
|
96
|
+
|
97
|
+
basedir = File.join(File.expand_path("."), "")
|
98
|
+
|
99
|
+
fcshd_command = $fcshd_arguments.join(" ")
|
100
|
+
warn fcshd_command.gsub(basedir, "") if $verbose
|
101
|
+
socket.puts fcshd_command
|
102
|
+
|
103
|
+
compiler_output = ""
|
104
|
+
socket.each_line do |line|
|
105
|
+
case line
|
106
|
+
when /^fcshd: /
|
107
|
+
warn line.chomp
|
108
|
+
else
|
109
|
+
compiler_output << line
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
output = FCSHD::CompilerOutput[compiler_output, basedir]
|
114
|
+
output.write! FCSHD::CompilerOutputWriter.new(STDOUT, basedir)
|
115
|
+
|
116
|
+
exit 1 if not output.succeeded?
|
data/bin/fcshd
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "fcshd"
|
5
|
+
rescue LoadError
|
6
|
+
require "pathname"
|
7
|
+
$: << File.expand_path("../../lib", Pathname.new(__FILE__).realpath)
|
8
|
+
require "fcshd"
|
9
|
+
end
|
10
|
+
|
11
|
+
logger = FCSHD::Logger.new(STDERR)
|
12
|
+
compiler = FCSHD::Compiler.new(logger)
|
13
|
+
compiler.start!
|
14
|
+
|
15
|
+
Thread.abort_on_exception = true
|
16
|
+
|
17
|
+
FCSHD_PORT = 34345
|
18
|
+
|
19
|
+
begin
|
20
|
+
logger.log "Listening to port #{FCSHD_PORT}."
|
21
|
+
FCSHD::Server.new(FCSHD_PORT, compiler, logger).run!
|
22
|
+
rescue Interrupt
|
23
|
+
logger.log "Exiting."
|
24
|
+
end
|
data/fcshd.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "./lib/fcshd/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = "fcshd"
|
5
|
+
gem.summary = "Usable CLI for the Adobe Flex compiler shell (fcsh)"
|
6
|
+
gem.description = <<'^D'
|
7
|
+
By using a client-server architecture, we are able to make the Adobe Flex
|
8
|
+
compiler run fast while still being usable in command-line environments.
|
9
|
+
In practice, you start the `fcshd' server, and are then able to use the
|
10
|
+
client program `fcshc' as a faster and more usable replacement for `mxmlc'.
|
11
|
+
^D
|
12
|
+
gem.version = FCSHD::VERSION
|
13
|
+
gem.author = "Daniel Brockman"
|
14
|
+
gem.email = "daniel@gointeractive.se"
|
15
|
+
gem.date = Time.now.utc.strftime("%Y-%m-%d")
|
16
|
+
gem.homepage = "http://github.com/dbrock/fcshd"
|
17
|
+
gem.files = `git ls-files`.lines.map(&:chomp)
|
18
|
+
gem.executables = %w"fcshd fcshc"
|
19
|
+
end
|
data/lib/fcshd.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module FCSHD
|
2
|
+
class CompilerOutputWriter
|
3
|
+
def initialize(output, basedir)
|
4
|
+
@output = output
|
5
|
+
@basedir = basedir
|
6
|
+
end
|
7
|
+
|
8
|
+
def write_uninterpreted_line! line
|
9
|
+
@output.puts line
|
10
|
+
end
|
11
|
+
|
12
|
+
def write_problem! problem
|
13
|
+
location = problem.source_location.with_basedir(@basedir)
|
14
|
+
for line in problem.formatted_message_lines do
|
15
|
+
@output.puts "#{location}: #{line}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module FCSHD
|
2
|
+
class CompilerOutput
|
3
|
+
def self.[] text, basedir
|
4
|
+
new.tap do |result|
|
5
|
+
Parser.new(text.lines.entries, basedir, result).parse!
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :n_compiled_files
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@events = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def << event
|
16
|
+
@events << event
|
17
|
+
end
|
18
|
+
|
19
|
+
def write! writer
|
20
|
+
for event in @events
|
21
|
+
case event
|
22
|
+
when String
|
23
|
+
writer.write_uninterpreted_line! event
|
24
|
+
when Problem
|
25
|
+
writer.write_problem! event
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def nothing_to_do?
|
31
|
+
n_compiled_files == 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def succeeded!
|
35
|
+
@succeeded = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def succeeded?
|
39
|
+
@succeeded
|
40
|
+
end
|
41
|
+
|
42
|
+
class Parser < Struct.new(:lines, :basedir, :result)
|
43
|
+
def parse!
|
44
|
+
parse_line! until lines.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_line!
|
48
|
+
take_line! do |line|
|
49
|
+
case line
|
50
|
+
when /^(Recompile|Reason): /
|
51
|
+
when /^Loading configuration file /
|
52
|
+
when /^(.+\.swf) \((\d+) bytes\)$/
|
53
|
+
result.succeeded!
|
54
|
+
when "Nothing has changed since the last compile. Skip..."
|
55
|
+
result.n_compiled_files = 0
|
56
|
+
when /^Files changed: (\d+) Files affected: (\d+)$/
|
57
|
+
result.n_compiled_files = $1.to_i + $2.to_i
|
58
|
+
when /^(\/.+?)(?:\((\d+)\))?: (?:col: (\d+) )?(.+)$/
|
59
|
+
location = SourceLocation[$1, $2.to_i, $3.to_i, basedir]
|
60
|
+
result << Problem[location, $4]
|
61
|
+
skip_indented_lines!
|
62
|
+
when /^Required RSLs:$/
|
63
|
+
skip_indented_lines!
|
64
|
+
when /^fcshd: /
|
65
|
+
result << line
|
66
|
+
else
|
67
|
+
result << "mxmlc: #{line}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def take_line!
|
73
|
+
yield skip_line!
|
74
|
+
end
|
75
|
+
|
76
|
+
def skip_line!
|
77
|
+
current_line
|
78
|
+
ensure
|
79
|
+
lines.shift
|
80
|
+
end
|
81
|
+
|
82
|
+
def current_line
|
83
|
+
lines[0].chomp
|
84
|
+
end
|
85
|
+
|
86
|
+
def skip_indented_lines!
|
87
|
+
skip_line! until lines.empty? or current_line =~ /^\S/
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require "find"
|
2
|
+
|
3
|
+
module FCSHD
|
4
|
+
class Compiler
|
5
|
+
FLEX_HOME = ENV["FLEX_HOME"]
|
6
|
+
|
7
|
+
def self.flex_path(*components)
|
8
|
+
File.join(FLEX_HOME, *components)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.standard_fcsh_executable
|
12
|
+
FLEX_HOME ? flex_path("bin", "fcsh") : "fcsh"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.standard_source_directory_root
|
16
|
+
flex_path("frameworks", "projects")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.barename(filename)
|
20
|
+
File.basename(filename).sub(/\..*/, "")
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.find_standard_component(name)
|
24
|
+
if FLEX_HOME
|
25
|
+
Find.find(standard_source_directory_root) do |filename|
|
26
|
+
if barename(filename) == name
|
27
|
+
break File.dirname(filename).
|
28
|
+
sub(%r{.+/src/}, "").gsub("/", ".")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
FCSH_EXECUTABLE = ENV["FCSH"] || standard_fcsh_executable
|
35
|
+
|
36
|
+
def initialize(logger)
|
37
|
+
@logger = logger
|
38
|
+
@output_buffer = ""
|
39
|
+
end
|
40
|
+
|
41
|
+
def start!
|
42
|
+
start_fcsh_process!
|
43
|
+
parse_fcsh_boilerplate!
|
44
|
+
@logger.log "Started Flex #@flex_version compiler shell."
|
45
|
+
rescue PromptNotFound => error
|
46
|
+
@logger.error "Could not find fcsh prompt:"
|
47
|
+
@logger.error @logger.format_command(FCSH_EXECUTABLE, error.message)
|
48
|
+
@logger.log "Please set $FLEX_HOME or $FCSH." if
|
49
|
+
error.message.include? "command not found"
|
50
|
+
@logger.exit
|
51
|
+
end
|
52
|
+
|
53
|
+
def compile! command, frontend
|
54
|
+
@command, @frontend = command, frontend
|
55
|
+
|
56
|
+
if have_command_id?
|
57
|
+
recompile!
|
58
|
+
else
|
59
|
+
compile_new!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def start_fcsh_process!
|
66
|
+
stop_fcsh_process!
|
67
|
+
@fcsh_process = IO.popen("#{FCSH_EXECUTABLE} 2>&1", "r+")
|
68
|
+
read_fcsh_output!
|
69
|
+
end
|
70
|
+
|
71
|
+
def stop_fcsh_process!
|
72
|
+
@fcsh_process.close if @fcsh_process
|
73
|
+
@fcsh_process = nil
|
74
|
+
@command_ids = {}
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_fcsh_boilerplate!
|
78
|
+
case @output
|
79
|
+
when /Version (\S+)/
|
80
|
+
@flex_version = $1
|
81
|
+
else
|
82
|
+
@flex_version = "(unknown version)"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def compile_new!
|
87
|
+
@frontend.puts "fcshd: Compiling from scratch..."
|
88
|
+
@frontend.flush
|
89
|
+
send_fcsh_command! @command
|
90
|
+
parse_compilation_output!
|
91
|
+
ensure
|
92
|
+
if not have_command_id?
|
93
|
+
@logger.error "Could not determine compilation ID:"
|
94
|
+
@logger.error @logger.format_command("(fcsh) #@command", @output)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def recompile!
|
99
|
+
send_fcsh_command! "compile #{command_id}"
|
100
|
+
parse_compilation_output!
|
101
|
+
end
|
102
|
+
|
103
|
+
def command_id
|
104
|
+
@command_ids[@command]
|
105
|
+
end
|
106
|
+
|
107
|
+
def command_id= id
|
108
|
+
@command_ids[@command] = id
|
109
|
+
end
|
110
|
+
|
111
|
+
def have_command_id?
|
112
|
+
@command_ids.include? @command
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse_compilation_output!
|
116
|
+
for line in @output.lines
|
117
|
+
case line
|
118
|
+
when /^fcsh: Assigned (\d+) as the compile target id$/
|
119
|
+
self.command_id = $1
|
120
|
+
else
|
121
|
+
@frontend.puts(line)
|
122
|
+
@logger.log_raw(line) if line =~ /^fcsh: /
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def send_fcsh_command! command
|
128
|
+
@logger.log_raw("> #{command}")
|
129
|
+
@fcsh_process.puts(command)
|
130
|
+
read_fcsh_output!
|
131
|
+
end
|
132
|
+
|
133
|
+
FCSH_PROMPT = "\n(fcsh) "
|
134
|
+
class PromptNotFound < Exception ; end
|
135
|
+
|
136
|
+
def read_fcsh_output!
|
137
|
+
@output_buffer << @fcsh_process.readpartial(256) until
|
138
|
+
@output_buffer.include? FCSH_PROMPT
|
139
|
+
@output, @output_buffer =
|
140
|
+
@output_buffer.split(FCSH_PROMPT, 2)
|
141
|
+
rescue EOFError
|
142
|
+
raise PromptNotFound, @output_buffer
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/fcshd/logger.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module FCSHD
|
2
|
+
class Logger
|
3
|
+
def initialize(output)
|
4
|
+
@stderr = output
|
5
|
+
end
|
6
|
+
|
7
|
+
def log_raw(message)
|
8
|
+
@stderr.puts message
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(message)
|
12
|
+
for line in message.lines
|
13
|
+
log_raw "#{program_name}: #{line.chomp}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def program_name
|
18
|
+
File.basename($0)
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(message)
|
22
|
+
for line in message.lines
|
23
|
+
log "error: #{line.chomp}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def die(message)
|
28
|
+
error message ; exit
|
29
|
+
end
|
30
|
+
|
31
|
+
def exit(code=1)
|
32
|
+
Kernel.exit code
|
33
|
+
end
|
34
|
+
|
35
|
+
def format_command(command, output)
|
36
|
+
["$ #{command}", *output.lines].
|
37
|
+
map { |line| " #{line.chomp}" }.
|
38
|
+
join("\n")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module FCSHD
|
4
|
+
class Problem < Struct.new(:source_location, :raw_mxmlc_message)
|
5
|
+
ERROR_PREFIX = /^\s*Error: /
|
6
|
+
|
7
|
+
def mxmlc_message
|
8
|
+
raw_mxmlc_message.sub(ERROR_PREFIX, "")
|
9
|
+
end
|
10
|
+
|
11
|
+
def error?
|
12
|
+
raw_mxmlc_message =~ ERROR_PREFIX
|
13
|
+
end
|
14
|
+
|
15
|
+
def quote(string)
|
16
|
+
"‘#{string}’"
|
17
|
+
end
|
18
|
+
|
19
|
+
def message
|
20
|
+
case raw = raw_message
|
21
|
+
when String then raw
|
22
|
+
when Array then raw * "\n"
|
23
|
+
else fail
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_message
|
28
|
+
case mxmlc_message
|
29
|
+
|
30
|
+
when "Unable to resolve MXML language version. Please specify the language namespace on the root document tag."
|
31
|
+
then
|
32
|
+
<<"^D"
|
33
|
+
missing MXML version
|
34
|
+
→ xmlns:fx="library://ns.adobe.com/mxml/2009"
|
35
|
+
→ xmlns="library://ns.adobe.com/flex/spark"
|
36
|
+
→ xmlns:mx="library://ns.adobe.com/flex/mx" (Flex 3 compatibility)
|
37
|
+
→ xmlns="http://www.adobe.com/2006/mxml" (Flex 3)
|
38
|
+
^D
|
39
|
+
|
40
|
+
when /^Incorrect number of arguments. Expected (\d+)\.$/
|
41
|
+
then "expected #$1 arguments"
|
42
|
+
|
43
|
+
when /^(?:Access of possibly undefined property|Call to a possibly undefined method) (.+) through a reference with static type (.+)\.$/
|
44
|
+
then "#{quote $1} undeclared in #$2"
|
45
|
+
|
46
|
+
when /^Attempted access of inaccessible property (.+) through a reference with static type (.+)\.$/
|
47
|
+
then "#{quote $1} inaccessible in #$2"
|
48
|
+
|
49
|
+
when
|
50
|
+
/^Could not resolve <(.+)> to a component implementation.$/,
|
51
|
+
/^Call to a possibly undefined method (.+).$/,
|
52
|
+
/^Access of undefined property (.+).$/,
|
53
|
+
/^The definition of base class (.+) was not found.$/,
|
54
|
+
/^Type was not found or was not a compile-time constant: (.+)\.$/
|
55
|
+
then
|
56
|
+
["#{quote $1} undeclared"].tap do |result|
|
57
|
+
Compiler.find_standard_component($1).tap do |package|
|
58
|
+
result << "→ import #{package}.*" if package
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
when /^Definition (.+) could not be found\.$/
|
63
|
+
then "#{quote $1} not found"
|
64
|
+
|
65
|
+
when
|
66
|
+
/^Implicit coercion of a value of type (.+) to an unrelated type (.+)\.$/,
|
67
|
+
|
68
|
+
/^Implicit coercion of a value with static type (.+) to a possibly unrelated type (.+)\./
|
69
|
+
|
70
|
+
then
|
71
|
+
actual, expected = $1, $2
|
72
|
+
expected_base = expected.sub(/.+:/, "")
|
73
|
+
actual_base = actual.sub(/.+:/, "")
|
74
|
+
if actual_base != expected_base
|
75
|
+
"expected #{expected_base} (got #{actual_base})"
|
76
|
+
else
|
77
|
+
"expected #{expected} (got #{actual})"
|
78
|
+
end
|
79
|
+
|
80
|
+
when "Method marked override must override another method."
|
81
|
+
then "overriding nonexistent method"
|
82
|
+
|
83
|
+
when "Overriding a function that is not marked for override."
|
84
|
+
then ["unmarked override", "→ add override keyword"]
|
85
|
+
|
86
|
+
when "Incompatible override."
|
87
|
+
then "incompatible override"
|
88
|
+
|
89
|
+
when /^Ambiguous reference to (.+)\.$/
|
90
|
+
then "#{quote $1} is ambiguous"
|
91
|
+
|
92
|
+
when /^A conflict exists with definition (.+) in namespace internal\.$/
|
93
|
+
then "#{quote $1} is conflicting"
|
94
|
+
|
95
|
+
when
|
96
|
+
/^Warning: parameter '(.+)' has no type declaration\.$/,
|
97
|
+
/^Warning: return value for function '(.+)' has no type declaration\.$/
|
98
|
+
then
|
99
|
+
case $1
|
100
|
+
when "anonymous" then "anonymous function"
|
101
|
+
else quote $1
|
102
|
+
end + " missing type declaration"
|
103
|
+
|
104
|
+
when /^A file found in a source-path must have the same package structure '(.*)', as the definition's package, '(.*)'\.$/
|
105
|
+
then "package should be #{quote $1}"
|
106
|
+
|
107
|
+
when /^Comparison between a value with static type (.+) and a possibly unrelated type (.+)\.$/
|
108
|
+
then "comparing #$1 to #$2"
|
109
|
+
|
110
|
+
when "Illegal assignment to a variable specified as constant."
|
111
|
+
then "modifying constant"
|
112
|
+
|
113
|
+
when "Function does not have a body."
|
114
|
+
then "missing function body"
|
115
|
+
|
116
|
+
when "Return type of a setter definition must be unspecified or void."
|
117
|
+
then "setter must return void"
|
118
|
+
|
119
|
+
when "Function does not return a value."
|
120
|
+
then "missing return statement"
|
121
|
+
|
122
|
+
when "Syntax error: expecting identifier before rightparen."
|
123
|
+
then "#{quote ")"} unexpected"
|
124
|
+
|
125
|
+
when
|
126
|
+
/^The (.+) attribute can only be used inside a package\./,
|
127
|
+
/^The (.+) attribute may be used only on class property definitions\./
|
128
|
+
then
|
129
|
+
"#{quote $1} unexpected"
|
130
|
+
|
131
|
+
else
|
132
|
+
mxmlc_message
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def formatted_message_lines
|
137
|
+
lines = message.lines.entries
|
138
|
+
if error?
|
139
|
+
first = <<"^D"
|
140
|
+
error: #{lines[0].chomp}
|
141
|
+
^D
|
142
|
+
rest = lines[1..-1].map do |line|
|
143
|
+
<<"^D"
|
144
|
+
#{line.chomp}
|
145
|
+
^D
|
146
|
+
end
|
147
|
+
[first] + rest
|
148
|
+
else
|
149
|
+
lines
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/fcshd/server.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module FCSHD
|
4
|
+
class Server
|
5
|
+
def initialize(port, compiler, logger)
|
6
|
+
@server = TCPServer.new("localhost", port)
|
7
|
+
@compiler = compiler
|
8
|
+
@logger = logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def run!
|
12
|
+
loop do
|
13
|
+
Thread.start(@server.accept) do |socket|
|
14
|
+
Client.new(socket, @compiler).run!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Client < Struct.new(:socket, :compiler)
|
20
|
+
def run!
|
21
|
+
case command = socket.gets
|
22
|
+
when /^mxmlc /
|
23
|
+
compiler.compile! command, socket
|
24
|
+
else
|
25
|
+
sockets.puts "fcshd: Unrecognized command: #{command}"
|
26
|
+
end
|
27
|
+
rescue Errno::EPIPE
|
28
|
+
logger.log "Broken pipe."
|
29
|
+
ensure
|
30
|
+
socket.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module FCSHD
|
2
|
+
class SourceLocation < Struct.new \
|
3
|
+
:filename, :line_number, :column_number, :basedir
|
4
|
+
|
5
|
+
def to_s
|
6
|
+
relative_filename.tap do |result|
|
7
|
+
result << ":#{line_number}" if line_number
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def relative_filename
|
12
|
+
if basedir
|
13
|
+
filename.sub(/^#{Regexp.quote(basedir)}/, "")
|
14
|
+
else
|
15
|
+
filename
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_basedir(new_basedir)
|
20
|
+
dup.tap { |result| result.basedir = new_basedir }
|
21
|
+
end
|
22
|
+
|
23
|
+
def without_column_number
|
24
|
+
dup.tap { |result| result.column_number = nil }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fcshd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Daniel Brockman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-08-31 00:00:00 Z
|
18
|
+
dependencies: []
|
19
|
+
|
20
|
+
description: |
|
21
|
+
By using a client-server architecture, we are able to make the Adobe Flex
|
22
|
+
compiler run fast while still being usable in command-line environments.
|
23
|
+
In practice, you start the `fcshd' server, and are then able to use the
|
24
|
+
client program `fcshc' as a faster and more usable replacement for `mxmlc'.
|
25
|
+
|
26
|
+
email: daniel@gointeractive.se
|
27
|
+
executables:
|
28
|
+
- fcshd
|
29
|
+
- fcshc
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files: []
|
33
|
+
|
34
|
+
files:
|
35
|
+
- .gitignore
|
36
|
+
- .rvmrc
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- bin/fcshc
|
40
|
+
- bin/fcshd
|
41
|
+
- fcshd.gemspec
|
42
|
+
- lib/fcshd.rb
|
43
|
+
- lib/fcshd/compiler-output-writer.rb
|
44
|
+
- lib/fcshd/compiler-output.rb
|
45
|
+
- lib/fcshd/compiler.rb
|
46
|
+
- lib/fcshd/logger.rb
|
47
|
+
- lib/fcshd/problem.rb
|
48
|
+
- lib/fcshd/server.rb
|
49
|
+
- lib/fcshd/source-location.rb
|
50
|
+
- lib/fcshd/version.rb
|
51
|
+
homepage: http://github.com/dbrock/fcshd
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.8.8
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Usable CLI for the Adobe Flex compiler shell (fcsh)
|
84
|
+
test_files: []
|
85
|
+
|