Parse output of command that interpret crystal script

Hi guys, I have quite a specific question. I would like to know how can I parse the error of the result of running a crystal script by the command Process.run ?

Basically, I need to get the line number where the problem occurred, and get the error message. Because the ouput is formatted with colors and other things, I don’t know how to do ?

Because then I would like to show something else based on the information I have got.

So from that beginning, how should I do then ?

processResult = IO::Memory.new

process = Process.run(  "crystal error.cr",
                        error: processResult,
                        #error: :inherit,
                        shell: true)

Best bet would prob doing something like:

output = IO::Memory.new

Process.run "crystal", ["run", "--no-color", "error.cr"], error: output

output_string = output.to_s

# Parse the data from output_string somehow

This’ll at least remove the coloring, so will make writing a regex or parser easier.

There also is a -f json option to output json instead of text.

I tried that, but didn’t seem to make a difference in this case.

When i run crystal run zzz.cr -f json, where the file only contains asd, then i get:

[{"file":"[snip]/zzz.cr","line":3,"column":1,"size":3,"message":"undefined local variable or method 'asd' for top-level"}]
1 Like

Ahh, seems the difference is it’ll be JSON if the error is a compile time error. If it’s a runtime exception, then it won’t be.

If @Fulgurance’s error is a compile time one, then this would be perfect! As it’s already in a consumable format. Otherwise if its a runtime error will have to parse that out somehow.

1 Like

Actually it’s a compile time errot I need ! So it’s perfect . Thanks a lot guys !

So I did that test but I get an error:

require "json"

class Output

        property path : String
        property line : Int32
        property column : Int32
        property size : Int32
        property message : String

        include JSON::Serializable

end

processResult = IO::Memory.new

process = Process.run(  "crystal build error.cr -f json",
                        error: processResult,
                        #error: :inherit,
                        shell: true)

puts Output.from_json(processResult)
zohran@alienware-m17-r3:~/Downloads$ crystal test.cr 
Unhandled exception: Expected BeginObject but was EOF at line 1, column 1
  parsing Output at line 0, column 0 (JSON::SerializableError)
  from /usr/share/crystal/src/json/serialization.cr:182:7 in 'initialize:__pull_for_json_serializable'
  from test.cr:11:9 in 'new_from_json_pull_parser'
  from test.cr:11:9 in 'new'
  from /usr/share/crystal/src/json/from_json.cr:13:3 in 'from_json'
  from test.cr:22:6 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:129:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:115:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:141:3 in 'main'
  from /lib64/libc.so.6 in '??'
  from /lib64/libc.so.6 in '__libc_start_main'
  from /home/zohran/.cache/crystal/crystal-run-test.tmp in '_start'
  from ???
Caused by: Expected BeginObject but was EOF at line 1, column 1 (JSON::ParseException)
  from /usr/share/crystal/src/json/pull_parser.cr:705:5 in 'raise'
  from /usr/share/crystal/src/json/pull_parser.cr:696:5 in 'expect_kind'
  from /usr/share/crystal/src/json/pull_parser.cr:167:5 in 'read_begin_object'
  from /usr/share/crystal/src/json/serialization.cr:182:7 in 'initialize:__pull_for_json_serializable'
  from test.cr:11:9 in 'new_from_json_pull_parser'
  from test.cr:11:9 in 'new'
  from /usr/share/crystal/src/json/from_json.cr:13:3 in 'from_json'
  from test.cr:22:6 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:129:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:115:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:141:3 in 'main'
  from /lib64/libc.so.6 in '??'
  from /lib64/libc.so.6 in '__libc_start_main'
  from /home/zohran/.cache/crystal/crystal-run-test.tmp in '_start'
  from ???

Few issues:

  1. You need to rewind your IO::Memory before trying to read from it
  2. The result is a Array(Output), not just a single Output
  3. The one property is called file, not path
  4. Given the data is immutable, might be better to use a struct with getter instead of a class with property.

Okay got it, as usual, thanks a lot Blacksmoke16 !

I have one last question because I am facing a problem, is it normal sometime the field size of the json output return null instead of a Int ???

It’s nilable in the compiler, so guess so.

Okay so I will code something to manage that

Not sure what you mean by “code something to manage that”, you just need to make that field nilable too. E.g. getter size : Int32?

Yeah it’s what I mean :slightly_smiling_face:

But I think probably instead I will perform a gsub to ensure always that entry return a int. I don’t like to have variable with different types.

Keep it not nilable, but give it a default value of 0 or something then.