Author: rinrab
Date: Wed Apr 8 14:08:39 2026
New Revision: 1932903
Log:
svnbrowse: Support proper revision/target system in the command-line handling.
The model, when created, will accept a path_or_url parameter and, if a path is
supplied, go and get the URL from WC. It also receives a revision/peg_revision
as svn_opt_revision_t. The standard client framework will be used to resolve
those. If both of those revisions are HEAD, we'll directly read directories at
HEAD.
* subversion/svnbrowse/svnbrowse.h
(svn_browse__opt_state_t): Add revision, peg_revision, and path_or_url to
the struct.
(svn_browse__model_create): Update function declaration.
* subversion/svnbrowse/model.c
(includes): Update includes.
(svn_browse__model_create): Update arguments that the function accepts, use
svn_client__ra_session_from_path2() instead of svn_client_open_ra_session2()
for initializing RA sessions, and use the revision/URL it resolves for the
newly created model.
* subversion/svnbrowse/svnbrowse.c
(sub_main): Handle all extra args with svn_client_args_to_target_array2() and
extract "the target" from it (the array should only contain of those). Parse
this target onto peg_revision and path_or_url using svn_opt_parse_path().
Modified:
subversion/trunk/subversion/svnbrowse/model.c
subversion/trunk/subversion/svnbrowse/svnbrowse.c
subversion/trunk/subversion/svnbrowse/svnbrowse.h
Modified: subversion/trunk/subversion/svnbrowse/model.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/model.c Wed Apr 8 14:08:31
2026 (r1932902)
+++ subversion/trunk/subversion/svnbrowse/model.c Wed Apr 8 14:08:39
2026 (r1932903)
@@ -24,12 +24,14 @@
#include <apr.h>
#include "svn_client.h"
-#include "svn_cmdline.h"
#include "svn_dirent_uri.h"
+#include "svn_path.h"
#include "svn_ra.h"
#include "svn_pools.h"
#include "svn_error.h"
+#include "private/svn_client_private.h"
+
#include "svnbrowse.h"
svn_error_t *
@@ -130,36 +132,65 @@ svn_browse__model_move_selection(svn_bro
svn_error_t *
svn_browse__model_create(svn_browse__model_t **model_p,
svn_client_ctx_t *ctx,
- const char *url,
- svn_revnum_t revision,
+ const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *revision,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_browse__model_t *model = apr_pcalloc(result_pool, sizeof(*model));
svn_ra_session_t *session;
apr_pool_t *state_pool;
- svn_browse__state_t *state;
const char *root, *relpath;
- SVN_ERR(svn_client_open_ra_session2(&session, url, NULL, ctx, result_pool,
- scratch_pool));
+ svn_opt_revision_t peg_rev = *peg_revision;
+ svn_opt_revision_t start_rev = *revision;
+ svn_client__pathrev_t *loc;
+
+ /* Default revisions: peg -> working or head; operative -> peg. */
+ SVN_ERR(svn_opt_resolve_revisions(&peg_rev, &start_rev,
+ svn_path_is_url(path_or_url),
+ TRUE /* notice_local_mods */,
+ scratch_pool));
+
+ SVN_ERR(svn_client__ra_session_from_path2(&session, &loc, path_or_url, NULL,
+ &peg_rev, &start_rev, ctx,
+ result_pool));
+
+ model->root = apr_pstrdup(result_pool, loc->repos_root_url);
+ model->client = ctx;
+ model->session = session;
- SVN_ERR(svn_ra_get_repos_root2(session, &root, scratch_pool));
- SVN_ERR(svn_ra_reparent(session, root, scratch_pool));
+ /* If the revision is ovbiously HEAD, we are not going to use the resolved
+ * revnum, but rely on svn_ra_get_dir2() doing that for us. It allows the
+ * browser to always browse on the latest revision and catch-up recent
+ * commits as session is active.
+ *
+ * Note: only head+head combination of peg_revision and revision should be
+ * considered as the "real" head. If we were to for example go to r123 and
+ * then resolve HEAD, its value may change as session progresses. This logic
+ * would be too complicated and rather confusing. That's why we will fallback
+ * to what the client is doing instead of reinventing the wheel.
+ *
+ * When invoked from a working copy, it's not HEAD either. It's should point
+ * to WORKING, i.e. revnum should not change. Again rescanning the working
+ * copy is possible but we assume it never changes.
+ */
+
+ if (peg_rev.kind == svn_opt_revision_head &&
+ start_rev.kind == svn_opt_revision_head)
+ model->revision = SVN_INVALID_REVNUM;
+ else
+ model->revision = loc->rev;
- relpath = svn_uri_skip_ancestor(root, url, scratch_pool);
+ SVN_ERR(svn_ra_reparent(session, loc->repos_root_url, scratch_pool));
+
+ relpath = svn_uri_skip_ancestor(loc->repos_root_url, loc->url, 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(svn_browse__state_create(&state, session, relpath, revision,
- state_pool, scratch_pool));
-
- model->root = apr_pstrdup(result_pool, root);
- model->revision = revision;
- model->client = ctx;
- model->session = session;
- model->current = state;
- model->pool = result_pool;
+ SVN_ERR(svn_browse__state_create(&model->current, session, relpath,
+ model->revision, state_pool, scratch_pool));
*model_p = model;
return SVN_NO_ERROR;
Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c Wed Apr 8 14:08:31
2026 (r1932902)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.c Wed Apr 8 14:08:39
2026 (r1932903)
@@ -217,7 +217,6 @@ show_version(apr_pool_t *scratch_pool,
static svn_error_t *
sub_main(int *code, int argc, const char *argv[], apr_pool_t *pool)
{
- const char *url;
svn_client_ctx_t *client;
svn_auth_baton_t *auth;
svn_browse__model_t *ctx;
@@ -226,6 +225,7 @@ sub_main(int *code, int argc, const char
svn_boolean_t read_pass_from_stdin = FALSE;
apr_pool_t *iterpool;
apr_getopt_t *os;
+ apr_array_header_t *targets = NULL;
opt_state.revision.kind = svn_opt_revision_head;
opt_state.config_options =
@@ -313,20 +313,6 @@ sub_main(int *code, int argc, const char
return SVN_NO_ERROR;
}
- /* TODO: WC paths are not implemented; svn_uri_canonicalize_safe() will just
- * fail in case of one */
- url = (os->ind < argc) ? os->argv[os->ind++] : ".";
- SVN_ERR(svn_uri_canonicalize_safe(&url, NULL, url, pool, pool));
-
- /* we must fail if there are extra arguments */
- if (os->ind < argc - 1)
- {
- printf("%d\n", os->ind);
- *code = EXIT_FAILURE;
- SVN_ERR(show_usage(pool));
- return SVN_NO_ERROR;
- }
-
SVN_ERR(svn_config_ensure(opt_state.config_dir, pool));
/* Set up Authentication stuff. */
@@ -348,8 +334,23 @@ sub_main(int *code, int argc, const char
SVN_ERR(svn_client_create_context2(&client, NULL, pool));
client->auth_baton = auth;
- SVN_ERR(svn_browse__model_create(&ctx, client, url, SVN_INVALID_REVNUM, pool,
- pool));
+ SVN_ERR(svn_client_args_to_target_array2(&targets, os, NULL, client, FALSE,
+ pool));
+
+ /* we must fail if there are extra arguments */
+ if (targets->nelts != 1)
+ {
+ *code = EXIT_FAILURE;
+ SVN_ERR(show_usage(pool));
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(svn_opt_parse_path(&opt_state.peg_revision, &opt_state.path_or_url,
+ APR_ARRAY_IDX(targets, 0, const char *), pool));
+
+ SVN_ERR(svn_browse__model_create(&ctx, client, opt_state.path_or_url,
+ &opt_state.peg_revision,
+ &opt_state.revision, pool, pool));
/* init the display */
initscr();
Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.h
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.h Wed Apr 8 14:08:31
2026 (r1932902)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.h Wed Apr 8 14:08:39
2026 (r1932903)
@@ -48,11 +48,12 @@ typedef struct svn_browse__opt_state_t {
const char *auth_username; /* auth username */
const char *auth_password; /* auth password */
- apr_array_header_t *targets; /* target list from file */
svn_boolean_t no_auth_cache; /* do not cache authentication information */
const char *config_dir; /* over-riding configuration directory */
apr_array_header_t *config_options; /* over-riding configuration options */
- svn_opt_revision_t revision;
+ svn_opt_revision_t revision; /* --revision */
+ const char *path_or_url;
+ svn_opt_revision_t peg_revision; /* @PEGREV*/
/* trust server SSL certs that would otherwise be rejected as "untrusted" */
svn_boolean_t trust_server_cert_unknown_ca;
@@ -125,7 +126,8 @@ svn_browse__model_move_selection(svn_bro
svn_error_t *
svn_browse__model_create(svn_browse__model_t **model_p,
svn_client_ctx_t *ctx,
- const char *url,
- svn_revnum_t revision,
+ const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *revision,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);