You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Martin Obermeir <ma...@lauterbach.com> on 2022/02/11 08:22:25 UTC

svn copy --pin-externals pins relative paths to non existing revision/path

Hi,

When using `svn copy --pin-externals` to create a tag, svn:externals 
with a relative path get pinned a non existing path: They get pinned to 
the revision before the commit, but the path doesn't exist yet in that 
revision. I expected them to be pinned to the revision which gets 
created during the svn copy operation.

In the example below:
   actual result: A/D - ../B/lambda@2 lambda
   expected result: A/D - ../B/lambda@3 lambda

Please find the script to reproduce this attached. Commented excerpt:

   cd A/D/
   svn propset svn:externals "../B/lambda lambda" . # relative path
   svn commit -m "msg1" # creates revision 2
   cd ../..
   svn copy --pin-externals ${URL}/trunk ${URL}/tags/pinnedExternals -m 
"msg2" # creates revision 3
   svn switch ^/tags/pinnedExternals
   # gives warnings:
   #   svn: warning: W205011: Error handling externals definition for 
'A/D/lambda':
   #   svn: warning: W170000: URL 
'file:///tmp/pinExternalsBug/repos/tags/pinnedExternals/A/B/lambda' at 
revision 2 doesn't exist
   svn propget -R svn:externals
   # gives: A/D - ../B/lambda@2 lambda
   #   i.e. pinned to revision 2, but the path doesn't exist (created in 
revision 3)
   #   I would expect: A/D - ../B/lambda@3 lambda


Tested on Kubuntu 20.04.3 LTS and SUSE Linux Enterprise Server 15 SP3  
(x86_64) with:
- todays trunk (Revision: 1897960): svn, version 1.15.0-dev (under 
development) compiled Feb 11 2022, 08:01:11 on x86_64-pc-linux-gnu
- svn, version 1.14.1 (r1886195)
- svn, version 1.13.0 (r1867053)   compiled Mar 24 2020, 12:33:36 on 
x86_64-pc-linux-gnu
- svn, version 1.10.6 (r1863367)

Best regards
Martin

Re: svn copy --pin-externals pins relative paths to non existing revision/path

Posted by Martin Obermeir <ma...@lauterbach.com>.
Hi Stefan,

thank you very much for your detailed answer!

Your explanations very much make sense to me. I understand that a 
universal solution for all types of externals is difficult or maybe even 
impossible.

Probably my point of view on svn:externals is a bit different, because 
we quite often use them like softlinks inside a repository trunk or 
branch (it's a way to have one source file in two different 
directories). For us, externals with relative paths are allowed to be 
unpinned, while references to other repositories are enforced to be 
always pinned. The idea is that a every newly created branch or tag will 
automatically be valid (referencing relative externals only inside 
itself). In other words: a tag should not reference a file from 
trunk@HEAD, because this can render the tag unusable later on.

In my case, I don't really need the --pin-externals feature. When I 
noticed the option, it made sense to me and I tried to use it. Then I 
didn't find any bug report mentioning this and thought I let you know.

The solution I will go for will probably be a script, which

1. pins unpinned externals in the trunk or branch
2. creates the tag from it
3. reverts the pinning in the trunk or branch

(I know that for SVN a tag is nothing else than any other branch, but I 
like to avoid additional commits to tags.)

> The client could at least check whether the path is is pinning does in
> fact exist. It could either error out if the path cannot be found, or
> simply leave the external alone and avoid pinning it.
If it is possible to check the path, both options make sense to me. I 
don't know how complex this will get and if it's worth the effort. If 
you will go for the latter, --pin-externals would work for my use-case.

Another solution I could imagine: Pin all externals, which can be 
resolved at the time of creating the tag/branch, avoid pinning all 
others and throw corresponding warnings. This could be an approach for 
any kind of external. In my repro-template.sh example, the client could 
notice that "../B/lambda@2 lambda" will not exist in the new tag and 
keep it untouched at "../B/lambda lambda". Even if the actual new 
revision can not be known by the client, it knows that it must be at 
least HEAD+1, so @2 does for sure not exist. I hope I didn't miss anything.

Best regards,
Martin

On 11.02.22 23:30, Stefan Sperling wrote:
> On Fri, Feb 11, 2022 at 09:22:25AM +0100, Martin Obermeir wrote:
>> Hi,
>>
>> When using `svn copy --pin-externals` to create a tag, svn:externals with a
>> relative path get pinned a non existing path: They get pinned to the
>> revision before the commit, but the path doesn't exist yet in that revision.
>> I expected them to be pinned to the revision which gets created during the
>> svn copy operation.
>>
>> In the example below:
>>    actual result: A/D - ../B/lambda@2 lambda
>>    expected result: A/D - ../B/lambda@3 lambda
>>
>> Please find the script to reproduce this attached. Commented excerpt:
>>
>>    cd A/D/
>>    svn propset svn:externals "../B/lambda lambda" . # relative path
>>    svn commit -m "msg1" # creates revision 2
>>    cd ../..
>>    svn copy --pin-externals ${URL}/trunk ${URL}/tags/pinnedExternals -m
>> "msg2" # creates revision 3
>>    svn switch ^/tags/pinnedExternals
>>    # gives warnings:
>>    #   svn: warning: W205011: Error handling externals definition for
>> 'A/D/lambda':
>>    #   svn: warning: W170000: URL
>> 'file:///tmp/pinExternalsBug/repos/tags/pinnedExternals/A/B/lambda' at
>> revision 2 doesn't exist
>>    svn propget -R svn:externals
>>    # gives: A/D - ../B/lambda@2 lambda
>>    #   i.e. pinned to revision 2, but the path doesn't exist (created in
>> revision 3)
>>    #   I would expect: A/D - ../B/lambda@3 lambda
>>
>>
>> Tested on Kubuntu 20.04.3 LTS and SUSE Linux Enterprise Server 15 SP3
>> (x86_64) with:
>> - todays trunk (Revision: 1897960): svn, version 1.15.0-dev (under
>> development) compiled Feb 11 2022, 08:01:11 on x86_64-pc-linux-gnu
>> - svn, version 1.14.1 (r1886195)
>> - svn, version 1.13.0 (r1867053)   compiled Mar 24 2020, 12:33:36 on
>> x86_64-pc-linux-gnu
>> - svn, version 1.10.6 (r1863367)
>>
>> Best regards
>> Martin
>
> Hi Martin,
>
> Thank you for this report. This is a problem which was already present in
> the commit which added this feature (https://svn.apache.org/r1659395).
>
> I am afraid it is impossible to implement a solution for the issue as
> you have presented it because your desired solution has an inherent
> chicken-and-egg problem:
>
> The external definition is created by the client as part of creating the
> new commit. At this time, the new revision number is not yet known.
> The client only learns about the new revision number after the commit has
> been created on the server. And the client must prepare properties which
> contain external definitions as part of creating the commit. So there is
> an inherent contradiction between the behaviour you would like to see and
> the way the system works internally.
>
> The revision number cannot even be inferred as something like HEAD+1 because
> the server can process commits from multiple clients in parallel while clients
> upload data, assigning a new number to whichever commit finishes first.
>
> The best suggestion I have is to only refer to already existing source paths
> in externals definitions added with your commit which creates your new tag.
> This means instead of using a relative external that points inside the path
> space of your new tag, use a path that points into trunk or some other branch
> where the same files and directories already exist. Because any tag created
> by a URL-URL copy is a copy of something that already exists somewhere else
> in the repository, this should always be possible, should it not?
> Once the tag has been created and the new revision number is known, you
> could then make a subsequent commit which manually pins the external to a
> path which now exists inside the tag's path space, if you prefer that.
>
> Does this make sense?
>
> The behaviour exposed by your script is certainly not ideal.
> In the URL-URL copy case the client does not check whether the pinned
> paths even exist!
> The client could at least check whether the path is is pinning does in
> fact exist. It could either error out if the path cannot be found, or
> simply leave the external alone and avoid pinning it.
>
> Verifying externals in general is not an easy problem. If an external
> definition is wrong or no longer working due to circumstances such as
> URLs having become unusable, SVN will error out when trying to use the
> external. There is little we can do about that, as it is somewhat
> inherent in the design of the externals feature. Any external that is
> valid today could become invalid tomorrow.
>
> Regards,
> Stefan


Re: svn copy --pin-externals pins relative paths to non existing revision/path

Posted by Stefan Sperling <st...@elego.de>.
On Fri, Feb 11, 2022 at 09:22:25AM +0100, Martin Obermeir wrote:
> Hi,
> 
> When using `svn copy --pin-externals` to create a tag, svn:externals with a
> relative path get pinned a non existing path: They get pinned to the
> revision before the commit, but the path doesn't exist yet in that revision.
> I expected them to be pinned to the revision which gets created during the
> svn copy operation.
> 
> In the example below:
>   actual result: A/D - ../B/lambda@2 lambda
>   expected result: A/D - ../B/lambda@3 lambda
> 
> Please find the script to reproduce this attached. Commented excerpt:
> 
>   cd A/D/
>   svn propset svn:externals "../B/lambda lambda" . # relative path
>   svn commit -m "msg1" # creates revision 2
>   cd ../..
>   svn copy --pin-externals ${URL}/trunk ${URL}/tags/pinnedExternals -m
> "msg2" # creates revision 3
>   svn switch ^/tags/pinnedExternals
>   # gives warnings:
>   #   svn: warning: W205011: Error handling externals definition for
> 'A/D/lambda':
>   #   svn: warning: W170000: URL
> 'file:///tmp/pinExternalsBug/repos/tags/pinnedExternals/A/B/lambda' at
> revision 2 doesn't exist
>   svn propget -R svn:externals
>   # gives: A/D - ../B/lambda@2 lambda
>   #   i.e. pinned to revision 2, but the path doesn't exist (created in
> revision 3)
>   #   I would expect: A/D - ../B/lambda@3 lambda
> 
> 
> Tested on Kubuntu 20.04.3 LTS and SUSE Linux Enterprise Server 15 SP3 
> (x86_64) with:
> - todays trunk (Revision: 1897960): svn, version 1.15.0-dev (under
> development) compiled Feb 11 2022, 08:01:11 on x86_64-pc-linux-gnu
> - svn, version 1.14.1 (r1886195)
> - svn, version 1.13.0 (r1867053)   compiled Mar 24 2020, 12:33:36 on
> x86_64-pc-linux-gnu
> - svn, version 1.10.6 (r1863367)
> 
> Best regards
> Martin


Hi Martin,

Thank you for this report. This is a problem which was already present in
the commit which added this feature (https://svn.apache.org/r1659395).

I am afraid it is impossible to implement a solution for the issue as
you have presented it because your desired solution has an inherent
chicken-and-egg problem:

The external definition is created by the client as part of creating the
new commit. At this time, the new revision number is not yet known.
The client only learns about the new revision number after the commit has
been created on the server. And the client must prepare properties which
contain external definitions as part of creating the commit. So there is
an inherent contradiction between the behaviour you would like to see and
the way the system works internally.

The revision number cannot even be inferred as something like HEAD+1 because
the server can process commits from multiple clients in parallel while clients
upload data, assigning a new number to whichever commit finishes first.

The best suggestion I have is to only refer to already existing source paths
in externals definitions added with your commit which creates your new tag.
This means instead of using a relative external that points inside the path
space of your new tag, use a path that points into trunk or some other branch
where the same files and directories already exist. Because any tag created
by a URL-URL copy is a copy of something that already exists somewhere else
in the repository, this should always be possible, should it not?
Once the tag has been created and the new revision number is known, you
could then make a subsequent commit which manually pins the external to a
path which now exists inside the tag's path space, if you prefer that.

Does this make sense?

The behaviour exposed by your script is certainly not ideal.
In the URL-URL copy case the client does not check whether the pinned
paths even exist!
The client could at least check whether the path is is pinning does in
fact exist. It could either error out if the path cannot be found, or
simply leave the external alone and avoid pinning it.

Verifying externals in general is not an easy problem. If an external
definition is wrong or no longer working due to circumstances such as
URLs having become unusable, SVN will error out when trying to use the
external. There is little we can do about that, as it is somewhat
inherent in the design of the externals feature. Any external that is
valid today could become invalid tomorrow.

Regards,
Stefan