[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: bug report: svn client 1.7.x silently fails to fetch files via svn:externals under certain conditions.

From: Alex Siyanko <asiyanko_at_xdyne.com>
Date: Thu, 24 May 2012 14:07:09 +0300

On 5/24/2012 10:52 AM, Johan Corveleyn wrote:
> On Thu, May 24, 2012 at 1:57 AM, Alex Siyanko<asiyanko_at_xdyne.com> wrote:
>> On 5/23/2012 5:15 PM, Johan Corveleyn wrote:
>>> On Mon, May 21, 2012 at 2:41 PM, Alex Siyanko<asiyanko_at_xdyne.com> wrote:
>>>> On 5/21/2012 1:45 PM, Johan Corveleyn wrote:
>>>>
>>>> On Sat, May 19, 2012 at 5:59 PM, Alex Siyanko<asiyanko_at_xdyne.com> wrote:
>>>>
>>>> Hello,
>>>>
>>>> I've stumbled upon the following Subversion client 1.7.x bug:
>>>>
>>>> Under certain conditions SVN silently fails to fetch external file at
>>>> specified operative revision from repository into a working copy.
>>>> Here is the simplest scenario:
>>>>
>>>> 1) I create 'file.txt' and commit it to repository 'A/trunk' directory;
>>>> 2) then I copy entire 'A/trunk' directory to 'A/tags/1.0' using 'svn
>>>> copy
>>>> URL URL' command;
>>>> 3) next I create 'B' directory in the repository with one empty 'import'
>>>> subdirectory, which I want to use for importing 'A/tags/1.0/file.txt' via
>>>> svn:externals;
>>>> 4) to use explicit revision number in svn:externals property I run 'svn
>>>> list A/tags/1.0/file.txt -v' command, which gives me the last revision,
>>>> at
>>>> which file.txt was modified (say, revision 1).
>>>> 5) now I checkout 'B' into a working copy and set svn:externals property
>>>> over 'import' subdirectory as follows: ' -r1 ^/A/tags/1.0/file.txt
>>>> file.txt'
>>>> 6) finally I update 'B' working copy, which should fetch file.txt into
>>>> import directory; unfortunately, that doesn't happen - 'import' directory
>>>> remains empty, though svn reports no errors
>>>>
>>>> It is important to note, that this bug is not present in any SVN 1.6.x
>>>> client. It only manifests itself in SVN 1.7.x (up to its latest version
>>>> 1.7.5)
>>>> I tested it on Windows and Linux platforms using both pre-compiled
>>>> version
>>>> of svn client, which comes with TortoiseSVN, as well as svn client,
>>>> compiled
>>>> and installed from tar.
>>>> Also I tried to use both svn:// (with svnserve of 1.6.x and 1.7.x
>>>> versions)
>>>> and file:// access methods.
>>>> The result doesn't depend on the access method, neither it depends on the
>>>> version of the svnserve at the backend (in case of svn:// method ), so it
>>>> is
>>>> an svn client 1.7.x issue.
>>>>
>>>> Here is the script to reproduce the described bug:
>>>>
>>>> ##############################################################################################################
>>>> #!/bin/sh
>>>>
>>>> # You might need to adjust these lines to point to your
>>>> # compiled-from-source Subversion binaries, if using those:
>>>> if [ -z "$SVN" ]; then
>>>> SVN=`which svn`
>>>> SVNADMIN=`which svnadmin`
>>>> fi
>>>>
>>>> # Use English output.
>>>> LC_ALL=C; export LC_ALL
>>>>
>>>> # Select an access method. If svn://, the svnserve setup is
>>>> # handled automagically by this script; but if http://, then
>>>> # you'll have to configure it yourself first.
>>>> #
>>>> # URL=http://localhost/SOMETHING/repos
>>>> # URL=svn://localhost/repos
>>>> URL=file:///`pwd`/repos
>>>>
>>>> ${SVNADMIN} create repos
>>>>
>>>> echo "### Making a Greek Tree for import..."
>>>> mkdir import-me
>>>> mkdir import-me/A
>>>> mkdir import-me/A/trunk
>>>> mkdir import-me/A/tags
>>>> mkdir import-me/B
>>>> mkdir import-me/B/trunk
>>>> mkdir import-me/B/trunk/import
>>>> echo "This is the file 'file.txt'"> import-me/A/trunk/file.txt
>>>> echo "### Done."
>>>> echo ""
>>>> echo "### Importing it..."
>>>> (cd import-me; ${SVN} import -q -m "Initial import." ${URL})
>>>> echo "### Done."
>>>> echo ""
>>>>
>>>> echo "### copy A/trunk to A/tags/1.0 ###"
>>>> ${SVN} cp ${URL}/A/trunk ${URL}/A/tags/1.0 -m 'make 1.0 release of
>>>> project
>>>> A'
>>>> revision=`${SVN} ls ${URL}/A/tags/1.0/file.txt -v| grep -P -o '^\s+\d+' |
>>>> grep -P -o '\d+'`
>>>> echo "### 'A/tags/1.0/file.txt' Last Commit Revision: $revision ###"
>>>>
>>>> echo "### checkout B/trunk to wc ###"
>>>> ${SVN} co ${URL}/B/trunk wc
>>>> cd wc
>>>>
>>>> echo "### set svn:externals property over B/trunk/import to: '
>>>> -r$revision
>>>> ^/A/tags/1.0/file.txt file.txt' ###"
>>>> ${SVN} propset svn:externals " -r$revision ^/A/tags/1.0/file.txt
>>>> file.txt"
>>>> import
>>>>
>>>> echo "### update B/trunk working copy ###"
>>>> ${SVN} update
>>>>
>>>> echo "### list updated B/trunk wc contents ###"
>>>> ls -R
>>>>
>>>> ##############################################################################################################
>>>>
>>>>
>>>> The above script renders following output:
>>>>
>>>> --------------------------------------------------------------------------------------
>>>> ### Making a Greek Tree for import...
>>>> ### Done.
>>>>
>>>> ### Importing it...
>>>> ### Done.
>>>>
>>>> ### copy A/trunk to A/tags/1.0 ###
>>>>
>>>> Committed revision 2.
>>>> ### 'A/tags/1.0/file.txt' Last Commit Revision: 1 ###
>>>> ### checkout B/trunk to wc ###
>>>> A wc/import
>>>> Checked out revision 2.
>>>> ### set svn:externals property over B/trunk/import to: ' -r1
>>>> ^/A/tags/1.0/file.txt file.txt' ###
>>>> property 'svn:externals' set on 'import'
>>>> ### update B/trunk working copy ###
>>>> Updating '.':
>>>>
>>>> Fetching external item into 'import/file.txt':
>>>> External at revision 1.
>>>>
>>>> At revision 2.
>>>> ### list updated B/trunk wc contents ###
>>>> .:
>>>> import
>>>>
>>>> ./import:
>>>>
>>>> --------------------------------------------------------------------------------------
>>>>
>>>> The 'wc/import' directory is empty after update, when svn 1.7.x is used.
>>>> Again, that doesn't happen with svn 1.6.x.
>>>>
>>>> Thanks for the very detailed report, with reproduction script.
>>>>
>>>> However, I'm not sure if there is a bug here, and if there is, exactly
>>>> what the bug is ...
>>>>
>>>> The problem is that ^/A/tags/1.0/file.txt does not yet exist in r1. It
>>>> only appears after the copy, in r2. So I think you'd need "-r2
>>>> ^/A/tags/1.0/file.txt file.txt", or using peg revisions would be even
>>>> better: "^/A/tags/1.0/file.txt_at_2 file.txt"
>>>>
>>>> So "externals" isn't really at fault here. Apparently the "Last
>>>> changed revision" of ^/A/tags/1.0/file.txt is r1, the last revision in
>>>> which the file has changed (not the revision of the copy). I.e. "Last
>>>> changed revision" doesn't consider copies. I _think_ that's known and
>>>> desired behavior, which has always been that way. So I'm surprised
>>>> that this did work in 1.6, like you say. Has the behavior of 'svn
>>>> status' changed here?
>>>>
>>>>
>>>> Hi Johan and thank you for prompt reply. Nevertheless I don't agree with
>>>> your reasoning.
>>>> Let me give my point of view on this.
>>>>
>>>> I believe that svn:externals feature, when used with operative revision
>>>> (not
>>>> peg revision, this is important!)
>>>> should work the same way as other svn commands, such as for example 'cat'
>>>> or
>>>> 'co'.
>>>> In other words, when operative revision is used in svn:externals, it
>>>> should
>>>> cross copy command boundary.
>>>>
>>>> Getting back to my example, here is the question. Why then, if I, for
>>>> example, run:
>>>>
>>>> svn cat -r 1 file:///`pwd`/repos/A/tags/1.0/file.txt
>>>>
>>>>
>>>> or
>>>>
>>>> svn co -r 1 file:///`pwd`/repos/A/tags/1.0 tags-checkout
>>>>
>>>>
>>>> subversion happily prints file.txt contents or downloads it to a working
>>>> copy.
>>>> This happens because it is able to cross copy command boundary. BTW,
>>>> this
>>>> works fine both in 1.6.x and 1.7.x.
>>>> And this is the behavior, which is described in the Red Book "The Peg
>>>> Revision Algorithm" section.
>>>> Namely, it says:
>>>>
>>>>
>>>> ----------------------------------------------------------------------------------------------------------------
>>>>
>>>> The Subversion command-line client performs the peg revision algorithm
>>>> any
>>>> time it needs to resolve possible ambiguities in the paths and revisions
>>>> provided to it. Here's an example of such an invocation:
>>>>
>>>> $ svn command -r OPERATIVE-REV item_at_PEG-REV
>>>>
>>>> If OPERATIVE-REV is older than PEG-REV, the algorithm is as follows:
>>>>
>>>> Locate item in the revision identified by PEG-REV. There can be only one
>>>> such object.
>>>>
>>>> Trace the object's history backwards (through any possible renames) to
>>>> its
>>>> ancestor in the revision OPERATIVE-REV.
>>>>
>>>> Perform the requested action on that ancestor, wherever it is located, or
>>>> whatever its name might be or might have been at that time.
>>>>
>>>>
>>>> ----------------------------------------------------------------------------------------------------------------
>>>>
>>>> Please pay attention to "through any possible renames" phrase in item 2.
>>>>
>>>> So, I expect, that svn: externals rule, which uses operative revision,
>>>> should have identical behavior.
>>>> And, in fact, it does in 1.6.x. Also note, that 1.7.x "kind of has" it.
>>>> If you take a look at the output of the script, you'll see the following
>>>> lines:
>>>>
>>>> Fetching external item into 'import/file.txt':
>>>> External at revision 1.
>>>>
>>>> Which tells me, that file.txt has been successfully fetched - there are
>>>> no
>>>> error messages.
>>>> The thing is that it didn't really happen.
>>>> So this looks like a definite bug to me.
>>>>
>>>> I agree, that "file:///`pwd`/repos/A/tags/1.0/file.txt" doesn't exist at
>>>> revision 1.
>>>> Therefore, if I use the rule with peg revision in place of operative:
>>>>
>>>> ^/A/tags/1.0/file.txt_at_1 file.txt
>>>>
>>>>
>>>> svn responds with 'path not found' message, which, of course, is
>>>> expected
>>>> behavior.
>>>> But if I use operative revision, svn must cross copy command boundaries
>>>> according to official documentation.
>>>>
>>>> Am I right or not?
>>>> Please let me know your opinion.
>>> Sorry for the late response (I got sidetracked by other things). But I
>>> believe you're right. There is definitely something fishy here, or at
>>> least I don't know what the expected behavior should be.
>>>
>>> I see that you've filed an issue in the meantime (after confirming
>>> with stsp on irc). Hopefully someone can look into this a bit more in
>>> some not-too-distant future.
>>>
>>> For completeness of the archives, this is the issue:
>>>
>>> http://subversion.tigris.org/issues/show_bug.cgi?id=4185 (SVN client
>>> silently fails to fetch external file ancestor specified in
>>> svn:externals file definition via operative revision)
>>>
>> Hi Johan,
>>
>> thank you for taking your time to look at this.
>> I hope your opinion will help to draw more attention from the development
>> team.
>>
>> The thing is, that the in-house software, that I've developed on top of SVN
>> makes heavy use of this feature.
>> svn:externals definitions of described type are generated programmatically
>> for checking out compound working copies.
>> And so far I don't see any other easy way around this issue, then just
>> rolling back all clients back to 1.6.x.
> Have you tried if the following works?
>
> -r1 ^/A/tags/1.0/file.txt_at_2 file.txt
>
> So using a peg revision combined with the operational revision. It
> that works, maybe it could be a workaround?
>

Nope, that doesn't work either.
And I'm not surprised with this, since according to peg revision
algorithm description,
if peg revision is not specified, subversion assumes it to be equal to
HEAD (i.e. 2 in our case).
So explicit use of '@2' should render the same result.

Alex.

-- 
Alex Siyanko<br>
as_at_xdyne.com
Received on 2012-05-24 13:08:23 CEST

This is an archived mail posted to the Subversion Users mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.