# # old_revision [9f3769cf9cfad6e230a05bf69effb900571c4572] # # patch "ChangeLog" # from [475065e0075fea72070c1b9e3df9d6156a2d23d2] # to [3c78ab706bc27dfb612042684426b16377300c1c] # # patch "commands.cc" # from [33b8690ab922b91ac0218b9412ba6a84d024094d] # to [4cfb88859a1a856ecf9d5340e26d558fecc9a6e1] # # patch "lua.cc" # from [c8c228b16b396eaf8cbc1b41ca6363593e9abfee] # to [6b9dd32e7d083192b2996adf831d32a013e23fd8] # # patch "lua.hh" # from [71e2943fa623254b4e3e1340e1f8c4b442271a6c] # to [1c16c56eee90a8c7ab87d5e0bca28da928f3c248] # # patch "std_hooks.lua" # from [a5e3529e680469a911323f45286466780088f35d] # to [aee63195ac081781e08738050eb7e169dcef83b3] # ============================================================ --- ChangeLog 475065e0075fea72070c1b9e3df9d6156a2d23d2 +++ ChangeLog 3c78ab706bc27dfb612042684426b16377300c1c @@ -1,3 +1,12 @@ +2006-01-25 Blake Kaplan + + * commands.cc CMD(commit): Call a new lua hook to validate the commit + message. Don't ignore -m "" when it's passed on the command line. + * lua.cc, lua.hh: Add a new hook that validates a given commit message + and passes in the added files, deleted files, and modified files. + * std_hooks.lua: Give a default hook to validate commit messages. This + currently disallows empty messages, as monotone currently does. + 2006-01-20 Richard Levitte * po/sv.po: Added a \n at the end of a msgstr that was missing ============================================================ --- commands.cc 33b8690ab922b91ac0218b9412ba6a84d024094d +++ commands.cc 4cfb88859a1a856ecf9d5340e26d558fecc9a6e1 @@ -1,4 +1,5 @@ // -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*- +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: // copyright (C) 2002, 2003 graydon hoare // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) @@ -2258,12 +2259,12 @@ N(app.message().length() == 0 || app.message_file().length() == 0, F("--message and --message-file are mutually exclusive")); - if (app.message().length() > 0) + if (app.is_explicit_option(OPT_MESSAGE)) { log_message = app.message(); given = true; } - else if (app.message_file().length() > 0) + else if (app.is_explicit_option(OPT_MSGFILE)) { data dat; read_data_for_command_line(app.message_file(), dat); @@ -2274,7 +2275,56 @@ given = false; } +static void +revision_set_to_vectors(revision_set const & rs, + vector & additions, + vector & deletions, + vector & modifications) +{ + // Iterate over the edges, extracting the useful information out of each + // one. XXX We might be able to assume only 1 or 2 edges here. + for (edge_map::const_iterator beg = rs.edges.begin(), end = rs.edges.end(); + beg != end; ++beg) + { + cset const & changes = edge_changes(beg); + // Grab the deletions. + for (path_set::const_iterator change = changes.nodes_deleted.begin(), + lastchange = changes.nodes_deleted.end(); + change != lastchange; ++change) + { + file_path current(*change); + ostringstream os; + os << current; + deletions.push_back(os.str()); + } + + // Grab the additions. + for (std::map::const_iterator change = changes.files_added.begin(), + lastchange = changes.files_added.end(); change != lastchange; ++change) + { + file_path current(change->first); + ostringstream os; + os << current; + additions.push_back(os.str()); + } + + // Grab the modifications. + typedef std::map >::const_iterator + delta_iterator; + for (delta_iterator change = changes.deltas_applied.begin(), + lastchange = changes.deltas_applied.end(); + change != lastchange; ++change) + { + file_path current(change->first); + ostringstream os; + os << current; + modifications.push_back(os.str()); + } + } +} + CMD(commit, N_("working copy"), N_("[PATH]..."), N_("commit working copy to database"), OPT_BRANCH_NAME % OPT_MESSAGE % OPT_MSGFILE % OPT_DATE % @@ -2340,6 +2390,18 @@ write_user_log(data(log_message)); } + // If the hook doesn't exist, allow the message to be used. + bool message_validated; + string reason; + + vector deletions, additions, modifications; + revision_set_to_vectors(rs, additions, deletions, modifications); + + app.lua.hook_validate_commit_message(log_message, additions, deletions, + modifications, message_validated, + reason); + N(message_validated, F("log message rejected: %s\n") % reason); + { transaction_guard guard(app.db); packet_db_writer dbw(app); ============================================================ --- lua.cc c8c228b16b396eaf8cbc1b41ca6363593e9abfee +++ lua.cc 6b9dd32e7d083192b2996adf831d32a013e23fd8 @@ -1,4 +1,5 @@ // -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*- +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: // copyright (C) 2002, 2003 graydon hoare // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) @@ -1382,6 +1383,50 @@ return ll.ok(); } +static bool +push_vector_as_table(Lua & ll, std::vector const & source) +{ + typedef std::vector::const_iterator iterator_t; + int k = 1; + + ll.push_table(); + + for (iterator_t beg = source.begin(), end = source.end(); beg != end; ++beg, ++k) + { + ll.push_int(k); + ll.push_str(*beg); + ll.set_table(); + } + + return ll.ok(); +} + +bool +lua_hooks::hook_validate_commit_message(std::string const & message, + std::vector const & added, + std::vector const & deleted, + std::vector const & modified, + bool & validated, + std::string & reason) +{ + Lua ll(st); + ll + .func("validate_commit_message") + .push_str(message); + + push_vector_as_table(ll, added); + push_vector_as_table(ll, deleted); + push_vector_as_table(ll, modified); + + return ll + .call(4, 2) + .extract_str(reason) + // XXX When validated, the extra returned string is superfluous. + .pop() + .extract_bool(validated) + .ok(); +} + bool lua_hooks::hook_note_commit(revision_id const & new_id, revision_data const & rdat, ============================================================ --- lua.hh 71e2943fa623254b4e3e1340e1f8c4b442271a6c +++ lua.hh 1c16c56eee90a8c7ab87d5e0bca28da928f3c248 @@ -106,6 +106,14 @@ bool hook_get_linesep_conv(file_path const & p, std::string & db, std::string & ext); + // validation hooks + bool hook_validate_commit_message(std::string const & message, + std::vector const & added, + std::vector const & deleted, + std::vector const & modified, + bool & validated, + std::string & reason); + // notification hooks bool hook_note_commit(revision_id const & new_id, revision_data const & rdat, ============================================================ --- std_hooks.lua a5e3529e680469a911323f45286466780088f35d +++ std_hooks.lua aee63195ac081781e08738050eb7e169dcef83b3 @@ -705,3 +705,10 @@ io.close(permfile) return matches end + +function validate_commit_message(message, additions, deletions, modifications) + if (message == "") then + return false, "empty messages aren't allowed" + end + return true, "" +end