Discussion:
svn info not setting exit status.
Mark E. Hamilton
2008-05-20 16:15:11 UTC
Permalink
I'm trying to check to see if a path exists in my repository or not.
However, when I use 'svn info' on an invalid URL it does not set the
exit status to a non-zero value as I expected. It also prints what seems
to be an extra blank line to stderr, as shown below.

$ svn info file:///svnroot/test_repos/boogers >/dev/null ; echo $?
file:///svnroot/test_repos/boogers: (Not a valid URL)

0
$

When I use 'svn checkout' on the same URL is reports that it doesn't
exist and sets the exit status to '1'.

$ svn checkout file:///svnroot/test_repos/boogers >/dev/null ; echo $?
svn: URL 'file:///svnroot/test_repos/boogers' doesn't exist
1
$

I'm using 1.5.0rc4.

Am I incorrect in expecting 'svn info' to set the exit status if the URL
doesn't exist? If so, what is the correct way to (silently) check to see
if something exists in the repository? I don't want to have to parse
stderr (or stdout, for that matter, which is why I'm redirecting it to
/dev/null.) All I want is a simple True/False (0/1 in the shell)
response as to whether the URL exists.
--
----------------
Mark E. Hamilton
Orion International Technologies, Inc.
Sandia National Laboratory, NM.
505-844-7666
Karl Fogel
2008-05-20 16:55:46 UTC
Permalink
Post by Mark E. Hamilton
I'm trying to check to see if a path exists in my repository or
not. However, when I use 'svn info' on an invalid URL it does not set
the exit status to a non-zero value as I expected. It also prints what
seems to be an extra blank line to stderr, as shown below.
$ svn info file:///svnroot/test_repos/boogers >/dev/null ; echo $?
file:///svnroot/test_repos/boogers: (Not a valid URL)
0
$
When I use 'svn checkout' on the same URL is reports that it doesn't
exist and sets the exit status to '1'.
$ svn checkout file:///svnroot/test_repos/boogers >/dev/null ; echo $?
svn: URL 'file:///svnroot/test_repos/boogers' doesn't exist
1
$
I'm using 1.5.0rc4.
Am I incorrect in expecting 'svn info' to set the exit status if the
URL doesn't exist? If so, what is the correct way to (silently) check
to see if something exists in the repository? I don't want to have to
parse stderr (or stdout, for that matter, which is why I'm redirecting
it to /dev/null.) All I want is a simple True/False (0/1 in the shell)
response as to whether the URL exists.
Your question is complex. First, note that the user might run 'svn
info' on multiple targets in one command, like:

$ svn info URL1 URL2 ... -or-
$ svn info PATH1 PATH2 ... -or even-
$ svn info URL1 PATH1 URL2 PATH2 ...

(The multi-target behavior was implemented in r13123, with trivial
bugfix followups in r13124 and r14688; URLs were added in r13144.)

In order to make the multi-target behavior work, we decided that a
non-existent target shouldn't cause svn to bail out, but should instead
print a warning and then continue to the next target. See this code
from subversion/svn/info-cmd.c:svn_cl__info():

for (i = 0; i < targets->nelts; i++)
{

[...]

err = svn_client_info2(truepath,
&peg_revision, &(opt_state->start_revision),
receiver, NULL, opt_state->depth,
opt_state->changelists, ctx, subpool);

/* If one of the targets is a non-existent URL or wc-entry,
don't bail out. Just warn and move on to the next target. */
if (err && err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE)
{
svn_error_clear(err);
SVN_ERR(svn_cmdline_fprintf
(stderr, subpool,
_("%s: (Not a versioned resource)\n\n"),
svn_path_local_style(target, pool)));
continue;
}
else if (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
{
svn_error_clear(err);
SVN_ERR(svn_cmdline_fprintf
(stderr, subpool,
_("%s: (Not a valid URL)\n\n"),
svn_path_local_style(target, pool)));
continue;
}
else if (err)
return err;

}
svn_pool_destroy(subpool);

if (opt_state->xml && (! opt_state->incremental))
SVN_ERR(svn_cl__xml_print_footer("info", pool));

return SVN_NO_ERROR;

That's the end of the function at the bottom there -- we just return
SVN_NO_ERROR unconditionally.

In passing, let me note a stylistic problem here so I won't forgt: if
we're going to svn_error_clear(err), then we ought to set err = NULL as
well, even though due to the current code flow it's not strictly
necessary. Yes, err will get reassigned from svn_client_info2() on the
next iteration of the loop, but that won't happen on the last iteration,
which that means that if the last target is non-existent, we'll have a
dangling error that we simply happen not to check. That's likely to be
a bug source someday: someone may add a check for 'err' for some other
reason, not realizing the subtleties of the loop's logic.

Okay, on to the real question:

We definitely should continue the loop even in case of error, so we try
every target. But when we do exit, should it be a non-zero exit code if
any target received an error? Currently, we exit with zero.

There may be precedents for this sort of situation, and if there are,
Subversion should follow them. But I don't know what they are. Does
anyone else?

-Karl
Eric Gillespie
2008-05-20 17:44:49 UTC
Permalink
Post by Karl Fogel
We definitely should continue the loop even in case of error, so we try
every target. But when we do exit, should it be a non-zero exit code if
any target received an error? Currently, we exit with zero.
If svn didn't successfully complete every task I gave it, it
should not exit zero. Note that this may be my fault ;->; I
remember making some of these commands warn and continue many
years ago...
Post by Karl Fogel
There may be precedents for this sort of situation, and if there are,
Subversion should follow them. But I don't know what they are. Does
anyone else?
0 ~% ls notexist .zshrc
ls: notexist: No such file or directory
.zshrc
2 ~% ls .zshrc
.zshrc

The '2' in my prompt is the exit code from ls.

[Aside: Karl, your Mail-followup-to field is broken; it lists
only the users list.]

--
Eric Gillespie <*> ***@pretzelnet.org
Karl Fogel
2008-05-20 18:25:22 UTC
Permalink
Post by Eric Gillespie
Post by Karl Fogel
We definitely should continue the loop even in case of error, so we try
every target. But when we do exit, should it be a non-zero exit code if
any target received an error? Currently, we exit with zero.
If svn didn't successfully complete every task I gave it, it
should not exit zero. Note that this may be my fault ;->; I
remember making some of these commands warn and continue many
years ago...
Post by Karl Fogel
There may be precedents for this sort of situation, and if there are,
Subversion should follow them. But I don't know what they are. Does
anyone else?
0 ~% ls notexist .zshrc
ls: notexist: No such file or directory
.zshrc
2 ~% ls .zshrc
.zshrc
The '2' in my prompt is the exit code from ls.
Okay. Patch undergoing 'make check' right now.
Post by Eric Gillespie
[Aside: Karl, your Mail-followup-to field is broken; it lists
only the users list.]
Well, the way it gets set is complicated, but yes, in that instance it
was "broken" because I was following up to a users@ post but then
cross-posting my reply to ***@. It's fine in this reply, though.
Thanks for noticing.

-K
Henrik Sundberg
2008-05-20 19:06:15 UTC
Permalink
Post by Karl Fogel
Post by Mark E. Hamilton
I'm trying to check to see if a path exists in my repository or
not. However, when I use 'svn info' on an invalid URL it does not set
the exit status to a non-zero value as I expected.
Having the same need, and using pysvn I get:
try:
inf = client.info2("%s/%s" % (url, sf), recurse=False)
except:
client.mkdir("%s/%s" % (url, sf), "Setting up a root for %s" % sf)
client.mkdir("%s/%s/branches" % (url, sf), "Adding branches")
client.mkdir("%s/%s/tags" % (url, sf), "Adding tags")
client.mkdir("%s/%s/trunk" % (url, sf), "Adding trunk")

I though that was ugly, I wanted to say:
if not client.is_url("%s/%s" % (url, sf)):
client.mkdir("%s/%s" % (url, sf), "Setting up a root for %s" % sf)
...
But that doesn't work, since is_url returns True if the first part of
url matches a repository.

In the shell you'll have to settle for return codes.
Would it be better to have a special command, instead of using a side
effect of the info-command?
Post by Karl Fogel
In order to make the multi-target behavior work, we decided that a
non-existent target shouldn't cause svn to bail out, but should instead
print a warning and then continue to the next target.
<snip>
Post by Karl Fogel
We definitely should continue the loop even in case of error, so we try
every target. But when we do exit, should it be a non-zero exit code if
any target received an error? Currently, we exit with zero.
In the case of the OP there is only need to check one url a time.
This ought to be a common need.
If only one url is given and that one doesn't exist, then it ought to
be ok with an error. Wouldn't it?

This could be extended to: Fail if all targets are missing.

/$
Mark E. Hamilton
2008-05-20 19:35:47 UTC
Permalink
Post by Henrik Sundberg
Post by Karl Fogel
Post by Mark E. Hamilton
I'm trying to check to see if a path exists in my repository or
not. However, when I use 'svn info' on an invalid URL it does not set
the exit status to a non-zero value as I expected.
inf = client.info2("%s/%s" % (url, sf), recurse=False)
client.mkdir("%s/%s" % (url, sf), "Setting up a root for %s" % sf)
client.mkdir("%s/%s/branches" % (url, sf), "Adding branches")
client.mkdir("%s/%s/tags" % (url, sf), "Adding tags")
client.mkdir("%s/%s/trunk" % (url, sf), "Adding trunk")
client.mkdir("%s/%s" % (url, sf), "Setting up a root for %s" % sf)
...
But that doesn't work, since is_url returns True if the first part of
url matches a repository.
In the shell you'll have to settle for return codes.
Would it be better to have a special command, instead of using a side
effect of the info-command?
I don't think a special command is necessary. I like the idea of
allowing the --quiet option for 'svn info', however, since all I'm doing
it testing for the existence (or non-existence) of something.
Post by Henrik Sundberg
Post by Karl Fogel
In order to make the multi-target behavior work, we decided that a
non-existent target shouldn't cause svn to bail out, but should instead
print a warning and then continue to the next target.
<snip>
Post by Karl Fogel
We definitely should continue the loop even in case of error, so we try
every target. But when we do exit, should it be a non-zero exit code if
any target received an error? Currently, we exit with zero.
In the case of the OP there is only need to check one url a time.
This ought to be a common need.
If only one url is given and that one doesn't exist, then it ought to
be ok with an error. Wouldn't it?
This could be extended to: Fail if all targets are missing.
A single URL should be no different in this case than multiple URLs; all
should be tested, and if one or more causes a failure that failure (more
accurately the last failure) should be returned to the user, so he/she
can decide how to handle it.
--
----------------
Mark E. Hamilton
Orion International Technologies, Inc.
Sandia National Laboratory, NM.
505-844-7666
Mark E. Hamilton
2008-05-20 19:22:34 UTC
Permalink
Post by Karl Fogel
We definitely should continue the loop even in case of error, so we try
every target. But when we do exit, should it be a non-zero exit code if
any target received an error? Currently, we exit with zero.
There may be precedents for this sort of situation, and if there are,
Subversion should follow them. But I don't know what they are. Does
anyone else?
I can't really speak to precedent, only what I think. If I ask svn to do
something, I want to be able to decide easily if I should continue based
on whether or not it was able to do what I asked. In the case of
executing 'svn info' on the command it is reasonable for a user to do
'svn info A B C' and not care about the exit status, because they can
see any errors on the screen.

However, when scripting some process I would never do more than one at a
time, because there is no easy way to tell which one failed. You should,
IMO, always do

svn info A || handle error
svn info B || handle error
svn info C || handle error

Also, for 'svn info' it is reasonable for it to continue to run if it
encounters an error since it is a read-only operation. What I have done
in the past in similar code is to return the exit status of the last
failed operation after the end of the loop. Knowing that one (or more)
failed is better than not knowing at all.


--
----------------
Mark E. Hamilton
Orion International Technologies, Inc.
Sandia National Laboratory, NM.
505-844-7666
Karl Fogel
2008-05-20 21:12:01 UTC
Permalink
Post by Mark E. Hamilton
I can't really speak to precedent, only what I think. If I ask svn to
do something, I want to be able to decide easily if I should continue
based on whether or not it was able to do what I asked. In the case of
executing 'svn info' on the command it is reasonable for a user to do
svn info A B C' and not care about the exit status, because they can
see any errors on the screen.
However, when scripting some process I would never do more than one at
a time, because there is no easy way to tell which one failed. You
should, IMO, always do
svn info A || handle error
svn info B || handle error
svn info C || handle error
Also, for 'svn info' it is reasonable for it to continue to run if it
encounters an error since it is a read-only operation. What I have
done in the past in similar code is to return the exit status of the
last failed operation after the end of the loop. Knowing that one (or
more) failed is better than not knowing at all.
Done in r31320.

Loading...