# # # patch "Monotone/AutomateStdio.pm" # from [8edb42907ace0785da69df5a4d5ddc47bd776aac] # to [79f4e8c6faa82a51b7b935d84029ccbb39323dc5] # # patch "Monotone/AutomateStdio.pod" # from [6215f5d9ff689f2e035bdce079c436b8f5be62e6] # to [5772648235d8a606b8b96cb6fc7b52bd719ff71f] # # patch "TODO" # from [cb53adbd158f585f3789f705019fa01034e32427] # to [d0544ca5e9ac53e35891ec948fe72619ad2b9b7d] # # patch "mtn-tester" # from [7db94b5966868140cece98d943fb83f6ba07b97b] # to [b5805af0a8b9e8fe0dd3b84beae7250ad4161079] # ============================================================ --- Monotone/AutomateStdio.pm 8edb42907ace0785da69df5a4d5ddc47bd776aac +++ Monotone/AutomateStdio.pm 79f4e8c6faa82a51b7b935d84029ccbb39323dc5 @@ -42,6 +42,10 @@ package Monotone::AutomateStdio; package Monotone::AutomateStdio; +# ***** REQUIRED VERSION OF PERL ***** + +require 5.008; + # ***** REQUIRED PACKAGES ***** use strict; @@ -135,7 +139,7 @@ sub graph($$); sub get_option($\$$); sub get_revision($\$$); sub graph($$); -sub heads(address@hidden); +sub heads($\@;$); sub identify($\$$); sub interface_version($\$); sub inventory($$); @@ -195,6 +199,11 @@ sub new($;$) $this->{cmd_cnt} = 0; $this->{mtn_err_msg} = ""; + if ($this->{mtn_pid} == 0) + { + startup($this); + } + bless($this); $this->SUPER::new() if $this->can("SUPER::new"); @@ -684,12 +693,25 @@ sub get_attributes($\$$) my Monotone::AutomateStdio $this = shift(); my($ref, $file_name) = @_; + my $cmd; + + # This command was renamed in version 0.36 (i/f version 5.x). + + if ($this->{mtn_aif_major} >= 5) + { + $cmd = "get_attributes"; + } + else + { + $cmd = "attributes"; + } + # Run the command and get the data, either as one lump or as a structured # list. if (ref($ref) eq "SCALAR") { - return mtn_command($this, "attributes", $ref, $file_name); + return mtn_command($this, $cmd, $ref, $file_name); } else { @@ -702,7 +724,7 @@ sub get_attributes($\$$) $state, $value); - if (! mtn_command($this, "attributes", address@hidden, $file_name)) + if (! mtn_command($this, $cmd, address@hidden, $file_name)) { return; } @@ -1053,7 +1075,7 @@ sub get_manifest_of($$;$) $type = "directory"; get_quoted_value(@lines, $i, $name); } - if ($type) + if (defined($type)) { if ($type eq "file") { @@ -1354,7 +1376,8 @@ sub graph($$) # Routine - heads # # Description - Get a list of revision ids that are heads on the specified -# branch. +# branch. If no branch is given then the workspace's branch +# is used. # # Data - $this : The object. # address@hidden : A reference to a list that is to contain the @@ -1367,7 +1390,7 @@ sub graph($$) -sub heads(address@hidden) +sub heads($\@;$) { my Monotone::AutomateStdio $this = shift(); @@ -1478,34 +1501,136 @@ sub inventory($$) else { - my($i, - $j, - @lines, - $name, - $ref1, - $ref2, - $status); + my @lines; if (! mtn_command($this, "inventory", address@hidden)) { return; } - # Reformat the data into a structured array. + # The output format of this command was switched over to a basic_io + # stanza in 0.37 (i/f version 6.x). - for ($i = $j = 0, @$ref = (); $i <= $#lines; ++ $i) + if ($this->{mtn_aif_major} < 6) { - if ($lines[$i] =~ m/^[A-Z ]{3} \d+ \d+ .+$/o) + + my($i, + $j, + $name, + $ref1, + $ref2, + $status); + + # Reformat the data into a structured array. + + for ($i = $j = 0, @$ref = (); $i <= $#lines; ++ $i) { - ($status, $ref1, $ref2, $name) = - ($lines[$i] =~ m/^([A-Z ]{3}) (\d+) (\d+) (.+)$/o); - $$ref[$j ++] = {status => $status, - crossref_one => $ref1, - crossref_two => $ref2, - name => $name}; + if ($lines[$i] =~ m/^[A-Z ]{3} \d+ \d+ .+$/o) + { + ($status, $ref1, $ref2, $name) = + ($lines[$i] =~ m/^([A-Z ]{3}) (\d+) (\d+) (.+)$/o); + $$ref[$j ++] = {status => $status, + crossref_one => $ref1, + crossref_two => $ref2, + name => $name}; + } } + } + else + { + my(@changes, + $fs_type, + $i, + $j, + $list, + $new_path, + $new_type, + $old_path, + $old_type, + $path, + @status); + + # Reformat the data into a structured array. + + for ($i = $j = 0, $path = undef, @$ref = (); $i <= $#lines; ++ $i) + { + + # The `path' element always starts a new entry, the remaining + # lines may be in any order. + + if ($lines[$i] =~ m/^ *path \"/o) + { + + # Save any existing data to a new entry in the output list. + + if (defined($path)) + { + $$ref[$j ++] = {path => unescape($path), + old_type => $old_type, + new_type => $new_type, + fs_type => $fs_type, + old_path => unescape($old_path), + new_path => unescape($new_path), + status => address@hidden, + changes => address@hidden; + } + + $fs_type = $new_path = $new_type = $old_path = $old_type = + $path = undef; + @changes = @status = (); + + get_quoted_value(@lines, $i, $path); + + } + elsif ($lines[$i] =~ m/^ *old_type \"/o) + { + ($old_type) = + ($lines[$i] =~ m/^ *old_type \"([^\"]+)\"$/o); + } + elsif ($lines[$i] =~ m/^ *new_type \"/o) + { + ($new_type) = + ($lines[$i] =~ m/^ *new_type \"([^\"]+)\"$/o); + } + elsif ($lines[$i] =~ m/^ *fs_type \"/o) + { + ($fs_type) = + ($lines[$i] =~ m/^ *fs_type \"([^\"]+)\"$/o); + } + elsif ($lines[$i] =~ m/^ *old_path \"/o) + { + get_quoted_value(@lines, $i, $old_path); + } + elsif ($lines[$i] =~ m/^ *new_path \"/o) + { + get_quoted_value(@lines, $i, $new_path); + } + elsif ($lines[$i] =~ m/^ *status \"/o) + { + ($list) = ($lines[$i] =~ m/^ *\S+ \"(.+)\"$/o); + @status = split(/\" \"/o, $list); + } + elsif ($lines[$i] =~ m/^ *changes \"/o) + { + ($list) = ($lines[$i] =~ m/^ *\S+ \"(.+)\"$/o); + @changes = split(/\" \"/o, $list); + } + } + if (defined($path)) + { + $$ref[$j ++] = {path => unescape($path), + old_type => $old_type, + new_type => $new_type, + fs_type => $fs_type, + old_path => unescape($old_path), + new_path => unescape($new_path), + status => address@hidden, + changes => address@hidden; + } + } + return 1; } @@ -1600,7 +1725,7 @@ sub keys($$) ($list) = ($lines[$i ++] =~ m/^ *\S+ \"(.+)\"$/o); @priv_loc = split(/\" \"/o, $list); } - if ($priv_hash) + if (defined($priv_hash)) { $$ref[$j ++] = {type => "public-private", name => unescape($name), @@ -2321,6 +2446,8 @@ sub unescape($) my $data = $_[0]; + return undef unless defined($data); + $data =~ s/\\\\/\\/g; $data =~ s/\\\"/\"/g; ============================================================ --- Monotone/AutomateStdio.pod 6215f5d9ff689f2e035bdce079c436b8f5be62e6 +++ Monotone/AutomateStdio.pod 5772648235d8a606b8b96cb6fc7b52bd719ff71f @@ -1,8 +1,8 @@ =pod =head1 NAME -Monotone::automateStdio - Perl interface to Monotone via automate stdio +Monotone::AutomateStdio - Perl interface to Monotone via automate stdio =head1 VERSION @@ -279,9 +279,10 @@ containing the following fields: revision_id - The id of a revision. parent_ids - A list of parent revision ids. -=item $mtn->heads(address@hidden, $branch_name) +=item $mtn->heads(address@hidden, $branch_name]) -Get a list of revision ids that are heads on the specified branch. +Get a list of revision ids that are heads on the specified branch. If no branch +is given then the workspace's branch is used. =item $mtn->identify(\$buffer, $file_name) @@ -298,12 +299,36 @@ containing the following fields: is passed then the output is returned as a list of anonymous hashes, each one containing the following fields: - status - The three inventory status characters for the file - or directory. - crossref_one - The first cross-referencing number. - crossref_two - The second cross-referencing number. - name - The name of the file or directory. + Prior to version 0.37 of Monotone: + status - The three inventory status characters for the + file or directory. + crossref_one - The first cross-referencing number. + crossref_two - The second cross-referencing number. + name - The name of the file or directory. + From version 0.37 of Monotone onwards: + path - The name of the file or directory. + old_type - The type of the entry in the base manifest. Values + can be one of "directory", "file" or "none". + new_type - The type of the entry in the revision manifest. + Values can be one of "directory", "file" or + "none". + fs_type - The type of the entry on the file system. Values + can be one of "directory", "file" or "none". + old_path - The old name of the file or directory if it has + been renamed in the revision manifest. + new_path - The new name of the file or directory if it has + been renamed in the revision manifest. + status - A list of status flags. Values can be one of + "added", "dropped", "ignored", "invalid", "known", + "missing", "rename_source", "rename_target" or + "unknown". + changes - A list of change flags. Values can be one of + "attrs" or "content". + + Please note that some fields are not used by all entries, in + which case they are set to undef. + =item $mtn->keys(\$buffer | address@hidden) Get a list of all the keys known to mtn. If \$buffer is passed then the output @@ -383,6 +408,12 @@ opinions on this then please let me know to have a thread do that for you rather than use signals. If you have different opinions on this then please let me know. +When the output of a command from the automate stdio interface changes +dramatically, it will probably not be possible to protect Perl applications +from those changes. This library is a convenience wrapper rather than something +that will totally divorce you from the automate stdio interface. Also the +changes are you will want the new type of output anyway. + =head1 SEE ALSO http://monotone.ca @@ -394,10 +425,8 @@ efficient than the alternative. would come close to exposing this flaw and it is a lot simpler and more efficient than the alternative. -Whilst the object does know what version of mtn automate interface it is -dealing with it currently does nothing with that knowledge. However, hopefully -as usage of this library grows then it should not be too difficult to code in -exceptions to cleanly deal with differences. +Your mileage may vary if this library is used with versions of Monotone older +than 0.35 (automate stdio interface version 4.3). No doubt other bugs will crawl out of the wood-work. ============================================================ --- TODO cb53adbd158f585f3789f705019fa01034e32427 +++ TODO d0544ca5e9ac53e35891ec948fe72619ad2b9b7d @@ -1,4 +1,3 @@ -1) Update to version from 0.35 to 0.37. -2) Sort out a test database for use with a mtn-tester (use a script to generate +1) Sort out a test database for use with a mtn-tester (use a script to generate the database rather than use a static db). +2) Do CPAN stuff. -3) Do CPAN stuff. ============================================================ --- mtn-tester 7db94b5966868140cece98d943fb83f6ba07b97b +++ mtn-tester b5805af0a8b9e8fe0dd3b84beae7250ad4161079 @@ -24,7 +24,7 @@ if (0) { if (! $mtn->branches(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -32,7 +32,7 @@ if (0) } if (! $mtn->certs(address@hidden, "ae65e53a3beca7841a87eb4525f39e3369107b82")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -41,11 +41,11 @@ if (0) if (! $mtn->cert("ae65e53a3beca7841a87eb4525f39e3369107b82", "status", "EXTERMINATE")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } if (! $mtn->children(address@hidden, "78bfd27c26a0c8ac249f30293e6ef6d5f44e6084")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -54,7 +54,7 @@ if (0) } if (! $mtn->children(address@hidden, "ae65e53a3beca7841a87eb4525f39e3369107b82")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -64,7 +64,7 @@ if (0) "ed89ce366c3316f189f01229adc863b3285130e2", "65e51cd2a00b4ee60b9fcc356e8e503d1e690414")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -76,7 +76,7 @@ if (0) "78bfd27c26a0c8ac249f30293e6ef6d5f44e6084", "ff7e085fab7385fbaabc57c1f53a9bbea59bf132")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -86,7 +86,7 @@ if (0) "ae65e53a3beca7841a87eb4525f39e3369107b82", "d612b1ed732ea565085eede32bb2a1fae2ca8804")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -97,7 +97,7 @@ if (0) "d612b1ed732ea565085eede32bb2a1fae2ca8804", "Makefile")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -105,7 +105,7 @@ if (0) } if (! $mtn->descendents(address@hidden, "d612b1ed732ea565085eede32bb2a1fae2ca8804")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -115,7 +115,7 @@ if (0) "ae65e53a3beca7841a87eb4525f39e3369107b82", "d612b1ed732ea565085eede32bb2a1fae2ca8804")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -123,7 +123,7 @@ if (0) } if (! $mtn->get_base_revision_id(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -133,7 +133,7 @@ if (0) "ae65e53a3beca7841a87eb4525f39e3369107b82", "Makefile")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -145,7 +145,7 @@ if (0) "Makefile", "d612b1ed732ea565085eede32bb2a1fae2ca8804")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -153,7 +153,7 @@ if (0) } if (! $mtn->get_current_revision_id(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -161,7 +161,7 @@ if (0) } if (! $mtn->get_file(\$data, "f7bec98218953adbb833865ccc52ea74d410b24e")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -169,7 +169,7 @@ if (0) } if (! $mtn->get_file_of(\$data, "Makefile")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -177,7 +177,7 @@ if (0) } if (! $mtn->get_option(\$data, "database")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -187,7 +187,7 @@ if (! $mtn->get_attributes(\$data, "scri if (! $mtn->get_attributes(\$data, "script2")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -196,7 +196,7 @@ if (! $mtn->get_attributes(address@hidden, "scri if (! $mtn->get_attributes(address@hidden, "script2")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -205,7 +205,7 @@ if (! $mtn->branches(address@hidden)) if (! $mtn->branches(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -214,7 +214,7 @@ if (! $mtn->get_option(\$data, "database if (! $mtn->get_option(\$data, "database")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -223,7 +223,7 @@ if (! $mtn->get_revision(\$data, "d83907 if (! $mtn->get_revision(\$data, "d83907887a2a35229ef361a74e98bd296d84e60c")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -232,7 +232,7 @@ if (! $mtn->get_revision(\$data,)) if (! $mtn->get_revision(\$data,)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -241,7 +241,7 @@ if (! $mtn->get_manifest_of(address@hidden)) if (! $mtn->get_manifest_of(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -250,7 +250,7 @@ if (! $mtn->get_manifest_of(\$data)) if (! $mtn->get_manifest_of(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -259,7 +259,7 @@ if (! $mtn->certs(address@hidden, "d83907887a2a3 if (! $mtn->certs(address@hidden, "d83907887a2a35229ef361a74e98bd296d84e60c")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -268,7 +268,7 @@ if (! $mtn->certs(\$data, "d83907887a2a3 if (! $mtn->certs(\$data, "d83907887a2a35229ef361a74e98bd296d84e60c")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -277,12 +277,12 @@ if (! $mtn->db_set("database", "default- if (! $mtn->db_set("database", "default-server", "www.test.com")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } if (! $mtn->db_get(\$data, "database", "default-server")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -291,7 +291,7 @@ if (! $mtn->graph(address@hidden)) if (! $mtn->graph(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -300,7 +300,7 @@ if (! $mtn->graph(\$data)) if (! $mtn->graph(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -309,7 +309,7 @@ if (! $mtn->heads(address@hidden, "net.venge.mon if (! $mtn->heads(address@hidden, "net.venge.monotone.www")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -318,7 +318,7 @@ if (! $mtn->identify(\$data, "Makefile.a if (! $mtn->identify(\$data, "Makefile.am")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -327,7 +327,7 @@ if (! $mtn->interface_version(\$data)) if (! $mtn->interface_version(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -336,7 +336,7 @@ if (! $mtn->inventory(\$data)) if (! $mtn->inventory(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -345,7 +345,7 @@ if (! $mtn->inventory(address@hidden)) if (! $mtn->inventory(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -354,7 +354,7 @@ if (! $mtn->keys(\$data)) if (! $mtn->keys(\$data)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -363,7 +363,7 @@ if (! $mtn->keys(address@hidden)) if (! $mtn->keys(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -372,7 +372,7 @@ if (! $mtn->leaves(address@hidden)) if (! $mtn->leaves(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -381,7 +381,7 @@ if (! $mtn->parents(address@hidden, "d83907887a2 if (! $mtn->parents(address@hidden, "d83907887a2a35229ef361a74e98bd296d84e60c")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -390,7 +390,7 @@ if (! $mtn->roots(address@hidden)) if (! $mtn->roots(address@hidden)) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -399,7 +399,7 @@ if (! $mtn->select(address@hidden, "l:2007-01-01 if (! $mtn->select(address@hidden, "l:2007-01-01/b:net.venge.monotone")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -408,7 +408,7 @@ if (! $mtn->tags(\$data, "net.venge.mono if (! $mtn->tags(\$data, "net.venge.monotone")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -417,7 +417,7 @@ if (! $mtn->tags(address@hidden, "net.venge.mono if (! $mtn->tags(address@hidden, "net.venge.monotone")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -426,7 +426,7 @@ if (! $mtn->get_revision(\$data, "492d55 if (! $mtn->get_revision(\$data, "492d55d26d09e8358bc239eaf2bf422350bf2d13")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else { @@ -435,7 +435,7 @@ if (! $mtn->get_revision(address@hidden, "492d55 if (! $mtn->get_revision(address@hidden, "492d55d26d09e8358bc239eaf2bf422350bf2d13")) { - printf("OOPS: %s\n", $mtn->error_message()); + printf(STDERR "OOPS: %s\n", $mtn->error_message()); } else {