Prompted by Julian's review of this freshly-minted public API on IRC:
1. Question to API consumers (eg, client developers): would you find
this API useful? For reference, the current docstring is attached.
2. Should we print the symbolic name in release builds? For example:
% $svn upgrade /
svn: E155019 (WC_INVALID_OP_ON_CWD): Can't upgrade '/' as it is not a
working copy root
svn: E000002: Working copy database '/.svn/wc.db' not found
svn: E000002: Additional errors:
svn: E000002: Can't open file '/.svn/entries': No such file or directory
zsh: exit 1 $svn upgrade /
### (in maintainer mode, this would show
### subversion/libsvn_wc/wc_db.c:15006:
(apr_err=SVN_ERR_WC_INVALID_OP_ON_CWD)
### as well.)
3. Should the API return the error code, or the error code without the
"SVN_ERR_" prefix? I think stripping the error code is better because
then users who search for the error code will be more likely to reach
the users@ archive (with helpful posts) than commits@ archive (which
are unlikely to contain the information they seek). Julian disagrees,
but I'll let him present his own case :-)
I also attached a patch which implements (2), in case we want it.
(It'll be trivial to modify it to suit whichever route we pick for (2)
and (3).)
/**
* Return the symbolic name of an error code. If the error code
* is in svn_error_codes.h, return the name of the macro as a string.
* If the error number is not recognised, return @c NULL.
*
* An error number may not be recognised because it was defined in a future
* version of Subversion (e.g., a 1.9.x server may transmit a defined-in-1.9.0
* error number to a 1.8.x client).
*
* An error number may be recognised @em incorrectly if the @c apr_status_t
* value originates in another library (such as libserf) which also uses APR.
* (This is a theoretical concern only: the @c apr_err member of #svn_error_t
* should never contain a "foreign" @c apr_status_t value, and
* in any case Subversion and Serf use non-overlapping subsets of the
* @c APR_OS_START_USERERR range.)
*
* Support for error codes returned by APR itself (i.e., not in the
* @c APR_OS_START_USERERR range, as defined in apr_errno.h) may be implemented
* in the future.
*
* @note In rare cases, a single numeric code has more than one symbolic name.
* (For example, #SVN_ERR_WC_NOT_DIRECTORY and #SVN_ERR_WC_NOT_WORKING_COPY).
* In those cases, it is not guaranteed which symbolic name is returned.
*
* @since New in 1.8.
*/
const char *
svn_error_symbolic_name(apr_status_t statcode);
Index: subversion/libsvn_subr/error.c
===================================================================
--- subversion/libsvn_subr/error.c (revision 1467305)
+++ subversion/libsvn_subr/error.c (working copy)
@@ -483,9 +483,22 @@ print_error(svn_error_t *err, FILE *stream, const
{
const char *symbolic_name = svn_error_symbolic_name(err->apr_err);
+ const char *start;
+
+ /* ### Inside knowledge: re-add the SVN_ERR_ prefix.
+ (We could iterate error_table, but it's unlikely we'll add more error
+ codes that don't start with "SVN_ERR_" beyond these two.) */
+ if (symbolic_name
+ && !strcmp(symbolic_name, "SVN_WARNING")
+ && !strcmp(symbolic_name, "SVN_NO_ERROR"))
+ start = "";
+ else
+ start = "SVN_ERR_";
+
if (symbolic_name)
svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
- ": (apr_err=%s)\n", symbolic_name));
+ ": (apr_err=%s%s)\n",
+ start, symbolic_name));
else
svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
": (apr_err=%d)\n", err->apr_err));
@@ -500,12 +513,19 @@ print_error(svn_error_t *err, FILE *stream, const
/* Only print the same APR error string once. */
else if (err->message)
{
+ const char *symbolic_name = svn_error_symbolic_name(err->apr_err);
svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
- "%sE%06d: %s\n",
- prefix, err->apr_err, err->message));
+ "%sE%06d%s%s%s: %s\n",
+ prefix, err->apr_err,
+ symbolic_name ? " (" : "",
+ symbolic_name ? symbolic_name : "",
+ symbolic_name ? ")" : "",
+ err->message));
}
else
{
+ const char *symbolic_name = svn_error_symbolic_name(err->apr_err);
+
/* Is this a Subversion-specific error code? */
if ((err->apr_err > APR_OS_START_USEERR)
&& (err->apr_err <= APR_OS_START_CANONERR))
@@ -520,8 +540,12 @@ print_error(svn_error_t *err, FILE *stream, const
}
svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
- "%sE%06d: %s\n",
- prefix, err->apr_err, err_string));
+ "%sE%06d%s%s%s: %s\n",
+ prefix, err->apr_err,
+ symbolic_name ? " (" : "",
+ symbolic_name ? symbolic_name : "",
+ symbolic_name ? ")" : "",
+ err->message));
}
}
@@ -670,7 +694,12 @@ svn_error_symbolic_name(apr_status_t statcode)
for (defn = error_table; defn->errdesc != NULL; ++defn)
if (defn->errcode == (svn_errno_t)statcode)
- return defn->errname;
+ {
+ if (!strncmp(defn->errname, "SVN_ERR_", 8))
+ return defn->errname + 8;
+ else
+ return defn->errname;
+ }
/* "No error" is not in error_table. */
if (statcode == SVN_NO_ERROR)