On Sat, Nov 19, 2016 at 05:53:26AM +0000, Daniel Shahaf wrote:
> Patrick Steinhardt wrote on Wed, Nov 09, 2016 at 12:54:08 +0100:
> > +++ b/subversion/svn/checkout-cmd.c
> > @@ -61,6 +61,144 @@
> >    Is this the same as CVS?  Does it matter if it is not?
> >  */
> >  
> > +static svn_error_t *
> > +listing_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,
> > +           apr_pool_t *scratch_pool)
> > +{
> > +  size_t *count = (size_t *) baton;
> > +
> > +  (*count)++;
> > +
> 
> Would it make sense, at this point, to raise an error
> (SVN_ERR_CEASE_INVOCATION or SVN_ERR_ITER_BREAK) if count>1, so as to
> not iterate the remaining dirents?

Yes, it does make sense indeed.

> 
> > +  return SVN_NO_ERROR;
> > +}
> > +
> > +/* Check if the target directory which should be checked out to
> > + * is a valid target directory. A target directory is valid if we
> > + * are sure that a checkout to the directory will not create any
> > + * unexpected situations for the user. This is the case if one of
> > + * the following criteria is true:
> > + *
> > + * - the target directory does not exist
> > + * - the target directory is empty
> > + * - the target directory is the same repository with the same
> > + *   relative URL as the one that is to be checked out (e.g. we
> > + *   resume a checkout)
> > + * - the repository that is to be checked out is empty
> > + */
> > +static svn_error_t *
> > +verify_checkout_target(const char *repo_url,
> > +                       const char *target_dir,
> > +                       const svn_opt_revision_t *peg_revision,
> > +                       const svn_opt_revision_t *revision,
> > +                       svn_client_ctx_t *ctx,
> > +                       apr_pool_t *pool)
> > +{
> > +  svn_node_kind_t kind;
> > +  apr_pool_t *scratch_pool;
> > +  const char *absolute_path;
> > +  size_t count = 0;
> > +  svn_wc_status3_t *status;
> > +  svn_error_t *error;
> 
> Variables of type 'svn_error_t *' are conventionally named 'err'.

Okay.

> > +  svn_boolean_t empty;
> > +
> > +  scratch_pool = svn_pool_create(pool);
> > +
> > +  SVN_ERR(svn_dirent_get_absolute(&absolute_path,
> > +                                  target_dir,
> > +                                  pool));
> > +
> > +  SVN_ERR(svn_io_check_path(absolute_path,
> > +                            &kind,
> > +                            pool));
> > +
> > +  /* If the directory does not exist yet, it will be created
> > +   * anew and is thus considered valid. */
> > +  if (kind == svn_node_none)
> > +    return SVN_NO_ERROR;
> > +
> > +  /* Checking out to a file or symlink cannot work. */
> > +  if (kind != svn_node_dir)
> > +    return svn_error_createf(
> > +        SVN_ERR_ILLEGAL_TARGET,
> > +        NULL,
> > +        _("Rejecting checkout to existing %s '%s'"),
> > +        svn_node_kind_to_word(kind),
> 
> Would using 'kind' through %s cause a problem for translators?
> It would result in a nominative English noun being used in a dative
> local-language context.

Is there any recommendation what to use instead here?

> > +        absolute_path);
> 
> Paths in error messages should be converted to local style
> (with svn_dirent_local_style()).

Okay.

> > +  error = svn_wc_status3(&status,
> > +                         ctx->wc_ctx,
> > +                         absolute_path,
> > +                         pool,
> > +                         scratch_pool);
> > +
> > +  /* If the remote repository UUID and working copy UUID are the
> > +   * same and if the relative paths inside the repository match,
> > +   * we assume that the command is a resumed checkout. */
> > +  if (error == SVN_NO_ERROR)
> > +    {
> > +      if (repo_relpath
> > +          && !strcmp(status->repos_uuid, repo_uuid)
> > +          && !strcmp(status->repos_relpath, repo_relpath))
> > +        return SVN_NO_ERROR;
> > +    }
> > +  else
> > +    {
> > +      svn_error_clear(error);
> 
> Shouldn't you check for a specific error code here?  I.e.,
> 
>    if (err == SVN_NO_ERROR)
>        ⋮
>    else if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
>        svn_error_clear();
>    else
>        SVN_ERR(err)
> 
> (possibly a few more error codes in the second branch)?
> 
> To catch the case that ABSOLUTE_PATH denotes a wedged working copy,
> for example.

Yeah, I was reasoning about the same thing here while I wrote
this. It probably makes sense to do.

> > +  SVN_ERR(svn_client_list4(repo_url,
> > +                           pool));
> > +
> > +  /* If the remote respotiory has more than one file (that is, it
> 
> Typo for "repository".
> 
> > +   * is not an empty root directory only), we refuse to check out
> > +   * into a non-empty target directory. Otherwise Subversion
> > +   * would create tree conflicts. */
> > +  if (count > 1)
> > +    return svn_error_createf(
> > +      SVN_ERR_ILLEGAL_TARGET,
> > +      NULL,
> > +      _("Rejecting checkout of non-empty repository into non-empty 
> > directory '%s'"),
> 
> I think it would be more accurate to s/repository/repository URL/
> or s/repository/repository directory/.
> 
> > +      absolute_path);
> 
> Again svn_dirent_local_style().
> 
> > +
> > +  svn_pool_clear(scratch_pool);
> > +
> 
> This pool usage is not idiomatic.
> 
> Does this function (verify_checkout_target()) return a value to its
> caller?  If it does, then let its signature have two pools.  If it does
> not, then let it take a single 'apr_pool_t *scratch_pool' argument, use
> that pool for both pool arguments of callees, and leave that pool for
> its (verify_checkout_target()'s) caller to clear.  (In this case,
> probably at apr_terminate().)

No, `verify_checkout_target()` does not return a value, it only
indicates an error if the target is not valid. The reason why I
created the scratch pool was that I have to pass both a result
and scratch pool to `svn_client_get_repos_root`, where I wasn't
exactly sure which semantics one may expect when passing the same
pool as both result and scratch pool to a callee.

So if I understand it correctly I can expect
`svn_client_get_repos_root` to behave correct in that case, so I
can pass a scratch pool twice?

> The rationale for this is (quoting HACKING):
> 
>     Functions should not create/destroy pools for their operation; they
>     should use a pool provided by the caller. Again, the caller knows
>     more about how the function will be used, how often, how many times,
>     etc. thus, it should be in charge of the function's memory usage.
> 
> >
> 
> As to the actual business logic, it seems okay to me (meaning I'm +0),
> however, I'll leave it for others to review it in detail.
> 
> Thanks for the detailed comments and log message.
> 
> Cheers,
> 
> Daniel
> 
> P.S. Two more minor points: One, listing_cb() might grow a "This
> implements the `svn_client_list_func2_t' interface." docstring.  Two,
> I found the variable name "absolute_path" somewhat opaque; I would
> suggest a name based on the semantics, rather than the data type, e.g.,
> "target" or "candidate_target_directory".

Thanks for your review.

Regards
Patrick

Attachment: signature.asc
Description: PGP signature

Reply via email to