Ejemplo n.º 1
0
svn_error_t *
svn_cl__get_log_message(const char **log_msg,
                        const char **tmp_file,
                        const apr_array_header_t *commit_items,
                        void *baton,
                        apr_pool_t *pool)
{
  svn_stringbuf_t *default_msg = NULL;
  struct log_msg_baton *lmb = baton;
  svn_stringbuf_t *message = NULL;
  svn_config_t *cfg;
  const char *mfc_after, *sponsored_by;

  cfg = lmb->config ? svn_hash_gets(lmb->config, SVN_CONFIG_CATEGORY_CONFIG) : NULL;

  /* Set default message.  */
  default_msg = svn_stringbuf_create(APR_EOL_STR, pool);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "PR:\t\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Submitted by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Reported by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Reviewed by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Approved by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Obtained from:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "MFC after:\t");
  svn_config_get(cfg, &mfc_after, SVN_CONFIG_SECTION_MISCELLANY, "freebsd-mfc-after", NULL);
  if (mfc_after != NULL)
	  svn_stringbuf_appendcstr(default_msg, mfc_after);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "MFH:\t\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Relnotes:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Security:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Sponsored by:\t");
  svn_config_get(cfg, &sponsored_by, SVN_CONFIG_SECTION_MISCELLANY, "freebsd-sponsored-by",
#ifdef HAS_ORGANIZATION_NAME
  	ORGANIZATION_NAME);
#else
	NULL);
#endif
  if (sponsored_by != NULL)
	  svn_stringbuf_appendcstr(default_msg, sponsored_by);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Differential Revision:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Description of fields to fill in above:                     76 columns --|" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> PR:                       If and which Problem Report is related." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Submitted by:             If someone else sent in the change." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Reported by:              If someone else reported the issue." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Reviewed by:              If someone else reviewed your modification." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Approved by:              If you needed approval for this commit." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Obtained from:            If the change is from a third party." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> MFC after:                N [day[s]|week[s]|month[s]].  Request a reminder email." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> MFH:                      Ports tree branch name.  Request approval for merge." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Relnotes:                 Set to 'yes' for mention in release notes." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Security:                 Vulnerability reference (one per line) or description." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Sponsored by:             If the change was sponsored by an organization." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Differential Revision:    https://reviews.freebsd.org/D### (*full* phabric URL needed)." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Empty fields above will be automatically removed." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);

  *tmp_file = NULL;
  if (lmb->message)
    {
      svn_string_t *log_msg_str = svn_string_create(lmb->message, pool);

      SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, NULL, NULL,
                                            log_msg_str, lmb->message_encoding,
                                            FALSE, pool, pool),
                _("Error normalizing log message to internal format"));

      /* Strip off the EOF marker text and the junk that follows it. */
      truncate_buffer_at_prefix(&(log_msg_str->len), (char *)log_msg_str->data,
                                EDITOR_EOF_PREFIX);

      cleanmsg(&(log_msg_str->len), (char*)log_msg_str->data);

      *log_msg = log_msg_str->data;
      return SVN_NO_ERROR;
    }

  if (! commit_items->nelts)
    {
      *log_msg = "";
      return SVN_NO_ERROR;
    }

  while (! message)
    {
      /* We still don't have a valid commit message.  Use $EDITOR to
         get one.  Note that svn_cl__edit_string_externally will still
         return a UTF-8'ized log message. */
      int i;
      svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool);
      svn_error_t *err = SVN_NO_ERROR;
      svn_string_t *msg_string = svn_string_create_empty(pool);

      for (i = 0; i < commit_items->nelts; i++)
        {
          svn_client_commit_item3_t *item
            = APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
          const char *path = item->path;
          char text_mod = '_', prop_mod = ' ', unlock = ' ';

          if (! path)
            path = item->url;
          else if (lmb->base_dir)
            path = svn_dirent_is_child(lmb->base_dir, path, pool);

          /* If still no path, then just use current directory. */
          if (! path || !*path)
            path = ".";

          if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
              && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
            text_mod = 'R';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
            text_mod = 'A';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
            text_mod = 'D';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
            text_mod = 'M';

          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
            prop_mod = 'M';

          if (! lmb->keep_locks
              && item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)
            unlock = 'U';

          svn_stringbuf_appendbyte(tmp_message, text_mod);
          svn_stringbuf_appendbyte(tmp_message, prop_mod);
          svn_stringbuf_appendbyte(tmp_message, unlock);
          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
            /* History included via copy/move. */
            svn_stringbuf_appendcstr(tmp_message, "+ ");
          else
            svn_stringbuf_appendcstr(tmp_message, "  ");
          svn_stringbuf_appendcstr(tmp_message, path);
          svn_stringbuf_appendcstr(tmp_message, APR_EOL_STR);
        }

      msg_string->data = tmp_message->data;
      msg_string->len = tmp_message->len;

      /* Use the external edit to get a log message. */
      if (! lmb->non_interactive)
        {
          err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left,
                                                    lmb->editor_cmd,
                                                    lmb->base_dir ? lmb->base_dir : "",
                                                    msg_string, "svn-commit",
                                                    lmb->config, TRUE,
                                                    lmb->message_encoding,
                                                    pool);
        }
      else /* non_interactive flag says we can't pop up an editor, so error */
        {
          return svn_error_create
            (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
             _("Cannot invoke editor to get log message "
               "when non-interactive"));
        }

      /* Dup the tmpfile path into its baton's pool. */
      *tmp_file = lmb->tmpfile_left = apr_pstrdup(lmb->pool,
                                                  lmb->tmpfile_left);

      /* If the edit returned an error, handle it. */
      if (err)
        {
          if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR)
            err = svn_error_quick_wrap
              (err, _("Could not use external editor to fetch log message; "
                      "consider setting the $SVN_EDITOR environment variable "
                      "or using the --message (-m) or --file (-F) options"));
          return svn_error_trace(err);
        }

      if (msg_string)
        message = svn_stringbuf_create_from_string(msg_string, pool);

      /* Strip off the EOF marker text and the junk that follows it. */
      if (message)
        truncate_buffer_at_prefix(&message->len, message->data,
                                  EDITOR_EOF_PREFIX);
      /*
       * Since we're adding freebsd-specific tokens to the log message,
       * clean out any leftovers to avoid accidently sending them to other
       * projects that won't be expecting them.
       */
      if (message)
	cleanmsg(&message->len, message->data);

      if (message)
        {
          /* We did get message, now check if it is anything more than just
             white space as we will consider white space only as empty */
          apr_size_t len;

          for (len = 0; len < message->len; len++)
            {
              /* FIXME: should really use an UTF-8 whitespace test
                 rather than svn_ctype_isspace, which is ASCII only */
              if (! svn_ctype_isspace(message->data[len]))
                break;
            }
          if (len == message->len)
            message = NULL;
        }

      if (! message)
        {
          const char *reply;
          SVN_ERR(svn_cmdline_prompt_user2
                  (&reply,
                   _("\nLog message unchanged or not specified\n"
                     "(a)bort, (c)ontinue, (e)dit:\n"), NULL, pool));
          if (reply)
            {
              int letter = apr_tolower(reply[0]);

              /* If the user chooses to abort, we cleanup the
                 temporary file and exit the loop with a NULL
                 message. */
              if ('a' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  break;
                }

              /* If the user chooses to continue, we make an empty
                 message, which will cause us to exit the loop.  We
                 also cleanup the temporary file. */
              if ('c' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  message = svn_stringbuf_create_empty(pool);
                }

              /* If the user chooses anything else, the loop will
                 continue on the NULL message. */
            }
        }
    }

  *log_msg = message ? message->data : NULL;
  return SVN_NO_ERROR;
}
Ejemplo n.º 2
0
svn_error_t *
svn_cl__get_log_message(const char **log_msg,
                        const char **tmp_file,
                        const apr_array_header_t *commit_items,
                        void *baton,
                        apr_pool_t *pool)
{
  svn_stringbuf_t *default_msg = NULL;
  struct log_msg_baton *lmb = baton;
  svn_stringbuf_t *message = NULL;

  /* Set default message.  */
  default_msg = svn_stringbuf_create(APR_EOL_STR, pool);
  svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR APR_EOL_STR);

  *tmp_file = NULL;
  if (lmb->message)
    {
      svn_stringbuf_t *log_msg_buf = svn_stringbuf_create(lmb->message, pool);
      svn_string_t *log_msg_str = apr_pcalloc(pool, sizeof(*log_msg_str));

      /* Trim incoming messages of the EOF marker text and the junk
         that follows it.  */
      truncate_buffer_at_prefix(&(log_msg_buf->len), log_msg_buf->data,
                                EDITOR_EOF_PREFIX);

      /* Make a string from a stringbuf, sharing the data allocation. */
      log_msg_str->data = log_msg_buf->data;
      log_msg_str->len = log_msg_buf->len;
      SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, FALSE, FALSE,
                                            log_msg_str, lmb->message_encoding,
                                            FALSE, pool, pool),
                _("Error normalizing log message to internal format"));

      *log_msg = log_msg_str->data;
      return SVN_NO_ERROR;
    }

  if (! commit_items->nelts)
    {
      *log_msg = "";
      return SVN_NO_ERROR;
    }

  while (! message)
    {
      /* We still don't have a valid commit message.  Use $EDITOR to
         get one.  Note that svn_cl__edit_externally will still return
         a UTF-8'ized log message. */
      int i;
      svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool);
      svn_error_t *err = SVN_NO_ERROR;
      svn_string_t *msg_string = svn_string_create("", pool);

      for (i = 0; i < commit_items->nelts; i++)
        {
          svn_client_commit_item3_t *item
            = APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
          const char *path = item->path;
          char text_mod = '_', prop_mod = ' ', unlock = ' ';

          if (! path)
            path = item->url;
          else if (! *path)
            path = ".";

          if (! svn_path_is_url(path) && lmb->base_dir)
            path = svn_dirent_is_child(lmb->base_dir, path, pool);

          /* If still no path, then just use current directory. */
          if (! path)
            path = ".";

          if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
              && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
            text_mod = 'R';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
            text_mod = 'A';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
            text_mod = 'D';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
            text_mod = 'M';

          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
            prop_mod = 'M';

          if (! lmb->keep_locks
              && item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)
            unlock = 'U';

          svn_stringbuf_appendbyte(tmp_message, text_mod);
          svn_stringbuf_appendbyte(tmp_message, prop_mod);
          svn_stringbuf_appendbyte(tmp_message, unlock);
          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
            /* History included via copy/move. */
            svn_stringbuf_appendcstr(tmp_message, "+ ");
          else
            svn_stringbuf_appendcstr(tmp_message, "  ");
          svn_stringbuf_appendcstr(tmp_message, path);
          svn_stringbuf_appendcstr(tmp_message, APR_EOL_STR);
        }

      msg_string->data = tmp_message->data;
      msg_string->len = tmp_message->len;

      /* Use the external edit to get a log message. */
      if (! lmb->non_interactive)
        {
          err = svn_cl__edit_string_externally(&msg_string, &lmb->tmpfile_left,
                                               lmb->editor_cmd, lmb->base_dir,
                                               msg_string, "svn-commit",
                                               lmb->config, TRUE,
                                               lmb->message_encoding,
                                               pool);
        }
      else /* non_interactive flag says we can't pop up an editor, so error */
        {
          return svn_error_create
            (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
             _("Cannot invoke editor to get log message "
               "when non-interactive"));
        }

      /* Dup the tmpfile path into its baton's pool. */
      *tmp_file = lmb->tmpfile_left = apr_pstrdup(lmb->pool,
                                                  lmb->tmpfile_left);

      /* If the edit returned an error, handle it. */
      if (err)
        {
          if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR)
            err = svn_error_quick_wrap
              (err, _("Could not use external editor to fetch log message; "
                      "consider setting the $SVN_EDITOR environment variable "
                      "or using the --message (-m) or --file (-F) options"));
          return svn_error_trace(err);
        }

      if (msg_string)
        message = svn_stringbuf_create_from_string(msg_string, pool);

      /* Strip the prefix from the buffer. */
      if (message)
        truncate_buffer_at_prefix(&message->len, message->data,
                                  EDITOR_EOF_PREFIX);

      if (message)
        {
          /* We did get message, now check if it is anything more than just
             white space as we will consider white space only as empty */
          apr_size_t len;

          for (len = 0; len < message->len; len++)
            {
              /* FIXME: should really use an UTF-8 whitespace test
                 rather than svn_ctype_isspace, which is ASCII only */
              if (! svn_ctype_isspace(message->data[len]))
                break;
            }
          if (len == message->len)
            message = NULL;
        }

      if (! message)
        {
          const char *reply;
          SVN_ERR(svn_cmdline_prompt_user2
                  (&reply,
                   _("\nLog message unchanged or not specified\n"
                     "(a)bort, (c)ontinue, (e)dit:\n"), NULL, pool));
          if (reply)
            {
              int letter = apr_tolower(reply[0]);

              /* If the user chooses to abort, we cleanup the
                 temporary file and exit the loop with a NULL
                 message. */
              if ('a' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  break;
                }

              /* If the user chooses to continue, we make an empty
                 message, which will cause us to exit the loop.  We
                 also cleanup the temporary file. */
              if ('c' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  message = svn_stringbuf_create("", pool);
                }

              /* If the user chooses anything else, the loop will
                 continue on the NULL message. */
            }
        }
    }

  *log_msg = message ? message->data : NULL;
  return SVN_NO_ERROR;
}