[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:27:42 +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?
>

In a meantime I've tried to import '/A/tags/1.0' folder in place of
'/A/tags/1.0/file.txt':

i.e. used:
svn propset svn:externals " -r1 ^/A/tags/1.0 import" .

instead of:
svn propset svn:externals " -r1 ^/A/tags/1.0/file.txt file.txt" import

and it worked (though of course this is not the way around, since I need
to import files, not folders).
But this tells me, that the problem relates to only external file
definitions.

Alex.

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

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