[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] move 'svnversion' functionnality in libsvn_wc v3j

From: Julian Foad <julianfoad_at_btopenworld.com>
Date: 2005-11-30 00:53:54 CET

Other reviewers: please could you help with a few questions, right at the end.

Fabien, I've put notes in line about the problems I found, but I decided to
make the changes myself and attach a new patch. I hope that's OK.

Fabien COELHO wrote:
>
> This patch moves the 'svnversion' functionnality to libsvn_wc so that
> it could be used by other clients such as 'svn'.

[...]
> - I let the cancelation feature in although they are not used by svnversion.
> It seems reasonnable that the working copy walking may be canceled?
> - no_ignore and config are removed as they are not used (yet?).
> no_ignore being TRUE does not make sense if no details about
> what is found is reported. As for config, I have no opinion,
> it is easy to put it back so that it may be forwarded downwards.

That's all good.

[...]
> +/** This structure reports the mix of revisions found within
> + * a working copy, including whether some parts are switched
> + * or currently modified. If no working copy is found, an error
> + * is raised, possibly SVN_ERR_WC_PATH_NOT_FOUND if the path
> + * is a directory or SVN_ERR_WC_NOT_DIRECTORY if it is anything else.

This structure doesn't know anything about error codes. I've re-written these
doc strings.

> + */
> +typedef struct svn_wc_revision_status_t
> +{
> + svn_revnum_t min_rev; /* lowest revision found. */
> + svn_revnum_t max_rev; /* highest revision found. */
> +
> + /* is anything ... */
> + svn_boolean_t switched;
> + svn_boolean_t modified; /* any type of modification... */
> +}
> +svn_wc_revision_status_t;
> +
> +/** Compute the revision summary status in the @a result structure
> + * for a working copy at @a wc_path. The @a trail_url is used to
> + * determine if WC_PATH itself is switched. The summary may address the
> + * last changed vs the current revisions if @a committed.
> + * Cancel stuff @a cancal_func and @a cancel_baton is passed downwards,
> + * although they may be NULL.
> + *
> + * @since New in 1.4
> + */
> +svn_error_t *
> +svn_wc_revision_status (svn_wc_revision_status_t *result,
> + const char *wc_path,
> + const char *trail_url,
> + svn_boolean_t committed,
> + svn_cancel_func_t cancel_func,
> + void *cancel_baton,
> + apr_pool_t *pool);

> Index: subversion/libsvn_wc/revision_status.c
> ===================================================================
[...]
> +/* public interface. */
> +svn_error_t *
> +svn_wc_revision_status (svn_wc_revision_status_t *result,
> + const char *wc_path,
> + const char *trail_url,
> + svn_boolean_t committed,
> + svn_cancel_func_t cancel_func,
> + void *cancel_baton,
> + apr_pool_t *pool)
> {
> int wc_format;
> struct status_baton sb;
> + apr_pool_t *subpool;
> + const char *anchor, *target;
> + svn_wc_adm_access_t *anchor_access, *target_access;
> + svn_wc_traversal_info_t *traversal_info;
> + const svn_delta_editor_t *editor;
> + void *edit_baton, *set_locks_baton;
> + svn_revnum_t edit_revision = SVN_INVALID_REVNUM;

No value is needed for "edit_revision".

>
> + /* set result as nil */
> + result->min_rev = SVN_INVALID_REVNUM;
> + result->max_rev = SVN_INVALID_REVNUM;
> + result->switched = FALSE;
> + result->modified = FALSE;
>
> + /* initialize walking stick */

That's amusing. Maybe you know why, but I'll explain anyway. A "walking
stick" is specifically what an old or infirm person uses to help them walk.
For these structures we always say "baton", because a baton is something (OK, a
stick) that is passed on from one person to the next, to the next, in a relay
race. In Subversion it is passed on from one function to the next, to the
next. <http://subversion.tigris.org/faq.html#baton>

> + subpool = svn_pool_create (pool);
> + sb.result = result;
> + sb.committed = committed;
> sb.wc_path = NULL;
> sb.wc_url = NULL;
> - sb.pool = pool;
> + sb.pool = subpool;

I don't think we need a sub-pool here - there's no iteration going on at this
level.

>
> + wc_path = svn_path_internal_style (wc_path, subpool);

Internal style is part of the API conventions, so this line goes in the caller.

>
> + SVN_ERR (svn_wc_check_wc (wc_path, &wc_format, subpool));
>
> if (! wc_format)
> {
> svn_node_kind_t kind;
> + SVN_ERR(svn_io_check_path (wc_path, &kind, subpool));
> + svn_pool_destroy (subpool);
> if (kind == svn_node_dir)
> {
> - SVN_INT_ERR (svn_cmdline_printf (pool, _("exported%s"),
> - no_newline ? "" : "\n"));
> - svn_pool_destroy (pool);
> - return EXIT_SUCCESS;
> + return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
> + _("'%s' is exported\n"), wc_path);
> }
> else
> {
> - svn_error_clear
> - (svn_cmdline_fprintf (stderr, pool,
> - _("'%s' not versioned, and not exported\n"),
> - wc_path));
> - svn_pool_destroy (pool);
> - return EXIT_FAILURE;
> + return svn_error_createf(SVN_ERR_WC_NOT_DIRECTORY, NULL,
> + _("'%s' not versioned, and not exported\n"),
> + wc_path);
> }
> }

That whole block (svn_wc_check_wc; if (! wc_format) {...}) should go in the
caller. This function should just return an error if the path isn't a WC, and
it probably doesn't need to check that explicitly because the first WC
operation it attempts will probably return an appropriate error. (I'll try to
check that.)

[...]
> + traversal_info = svn_wc_init_traversal_info (subpool);
>
> + SVN_ERR (svn_wc_adm_open_anchor (&anchor_access, &target_access, &target,
> + wc_path, FALSE, -1,
> + cancel_func, cancel_baton,
> + subpool));
> +
> + anchor = svn_wc_adm_access_path (anchor_access);

"anchor" is not used.

> +
> + SVN_ERR (svn_wc_get_status_editor2 (&editor, &edit_baton, &set_locks_baton,

You can pass NULL instead of "&set_locks_baton", as you don't want it.

> + &edit_revision, anchor_access, target,
> + NULL /* config */,
> + TRUE /* recurse */,
> + TRUE /* get_all */,
> + FALSE /* no_ignore */,
> + analyze_status, &sb,
> + cancel_func, cancel_baton,
> + traversal_info,

You can pass NULL instead of "traversal_info" ... or at least the doc string
says you can, and you will be able to after we fix the crash that presently
results.

> + subpool));
[...]

> Index: subversion/svnversion/main.c
> ===================================================================
[...]
> - wc_path = svn_path_internal_style (wc_path, pool);

That "internal style" conversion should stay here; the "internal style" is used
for paths in APIs (as well as UTF-8).

[...]
> + /* but it was a directory, let us guess it was exported... */
> + SVN_INT_ERR (svn_cmdline_fputs(N_("exported"), stdout, pool));

That should be "_" rather than "N_". It's an internationalisation thing. "_"
is normally used. "N_" is used where a constant result is needed (array
initialisers, etc.).

[...]

OK. I decided to make these changes myself, and am attaching my version "3j"
(for "Julian"). At the same time, I made several other tweaks such as undoing
some changes of layout and style and the like that just caused extra
differences that made the patch bigger (harder to review).

Probably the biggest change I made was in the error handling that deals with a
target that is not versioned, and calls it "exported" if it's a directory. I
put back the code that was there originally, to check this before calling the
new function, and removed all such specific error handling from the new function.

Note: In the svn_wc_get_status_editor2() call I have set traversal_info to
null. That requires a fix such as the one I posted earlier today: "[PATCH] Fix
crash in svn_wc_get_status_editor2".

On my version of Fabien's patch, I would like help on these specific questions:

* Is svn_wc_get_status_editor2() called correctly (with associated "open" and
"close" calls around it)? I'm not familiar enough with it to spot any subtle
problems.

* Is the "trail_url" a reasonable thing to put in an API? It seems a bit ...
hackish. Would it be better to require a full expected URL? Would it be
better to not have the function do that particular processing, but let the
caller do it?

* The patch removes a bit of code from svnversion that appears to have been
saying, "If the user cancels, don't error out, just print whatever results we
have found so far." I think it's fine to remove this, but it's not related to
the purpose of the patch. I think I should do that in a separate patch. Yes?
  (The "###" in the log message is only a review-stage reminder.)

- Julian

[[[
Move the core of 'svnversion' functionality into libsvn_wc as a function, so
that it can be used by other client applications, e.g. possibly 'svn' later.
Rewrite this code so that it no longer uses libsvn_client, just libsvn_wc.

Patch by: Fabien COELHO <fabien@coelho.net>

* subversion/include/svn_wc.h
   (svn_wc_revision_status_t): New structure.
   (svn_wc_revision_status): New function.

* subversion/libsvn_wc/revision_status.c
   New file, copied from subversion/svnversion/main.c and modified,
   implementing svn_wc_revision_status().

* subversion/svnversion/main.c
   (status_baton, analyze_status): Remove.
   (version): Don't require "svn_client".
   (main): Call svn_wc_revision_status() instead of doing the job.
### Remove code that trapped a cancellation request and silently proceeded to print whatever status we had found so far.

* build.conf
   Remove svn_client from the dependencies of svnversion.
]]]

Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h (revision 17555)
+++ subversion/include/svn_wc.h (working copy)
@@ -3322,6 +3322,49 @@
                                  apr_pool_t *pool);
 
 
+/** A structure to report the mix of revisions found within
+ * a working copy, including whether some parts are switched
+ * or currently modified.
+ *
+ * @since New in 1.4
+ */
+typedef struct svn_wc_revision_status_t
+{
+ svn_revnum_t min_rev; /**< Lowest revision found */
+ svn_revnum_t max_rev; /**< Highest revision found */
+
+ svn_boolean_t switched; /**< Is anything switched? */
+ svn_boolean_t modified; /**< Is anything modified? */
+}
+svn_wc_revision_status_t;
+
+/** Fill @a *result with a summary of the revision range and status of the
+ * working copy at @a wc_path.
+ *
+ * If @a trail_url is non-null, use it to determine if @a wc_path itself is
+ * switched. It should be any trailing portion of @a wc_path's expected URL,
+ * long enough to include any parts that the caller considers might be changed
+ * by a switch. If it does not match the end of @a wc_path's actual URL, then
+ * report a "switched" status.
+ *
+ * If @a committed is true, summarize the last changed revisions, else the base
+ * revisions.
+ *
+ * If @a cancel_func is non-null, call it with @a cancel_baton to determine
+ * if the client has cancelled the operation.
+ *
+ * @since New in 1.4
+ */
+svn_error_t *
+svn_wc_revision_status (svn_wc_revision_status_t *result,
+ const char *wc_path,
+ const char *trail_url,
+ svn_boolean_t committed,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: subversion/libsvn_wc/revision_status.c
===================================================================
--- subversion/libsvn_wc/revision_status.c (revision 17521)
+++ subversion/libsvn_wc/revision_status.c (working copy)
@@ -1,4 +1,6 @@
 /*
+ * revision_status.c: report the range of revisions in a working copy
+ *
  * ====================================================================
  * Copyright (c) 2003-2004 CollabNet. All rights reserved.
  *
@@ -14,31 +16,23 @@
  * ====================================================================
  */
 
-#include "svn_cmdline.h"
 #include "svn_pools.h"
-#include "svn_client.h"
 #include "svn_utf.h"
 #include "svn_path.h"
-#include "svn_opt.h"
+#include "svn_wc.h"
 
 #include "svn_private_config.h"
 
-#define SVNVERSION_OPT_VERSION SVN_OPT_FIRST_LONGOPT_ID
-
 struct status_baton
 {
- svn_revnum_t min_rev; /* lowest revision found. */
- svn_revnum_t max_rev; /* highest revision found. */
- svn_boolean_t switched; /* is anything switched? */
- svn_boolean_t modified; /* is anything modified? */
- svn_boolean_t committed; /* examine last committed revisions */
- const char *wc_path; /* path whose URL we're looking for. */
- const char *wc_url; /* URL for the path whose URL we're looking for. */
- apr_pool_t *pool; /* pool in which to store alloc-needy things. */
+ svn_wc_revision_status_t *result; /* where to put the result */
+ svn_boolean_t committed; /* examine last committed revisions */
+ const char *wc_path; /* path whose URL we're looking for */
+ const char *wc_url; /* URL for the path whose URL we're looking for */
+ apr_pool_t *pool; /* pool in which to store alloc-needy things */
 };
 
-
-/* An svn_wc_status_func_t callback function for anaylyzing status
+/* An svn_wc_status_func2_t callback function for analyzing status
    structures. */
 static void
 analyze_status (void *baton,
@@ -46,7 +40,7 @@
                 svn_wc_status2_t *status)
 {
   struct status_baton *sb = baton;
-
+
   if (! status->entry)
     return;
 
@@ -57,292 +51,93 @@
                                ? status->entry->cmt_rev
                                : status->entry->revision);
 
- if (sb->min_rev == SVN_INVALID_REVNUM || item_rev < sb->min_rev)
- sb->min_rev = item_rev;
+ if (sb->result->min_rev == SVN_INVALID_REVNUM
+ || item_rev < sb->result->min_rev)
+ sb->result->min_rev = item_rev;
+
+ if (sb->result->max_rev == SVN_INVALID_REVNUM
+ || item_rev > sb->result->max_rev)
+ sb->result->max_rev = item_rev;
+ }
+
+ sb->result->switched |= status->switched;
+ sb->result->modified |= (status->text_status != svn_wc_status_normal);
+ sb->result->modified |= (status->prop_status != svn_wc_status_normal
+ && status->prop_status != svn_wc_status_none);
 
- if (sb->max_rev == SVN_INVALID_REVNUM || item_rev > sb->max_rev)
- sb->max_rev = item_rev;
- }
-
- sb->switched |= status->switched;
- sb->modified |= (status->text_status != svn_wc_status_normal);
- sb->modified |= (status->prop_status != svn_wc_status_normal
- && status->prop_status != svn_wc_status_none);
-
- if (sb->wc_path
- && (! sb->wc_url)
+ if (sb->wc_path
+ && (! sb->wc_url)
       && (strcmp (path, sb->wc_path) == 0)
       && (status->entry))
     sb->wc_url = apr_pstrdup (sb->pool, status->entry->url);
 }
 
-
-static svn_error_t * version(apr_getopt_t *os, apr_pool_t *pool)
-{
- return svn_opt_print_help(os, "svnversion", TRUE, FALSE, NULL, NULL,
- NULL, NULL, NULL, pool);
-}
-
-static void
-usage(apr_pool_t *pool)
-{
- svn_error_clear (svn_cmdline_fprintf
- (stderr, pool, _("Type 'svnversion --help' for usage.\n")));
- exit(1);
-}
-
-
-static void
-help(const apr_getopt_option_t *options, apr_pool_t *pool)
+svn_error_t *
+svn_wc_revision_status (svn_wc_revision_status_t *result,
+ const char *wc_path,
+ const char *trail_url,
+ svn_boolean_t committed,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool)
 {
- svn_error_clear
- (svn_cmdline_fprintf
- (stdout, pool,
- _("usage: svnversion [OPTIONS] [WC_PATH [TRAIL_URL]]\n\n"
- " Produce a compact 'version number' for the working copy path\n"
- " WC_PATH. TRAIL_URL is the trailing portion of the URL used to\n"
- " determine if WC_PATH itself is switched (detection of switches\n"
- " within WC_PATH does not rely on TRAIL_URL). The version number\n"
- " is written to standard output. For example:\n"
- "\n"
- " $ svnversion . /repos/svn/trunk \n"
- " 4168\n"
- "\n"
- " The version number will be a single number if the working\n"
- " copy is single revision, unmodified, not switched and with\n"
- " an URL that matches the TRAIL_URL argument. If the working\n"
- " copy is unusual the version number will be more complex:\n"
- "\n"
- " 4123:4168 mixed revision working copy\n"
- " 4168M modified working copy\n"
- " 4123S switched working copy\n"
- " 4123:4168MS mixed revision, modified, switched working copy\n"
- "\n"
- " If invoked on a directory that is not a working copy, an\n"
- " exported directory say, the program will output 'exported'.\n"
- "\n"
- " If invoked without arguments WC_PATH will be the current directory.\n"
- "\n"
- "Valid options:\n")));
- while (options->description)
- {
- const char *optstr;
- svn_opt_format_option(&optstr, options, TRUE, pool);
- svn_error_clear (svn_cmdline_fprintf(stdout, pool, " %s\n", optstr));
- ++options;
- }
- svn_error_clear (svn_cmdline_fprintf(stdout, pool, "\n"));
- exit(0);
-}
-
-
-/* Version compatibility check */
-static svn_error_t *
-check_lib_versions (void)
-{
- static const svn_version_checklist_t checklist[] =
- {
- { "svn_subr", svn_subr_version },
- { "svn_client", svn_client_version },
- { "svn_wc", svn_wc_version },
- { NULL, NULL }
- };
-
- SVN_VERSION_DEFINE (my_version);
- return svn_ver_check_list (&my_version, checklist);
-}
-
-
-/*
- * Why is this not an svn subcommand? I have this vague idea that it could
- * be run as part of the build process, with the output embedded in the svn
- * program. Obviously we don't want to have to run svn when building svn.
- * We could always put this into libsvn_client and share it between
- * svnversion and svn.
- */
-int
-main(int argc, const char *argv[])
-{
- const char *wc_path;
- apr_allocator_t *allocator;
- apr_pool_t *pool;
- int wc_format;
- svn_client_ctx_t ctx = { 0 };
   struct status_baton sb;
- svn_opt_revision_t rev;
- svn_boolean_t no_newline = FALSE;
- svn_error_t *err;
- apr_getopt_t *os;
- const apr_getopt_option_t options[] =
- {
- {"no-newline", 'n', 0, N_("do not output the trailing newline")},
- {"committed", 'c', 0, N_("last changed rather than current revisions")},
- {"help", 'h', 0, N_("display this help")},
- {"version", SVNVERSION_OPT_VERSION, 0, N_("show version information")},
- {0, 0, 0, 0}
- };
-
- /* Initialize the app. */
- if (svn_cmdline_init ("svnversion", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- /* Create our top-level pool. Use a seperate mutexless allocator,
- * given this application is single threaded.
- */
- if (apr_allocator_create (&allocator))
- return EXIT_FAILURE;
-
- apr_allocator_max_free_set (allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);
-
- pool = svn_pool_create_ex (NULL, allocator);
- apr_allocator_owner_set (allocator, pool);
-
- /* Check library versions */
- err = check_lib_versions ();
- if (err)
- {
- svn_handle_error2 (err, stderr, FALSE, "svnversion: ");
- svn_error_clear (err);
- svn_pool_destroy (pool);
- return EXIT_FAILURE;
- }
-
-#if defined(WIN32) || defined(__CYGWIN__)
- /* Set the working copy administrative directory name. */
- if (getenv ("SVN_ASP_DOT_NET_HACK"))
- {
- err = svn_wc_set_adm_dir ("_svn", pool);
- if (err)
- {
- svn_handle_error2 (err, stderr, FALSE, "svnversion: ");
- return EXIT_FAILURE;
- }
- }
-#endif
-
- sb.switched = FALSE;
- sb.modified = FALSE;
- sb.committed = FALSE;
- sb.min_rev = SVN_INVALID_REVNUM;
- sb.max_rev = SVN_INVALID_REVNUM;
- sb.wc_path = NULL;
+ const char *target;
+ svn_wc_adm_access_t *anchor_access, *target_access;
+ const svn_delta_editor_t *editor;
+ void *edit_baton;
+ svn_revnum_t edit_revision;
+
+ /* set result as nil */
+ result->min_rev = SVN_INVALID_REVNUM;
+ result->max_rev = SVN_INVALID_REVNUM;
+ result->switched = FALSE;
+ result->modified = FALSE;
+
+ /* initialize walking baton */
+ sb.result = result;
+ sb.committed = committed;
+ sb.wc_path = wc_path;
   sb.wc_url = NULL;
   sb.pool = pool;
 
- apr_getopt_init(&os, pool, argc, argv);
- os->interleave = 1;
- while (1)
- {
- int opt;
- const char *arg;
- apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
- if (APR_STATUS_IS_EOF(status))
- break;
- if (status != APR_SUCCESS)
- {
- usage(pool);
- return EXIT_FAILURE;
- }
- switch (opt)
- {
- case 'n':
- no_newline = TRUE;
- break;
- case 'c':
- sb.committed = TRUE;
- break;
- case 'h':
- help(options, pool);
- break;
- case SVNVERSION_OPT_VERSION:
- SVN_INT_ERR(version(os, pool));
- exit(0);
- break;
- default:
- usage(pool);
- return EXIT_FAILURE;
- }
- }
-
- if (os->ind > argc || os->ind < argc - 2)
- {
- usage(pool);
- return EXIT_FAILURE;
- }
+ SVN_ERR (svn_wc_adm_open_anchor (&anchor_access, &target_access, &target,
+ wc_path, FALSE, -1,
+ cancel_func, cancel_baton,
+ pool));
+
+ SVN_ERR (svn_wc_get_status_editor2 (&editor, &edit_baton, NULL,
+ &edit_revision, anchor_access, target,
+ NULL /* config */,
+ TRUE /* recurse */,
+ TRUE /* get_all */,
+ FALSE /* no_ignore */,
+ analyze_status, &sb,
+ cancel_func, cancel_baton,
+ NULL /* traversal_info */,
+ pool));
 
- SVN_INT_ERR (svn_utf_cstring_to_utf8 (&wc_path,
- (os->ind == argc) ? "." : os->argv[os->ind++],
- pool));
- wc_path = svn_path_internal_style (wc_path, pool);
- SVN_INT_ERR (svn_wc_check_wc (wc_path, &wc_format, pool));
- if (! wc_format)
- {
- svn_node_kind_t kind;
- SVN_INT_ERR(svn_io_check_path (wc_path, &kind, pool));
- if (kind == svn_node_dir)
- {
- SVN_INT_ERR (svn_cmdline_printf (pool, _("exported%s"),
- no_newline ? "" : "\n"));
- svn_pool_destroy (pool);
- return EXIT_SUCCESS;
- }
- else
- {
- svn_error_clear
- (svn_cmdline_fprintf (stderr, pool,
- _("'%s' not versioned, and not exported\n"),
- wc_path));
- svn_pool_destroy (pool);
- return EXIT_FAILURE;
- }
- }
-
- sb.wc_path = wc_path;
- rev.kind = svn_opt_revision_unspecified;
- ctx.config = apr_hash_make (pool);
+ SVN_ERR (editor->close_edit (edit_baton, pool));
 
- err = svn_client_status2 (NULL, wc_path, &rev, analyze_status,
- &sb, TRUE, TRUE, FALSE, FALSE, TRUE, &ctx, pool);
- if (err && (err->apr_err == SVN_ERR_CANCELLED))
- svn_error_clear (err);
- else
- SVN_INT_ERR (err);
+ SVN_ERR (svn_wc_adm_close (anchor_access));
 
- if ((! sb.switched ) && (os->ind < argc))
+ if ((! result->switched) && (trail_url != NULL))
     {
       /* If the trailing part of the URL of the working copy directory
          does not match the given trailing URL then the whole working
          copy is switched. */
- const char *trail_url;
- SVN_INT_ERR (svn_utf_cstring_to_utf8 (&trail_url, os->argv[os->ind],
- pool));
       if (! sb.wc_url)
         {
- sb.switched = TRUE;
+ result->switched = TRUE;
         }
       else
         {
           apr_size_t len1 = strlen (trail_url);
           apr_size_t len2 = strlen (sb.wc_url);
           if ((len1 > len2) || strcmp (sb.wc_url + len2 - len1, trail_url))
- sb.switched = TRUE;
+ result->switched = TRUE;
         }
     }
 
- SVN_INT_ERR (svn_cmdline_printf (pool, "%ld", sb.min_rev));
- if (sb.min_rev != sb.max_rev)
- SVN_INT_ERR (svn_cmdline_printf (pool, ":%ld", sb.max_rev));
- if (sb.modified)
- SVN_INT_ERR (svn_cmdline_fputs ("M", stdout, pool));
- if (sb.switched)
- SVN_INT_ERR (svn_cmdline_fputs ("S", stdout, pool));
- if (! no_newline)
- SVN_INT_ERR (svn_cmdline_fputs ("\n", stdout, pool));
-
- svn_pool_destroy (pool);
-
- /* Flush stdout to make sure that the user will see any printing errors. */
- SVN_INT_ERR (svn_cmdline_fflush (stdout));
-
- return EXIT_SUCCESS;
+ return SVN_NO_ERROR;
 }
Index: subversion/svnversion/main.c
===================================================================
--- subversion/svnversion/main.c (revision 17555)
+++ subversion/svnversion/main.c (working copy)
@@ -16,7 +16,7 @@
 
 #include "svn_cmdline.h"
 #include "svn_pools.h"
-#include "svn_client.h"
+#include "svn_wc.h"
 #include "svn_utf.h"
 #include "svn_path.h"
 #include "svn_opt.h"
@@ -25,57 +25,6 @@
 
 #define SVNVERSION_OPT_VERSION SVN_OPT_FIRST_LONGOPT_ID
 
-struct status_baton
-{
- svn_revnum_t min_rev; /* lowest revision found. */
- svn_revnum_t max_rev; /* highest revision found. */
- svn_boolean_t switched; /* is anything switched? */
- svn_boolean_t modified; /* is anything modified? */
- svn_boolean_t committed; /* examine last committed revisions */
- const char *wc_path; /* path whose URL we're looking for. */
- const char *wc_url; /* URL for the path whose URL we're looking for. */
- apr_pool_t *pool; /* pool in which to store alloc-needy things. */
-};
-
-
-/* An svn_wc_status_func_t callback function for anaylyzing status
- structures. */
-static void
-analyze_status (void *baton,
- const char *path,
- svn_wc_status2_t *status)
-{
- struct status_baton *sb = baton;
-
- if (! status->entry)
- return;
-
- /* Added files have a revision of no interest */
- if (status->text_status != svn_wc_status_added)
- {
- svn_revnum_t item_rev = (sb->committed
- ? status->entry->cmt_rev
- : status->entry->revision);
-
- if (sb->min_rev == SVN_INVALID_REVNUM || item_rev < sb->min_rev)
- sb->min_rev = item_rev;
-
- if (sb->max_rev == SVN_INVALID_REVNUM || item_rev > sb->max_rev)
- sb->max_rev = item_rev;
- }
-
- sb->switched |= status->switched;
- sb->modified |= (status->text_status != svn_wc_status_normal);
- sb->modified |= (status->prop_status != svn_wc_status_normal
- && status->prop_status != svn_wc_status_none);
-
- if (sb->wc_path
- && (! sb->wc_url)
- && (strcmp (path, sb->wc_path) == 0)
- && (status->entry))
- sb->wc_url = apr_pstrdup (sb->pool, status->entry->url);
-}
-
 
 static svn_error_t * version(apr_getopt_t *os, apr_pool_t *pool)
 {
@@ -143,7 +92,6 @@
   static const svn_version_checklist_t checklist[] =
     {
       { "svn_subr", svn_subr_version },
- { "svn_client", svn_client_version },
       { "svn_wc", svn_wc_version },
       { NULL, NULL }
     };
@@ -152,25 +100,20 @@
    return svn_ver_check_list (&my_version, checklist);
 }
 
-
 /*
  * Why is this not an svn subcommand? I have this vague idea that it could
  * be run as part of the build process, with the output embedded in the svn
  * program. Obviously we don't want to have to run svn when building svn.
- * We could always put this into libsvn_client and share it between
- * svnversion and svn.
  */
 int
 main(int argc, const char *argv[])
 {
- const char *wc_path;
+ const char *wc_path, *trail_url;
   apr_allocator_t *allocator;
   apr_pool_t *pool;
   int wc_format;
- svn_client_ctx_t ctx = { 0 };
- struct status_baton sb;
- svn_opt_revision_t rev;
- svn_boolean_t no_newline = FALSE;
+ svn_wc_revision_status_t res;
+ svn_boolean_t no_newline = FALSE, committed = FALSE;
   svn_error_t *err;
   apr_getopt_t *os;
   const apr_getopt_option_t options[] =
@@ -220,15 +163,6 @@
     }
 #endif
 
- sb.switched = FALSE;
- sb.modified = FALSE;
- sb.committed = FALSE;
- sb.min_rev = SVN_INVALID_REVNUM;
- sb.max_rev = SVN_INVALID_REVNUM;
- sb.wc_path = NULL;
- sb.wc_url = NULL;
- sb.pool = pool;
-
   apr_getopt_init(&os, pool, argc, argv);
   os->interleave = 1;
   while (1)
@@ -249,11 +183,11 @@
           no_newline = TRUE;
           break;
         case 'c':
- sb.committed = TRUE;
+ committed = TRUE;
+ break;
+ case 'h':
+ help(options, pool);
           break;
- case 'h':
- help(options, pool);
- break;
         case SVNVERSION_OPT_VERSION:
           SVN_INT_ERR(version(os, pool));
           exit(0);
@@ -270,10 +204,17 @@
       return EXIT_FAILURE;
     }
 
- SVN_INT_ERR (svn_utf_cstring_to_utf8 (&wc_path,
- (os->ind == argc) ? "." : os->argv[os->ind++],
- pool));
+ SVN_INT_ERR (svn_utf_cstring_to_utf8
+ (&wc_path, (os->ind < argc) ? os->argv[os->ind] : ".",
+ pool));
   wc_path = svn_path_internal_style (wc_path, pool);
+
+ if (os->ind+1 < argc)
+ SVN_INT_ERR (svn_utf_cstring_to_utf8
+ (&trail_url, os->argv[os->ind+1], pool));
+ else
+ trail_url = NULL;
+
   SVN_INT_ERR (svn_wc_check_wc (wc_path, &wc_format, pool));
   if (! wc_format)
     {
@@ -297,45 +238,19 @@
         }
     }
 
- sb.wc_path = wc_path;
- rev.kind = svn_opt_revision_unspecified;
- ctx.config = apr_hash_make (pool);
-
- err = svn_client_status2 (NULL, wc_path, &rev, analyze_status,
- &sb, TRUE, TRUE, FALSE, FALSE, TRUE, &ctx, pool);
- if (err && (err->apr_err == SVN_ERR_CANCELLED))
- svn_error_clear (err);
- else
- SVN_INT_ERR (err);
 
- if ((! sb.switched ) && (os->ind < argc))
- {
- /* If the trailing part of the URL of the working copy directory
- does not match the given trailing URL then the whole working
- copy is switched. */
- const char *trail_url;
- SVN_INT_ERR (svn_utf_cstring_to_utf8 (&trail_url, os->argv[os->ind],
- pool));
- if (! sb.wc_url)
- {
- sb.switched = TRUE;
- }
- else
- {
- apr_size_t len1 = strlen (trail_url);
- apr_size_t len2 = strlen (sb.wc_url);
- if ((len1 > len2) || strcmp (sb.wc_url + len2 - len1, trail_url))
- sb.switched = TRUE;
- }
- }
+ SVN_INT_ERR (svn_wc_revision_status (&res, wc_path, trail_url, committed,
+ NULL, NULL, pool));
 
- SVN_INT_ERR (svn_cmdline_printf (pool, "%ld", sb.min_rev));
- if (sb.min_rev != sb.max_rev)
- SVN_INT_ERR (svn_cmdline_printf (pool, ":%ld", sb.max_rev));
- if (sb.modified)
+ /* Build compact '123[:456]M?S?' string. */
+ SVN_INT_ERR (svn_cmdline_printf (pool, "%ld", res.min_rev));
+ if (res.min_rev != res.max_rev)
+ SVN_INT_ERR (svn_cmdline_printf (pool, ":%ld", res.max_rev));
+ if (res.modified)
     SVN_INT_ERR (svn_cmdline_fputs ("M", stdout, pool));
- if (sb.switched)
+ if (res.switched)
     SVN_INT_ERR (svn_cmdline_fputs ("S", stdout, pool));
+
   if (! no_newline)
     SVN_INT_ERR (svn_cmdline_fputs ("\n", stdout, pool));
 
Index: build.conf
===================================================================
--- build.conf (revision 17555)
+++ build.conf (working copy)
@@ -284,7 +284,7 @@
 description = Subversion Revision Extractor
 type = exe
 path = subversion/svnversion
-libs = libsvn_client libsvn_subr libsvn_wc aprutil apriconv apr neon
+libs = libsvn_subr libsvn_wc aprutil apriconv apr neon
 install = bin
 manpages = subversion/svnversion/svnversion.1
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Wed Nov 30 00:54:52 2005

This is an archived mail posted to the Subversion Dev mailing list.