# # # patch "lib/Monotone/AutomateStdio.pm" # from [2ce5596be86084f4ee97abbff6481915dc3577ea] # to [0f0d0f003489b804d85858a0344191f739a01555] # # patch "lib/Monotone/AutomateStdio.pod" # from [e75487f854ba13f37c3fee550b308f58a15448a6] # to [84241a357af7876fe04e46a50c600b5c78049da9] # # patch "mtn-tester" # from [5058f0ee4edb5c61843b0ac11bcacf77fa4184a6] # to [7723f0e457e6ab1791fa70044eee07fbfae02829] # ============================================================ --- lib/Monotone/AutomateStdio.pm 2ce5596be86084f4ee97abbff6481915dc3577ea +++ lib/Monotone/AutomateStdio.pm 0f0d0f003489b804d85858a0344191f739a01555 @@ -74,18 +74,21 @@ use constant MTN_DROP_DB_VARIABLES use constant MTN_DB_GET => 0; use constant MTN_DROP_ATTRIBUTE => 1; use constant MTN_DROP_DB_VARIABLES => 2; -use constant MTN_GET_ATTRIBUTES => 3; -use constant MTN_GET_CURRENT_REVISION => 4; -use constant MTN_GET_DB_VARIABLES => 5; -use constant MTN_GET_WORKSPACE_ROOT => 6; -use constant MTN_IGNORE_SUSPEND_CERTS => 7; -use constant MTN_INVENTORY_IN_IO_STANZA_FORMAT => 8; -use constant MTN_INVENTORY_INCLUDE_BIRTH_ID => 9; -use constant MTN_INVENTORY_TAKE_OPTIONS => 10; -use constant MTN_USE_P_SELECTOR => 11; -use constant MTN_SET_ATTRIBUTE => 12; -use constant MTN_SET_DB_VARIABLE => 13; -use constant MTN_SHOW_CONFLICTS => 14; +use constant MTN_FILE_MERGE => 3; +use constant MTN_GET_ATTRIBUTES => 4; +use constant MTN_GET_CURRENT_REVISION => 5; +use constant MTN_GET_DB_VARIABLES => 6; +use constant MTN_GET_WORKSPACE_ROOT => 7; +use constant MTN_IGNORE_SUSPEND_CERTS => 8; +use constant MTN_INVENTORY_IN_IO_STANZA_FORMAT => 9; +use constant MTN_INVENTORY_INCLUDE_BIRTH_ID => 10; +use constant MTN_INVENTORY_TAKE_OPTIONS => 11; +use constant MTN_LUA => 12; +use constant MTN_READ_PACKETS => 13; +use constant MTN_SET_ATTRIBUTE => 14; +use constant MTN_SET_DB_VARIABLE => 15; +use constant MTN_SHOW_CONFLICTS => 16; +use constant MTN_USE_P_SELECTOR => 17; # Constants used to represent the different error levels. @@ -97,10 +100,11 @@ use constant HEX_ID => 0x02; # use constant BARE_PHRASE => 0x01; # E.g. orphaned_directory. use constant HEX_ID => 0x02; # E.g. [ab2 ... 1be]. -use constant OPTIONAL_HEX_ID => 0x04; # As HEX_ID but also []. -use constant STRING => 0x08; # Any quoted string, possibly escaped. -use constant STRING_ENUM => 0x10; # E.g. "rename_source". -use constant STRING_LIST => 0x20; # E.g. "..." "...", possibly escaped. +use constant NULL => 0x04; # Nothing, i.e. we just have the key. +use constant OPTIONAL_HEX_ID => 0x08; # As HEX_ID but also []. +use constant STRING => 0x10; # Any quoted string, possibly escaped. +use constant STRING_ENUM => 0x20; # E.g. "rename_source". +use constant STRING_LIST => 0x40; # E.g. "..." "...", possibly escaped. # Pre-compiled regular expressions for: finding the end of a quoted string # possibly containing escaped quotes (i.e. " preceeded by a non-backslash @@ -109,15 +113,16 @@ my $database_locked_re = qr/.*sqlite err my $closing_quote_re = qr/((^.*[^\\])|^)(\\{2})*\"$/; my $database_locked_re = qr/.*sqlite error: database is locked.*/; -my $io_stanza_re = qr/^ *[a-z_]+ \S/; +my $io_stanza_re = qr/^ *([a-z_]+)(?:(?: \S)|(?: ?$))/; # A map for quickly detecting valid mtn subprocess options and the number of -# their arguements. +# their arguments. my %valid_mtn_options = ("--confdir" => 1, "--key" => 1, "--keydir" => 1, "--no-default-confdir" => 0, + "--no-workspace" => 0, "--norc" => 0, "--nostd" => 0, "--root" => 1, @@ -168,24 +173,25 @@ my %revision_details_keys = ("add_dir" "set" => STRING, "to" => HEX_ID | STRING, "value" => STRING); -my %show_conflicts_keys = ("ancestor" => OPTIONAL_HEX_ID, - "ancestor_file_id" => HEX_ID, - "ancestor_name" => STRING, - "attr_name" => STRING, - "conflict" => BARE_PHRASE, - "left" => HEX_ID, - "left_attr_value" => STRING, - "left_file_id" => HEX_ID, - "left_name" => STRING, - "left_type" => STRING, - "node_type" => STRING, - "right" => HEX_ID, - "right_attr_state" => STRING, - "right_attr_value" => STRING, - "right_file_id" => HEX_ID, - "right_name" => STRING, - "right_type" => STRING); -my %tags_keys = ("branches" => STRING_LIST, +my %show_conflicts_keys = ("ancestor" => OPTIONAL_HEX_ID, + "ancestor_file_id" => HEX_ID, + "ancestor_name" => STRING, + "attr_name" => STRING, + "conflict" => BARE_PHRASE, + "left" => HEX_ID, + "left_attr_value" => STRING, + "left_file_id" => HEX_ID, + "left_name" => STRING, + "left_type" => STRING, + "node_type" => STRING, + "resolved_internal" => NULL, + "right" => HEX_ID, + "right_attr_state" => STRING, + "right_attr_value" => STRING, + "right_file_id" => HEX_ID, + "right_name" => STRING, + "right_type" => STRING); +my %tags_keys = ("branches" => NULL | STRING_LIST, "format_version" => STRING_ENUM, "revision" => HEX_ID, "signer" => STRING, @@ -226,6 +232,7 @@ sub erase_ancestors($$;@); sub drop_attribute($$$); sub drop_db_variables($$;$); sub erase_ancestors($$;@); +sub file_merge($$$$$$); sub genkey($$$$); sub get_attributes($$$); sub get_base_revision_id($$); @@ -252,6 +259,7 @@ sub leaves($$); sub inventory($$;$@); sub keys($$); sub leaves($$); +sub lua($$$;@); sub new_from_db($;$$); sub new_from_ws($;$$); sub packet_for_fdata($$$); @@ -261,6 +269,7 @@ sub put_revision($$$); sub parents($$$); sub put_file($$$$); sub put_revision($$$); +sub read_packets($$); sub register_db_locked_handler(;$$$); sub register_error_handler($;$$$); sub register_io_wait_handler(;$$$$); @@ -304,6 +313,7 @@ our %EXPORT_TAGS = (capabilities => [qw( our %EXPORT_TAGS = (capabilities => [qw(MTN_DB_GET MTN_DROP_ATTRIBUTE MTN_DROP_DB_VARIABLES + MTN_FILE_MERGE MTN_GET_ATTRIBUTES MTN_GET_CURRENT_REVISION MTN_GET_DB_VARIABLES @@ -312,16 +322,18 @@ our %EXPORT_TAGS = (capabilities => [qw( MTN_INVENTORY_IN_IO_STANZA_FORMAT MTN_INVENTORY_INCLUDE_BIRTH_ID MTN_INVENTORY_TAKE_OPTIONS - MTN_USE_P_SELECTOR + MTN_LUA + MTN_READ_PACKETS MTN_SET_ATTRIBUTE MTN_SET_DB_VARIABLE - MTN_SHOW_CONFLICTS)], - severities => [qw(MTN_SEVERITY_ALL + MTN_SHOW_CONFLICTS + MTN_USE_P_SELECTOR)], + severities => [qw(MTN_SEVERITY_ALL MTN_SEVERITY_ERROR MTN_SEVERITY_WARNING)]); our @EXPORT = qw(); Exporter::export_ok_tags(qw(capabilities severities)); -our $VERSION = 0.1; +our $VERSION = 0.2.0; # ############################################################################## # @@ -921,6 +933,49 @@ sub erase_ancestors($$;@) # ############################################################################## # +# Routine - file_merge +# +# Description - Get the result of merging two files, both of which are on +# separate revisions. +# +# Data - $this : The object. +# $buffer : A reference to a buffer that is to +# contain the output from this command. +# $left_revision_id : The left hand revision id. +# $left_file_name : The name of the file on the left hand +# revision. +# $right_revision_id : The right hand revision id. +# $right_file_name : The name of the file on the right hand +# revision. +# Return Value : True on success, otherwise false on +# failure. +# +############################################################################## + + + +sub file_merge($$$$$$) +{ + + my($this, + $buffer, + $left_revision_id, + $left_file_name, + $right_revision_id, + $right_file_name) = @_; + + return mtn_command($this, + "file_merge", + $buffer, + $left_revision_id, + $left_file_name, + $right_revision_id, + $right_file_name); + +} +# +############################################################################## +# # Routine - genkey # # Description - Generate a new key for use within the database. @@ -2061,6 +2116,36 @@ sub leaves($$) # ############################################################################## # +# Routine - lua +# +# Description - Call the specified LUA function with any required +# arguments. +# +# Data - $this : The object. +# $buffer : A reference to a buffer that is to contain +# the output from this command. +# $lua_function : The name of the LUA function that is to be +# called. +# @arguments : A list of arguments that are to be passed +# to the LUA function. +# Return Value : True on success, otherwise false on +# failure. +# +############################################################################## + + + +sub lua($$$;@) +{ + + my($this, $buffer, $lua_function, @arguments) = @_; + + return mtn_command($this, "lua", $buffer, $lua_function, @arguments); + +} +# +############################################################################## +# # Routine - packet_for_fdata # # Description - Get the contents of the file referenced by the specified @@ -2286,6 +2371,32 @@ sub put_revision($$$) # ############################################################################## # +# Routine - read_packets +# +# Description - Decode and store the specified packet data in the database. +# +# Data - $this : The object. +# $packet_data : The packet data that is to be stored in the +# database. +# Return Value : True on success, otherwise false on failure. +# +############################################################################## + + + +sub read_packets($$) +{ + + my($this, $packet_data) = @_; + + my $dummy; + + return mtn_command($this, "read_packets", \$dummy, $packet_data); + +} +# +############################################################################## +# # Routine - roots # # Description - Get a list of root revisions, i.e. revisions with no @@ -2594,7 +2705,8 @@ sub tags($$;$) unless (exists($kv_record->{$key})); } $kv_record->{branches} = [] - unless (exists($kv_record->{branches})); + unless (exists($kv_record->{branches}) + && defined($kv_record->{branches})); $kv_record->{revision_id} = $kv_record->{revision}; delete($kv_record->{revision}); push(@$ref, $kv_record); @@ -2708,6 +2820,16 @@ sub can($$) return 1 if ($this->{mtn_aif_major} >= 8); } + elsif ($feature == MTN_FILE_MERGE + || $feature == MTN_LUA + || $feature == MTN_READ_PACKETS) + { + + # These are only available from version 0.42 (i/f version 9.x). + + return 1 if ($this->{mtn_aif_major} >= 9); + + } else { @@ -3373,7 +3495,7 @@ sub parse_kv_record($$$$;$) $i < scalar(@$list) && $$list[$i] =~ m/$io_stanza_re/; ++ $i) { - ($key) = ($$list[$i] =~ m/^ *([a-z_]+) \S/); + $key = $1; if (exists($$key_type_map{$key})) { $type = $$key_type_map{$key}; @@ -3410,9 +3532,13 @@ sub parse_kv_record($$$$;$) push(@$value, unescape($string)); } } + elsif ($type & NULL && $$list[$i] =~ m/^ *[a-z_]+ ?$/) + { + } else { - &$croaker("Internal: Unsupported key type detected"); + &$croaker("Unsupported key type or corrupt field value " + . "detected"); } $$record->{$key} = $value; } ============================================================ --- lib/Monotone/AutomateStdio.pod e75487f854ba13f37c3fee550b308f58a15448a6 +++ lib/Monotone/AutomateStdio.pod 84241a357af7876fe04e46a50c600b5c78049da9 @@ -6,7 +6,7 @@ Monotone::AutomateStdio - Perl interface =head1 VERSION -0.1 +0.2.0 =head1 SYNOPSIS @@ -36,7 +36,7 @@ are supported by this class range from 0 All automate commands have been implemented in this class except for the `stdio' command, hopefully the reason is obvious. :-) Versions of Monotone that are supported by this class range from 0.35 up to and including the latest -version (currently 0.41). If you happen to be using a newer version of Monotone +version (currently 0.42). If you happen to be using a newer version of Monotone then this class will hopefully largely work but without the support for new or changed features. @@ -70,6 +70,7 @@ would be passed to the constructor) is: "--key" => , "--keydir" => , "--no-default-confdir", + "--no-workspace", "--norc", "--nostd", "--root" => , @@ -250,6 +251,7 @@ that is currently being used by this obj MTN_DB_GET MTN_DROP_ATTRIBUTE MTN_DROP_DB_VARIABLES + MTN_FILE_MERGE MTN_GET_ATTRIBUTES MTN_GET_CURRENT_REVISION MTN_GET_DB_VARIABLES @@ -258,10 +260,12 @@ that is currently being used by this obj MTN_INVENTORY_IN_IO_STANZA_FORMAT MTN_INVENTORY_INCLUDE_BIRTH_ID MTN_INVENTORY_TAKE_OPTIONS - MTN_USE_P_SELECTOR + MTN_LUA + MTN_READ_PACKETS MTN_SET_ATTRIBUTE MTN_SET_DB_VARIABLE MTN_SHOW_CONFLICTS + MTN_USE_P_SELECTOR In order to get these constants into your namespace you need to use the following to load in this library. @@ -358,6 +362,13 @@ revisions specified within the list. For a given list of revisions, weed out those that are ancestors to other revisions specified within the list. +=item B<$mtn-Efile_merge(\$buffer, $left_revision_id, $left_file_name, +$right_revision_id, $right_file_name)> + +Get the result of merging two files, both of which are on separate revisions. + +(feature: MTN_FILE_MERGE) + =item B<$mtn-Egenkey(\$buffer | \%hash, $key_id, $pass_phrase)> Generate a new key for use within the database. If \$buffer is passed then the @@ -672,6 +683,12 @@ Get a list of leaf revisions. Get a list of leaf revisions. +=item B<$mtn-Elua(\$buffer, $lua_function[, $argument ...])> + +Call the specified LUA function with any required arguments. + +(feature: MTN_LUA) + =item B<$mtn-Epacket_for_fdata(\$buffer, $file_id)> Get the contents of the file referenced by the specified file id in packet @@ -708,6 +725,12 @@ method. associated with them and so these have to be added using the $mtn-Ecert() method. +=item B<$mtn-Eread_packets($packet_data)> + +Decode and store the specified packet data in the database. + +(feature: MTN_READ_PACKETS) + =item B<$mtn-Eregister_db_locked_handler([$handler[, $client_data]])> Registers a database locked handler for the object rather than the class. For @@ -751,45 +774,50 @@ or more of the following fields: the output is returned as a list of anonymous hashes, each one containing one or more of the following fields: - ancestor - The id of the common ancestor revision for - both revisions in conflict. - ancestor_file_id - The common ancestor file id for both files in - conflict. - ancestor_name - The name of the ancestor file or directory. - attr_name - The name of the Monotone file or directory - attribute that is in conflict. - conflict - The nature of the conflict. Values can be one - of "attribute", "content", - "directory_loop_created", "duplicate_name", - "invalid_name", "missing_root", - "multiple_names", "orphaned_directory" or - "orphaned_file". - left - The id of the left hand revision that is in - conflict. - left_attr_value - The value of the attribute on the file or - directory in the left hand revision. - left_file_id - The id of the file in the left hand revision. - left_name - The name of the file or directory in the left - hand revision. - left_type - The type of conflict relating to the file or - directory in the left hand revision. Values - can be one of "added directory", "added file", - "deleted directory", "pivoted root", - "renamed directory" or "renamed file". - node_type - The type of manifest node. Values can be one - of "file" or "directory". - right - The id of the right hand revision that is in - conflict. - right_attr_state - The state of the attribute in the right hand - revision. Values can only be "dropped". - right_attr_value - The value of the attribute on the file or - directory in the right hand revision. - right_file_id - The id of the file in the right hand revision. - right_name - The name of the file or directory in the right - hand revision. - right_type - The type of conflict relating to the file or - directory in the left revision. Values are as - documented for left_type. + ancestor - The id of the common ancestor revision for + both revisions in conflict. + ancestor_file_id - The common ancestor file id for both files in + conflict. + ancestor_name - The name of the ancestor file or directory. + attr_name - The name of the Monotone file or directory + attribute that is in conflict. + conflict - The nature of the conflict. Values can be one + of "attribute", "content", + "directory_loop", "duplicate_name", + "invalid_name", "missing_root", + "multiple_names", "orphaned_directory" or + "orphaned_file". + left - The id of the left hand revision that is in + conflict. + left_attr_value - The value of the attribute on the file or + directory in the left hand revision. + left_file_id - The id of the file in the left hand revision. + left_name - The name of the file or directory in the left + hand revision. + left_type - The type of conflict relating to the file or + directory in the left hand revision. Values + can be one of "added directory", + "added file", "deleted directory", + "pivoted root", "renamed directory" or + "renamed file". + node_type - The type of manifest node. Values can be one + of "file" or "directory". + resolved_internal - Only present if the conflict can be resolved + internally by Monotone during the merge + process. + right - The id of the right hand revision that is in + conflict. + right_attr_state - The state of the attribute in the right hand + revision. Values can only be "dropped". + right_attr_value - The value of the attribute on the file or + directory in the right hand revision. + right_file_id - The id of the file in the right hand + revision. + right_name - The name of the file or directory in the + right hand revision. + right_type - The type of conflict relating to the file or + directory in the left revision. Values are as + documented for left_type. Please note that some fields are not used by all entries, in which case they are not present (use Perl's exists() function @@ -852,6 +880,68 @@ defined as 1 and undef respectively. Please note that the boolean true and false values used by this class are defined as 1 and undef respectively. +=head1 EXAMPLES + +=head2 Detecting Warnings And Errors + +Errors cause exceptions to be thrown. Warnings cause the responsible method to +return false rather than true. + +Therefore warnings would typically be detected by using code like this: + + $mtn->get_file(\$data, $file_id) + or die('$mtn->get_file() failed with: ' + . $mtn->get_error_message()); + +However this can get clumsy and cluttered after a while, especially when the +calling application knows that there is very little likelihood of there being a +problem. Having exceptions being thrown for warnings as well as errors may be a +better approach. By doing: + + Monotone::AutomateStdio->register_error_handler + (MTN_SEVERITY_ALL, + sub + { + my($severity, $message) = @_; + die($message); + }); + +or more tersely: + + Monotone::AutomateStdio->register_error_handler + (MTN_SEVERITY_ALL, sub { die($_[1]); }); + +at the beginning of your application will mean that all errors and warnings +detected by this class will generate an exception, thus making the checking of +a method's return status redundant. + +=head2 Silently Retrying Operations When The Database Is Locked + +If the Monotone database is locked then, by default, this class will report +that condition as a warning. However, it may be more convenient to ask this +class to silently retry the operation until it succeeds. This can easily be +done by using the database locked handler as follows: + + Monotone::AutomateStdio->register_db_locked_handler + (sub { sleep(1); return 1; }); + +This will mean that should any database locked conditions occur then this class +will silently sleep for one second before retrying the operation. + +=head2 Dealing With Processing Lockouts And Delays + +Sometimes you may make a complex request to the mtn subprocess that takes a +number of seconds to process. Consequently this class will take that amount of +time, plus a very small processing overhead, to return. Whilst one can get +around this by using threads, another way is to register an I/O wait +handler. For example: + + Monotone::AutomateStdio->register_io_wait_handler + (sub { WindowManager->instance()->update_gui(); }, 1); + +will instruct this class to update the user display every second whilst it is +waiting for the mtn subprocess to finish processing a request. + =head1 NOTES There are situations where this class does legitimately terminate the mtn @@ -890,8 +980,8 @@ maintenance and regression testing. for some time, support may be dropped for older versions in order to aid maintenance and regression testing. -The $mtn-Eget_content_changed() method is very slow since Monotone version -0.40. Hopefully this will be fixed in version 0.42. +The $mtn-Eget_content_changed() method is very slow in Monotone versions +0.40 and 0.41. =head1 SEE ALSO @@ -902,8 +992,16 @@ than 0.35 (automate stdio interface vers Your mileage may vary if this class 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. +This class is not thread safe. If you wish to use this class in a +multi-threaded environment then you either need to use a separate object per +thread or use threads::lock to protect each method call. +=head1 AUTHORS + +Anthony Cooper with contributions and ideas from Thomas Keller. Currently +maintained by Anthony Cooper. Please report all faults and suggestions to +. + =head1 COPYRIGHT Copyright (C) 2008 by Anthony Cooper . ============================================================ --- mtn-tester 5058f0ee4edb5c61843b0ac11bcacf77fa4184a6 +++ mtn-tester 7723f0e457e6ab1791fa70044eee07fbfae02829 @@ -3,7 +3,7 @@ # - You may need to comment the next line out or change it to where # you have the Monotone::AutomateStdio library installed. -use lib "/home/aecoope/perl"; +use lib ""; use strict; use integer; @@ -27,6 +27,10 @@ use constant VARIABLE => 5; use constant CODE => 4; use constant VARIABLE => 5; +# - Enter your key id in the line below. + +my $key_id = ""; + my($data, %hash, @list, @@ -156,6 +160,24 @@ my @test_list = "110816e646d42ca45e8205778255cece9c8f2159", "95c9125530ea297d244b522426997942635d3891"]}, + {fn => \&Monotone::AutomateStdio::file_merge, + desc => "file_merge (on a mergeable conflict)", + feat => MTN_FILE_MERGE, + type => RAW, + args => ["05cb265ad778107218701fa76a91bdf4770b85a8", + "Makefile.am", + "110816e646d42ca45e8205778255cece9c8f2159", + "Makefile.am"]}, + + {fn => \&Monotone::AutomateStdio::file_merge, + desc => "file_merge (on an unmergeable conflict)", + feat => MTN_FILE_MERGE, + type => RAW, + args => ["5fee1e9c463d3cd7439bea9c483d9d88d0b057d5", + "ui.cc", + "b9a5862a8ba577538f27c69656d8a6bb60ecb777", + "ui.cc"]}, + {fn => \&Monotone::AutomateStdio::genkey, desc => "genkey", type => RECORD, @@ -442,6 +464,13 @@ my @test_list = type => LIST, args => []}, + {fn => \&Monotone::AutomateStdio::lua, + desc => "lua", + feat => MTN_LUA, + type => RAW, + args => ["ignore_file", + "'Makefile.am'"]}, + {fn => \&Monotone::AutomateStdio::packet_for_fdata, desc => "packet_for_fdata", type => RAW, @@ -529,6 +558,24 @@ my @test_list = system("mtn log --last 5 --no-graph | less -S"); }}, + {fn => undef, + desc => "read_packets", + feat => MTN_READ_PACKETS, + type => CODE, + code => sub { + $mtn->read_packets + ('[pubkey address@hidden ' + . 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKBEOCGipeYi1/' + . 'dVI93aks2jMZbU4PBj2p ' + . '+gtncni0xEd8MffZ3Zx4FQOsI1PAqVPmNhxA18VKJ0kRg97IUj/' + . 'GpsZMFemhEO96mp3tLT29 ' + . 'F8mW302RlfaXEk7BdP0MXHuRrpXyDJ30YDzUZ+tNqlcgkQTvS+' + . 'LfUr/US71/blGDzwIDAQAB ' + . '[end]'); + print("Added the address@hidden key\n"); + system("mtn ls keys"); + }}, + {fn => \&Monotone::AutomateStdio::roots, desc => "roots", type => LIST, @@ -557,6 +604,13 @@ my @test_list = args => ["26cfbb87b400321bda71277e1d2c0ba1d5e9898f", "15db9bc261c01c4ca5cdb052aec69d29f3bec58a"]}, + {fn => \&Monotone::AutomateStdio::show_conflicts, + desc => "show_conflicts (with internal merge resolution)", + feat => MTN_SHOW_CONFLICTS, + type => RECORD_LIST, + args => ["05cb265ad778107218701fa76a91bdf4770b85a8", + "110816e646d42ca45e8205778255cece9c8f2159"]}, + {fn => \&Monotone::AutomateStdio::tags, desc => "tags (no branch restrictions)", type => RECORD_LIST, @@ -601,10 +655,8 @@ readline(STDIN); EOF readline(STDIN); -# - Enter your key id in the line below. +$mtn = Monotone::AutomateStdio->new(["--key" => $key_id]); -$mtn = Monotone::AutomateStdio->new(["--key" => "address@hidden"]); - $data = undef; if ($mtn->can(MTN_DB_GET)) { @@ -626,6 +678,11 @@ die("Your test database will sync to `" die("Your test database will sync to `" . $data . "' - this is unsafe") if (defined($data)); +# Clear out any error state created from the above tests. + +$mtn = undef; +$mtn = Monotone::AutomateStdio->new(["--key" => $key_id]); + Monotone::AutomateStdio->register_error_handler (MTN_SEVERITY_ALL, sub