Author: rinrab
Date: Thu Apr  2 15:51:07 2026
New Revision: 1932742

Log:
svnbrowse: Use libsvn_ra API directly to query directories. Do so for improved
performance (by reusing the same session) and more control of what is
actually transmitted over the wire.

* subversion/svnbrowse/svnbrowse.c
  (includes): Add svn_ra.h.
  (svn_browse__state_t): Change abspath to relpath and the revision is now just
   a number. Although most of the logic just ignore it for now.
  (svn_browse__model_t): Store ra_session and change how we store revision.
  (list_cb): Implement svn_ra_dirent_receiver_t instead of
   svn_client_list_func2_t. Take basename of relpath when processing it.
  (state_create): Change the API used to back the operation.
  (enter_path): Update state_create() invokation and change abspath back to
   relpath.
  (model_create): Ask for a numeric revision and add code to initialize
   ra_session.
  (view_draw): Add back the logic that combines root and relpath for the
   header.
  (sub_main): Use numeric revisions and treat current path of browser as a
   relative path.

Modified:
   subversion/trunk/subversion/svnbrowse/svnbrowse.c

Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c   Thu Apr  2 15:12:23 
2026        (r1932741)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.c   Thu Apr  2 15:51:07 
2026        (r1932742)
@@ -26,6 +26,7 @@
 
 #include "svn_client.h"
 #include "svn_opt.h"
+#include "svn_ra.h"
 #include "svn_path.h"
 #include "svn_pools.h"
 #include "svn_cmdline.h"
@@ -45,8 +46,8 @@ typedef struct svn_browse__item_t {
 /* a state of a single directory */
 typedef struct svn_browse__state_t {
   /* information about this node */
-  const char *abspath;
-  svn_opt_revision_t revision;
+  const char *relpath;
+  svn_revnum_t revision;
 
   /* stores the list of nodes in this state; an array of svn_browse__item_t */
   apr_array_header_t *list;
@@ -60,27 +61,24 @@ typedef struct svn_browse__state_t {
 
 typedef struct svn_browse__model_t {
   const char *root;
-  svn_opt_revision_t revision;
+  svn_revnum_t revision;
 
   svn_client_ctx_t *client;
+  svn_ra_session_t *session;
 
   svn_browse__state_t *current;
   apr_pool_t *pool;
 } svn_browse__model_t;
 
 static svn_error_t *
-list_cb(void *baton,
-        const char *path,
-        const svn_dirent_t *dirent,
-        const svn_lock_t *lock,
-        const char *abs_path,
-        const char *external_parent_url,
-        const char *external_target,
+list_cb(const char *relpath,
+        svn_dirent_t *dirent,
+        void *baton,
         apr_pool_t *scratch_pool)
 {
   svn_browse__state_t *state = baton;
   svn_browse__item_t *item = apr_pcalloc(state->pool, sizeof(*item));
-  item->relpath = apr_pstrdup(state->pool, path);
+  item->relpath = svn_dirent_basename(relpath, state->pool);
   item->dirent = svn_dirent_dup(dirent, state->pool);
   APR_ARRAY_PUSH(state->list, svn_browse__item_t *) = item;
   return SVN_NO_ERROR;
@@ -88,36 +86,41 @@ list_cb(void *baton,
 
 static svn_error_t *
 state_create(svn_browse__state_t **state_p,
-             svn_client_ctx_t *ctx,
-             const char *url,
-             svn_opt_revision_t *revision,
+             svn_ra_session_t *session,
+             const char *relpath,
+             svn_revnum_t revision,
              apr_pool_t *result_pool,
              apr_pool_t *scratch_pool)
 {
   svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
+  svn_revnum_t revnum;
 
-  state->abspath = apr_pstrdup(result_pool, url);
+  state->relpath = apr_pstrdup(result_pool, relpath);
   state->revision = state->revision;
   state->list = apr_array_make(result_pool, 0, sizeof(svn_browse__item_t *));
   state->selection = 0;
   state->pool = result_pool;
 
-  SVN_ERR(svn_client_list4(url, revision, revision, NULL, svn_depth_immediates,
-                           SVN_DIRENT_ALL, TRUE, TRUE, list_cb, state, ctx,
-                           scratch_pool));
+  /* TODO: use svn_ra_get_dir2() as it automatically treats SVN_INVALID_REVNUM
+   * as HEAD and returns a list directly. */
+
+  SVN_ERR(svn_ra_get_latest_revnum(session, &revnum, scratch_pool));
+
+  SVN_ERR(svn_ra_list(session, relpath, revnum, NULL, svn_depth_immediates,
+                      SVN_DIRENT_ALL, list_cb, state, scratch_pool));
 
   *state_p = state;
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
-enter_path(svn_browse__model_t *ctx, const char *abspath,
+enter_path(svn_browse__model_t *ctx, const char *relpath,
            apr_pool_t *scratch_pool)
 {
   svn_browse__state_t *newstate;
   apr_pool_t *state_pool = svn_pool_create(ctx->pool);
 
-  SVN_ERR(state_create(&newstate, ctx->client, abspath, &ctx->revision,
+  SVN_ERR(state_create(&newstate, ctx->session, relpath, ctx->revision,
                        state_pool, scratch_pool));
 
   /* switch to the next state and nuke the previous one */
@@ -130,13 +133,14 @@ enter_path(svn_browse__model_t *ctx, con
 static svn_error_t *
 model_create(svn_browse__model_t **model_p,
              const char *url,
-             svn_opt_revision_t revision,
+             svn_revnum_t revision,
              apr_pool_t *result_pool,
              apr_pool_t *scratch_pool)
 {
   svn_browse__model_t *model = apr_pcalloc(result_pool, sizeof(*model));
   svn_auth_baton_t *auth;
   svn_client_ctx_t *client;
+  svn_ra_session_t *session;
   apr_pool_t *state_pool;
   svn_browse__state_t *state;
 
@@ -148,15 +152,18 @@ model_create(svn_browse__model_t **model
   SVN_ERR(svn_client_create_context2(&client, NULL, result_pool));
   client->auth_baton = auth;
 
+  SVN_ERR(svn_client_open_ra_session2(&session, url, NULL, client, result_pool,
+                                      scratch_pool));
+
   /* the state should be in a separate pool so it's safe to free it */
   state_pool = svn_pool_create(result_pool);
-  SVN_ERR(state_create(&state, client, url, &revision, state_pool,
+  SVN_ERR(state_create(&state, session, "", revision, state_pool,
                        scratch_pool));
-
   /* TODO: we must use the repository root URL */
-  model->root = apr_pstrdup(result_pool, url);
+  SVN_ERR(svn_ra_get_session_url(session, &model->root, result_pool));
   model->revision = revision;
   model->client = client;
+  model->session = session;
   model->current = state;
   model->pool = result_pool;
 
@@ -181,8 +188,10 @@ static void
 view_draw(svn_browse__view_t *view, apr_pool_t *pool)
 {
   int i;
+  const char *abspath = svn_path_url_add_component2(
+      view->model->root, view->model->current->relpath, pool);
 
-  mvprintw(0, 4, "Browsing: %s", view->model->current->abspath);
+  mvprintw(0, 4, "Browsing: %s", abspath);
 
   for (i = 0; i < view->model->current->list->nelts; i++)
     {
@@ -215,7 +224,6 @@ static svn_error_t *
 sub_main(int *code, int argc, char *argv[], apr_pool_t *pool)
 {
   const char *url;
-  svn_opt_revision_t revision;
   svn_browse__model_t *ctx;
   svn_browse__view_t *view;
   apr_pool_t *iterpool;
@@ -225,9 +233,8 @@ sub_main(int *code, int argc, char *argv
                             "usage: svnbrowse <URL>");
 
   SVN_ERR(svn_uri_canonicalize_safe(&url, NULL, argv[1], pool, pool));
-  revision.kind = svn_opt_revision_head;
 
-  SVN_ERR(model_create(&ctx, url, revision, pool, pool));
+  SVN_ERR(model_create(&ctx, url, SVN_INVALID_REVNUM, pool, pool));
 
   /* init the display */
   initscr();
@@ -275,14 +282,14 @@ sub_main(int *code, int argc, char *argv
           case '\r':
             item = APR_ARRAY_IDX(ctx->current->list, ctx->current->selection,
                                  svn_browse__item_t *);
-            new_url = svn_path_url_add_component2(ctx->current->abspath,
-                                                  item->relpath, iterpool);
+            new_url = svn_relpath_join(ctx->current->relpath, item->relpath,
+                                       iterpool);
             SVN_ERR(enter_path(ctx, new_url, iterpool));
             break;
           case KEY_BACKSPACE:
           case '-':
           case 'u':
-            new_url = svn_uri_dirname(ctx->current->abspath, iterpool);
+            new_url = svn_relpath_dirname(ctx->current->relpath, iterpool);
             SVN_ERR(enter_path(ctx, new_url, iterpool));
             break;
           /* TODO: quit via escape. some say just check for 27, but it I think 
it's

Reply via email to