You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by kf...@collab.net on 2005/05/04 19:00:45 UTC

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

jszakmeister@tigris.org writes:
> --- trunk/subversion/libsvn_client/cat.c	(original)
> +++ trunk/subversion/libsvn_client/cat.c	Mon Apr 11 05:08:14 2005
> @@ -37,6 +37,8 @@
>  
>  /*** Code. ***/
>  
> +/* Helper function to handle copying a potentially translated verison of BASE
> +   or WORKING revision of a file to an output stream. */
>  static svn_error_t *
>  cat_local_file (const char *path,
>                  svn_stream_t *output,

Go all the way and document the function according to the full
standards: document every parameter, and the return value, etc.
It's important for internal functions too, not just public APIs.

For example, from the current doc string, I can't tell whether any
value is allowable for REVISION.  Is it limited to just
svn_opt_revision_working and svn_opt_revision_base?  (See below for
more on that.)

Also, typo: "version" not "verison" :-).

The rest of this is from r14081, not r14098:

> +  if (revision->kind != svn_opt_revision_working)
> +    {
> +      SVN_ERR (svn_wc_get_pristine_copy_path (path, &base, pool));
> +      SVN_ERR (svn_wc_get_prop_diffs (NULL, &props, path, adm_access, pool));
> +    }
> +  else
> +    {
> +      svn_wc_status2_t *status;
> +      
> +      base = path;
> +      SVN_ERR (svn_wc_prop_list (&props, path, adm_access, pool));
> +      SVN_ERR (svn_wc_status2 (&status, path, adm_access, pool));
> +      if (status->text_status != svn_wc_status_normal)
> +        local_mod = TRUE;
> +    }

This just assumes that if it's not svn_opt_revision_working, it must
be svn_opt_revision_base.  If those are the only acceptable two, then
we should check strictly for that, and error if passed something else.

> +  if (local_mod && (! special))
> +    {
> +      /* Use the modified time from the working copy if
> +         the file */
> +      SVN_ERR (svn_io_file_affected_time (&tm, path, pool));
> +    }
> +  else
> +    {
> +      tm = entry->cmt_date;
> +    }

"of the file" not "if the file".  (Being picky about this typo because
it can lead to genuine misunderstanding -- especially without the
period at the end, someone might wonder if it was just a sentence left
unfinished.  Of course, reading the code clarifies it immediately.)

In svn_client_cat2():

> +  if (! svn_path_is_url (path_or_url)
> +      && (peg_revision->kind == svn_opt_revision_base
> +          || peg_revision->kind == svn_opt_revision_committed
> +          || peg_revision->kind == svn_opt_revision_unspecified)
> +      && (revision->kind == svn_opt_revision_base
> +          || revision->kind == svn_opt_revision_committed
> +          || revision->kind == svn_opt_revision_unspecified))
> +    {
> +      svn_wc_adm_access_t *adm_access;
> +    
> +      SVN_ERR (svn_wc_adm_open3 (&adm_access, NULL,
> +                                 svn_path_dirname (path_or_url, pool), FALSE,
> +                                 0, ctx->cancel_func, ctx->cancel_baton,
> +                                 pool));
> +
> +      SVN_ERR (cat_local_file (path_or_url, out, adm_access, revision, pool));
> +
> +      SVN_ERR (svn_wc_adm_close (adm_access));
> +
> +      return SVN_NO_ERROR;
> +    }

This is tricky.

Formally, I'm not sure that peg_revision matters here.  I mean, you've
already determined that path_or_url is a local path.  If you also know
that revision is BASE or COMMITTED or something else that can be found
locally, then from a pure correctness standpoint it really doesn't
matter what peg_revision is -- the only question is, have you got the
appropriate revision of that node at hand locally.

However, I can see why (as a code simplification) you might want to
check that peg_revision is also locally determinable here, so that you
don't need special cases to handle identity switcheroos in the node's
history.

If this is what's going on, maybe a comment explaining this would be a
good idea?

-Karl

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by Philip Martin <ph...@codematters.co.uk>.
John Szakmeister <jo...@szakmeister.net> writes:

> It's all hidden behind svn_client_cat2().

OK, then an assert makes sense.

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by John Szakmeister <jo...@szakmeister.net>.
Philip Martin wrote:
> John Szakmeister <jo...@szakmeister.net> writes:
> 
> 
>> However, I didn't implement the input validation.  I sat down to do
>>  it twice, and I kept stumbling on how to create an appropriate 
>> error for the user.  I think it would be confusing to say something
>>  like "Must be one of revision BASE, COMMITTED, WORKING, or 
>> UNSPECIFIED" or that a revision is disallowed for any reason.
> 
> 
> How else is the user going to know what to change?

The user can do nothing about this error.  If this function fails, it's
because there is incorrect logic in the svn_client_cat2().

> 
>> The user did nothing wrong,
> 
> 
> Something is wrong since the revision cannot be used.

Nope.  See above.

> 
>> and may have supplied a completely sound argument.  So the attached
>>  patch has an assert() statement the for the moment.  Do you have 
>> suggestions for what an appropriate error might look like?
> 
> 
> How about SVN_ERR_UNSUPPORTED_FEATURE?  I think any error is better 
> than an assert, for example you are forcing TSVN to implement the 
> same restriction to avoid the assert.
> 

No, absolutely not.  Karl was talking about making cat_local_file()
return an error if the revision isn't what we expect.  From a user
perspective, 'svn cat -rBASE' makes sense.  If we fail because an
internal API's pre-condition was violated, saying something to the
effect that "'svn cat -rBASE' is not allowed" would be very confusing to
the user.  I think it would be even more frustrating to find out it
wasn't a user error at all, but an internal library one. Keep in mind
cat_local_file() is a static helper function, with one caller. :-)  And
no, TortoiseSVN doesn't have to add similar code to avoid a problem.
It's all hidden behind svn_client_cat2().

I don't mind making it a runtime error, I just don't know what the
appropriate, non-confusing feedback would be to a user.  An assert()
comes off as an obvious internal application error, where as most
feedback on the command-line is a result of user error.  I just want
them to know the difference between their mistake and one that's
obviously ours.

-John

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by Philip Martin <ph...@codematters.co.uk>.
John Szakmeister <jo...@szakmeister.net> writes:

> However, I didn't implement the input 
> validation.  I sat down to do it twice, and I kept stumbling on how to 
> create an appropriate error for the user.  I think it would be confusing 
> to say something like "Must be one of revision BASE, COMMITTED, WORKING, 
> or UNSPECIFIED" or that a revision is disallowed for any reason.

How else is the user going to know what to change?

> The user did nothing wrong,

Something is wrong since the revision cannot be used.

> and may have supplied a completely sound 
> argument.  So the attached patch has an assert() statement the for the 
> moment.  Do you have suggestions for what an appropriate error might look 
> like?

How about SVN_ERR_UNSUPPORTED_FEATURE?  I think any error is better
than an assert, for example you are forcing TSVN to implement the same
restriction to avoid the assert.

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by John Szakmeister <jo...@szakmeister.net>.
On Thursday 05 May 2005 16:00, kfogel@collab.net wrote:
> John Szakmeister <jo...@szakmeister.net> writes:
> > I guess it depends on your point of view.  In this case, if I
> > document that you can only send it
> > svn_opt_revision_base/committed/working and you send it something
> > else, then you violated the API.  In that case, I feel assert() is
> > okay (in much the same way that we verify that input buffers and
> > paths aren't NULL).  This function leaves the job of input validation
> > to the next level up.  *shrug*  I don't care all that much, I'm just
> > trying to understand why a runtime error is better than assert() in
> > this case. :-)
>
> Ah.  I see what you're saying.  Here are my thoughts.
>
> First, an error is much easier to understand.

I've attached a patch that does most of what you asked (which was actually 
a very good exercise since I forgot the unspecified revision was being 
mapped to base, thank you).  However, I didn't implement the input 
validation.  I sat down to do it twice, and I kept stumbling on how to 
create an appropriate error for the user.  I think it would be confusing 
to say something like "Must be one of revision BASE, COMMITTED, WORKING, 
or UNSPECIFIED" or that a revision is disallowed for any reason.  The 
user did nothing wrong, and may have supplied a completely sound 
argument.  So the attached patch has an assert() statement the for the 
moment.  Do you have suggestions for what an appropriate error might look 
like?  Our error messages are terse enough without confusing the user 
between a programmatic error (us violating a pre-condition) and a real 
user error (they specified an invalid revision).  I also grepped through 
the current code looking for a similar situation, and didn't find one 
that was sufficiently close to this to model after.

> Second, we can force every caller to validate the revision, or it can
> just pass the revision along and count on this function to error if
> appropriate.  Result: avoidance of duplicated code.

It's a static helper function, with 1 caller and the caller already has to 
do range checking to know whether or not contact the repository.  In this 
case, it looks like it actually generates code duplication, since I'll 
basically have to do the same checks in cat_local_file(). *shrug*

-John


Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by John Szakmeister <jo...@szakmeister.net>.
kfogel@collab.net wrote:
> John Szakmeister <jo...@szakmeister.net> writes:
> 
>>I guess it depends on your point of view.  In this case, if I document 
>>that you can only send it svn_opt_revision_base/committed/working and you 
>>send it something else, then you violated the API.  In that case, I feel 
>>assert() is okay (in much the same way that we verify that input buffers 
>>and paths aren't NULL).  This function leaves the job of input validation 
>>to the next level up.  *shrug*  I don't care all that much, I'm just 
>>trying to understand why a runtime error is better than assert() in this 
>>case. :-)
> 
> 
> Ah.  I see what you're saying.  Here are my thoughts.
> 
> First, an error is much easier to understand.
> 
> Second, we can force every caller to validate the revision, or it can
> just pass the revision along and count on this function to error if
> appropriate.  Result: avoidance of duplicated code.
> 
> That's why I would prefer an error.

Makes sense.  I hope to get to resolving all of the remaining issues
over the weekend.

-John


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by kf...@collab.net.
John Szakmeister <jo...@szakmeister.net> writes:
> I guess it depends on your point of view.  In this case, if I document 
> that you can only send it svn_opt_revision_base/committed/working and you 
> send it something else, then you violated the API.  In that case, I feel 
> assert() is okay (in much the same way that we verify that input buffers 
> and paths aren't NULL).  This function leaves the job of input validation 
> to the next level up.  *shrug*  I don't care all that much, I'm just 
> trying to understand why a runtime error is better than assert() in this 
> case. :-)

Ah.  I see what you're saying.  Here are my thoughts.

First, an error is much easier to understand.

Second, we can force every caller to validate the revision, or it can
just pass the revision along and count on this function to error if
appropriate.  Result: avoidance of duplicated code.

That's why I would prefer an error.

-K

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by John Szakmeister <jo...@szakmeister.net>.
On Wednesday 04 May 2005 16:31, kfogel@collab.net wrote:
> John Szakmeister <jo...@szakmeister.net> writes:
> > Hmph... I was following the pattern that I saw in other files (the
> > internal functions were document a lot less formally than
> > public/semi-public ones).  I can go back and update this though.
>
> Thanks!  (See "Document everything" in HACKING, btw.  It is lamentable
> that not all of our internal functions live up to this ideal.)

Thanks.

> > I assume that it should be doxygenified? :-)
>
> Nope, just use all caps for parameter names.
>
> > svn_opt_revision_working, svn_opt_revision_base, and
> > svn_opt_revision_comitted are the acceptable values.  I'll make sure
> > to document that as well as put in a few assert() statements.
>
> Cool.
>
> But not assert()!  Just return an error, and document what the error
> will be.  Assertions check "can't happen" cases, stuff that's worth
> exiting immediately for (i.e., there is a bug in the code itself).
> Error checks are for situations where the code is good but the input
> might be bad, which is what we'd have here.

I guess it depends on your point of view.  In this case, if I document 
that you can only send it svn_opt_revision_base/committed/working and you 
send it something else, then you violated the API.  In that case, I feel 
assert() is okay (in much the same way that we verify that input buffers 
and paths aren't NULL).  This function leaves the job of input validation 
to the next level up.  *shrug*  I don't care all that much, I'm just 
trying to understand why a runtime error is better than assert() in this 
case. :-)

> > I missed some of the peg discussions, so I wasn't certain if it was
> > really feasible to specify a peg revision on a local path.  I
> > actually tried it on the command line, and the peg revision is
> > something other than unspecified if you @REVISION syntax
> > (my-local-file@BASE, for example). From my understanding of the peg
> > revision, it's where we're supposed to start looking as far as
> > history tracing is concerned.  If it's anything other than
> > unspecified, base, or committed, then I assumed we'd have to ask the
> > repository for that information (how would I know if the file was
> > called x at revision y without contacting the repository?).  Hence
> > the check.  If I'm wrong, please enlighten me, and I'll either remove
> > the redundant code or document why I chose to check the peg revision.
>
> No, you're right.  We would have to contact the repository to
> determine the node identity, but (interestingly enough) we might not
> have to contact the repository for the actual *contents*, since we
> might have them locally.  Your code is correct as it stands, so I'm
> not suggesting a change.  If you want to add a comment, that'd be
> great, but no big deal.

Cool.  I thought I missed something substantial. :-)

-John

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by kf...@collab.net.
John Szakmeister <jo...@szakmeister.net> writes:
> Hmph... I was following the pattern that I saw in other files (the 
> internal functions were document a lot less formally than 
> public/semi-public ones).  I can go back and update this though.  

Thanks!  (See "Document everything" in HACKING, btw.  It is lamentable
that not all of our internal functions live up to this ideal.)

> I assume that it should be doxygenified? :-)

Nope, just use all caps for parameter names.

> svn_opt_revision_working, svn_opt_revision_base, and 
> svn_opt_revision_comitted are the acceptable values.  I'll make sure to 
> document that as well as put in a few assert() statements.

Cool.

But not assert()!  Just return an error, and document what the error
will be.  Assertions check "can't happen" cases, stuff that's worth
exiting immediately for (i.e., there is a bug in the code itself).
Error checks are for situations where the code is good but the input
might be bad, which is what we'd have here.

> I missed some of the peg discussions, so I wasn't certain if it was really 
> feasible to specify a peg revision on a local path.  I actually tried it 
> on the command line, and the peg revision is something other than 
> unspecified if you @REVISION syntax (my-local-file@BASE, for example).  
> From my understanding of the peg revision, it's where we're supposed to 
> start looking as far as history tracing is concerned.  If it's anything 
> other than unspecified, base, or committed, then I assumed we'd have to 
> ask the repository for that information (how would I know if the file was 
> called x at revision y without contacting the repository?).  Hence the 
> check.  If I'm wrong, please enlighten me, and I'll either remove the 
> redundant code or document why I chose to check the peg revision.

No, you're right.  We would have to contact the repository to
determine the node identity, but (interestingly enough) we might not
have to contact the repository for the actual *contents*, since we
might have them locally.  Your code is correct as it stands, so I'm
not suggesting a change.  If you want to add a comment, that'd be
great, but no big deal.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: svn commit: r14098 - in trunk: . subversion/libsvn_client subversion/tests/clients/cmdline

Posted by John Szakmeister <jo...@szakmeister.net>.
On Wednesday 04 May 2005 15:00, kfogel@collab.net wrote:
> jszakmeister@tigris.org writes:
> > --- trunk/subversion/libsvn_client/cat.c	(original)
> > +++ trunk/subversion/libsvn_client/cat.c	Mon Apr 11 05:08:14 2005
> > @@ -37,6 +37,8 @@
> >  
> >  /*** Code. ***/
> >
> > +/* Helper function to handle copying a potentially translated
> > verison of BASE +   or WORKING revision of a file to an output
> > stream. */
> >  static svn_error_t *
> >  cat_local_file (const char *path,
> >                  svn_stream_t *output,
>
> Go all the way and document the function according to the full
> standards: document every parameter, and the return value, etc.
> It's important for internal functions too, not just public APIs.
>
> For example, from the current doc string, I can't tell whether any
> value is allowable for REVISION.  Is it limited to just
> svn_opt_revision_working and svn_opt_revision_base?  (See below for
> more on that.)

Hmph... I was following the pattern that I saw in other files (the 
internal functions were document a lot less formally than 
public/semi-public ones).  I can go back and update this though.  I 
assume that it should be doxygenified? :-)

> Also, typo: "version" not "verison" :-).

I believe the typo was corrected in r14133.

> The rest of this is from r14081, not r14098:
> > +  if (revision->kind != svn_opt_revision_working)
> > +    {
> > +      SVN_ERR (svn_wc_get_pristine_copy_path (path, &base, pool));
> > +      SVN_ERR (svn_wc_get_prop_diffs (NULL, &props, path,
> > adm_access, pool)); +    }
> > +  else
> > +    {
> > +      svn_wc_status2_t *status;
> > +
> > +      base = path;
> > +      SVN_ERR (svn_wc_prop_list (&props, path, adm_access, pool));
> > +      SVN_ERR (svn_wc_status2 (&status, path, adm_access, pool));
> > +      if (status->text_status != svn_wc_status_normal)
> > +        local_mod = TRUE;
> > +    }
>
> This just assumes that if it's not svn_opt_revision_working, it must
> be svn_opt_revision_base.  If those are the only acceptable two, then
> we should check strictly for that, and error if passed something else.

svn_opt_revision_working, svn_opt_revision_base, and 
svn_opt_revision_comitted are the acceptable values.  I'll make sure to 
document that as well as put in a few assert() statements.

> > +  if (local_mod && (! special))
> > +    {
> > +      /* Use the modified time from the working copy if
> > +         the file */
> > +      SVN_ERR (svn_io_file_affected_time (&tm, path, pool));
> > +    }
> > +  else
> > +    {
> > +      tm = entry->cmt_date;
> > +    }
>
> "of the file" not "if the file".  (Being picky about this typo because
> it can lead to genuine misunderstanding -- especially without the
> period at the end, someone might wonder if it was just a sentence left
> unfinished.  Of course, reading the code clarifies it immediately.)

Will fix.

> In svn_client_cat2():
> > +  if (! svn_path_is_url (path_or_url)
> > +      && (peg_revision->kind == svn_opt_revision_base
> > +          || peg_revision->kind == svn_opt_revision_committed
> > +          || peg_revision->kind == svn_opt_revision_unspecified)
> > +      && (revision->kind == svn_opt_revision_base
> > +          || revision->kind == svn_opt_revision_committed
> > +          || revision->kind == svn_opt_revision_unspecified))
> > +    {
> > +      svn_wc_adm_access_t *adm_access;
> > +
> > +      SVN_ERR (svn_wc_adm_open3 (&adm_access, NULL,
> > +                                 svn_path_dirname (path_or_url,
> > pool), FALSE, +                                 0, ctx->cancel_func,
> > ctx->cancel_baton, +                                 pool));
> > +
> > +      SVN_ERR (cat_local_file (path_or_url, out, adm_access,
> > revision, pool)); +
> > +      SVN_ERR (svn_wc_adm_close (adm_access));
> > +
> > +      return SVN_NO_ERROR;
> > +    }
>
> This is tricky.
>
> Formally, I'm not sure that peg_revision matters here.  I mean, you've
> already determined that path_or_url is a local path.  If you also know
> that revision is BASE or COMMITTED or something else that can be found
> locally, then from a pure correctness standpoint it really doesn't
> matter what peg_revision is -- the only question is, have you got the
> appropriate revision of that node at hand locally.
>
> However, I can see why (as a code simplification) you might want to
> check that peg_revision is also locally determinable here, so that you
> don't need special cases to handle identity switcheroos in the node's
> history.
>
> If this is what's going on, maybe a comment explaining this would be a
> good idea?

I missed some of the peg discussions, so I wasn't certain if it was really 
feasible to specify a peg revision on a local path.  I actually tried it 
on the command line, and the peg revision is something other than 
unspecified if you @REVISION syntax (my-local-file@BASE, for example).