Next: , Previous: Hook Reference, Up: Hook Reference


6.1 Hooks

This section documents the existing hook functions and their default definitions.

6.1.1 Event Notifications and Triggers

There are a number of hooks that are called when noteworthy events occur, such as commits or new revisions arriving over the network. These hooks can be used to feed the events into external notification systems, such as generating email.

By default, these hooks are undefined, so no special external actions are taken.

note_commit (new_id, revision, certs)
Called by monotone after the version new_id is committed. The second parameter, revision is the text of the revision, what would be given by mtn automate get_revision new_id. The third parameter, certs, is a Lua table containing the set of certificate names and values committed along with this version. There is no default definition for this hook.

Note that since the certs table does not contain cryptographic or trust information, and only contains one entry per cert name, it is an incomplete source of information about the committed version. This hook is only intended as an aid for integrating monotone with informal commit-notification systems such as mailing lists or news services. It should not perform any security-critical operations.

note_netsync_start (session_id, my_role, sync_type,
remote_host, remote_keyname, includes, excludes)

Called by monotone before any other of the netsync notification hooks are called. The session_id helps keep track of the current netsync session in case several are happening at the same time, and is used throughout all netsync notification hooks.

The other arguments are:

my_role
This will be either "client" or "server".
sync_type
This will be one of "sync", "push", or "pull".
remote_host
The network address of the remote host. At the client, this will be the name it was told to connect to; at the server, this will use the numerical IP address the connection was received from.
remote_keyname
The name of the key being used by the other end of the connection. This may be set to "-unknown-" at the server if the key used by the client is not present at the server.
includes and excludes
The include and exclude patterns used by the client.

note_netsync_revision_received (new_id, revision, certs, session_id)
Called by monotone after the revision new_id is received through netsync. revision is the text of the revision, what would be given by mtn automate get_revision new_id. certs is a Lua table containing one subtable for each cert attached to the revision new_id. These subtables have fields named "key", "name", and "value", containing the signing key for the cert, the name of the cert, and the value of the cert. There is no default definition for this hook. session_id is used together with note_netsync_start and note_netsync_end. If you're not interested in that type of tracking, you can ignore that variable entirely.
note_netsync_revision_sent (rev_id, revision, certs, session_id)
Called by monotone after the revision rev_id is sent through netsync. The arguments are the same as for note_netsync_revision_received.
note_netsync_cert_received (rev_id, key, name, value, session_id)
Called by monotone after a cert is received through netsync, if the revision that the cert is attached to was not also received in the same netsync operation. rev_id is the revision id that the cert is attached to, key is the key that the cert is signed with, name is the name of the cert, and value is the cert value. There is no default definition for this hook. session_id is used together with note_netsync_start and note_netsync_end. If you're not interested in that type of tracking, you can ignore that variable entirely.
note_netsync_cert_sent (rev_id, key, name, value, session_id)
Called by monotone after a cert is sent through netsync, if the revision that the cert is attached to was not also sent in the same netsync operation. The arguments are the same as for note_netsync_cert_received.
note_netsync_pubkey_received (keyname, session_id)
Called by monotone after a pubkey is received through netsync. keyname is the name of the key received. There is no default definition for this hook. session_id is used together with note_netsync_start and note_netsync_end. If you're not interested in that type of tracking, you can ignore that variable entirely.
note_netsync_pubkey_sent (keyname, session_id)
Called by monotone after a pubkey is sent through netsync. The arguments are the same as for note_netsync_pubkey_received.
note_netsync_end (session_id, status,
bytes_in, bytes_out, certs_in, certs_out, revs_in, revs_out, keys_in, keys_out)

Called by monotone after all other the netsync notification hooks have been called. This hook would usually be used for post-netsync purposes, like collecting all the data from all other netsync notification hooks, make some nice output from them and finally send the result somewhere. It could also be used to prepare parallel databases with all the data to be displayed through something like viewmtn.

status is a three digit integer that tells whether there was an error, and if so what kind of error it was:

200
No error, connection successful.
211
The connection was interrupted after some data may have been transferred.
212
The connection was interrupted before any data could be transferred.
412
The request is not permitted.
422
The client tried to use a key that the server doesn't know about.
432
The client and server have different epochs for a branch.
512
Protocol error (source/sink confusion).
521
Protocol error (packet received at a time when it doesn't make sense).
532
The client did not identify itself correctly. (Possible replay attack?)

In general, 2xx means there was no error, 4xx means there was a permissions error, and 5xx means there was a protocol error. xx1 means some data may have been transferred, xx2 means no data was transferred, and xx0 means all data was transferred.

note_mtn_startup (...)
Called by monotone when it is first started, this hook was added so that usage of monotone could be monitored for user interface testing. Note that by default, no monitoring occurs. The arguments to the hook function are the arguments to monotone, without the initial mtn command. They can be accessed through the lua arg variable as in this example:
          function note_mtn_startup(...)
              print("Beginning note_mtn_startup")
              for i = 1,arg.n do
                  print(arg[i])
              end
              print("Ending note_mtn_startup")
          end

6.1.2 User Defaults

These are hooks that can be used to provide smart, context-sensitive default values for a number of parameters the user might otherwise be prompted for.

get_branch_key (branchname)
Returns a string which is the name of an rsa private key used to sign certificates in a particular branch branchname. There is no default definition for this hook. The command-line option --key=keyname overrides any value returned from this hook function. If you have only one private key in your database, you do not need to define this function or provide a --key=keyname option; monotone will guess that you want to use the unique private key.
get_netsync_key(server, include, exclude)
Returns a string which is the name of the key to use to authenticate the given netsync connection. When called by the serve command, server is the address monotone is listening on, include is "*", and exclude is "".

There is no default definition of this hook. The command-line option --key=keyname overrides any value returned from this hook function.

get_default_command_options(command)
Returns a table of program options, either valid for the given command or valid global options. The command argument is given as a table of command parts, i.e. for commands with subcommands like automate or db this argument contains at least two elements.

Note that there is no way to "override" these default options via a given command-line option once they've been set. This is especially true if you specify options with arguments in this hook such as --exclude=path - no subsequent command-line argument or --exclude option argument will be able to replace or remove the already excluded path.

Simple example which enables recursive directory scanning for mtn add by default:

          function get_default_command_options(command)
              local default_options = {}
              if (command[1] == "add") then
                  table.insert(default_options, "--recursive")
              end
              return default_options
          end

get_passphrase (keypair_id)
Returns a string which is the passphrase used to encrypt the private half of keypair_id in your database, using the arc4 symmetric cipher. keypair_id is a Lua string containing the label that you used when you created your key — something like "nicole@example.com". This hook has no default definition. If this hook is not defined or returns false, monotone will prompt you for a passphrase each time it needs to use a private key.
get_author (branchname, keypair_id)
Returns a string which is used as a value for automatically generated author certificates when you commit changes to branchname with the keypair identity keypair_id. Generally this hook remains undefined, and monotone selects your signing key name for the author certificate. You can use this hook to override that choice, if you like.

This hook has no default definition, but a couple of possible definitions might be:

          function get_author(branchname, keypair_id)
                  -- Key pair identity ignored.
                  local user = os.getenv("USER")
                  local host = os.getenv("HOSTNAME")
                  if ((user == nil) or (host == nil)) then return nil end
                  return string.format("%s@%s", user, host)
          end
          function get_author(branchname, keypair_id)
                  -- Branch name ignored.
                  if (keypair_id == "joe@example.com") then
                          return "Joe Random <joe@example.com>"
                  end
                  return keypair_id
          end

edit_comment (commentary, user_log_message)
Returns a log entry for a given set of changes, described in commentary. The commentary is identical to the output of mtn status. This hook is intended to interface with some sort of editor, so that you can interactively document each change you make. The result is used as the value for a changelog certificate, automatically generated when you commit changes.

The contents of _MTN/log are read and passed as user_log_message. This allows you to document your changes as you proceed instead of waiting until you are ready to commit. Upon a successful commit, the contents of _MTN/log are erased setting the system up for another edit/commit cycle.

For the default definition of this hook, see Default hooks.

persist_phrase_ok ()
Returns true if you want monotone to remember the passphrase of a private key for the duration of a single command, or false if you want monotone to prompt you for a passphrase for each certificate it generates. Since monotone often generates several certificates in quick succession, unless you are very concerned about security you probably want this hook to return true.

The default definition of this hook is:

          function persist_phrase_ok()
                  return true
          end

use_inodeprints ()
Returns true if you want monotone to automatically enable Inodeprints support in all workspaces. Only affects working copies created after you modify the hook.

The default definition of this hook is:

          function use_inodeprints()
                  return false
          end

ignore_file (filename)
Returns true if filename should be ignored while adding, dropping, or moving files. Otherwise returns false. This is most important when performing recursive actions on directories, which may affect multiple files simultaneously.

The default definition of this hook recognises a number of common file types and extensions for temporary and generated file types that users typically don't want to track. If the file .mtn-ignore exists, this hook will read a list of regular expressions from the file, one per line, and ignore all files matching one of these expressions. For the default definition of this hook, see Default hooks.

ignore_branch (branchname)
Returns true if branchname should be ignored while listing branches. Otherwise returns false. This hook has no default definition, therefore the default behavior is to list all branches.

6.1.3 Netsync Permission Hooks

These hooks are used when running a netsync server, via mtn serve. They are evaluated by the server for each new connection, based on the certificate used for authentication by the client. Note that a long-running server will need to be restarted in order to reload the hook definitions if the montonerc file is changed.

get_netsync_read_permitted (branch, identity)
Returns true if a peer authenticated as key identity should be allowed to read from your database certs, revisions, manifests, and files associated with branch; otherwise false. The default definition of this hook reads a file read-permissions in the configuration directory. This file looks like
          pattern "net.example.project.{private,security}*"
          allow "joe@example.net"
          allow "jim@example.net"
          
          comment "everyone can read these branches"
          pattern "net.example.{public,project}*"
          allow "*"

This example allows everyone access to branches net.example.project and net.example.public and their sub-branches, except for the branches in net.example.project.security and net.example.project.private, which are only readable by Joe and Jim.

The file is divided into stanzas of one pattern line followed by any number of allow and deny lines, and possibly a continue line. Anything from the unquoted word comment until the next unquoted word is ignored. A stanza is processed if the argument to pattern is a glob that matches branch. Any keys which match an allow line are given access, and any keys which match a deny line are denied access. If there is a continue "true" line, then if the key is not granted or denied access in this stanza the next matching stanza will be processed. If there is not a continue "true" line, then any key which has not been given access will be denied access even if it doesn't match any deny lines. Thus, deny lines are redundant unless there is also a continue "true" line.

If a client connects anonymously, this hook will be called with a identity of nil.

Note that the identity value is a key ID (such as “graydon@pobox.com”) but will correspond to a unique key fingerprint (hash) in your database. Monotone will not permit two keys in your database to have the same ID. Make sure you confirm the key fingerprints of each key in your database, as key ID strings are “convenience names”, not security tokens.

get_netsync_write_permitted (identity)
Returns true if a peer authenticated as key identity should be allowed to write into your database certs, revisions, manifests, and files; otherwise false. The default definition of this hook reads a file write-permissions in the configuration directory which contains a list of keys, one per line, which are allowed write access. The special value * means to allow access to anyone whose public key we already have.

If a client connects anonymously, it will be unconditionally denied write access; this hook will not be called with a identity of nil.

Note that the identity value is a key ID (such as “graydon@pobox.com”) but will correspond to a unique key fingerprint (hash) in your database. Monotone will not permit two keys in your database to have the same ID. Make sure you confirm the key fingerprints of each key in your database, as key ID strings are “convenience names”, not security tokens.

Note also that, unlike the equivalent read permission hook, the write permission hook does not take a branch name as an argument. There is presently no way to selectively grant write access to different branches via netsync, for a number of reasons. Contributions in the database from different authors can be selectively trusted using the Trust Evaluation Hooks instead.

6.1.4 Netsync Transport Hooks

When a monotone client initiates a netsync connection, these hooks are called to attempt to parse the host argument provided on the command line. If the hooks fail or return nil, monotone will interpret the host argument as a network name (possibly with a port number) and open a TCP socket.

get_netsync_connect_command (uri, args)
Returns a table describing a command to run to connect to the specified host. The uri argument is a table containing between 0 and 7 components:

The args argument is a table containing between 0 and 3 components:

The default definition of this hook follows:

          function get_netsync_connect_command(uri, args)
          
                  local argv = nil
          
                  if uri["scheme"] == "ssh"
                          and uri["host"]
                          and uri["path"] then
          
                          argv = { "ssh" }
                          if uri["user"] then
                                  table.insert(argv, "-l")
                                  table.insert(argv, uri["user"])
                          end
                          if uri["port"] then
                                  table.insert(argv, "-p")
                                  table.insert(argv, uri["port"])
                          end
          
                          table.insert(argv, uri["host"])
                  end
          
                  if uri["scheme"] == "file" and uri["path"] then
                          argv = { }
                  end
          
                  if argv then
          
                          table.insert(argv, get_mtn_command(uri["host"]))
          
                          if args["debug"] then
                                  table.insert(argv, "--debug")
                          else
                                  table.insert(argv, "--quiet")
                          end
          
                          table.insert(argv, "--db")
                          table.insert(argv, uri["path"])
                          table.insert(argv, "serve")
                          table.insert(argv, "--stdio")
                          table.insert(argv, "--no-transport-auth")
          
                          if args["include"] then
                                  table.insert(argv, args["include"])
                          end
          
                          if args["exclude"] then
                                  table.insert(argv, "--exclude")
                                  table.insert(argv, args["exclude"])
                          end
                  end
                  return argv
          end

use_transport_auth (uri)
Returns a boolean indicating whether monotone should use transport authentication mechanisms when communicating with uri. If this hook fails, the return value is assumed to be true. The form of the uri argument is a table, identical to the table provided as an argument to get_netsync_connect_command.

Note that the return value of this hook must "match" the semantics of the command returned by get_netsync_connect_command. In particular, if this hook returns false, the serve command line arguments passed to the remote end of the connection should include the --no-transport-auth option. A mismatch between this hook's return value and the command line returned by get_netsync_connect_command will cause a communication failure, as the local and remote monotone processes will have mismatched authentication assumptions.

          function use_transport_auth(uri)
                  if uri["scheme"] == "ssh"
                  or uri["scheme"] == "file" then
                          return false
                  else
                          return true
                  end
          end

get_mtn_command(host)
Returns a string containing the monotone command to be executed on host when communicating over ssh. The host argument is a string containing the name of the host to which ssh is connecting, from the server URI. This is useful when there are multiple monotone binaries on the remote host, or the monotone binary is not in the default path.
          function get_mtn_command(host)
              return "mtn"
          end

6.1.5 Trust Evaluation Hooks

Monotone makes heavy use of certs to provide descriptive information about revisions. In many projects, not all developers should have the same privileges, or be trusted for the same purposes (indeed, some signers might be automated robots, with very specific purposes).

These hooks allow the user to configure which signers will be trusted to make which kinds of assertions using certs. Monotone uses these certs when selecting available revisions for commands such as update.

Each user, or even each workspace, can have their own implementation of these hooks, and thus a different filtered view of valid revisions, according to their own preferences and purposes.

get_revision_cert_trust (signers, id, name, val)
Returns whether or not you trust the assertion name=value on a given revision id, given a valid signature from all the keys in signers. The signers parameter is a table containing all the key names which signed this cert, the other three parameters are strings.

The default definition of this hook simply returns true, which corresponds to a form of trust where every key which is defined in your database is trusted. This is a weak trust setting; you should change it to something stronger. A possible example of a stronger trust function (along with a utility function for computing the intersection of tables) is the following:

          function intersection(a,b)
             local s={}
             local t={}
             for k,v in pairs(a) do s[v] = 1 end
             for k,v in pairs(b) do if s[v] ~= nil then table.insert(t,v) end end
             return t
          end
          
          function get_revision_cert_trust(signers, id, name, val)
             local trusted_signers = { "bob@happyplace.example.com",
                                       "friend@trustedplace.example.com",
                                       "myself@home.example.com" }
             local t = intersection(signers, trusted_signers)
          
             if t == nil then return false end
          
             if    (name ~= "branch" and table.getn(t) >= 1)
                or (name == "branch" and table.getn(t) >= 2)
             then
                return true
             else
                return false
             end
          end

In this example, any revision certificate is trusted if it is signed by at least one of three “trusted” keys, unless it is an branch certificate, in which case it must be signed by two or more trusted keys. This is one way of requiring that the revision has been approved by an extra “reviewer” who used the approve command.

accept_testresult_change (old_results, new_results)
This hook is used by the update algorithm to determine whether a change in test results between update source and update target is acceptable. The hook is called with two tables, each of which maps a signing key – representing a particular testsuite – to a boolean value indicating whether or not the test run was successful. The function should return true if you consider an update from the version carrying the old_results to the version carrying the new_results to be acceptable.

The default definition of this hook follows:

          function accept_testresult_change(old_results, new_results)
             for test,res in pairs(old_results)
             do
                if res == true and new_results[test] ~= true
                then
               return false
                end
             end
             return true
          end

This definition accepts only those updates which preserve the set of true test results from update source to target. If no test results exist, this hook has no affect; but once a true test result is present, future updates will require it. If you want a more lenient behavior you must redefine this hook.

6.1.6 External Diff Tools

Differences between files can be shown in a number of ways, varying according to user preference and file type. These hooks allow customisation of the way file differences are shown.

get_encloser_pattern (file_path)
Called for each file unless diff is given the --no-show-encloser option (or the --external option). file_path is the pathname of the file that is being diffed. The hook should return a string constant containing a regular expression; this regular expression will be used to find lines that, in that file, name the “top-level” constructs enclosing each “hunk” of changes. The default is ^[[:alnum:]$_], which is correct for many programming languages; a few text authoring packages, like Texinfo, have special regular expressions that match their particular syntax. If you have a better regular expression for some language, you can add it to this hook; and if you send it to the monotone developers, we will likely make it the default for that language. See Regexps, for the regular expression syntax.
external_diff (file_path, old_data, new_data, is_binary, diff_args, old_rev, new_rev)
Called for each file when diff is given the --external option. file_path is the pathname of the file that is being diffed. old_data and new_data are the data contents of the old and the new file. If the data is binary, is_binary will be true, otherwise false. old_rev and new_rev are the revision IDs of the old and new data.

If an extra arguments are given via --diff-args, the string will be passed in as diff_args. Otherwise diff_args will be nil.

The default implementation of this hook calls the program diff, and if --diff-args were not passed, takes default arguments from the Lua variable external_diff_default_args. You can override this variable in your configuration file, without overriding the whole hook.

6.1.7 External Merge Tools

Monotone often needs to merge together the work of multiple distributed developers, and uses these hooks to help this process when the merge does not automatically succeed. Often these hooks will be used to invoke an external interactive merge tool.

The Default hooks include helper functions used by the hooks below to invoke a number of external merge tools known to monotone, and you can override or extend these hooks if you have a preferred tool, or if you have a tool specific to certain file types.

merge3 (ancestor_path, left_path, right_path, merged_path, ancestor_text, left_text, right_text)
This hook is called to resolve merges that monotone could not resolve automatically. The actual ancestor, left, and right contents of the file are passed in the ancestor_text, left_text, and right_text strings. In addition, the hook is given the names that this file had in the ancestor (ancestor_path), left (left_path), and right (right_path) trees, and the name it will end up having in the merged tree (merged_path). These paths are useful for merge tools that can display the names of files in their GUI, since the actual path names are likely more meaningful than the temporary file names the merge tool will actually be working on.

Returns a string, which should be the merger of the given texts. The default definition of this hook delegates the actual merge to the result of get_preferred_merge3_command. The default definition of get_preferred_merge3_command checks to see if the MTN_MERGE environment variable, or the Lua variable merger are set to the name of a merge tool that it recognizes, and if not, then simply searches for whatever is installed on the local system. For details, see the code in Default hooks.


get_preferred_merge3_command(tbl)
Returns the results of running an external merge on three strings. tbl wraps up the various arguments for each merge command and is always provided by merge3. If there is a particular editor that you would like to use to perform merge3 operations, override this hook to specify it.

6.1.8 Selector Expansion

Monotone's selectors are a powerful mechanism used to refer to revisions with symbolic names or groupings. Thanks to the hooks described in this section, it is possible to use various forms of shorthand in selection strings; these hooks are designed to recognise shorthand patterns and expand them to their full form.

For more detail on the use of selectors, see Selectors.

expand_selector (str)
Attempts to expand str as a selector. Expansion generally means providing a type prefix for the selector, such as a: for authors or d: for dates. This hook is called once for each element of a combined selector string (between / separators) prior to evaluation of the selector. For the default definition of this hook, see Default hooks.
expand_date (str)
Attempts to expand str as a date expression. Expansion means recognizing and interpreting special words such as yesterday or 6 months ago and converting them into well formed date expressions. For the default definition of this hook, see Default hooks.

6.1.9 Attribute Handling

Some files in a project are special; they may require different handling (such as binary or structured files that should always be manually merged – see Merging), or they may represent executable scripts or programs.

Monotone allows each file (or directory) in a repository to carry arbitrary File Attributes. Persistent attributes are stored in each revision's manifest. The hooks in this section allow files to be automatically recognised as having certain attributes at the time they're added, and for custom triggers to be invoked on each file according to its attributes when the workspace is changed.

attr_functions [attribute] (filename, value)
This is not a hook function, but a table of hook functions. Each entry in the table attr_functions, at table entry attribute, is a function taking a file name filename and an attribute value value. The function should “apply” the attribute to the file, possibly in a platform-specific way. When called to set an attribute the value this hook receives will be a string representing the value of the attribute. When called to clear an attribute the value this hook receives will be nil.

Hook functions from this table are called for each existing attribute, after any command which modifies the workspace. These functions are also called during creation and modification of a workspace by the update, merge_into_workspace, pluck, clone and checkout commands to set or clear attributes as they change.

This facility can be used to extend monotone's understanding of files with platform-specific attributes, such as permission bits, access control lists, or special file types.

By default, there is only one entry in this table, for the mtn:execute attribute. Its definition is:

          attr_functions["mtn:execute"] =
            function(filename, value)
                if (value == "true") then
                   set_executable(filename)
                else
                   clear_executable(filename)
                end
             end

attr_init_functions [attribute] (filename)
This is not a hook function, but a table of hook functions. Each entry in the table attr_init_functions, at table entry attribute, is a function taking a file (or directory) name filename. Each function defines the attributes that should be set on the file named filename. This table of hook functions is called once for each file during an add.

By default, there are only two entries in this table, for the mtn:execute and mtn:manual_merge attributes. Their definition is:

          attr_init_functions["mtn:execute"] =
             function(filename)
                if (is_executable(filename)) then
                  return "true"
                else
                  return nil
                end
             end
          attr_init_functions["mtn:manual_merge"] =
             function(filename)
                if (binary_file(filename)) then
                  return "true" -- binary files must be merged manually
                else
                  return nil
                end
             end

The binary_file function is also defined as a Lua hook. See Default hooks.

6.1.10 Validation Hooks

If there is a policy decision to make, Monotone defines certain hooks to allow a client to validate or reject certain behaviors.

validate_commit_message (message, revision_text, branchname)
This hook is called after the user has entered his/her commit message. message is the commit message that the user has entered and revision_text is the full text of the changes for this revision, which can be parsed with the parse_basic_io function. The branchname on which the new revision will be committed if all goes well is passed in as the third parameter. If the hook finds the commit message satisfactory, it can return true, "". If it finds fault, then it can return false, reason where reason is the reason the message was rejected. By default, this hook rejects empty log messages.

6.1.11 Meta Hooks

Monotone allows the execution of arbitrary Lua hooks and functions through a special generalized "meta hook". See automate lua for more information.

hook_wrapper (func_name, ...)
This hook is explicitely called on every execution of automate lua. It takes a function name and zero or more string function arguments which are internally evaluated into Lua code. It returns a dump of the return value of the called function in Lua code on success.