Excel错误调试
Execl error debuging
瞄准
我的 objective 是为 pandoc 创建一个简单的前端。我了解到 execl 是在系统中调用可执行文件的好方法。
请注意以下代码中的函数 btn_pressed,它使用上述方法调用 pandoc。
[indent=4]
uses
Posix
Gtk
class TestWindow:Window
_file_chooser:FileChooserButton
_entry:Gtk.Entry
_button:Gtk.Button
_file:File
construct()
title = "Pandoc GUI"
window_position = WindowPosition.CENTER
destroy.connect( Gtk.main_quit )
var folder_chooser = new FileChooserButton("Choose a Folder",FileChooserAction.SELECT_FOLDER)
folder_chooser.set_current_folder( Environment.get_home_dir() )
//I used selection_changed directly as per the question in stack_exchange
//
folder_chooser.selection_changed.connect( folder_changed )
_file_chooser = new FileChooserButton("Choose a File",FileChooserAction.OPEN)
_file_chooser.set_current_folder( Environment.get_home_dir() )
_file_chooser.file_set.connect( file_changed )
_entry = new Gtk.Entry()
_entry.set_text("Here the file name")
_button = new Button.with_label("Convert to pdf")
_button.set_sensitive(false)
_button.clicked.connect(btn_pressed)
var box = new Box( Orientation.VERTICAL, 0 )
box.pack_start( folder_chooser, true, true, 0 )
box.pack_start( _file_chooser, true, true, 0 )
box.pack_start( _entry, true, true, 0 )
box.pack_start( _button, true, true, 0 )
add( box )
def folder_changed( folder_chooser_widget:FileChooser )
folder:string = folder_chooser_widget.get_uri()
_file_chooser.set_current_folder_uri( folder )
def file_changed ( file_chooser_widget: FileChooser )
_file = File.new_for_uri(file_chooser_widget.get_uri())
try
info:FileInfo = _file.query_info (FileAttribute.ACCESS_CAN_WRITE, FileQueryInfoFlags.NONE, null)
writable: bool = info.get_attribute_boolean (FileAttribute.ACCESS_CAN_WRITE)
if !writable
_entry.set_sensitive (false)
else
_button.set_sensitive (true)
except e: Error
print e.message
_entry.set_text(_file.get_basename())
def btn_pressed ()
var md_name=_entry.get_text()+".md -s -o "+_entry.get_text()+".pdf"
execl("/usr/bin/pandoc", md_name)
_button.set_sensitive (false)
init
Gtk.init( ref args )
var test = new TestWindow()
test.show_all()
Gtk.main()
错误
在执行时,我的代码没有任何响应,也没有呈现任何 pdf。
问题
- 如何使用 execl 调试二进制文件的执行?
我会使用 GLib.Subprocess
来调用外部命令,因为它可以更好地控制外部命令的输入和输出。不过,将下面的示例更改为 execl
应该很容易。
第一件事是将外部命令与 window 对象分离。这使它更具可测试性。为此,使用了一个单独的对象 - Subprocess
调用的包装器。将此代码保存为 ToPDF.gs
:
namespace FileConverters
class ToPDF
const _command:string = "pandoc"
def async convert( source:string, output:string )
try
var flags = SubprocessFlags.STDOUT_PIPE \
| SubprocessFlags.STDERR_PIPE
var subprocess = new Subprocess( flags,
_command,
source,
output
)
output_buffer:Bytes
yield subprocess.communicate_async( null,
null,
out output_buffer,
null
)
if ( subprocess.get_exit_status() == 0 )
debug( "command successful: \n %s",
(string)output_buffer.get_data()
)
else
debug( "command failed" )
except err:Error
debug( err.message )
ToPDF
class 现在与应用程序的其余部分分离。这意味着它可以重复使用。为了说明这一点,下面显示了一个集成测试,它使用 class.
ToPDF
也使用了异步代码。所以我会先解释一下。使方法异步意味着它将 运行 与应用程序的主线程并发。通过同时调用外部程序 运行 意味着主线程在等待外部程序完成时不会锁定。使用 async
意味着函数被一分为二。第一部分使用 convert.begin( source, output )
调用,并将 运行 到 yield
命令。那时程序的执行分为两部分。主线程会return给convert.begin
的调用者,但是后台启动的是Subprocess
。当 Subprocess
完成后,它 returns 到 convert
并完成方法调用。
将集成测试另存为ToPDFTest.gs
:
uses FileConverters
init
var a = new ToPDF()
a.convert.begin( "source_file.md", "output_file.pdf" )
var loop = new MainLoop()
var loop_quitter = new LoopQuitter( loop )
Timeout.add_seconds( 2, loop_quitter.quit )
loop.run()
class LoopQuitter
_loop:MainLoop
construct( loop:MainLoop )
_loop = loop
def quit():bool
_loop.quit()
return false
用valac --pkg gio-2.0 ToPDF.gs ToPDFTest.gs
编译
然后 运行 用 G_MESSAGES_DEBUG=all ./ToPDFTest
测试
测试使用MainLoop
,它是Gtk.Main
的基础class。为了模拟一个长 运行ning 程序,设置了两秒的超时,然后调用 MainLoop.quit()
来结束测试。不幸的是,MainLoop.quit()
没有 Timeout
回调的正确函数签名,因此使用了包装器 class、LoopQuitter
。
Integration tests 这样的 运行 通常在软件发布之前保留,以确保应用程序与其他软件模块一起工作。
要将 ToPDF
与您的 window 集成,您需要更改
execl("/usr/bin/pandoc", md_name)
类似于
var to_pdf = new Fileconverts.ToPDF()
to_pdf.convert.begin( md_name, pdf_name )
您可能还想将其包装在类似于 的命令模式中。您可能还想修改它以向用户提供更好的反馈。
瞄准
我的 objective 是为 pandoc 创建一个简单的前端。我了解到 execl 是在系统中调用可执行文件的好方法。
请注意以下代码中的函数 btn_pressed,它使用上述方法调用 pandoc。
[indent=4]
uses
Posix
Gtk
class TestWindow:Window
_file_chooser:FileChooserButton
_entry:Gtk.Entry
_button:Gtk.Button
_file:File
construct()
title = "Pandoc GUI"
window_position = WindowPosition.CENTER
destroy.connect( Gtk.main_quit )
var folder_chooser = new FileChooserButton("Choose a Folder",FileChooserAction.SELECT_FOLDER)
folder_chooser.set_current_folder( Environment.get_home_dir() )
//I used selection_changed directly as per the question in stack_exchange
//
folder_chooser.selection_changed.connect( folder_changed )
_file_chooser = new FileChooserButton("Choose a File",FileChooserAction.OPEN)
_file_chooser.set_current_folder( Environment.get_home_dir() )
_file_chooser.file_set.connect( file_changed )
_entry = new Gtk.Entry()
_entry.set_text("Here the file name")
_button = new Button.with_label("Convert to pdf")
_button.set_sensitive(false)
_button.clicked.connect(btn_pressed)
var box = new Box( Orientation.VERTICAL, 0 )
box.pack_start( folder_chooser, true, true, 0 )
box.pack_start( _file_chooser, true, true, 0 )
box.pack_start( _entry, true, true, 0 )
box.pack_start( _button, true, true, 0 )
add( box )
def folder_changed( folder_chooser_widget:FileChooser )
folder:string = folder_chooser_widget.get_uri()
_file_chooser.set_current_folder_uri( folder )
def file_changed ( file_chooser_widget: FileChooser )
_file = File.new_for_uri(file_chooser_widget.get_uri())
try
info:FileInfo = _file.query_info (FileAttribute.ACCESS_CAN_WRITE, FileQueryInfoFlags.NONE, null)
writable: bool = info.get_attribute_boolean (FileAttribute.ACCESS_CAN_WRITE)
if !writable
_entry.set_sensitive (false)
else
_button.set_sensitive (true)
except e: Error
print e.message
_entry.set_text(_file.get_basename())
def btn_pressed ()
var md_name=_entry.get_text()+".md -s -o "+_entry.get_text()+".pdf"
execl("/usr/bin/pandoc", md_name)
_button.set_sensitive (false)
init
Gtk.init( ref args )
var test = new TestWindow()
test.show_all()
Gtk.main()
错误
在执行时,我的代码没有任何响应,也没有呈现任何 pdf。
问题
- 如何使用 execl 调试二进制文件的执行?
我会使用 GLib.Subprocess
来调用外部命令,因为它可以更好地控制外部命令的输入和输出。不过,将下面的示例更改为 execl
应该很容易。
第一件事是将外部命令与 window 对象分离。这使它更具可测试性。为此,使用了一个单独的对象 - Subprocess
调用的包装器。将此代码保存为 ToPDF.gs
:
namespace FileConverters
class ToPDF
const _command:string = "pandoc"
def async convert( source:string, output:string )
try
var flags = SubprocessFlags.STDOUT_PIPE \
| SubprocessFlags.STDERR_PIPE
var subprocess = new Subprocess( flags,
_command,
source,
output
)
output_buffer:Bytes
yield subprocess.communicate_async( null,
null,
out output_buffer,
null
)
if ( subprocess.get_exit_status() == 0 )
debug( "command successful: \n %s",
(string)output_buffer.get_data()
)
else
debug( "command failed" )
except err:Error
debug( err.message )
ToPDF
class 现在与应用程序的其余部分分离。这意味着它可以重复使用。为了说明这一点,下面显示了一个集成测试,它使用 class.
ToPDF
也使用了异步代码。所以我会先解释一下。使方法异步意味着它将 运行 与应用程序的主线程并发。通过同时调用外部程序 运行 意味着主线程在等待外部程序完成时不会锁定。使用 async
意味着函数被一分为二。第一部分使用 convert.begin( source, output )
调用,并将 运行 到 yield
命令。那时程序的执行分为两部分。主线程会return给convert.begin
的调用者,但是后台启动的是Subprocess
。当 Subprocess
完成后,它 returns 到 convert
并完成方法调用。
将集成测试另存为ToPDFTest.gs
:
uses FileConverters
init
var a = new ToPDF()
a.convert.begin( "source_file.md", "output_file.pdf" )
var loop = new MainLoop()
var loop_quitter = new LoopQuitter( loop )
Timeout.add_seconds( 2, loop_quitter.quit )
loop.run()
class LoopQuitter
_loop:MainLoop
construct( loop:MainLoop )
_loop = loop
def quit():bool
_loop.quit()
return false
用valac --pkg gio-2.0 ToPDF.gs ToPDFTest.gs
编译
然后 运行 用 G_MESSAGES_DEBUG=all ./ToPDFTest
测试使用MainLoop
,它是Gtk.Main
的基础class。为了模拟一个长 运行ning 程序,设置了两秒的超时,然后调用 MainLoop.quit()
来结束测试。不幸的是,MainLoop.quit()
没有 Timeout
回调的正确函数签名,因此使用了包装器 class、LoopQuitter
。
Integration tests 这样的 运行 通常在软件发布之前保留,以确保应用程序与其他软件模块一起工作。
要将 ToPDF
与您的 window 集成,您需要更改
execl("/usr/bin/pandoc", md_name)
类似于
var to_pdf = new Fileconverts.ToPDF()
to_pdf.convert.begin( md_name, pdf_name )
您可能还想将其包装在类似于