Discussion:
svn status merges intersected external records into single row
Andrey
2017-06-13 13:47:42 UTC
Permalink
Here is the batch script for the windows:

```
@echo off

set REPODIR=test_repo
set "REPOROOT=%~dp0%REPODIR%"
set "REPOURL=file:///%REPOROOT:\=/%"
set WCROOT=%REPODIR%_root

if exist "%REPOROOT%\" rmdir /S /Q "%REPOROOT%"
if exist "%WCROOT%\" rmdir /S /Q "%WCROOT%"

mkdir "%REPOROOT%"
svnadmin create "%REPOROOT%"
mkdir "%WCROOT%"

svn co "%REPOURL%" "%WCROOT%"

rem creating tree w/o externals
mkdir "%WCROOT%/dir1/dir1_subdir1" || goto :EOF
mkdir "%WCROOT%/dir1/dir1_subdir2" || goto :EOF
mkdir "%WCROOT%/dir2/dir2_subdir1" || goto :EOF
mkdir "%WCROOT%/dir2/dir2_subdir2" || goto :EOF

svn add "%WCROOT%/*.*" || goto :EOF

svn ci "%WCROOT%" -m "rev1" || goto :EOF

rem update to the head
svn up "%WCROOT%" || goto :EOF

rem creating externals
type nul > "$externals.txt"

(
echo.^^/dir1/dir1_subdir1 ext/dir1_subdir1
echo.^^/dir1/dir1_subdir2 ext/dir1_subdir2
echo.^^/dir2/dir2_subdir1 dir2_subdir1
echo.^^/dir2/dir2_subdir2 dir2_subdir2
) >> "$externals.txt"

svn pset svn:externals -F "$externals.txt" "%WCROOT%" || goto :EOF

svn ci "%WCROOT%" -m "rev2" || goto :EOF

rem update to the head
svn up "%WCROOT%" || goto :EOF

rem show status
svn status "%WCROOT%"
```

The output:

```
Checked out revision 0.
svn: Skipping argument: E200025: 'test_repo_root/.svn' ends in a reserved
name
A test_repo_root\dir1
A test_repo_root\dir1\dir1_subdir1
A test_repo_root\dir1\dir1_subdir2
A test_repo_root\dir2
A test_repo_root\dir2\dir2_subdir1
A test_repo_root\dir2\dir2_subdir2
Adding test_repo_root\dir1
Adding test_repo_root\dir1\dir1_subdir1
Adding test_repo_root\dir1\dir1_subdir2
Adding test_repo_root\dir2
Adding test_repo_root\dir2\dir2_subdir1
Adding test_repo_root\dir2\dir2_subdir2
Committing transaction...
Committed revision 1.
Updating 'test_repo_root':
At revision 1.
property 'svn:externals' set on 'test_repo_root'
Sending test_repo_root
Committing transaction...
Committed revision 2.
Updating 'test_repo_root':

Fetching external item into 'test_repo_root\ext\dir1_subdir1':
External at revision 2.


Fetching external item into 'test_repo_root\ext\dir1_subdir2':
External at revision 2.


Fetching external item into 'test_repo_root\dir2_subdir1':
External at revision 2.


Fetching external item into 'test_repo_root\dir2_subdir2':
External at revision 2.

At revision 2.
X test_repo_root\dir2_subdir1
X test_repo_root\dir2_subdir2
X test_repo_root\ext

Performing status on external item at 'test_repo_root\dir2_subdir1':

Performing status on external item at 'test_repo_root\dir2_subdir2':

Performing status on external item at 'test_repo_root\ext\dir1_subdir1':

Performing status on external item at 'test_repo_root\ext\dir1_subdir2':
```

The externals list is:

```
X test_repo_root\dir2_subdir1
X test_repo_root\dir2_subdir2
X test_repo_root\ext
```

instead of:

```
X test_repo_root\dir2_subdir1
X test_repo_root\dir2_subdir2
X test_repo_root\ext\dir1_subdir1
X test_repo_root\ext\dir1_subdir2
```

This forces to use `svn pget svn:externals` + `a parser` instead of `svn
status` + `a filter` in scripting to extract the records set.
Johan Corveleyn
2017-06-29 22:06:49 UTC
Permalink
Post by Andrey
```
@echo off
set REPODIR=test_repo
set "REPOROOT=%~dp0%REPODIR%"
set "REPOURL=file:///%REPOROOT:\=/%"
set WCROOT=%REPODIR%_root
if exist "%REPOROOT%\" rmdir /S /Q "%REPOROOT%"
if exist "%WCROOT%\" rmdir /S /Q "%WCROOT%"
mkdir "%REPOROOT%"
svnadmin create "%REPOROOT%"
mkdir "%WCROOT%"
svn co "%REPOURL%" "%WCROOT%"
rem creating tree w/o externals
mkdir "%WCROOT%/dir1/dir1_subdir1" || goto :EOF
mkdir "%WCROOT%/dir1/dir1_subdir2" || goto :EOF
mkdir "%WCROOT%/dir2/dir2_subdir1" || goto :EOF
mkdir "%WCROOT%/dir2/dir2_subdir2" || goto :EOF
svn add "%WCROOT%/*.*" || goto :EOF
svn ci "%WCROOT%" -m "rev1" || goto :EOF
rem update to the head
svn up "%WCROOT%" || goto :EOF
rem creating externals
type nul > "$externals.txt"
(
echo.^^/dir1/dir1_subdir1 ext/dir1_subdir1
echo.^^/dir1/dir1_subdir2 ext/dir1_subdir2
echo.^^/dir2/dir2_subdir1 dir2_subdir1
echo.^^/dir2/dir2_subdir2 dir2_subdir2
) >> "$externals.txt"
svn pset svn:externals -F "$externals.txt" "%WCROOT%" || goto :EOF
svn ci "%WCROOT%" -m "rev2" || goto :EOF
rem update to the head
svn up "%WCROOT%" || goto :EOF
rem show status
svn status "%WCROOT%"
```
```
Checked out revision 0.
svn: Skipping argument: E200025: 'test_repo_root/.svn' ends in a reserved
name
A test_repo_root\dir1
A test_repo_root\dir1\dir1_subdir1
A test_repo_root\dir1\dir1_subdir2
A test_repo_root\dir2
A test_repo_root\dir2\dir2_subdir1
A test_repo_root\dir2\dir2_subdir2
Adding test_repo_root\dir1
Adding test_repo_root\dir1\dir1_subdir1
Adding test_repo_root\dir1\dir1_subdir2
Adding test_repo_root\dir2
Adding test_repo_root\dir2\dir2_subdir1
Adding test_repo_root\dir2\dir2_subdir2
Committing transaction...
Committed revision 1.
At revision 1.
property 'svn:externals' set on 'test_repo_root'
Sending test_repo_root
Committing transaction...
Committed revision 2.
External at revision 2.
External at revision 2.
External at revision 2.
External at revision 2.
At revision 2.
X test_repo_root\dir2_subdir1
X test_repo_root\dir2_subdir2
X test_repo_root\ext
```
```
X test_repo_root\dir2_subdir1
X test_repo_root\dir2_subdir2
X test_repo_root\ext
```
```
X test_repo_root\dir2_subdir1
X test_repo_root\dir2_subdir2
X test_repo_root\ext\dir1_subdir1
X test_repo_root\ext\dir1_subdir2
```
This forces to use `svn pget svn:externals` + `a parser` instead of `svn
status` + `a filter` in scripting to extract the records set.
Hi Andrey,

I tried your repro script and I'm seeing the same. However, I'm not
sure whether this is a bug or not ... The 'ext' directory in your
example is an unversioned "intermediate" directory. It's supported,
but it's quite special (I've never used externals like that).

So what you're seeing is that 'svn status' only reports one single X
line for the entire "unversioned intermediate directory", even if
there are multiple externals below it.

Summarized, you're saying that with this svn:externals definition:

^/dir1/dir1_subdir1 ext/dir1_subdir1
^/dir1/dir1_subdir2 ext/dir1_subdir2

(with ext being an unversioned intermediate directory)
running 'svn status' only reports one X line (for 'ext') instead of a
line for each external definition (like it does with other externals):

X test_repo_root\ext


Strangely, if you define externals into a *versioned* subdir, it's
reported with two lines, as you expect:

(continuing from the result of your script)
[[[
svn mkdir ext2
svn ci -mm
svn up
# edit svn:externals property and add two more lines like the
ext-ones, with ext2.
svn ci -mm
svn up
svn st
]]]

Output of 'svn st':
X dir2_subdir1
X dir2_subdir2
X ext
X ext2\dir1_subdir1
X ext2\dir1_subdir2
--
Johan
Daniel Shahaf
2017-06-30 02:12:55 UTC
Permalink
Post by Andrey
^/dir1/dir1_subdir1 ext/dir1_subdir1
^/dir1/dir1_subdir2 ext/dir1_subdir2
(with ext being an unversioned intermediate directory)
running 'svn status' only reports one X line (for 'ext') instead of a
X test_repo_root\ext
'ext' is not a file external and is not the root of a directory
external, so it shouldn't be printed with status 'X'; therefore this
output is a bug.

... Right?
Johan Corveleyn
2017-06-30 05:52:06 UTC
Permalink
Post by Daniel Shahaf
Post by Andrey
^/dir1/dir1_subdir1 ext/dir1_subdir1
^/dir1/dir1_subdir2 ext/dir1_subdir2
(with ext being an unversioned intermediate directory)
running 'svn status' only reports one X line (for 'ext') instead of a
X test_repo_root\ext
'ext' is not a file external and is not the root of a directory
external, so it shouldn't be printed with status 'X'; therefore this
output is a bug.
... Right?
Yeah, the more I think about it, the more I think it's a bug indeed.
--
Johan
Johan Corveleyn
2017-06-30 20:20:11 UTC
Permalink
Post by Johan Corveleyn
Post by Daniel Shahaf
Post by Andrey
^/dir1/dir1_subdir1 ext/dir1_subdir1
^/dir1/dir1_subdir2 ext/dir1_subdir2
(with ext being an unversioned intermediate directory)
running 'svn status' only reports one X line (for 'ext') instead of a
X test_repo_root\ext
'ext' is not a file external and is not the root of a directory
external, so it shouldn't be printed with status 'X'; therefore this
output is a bug.
... Right?
Yeah, the more I think about it, the more I think it's a bug indeed.
Apparently, it's not a bug, but is implemented explicitly this way.

Bert Huijben said the following about it on #svn-dev (irc):

[[[
<Bert> This feature was deliberately designed that way... I spend
quite some time to get that working again in WC-NG.

<Bert> I didn't know about that intermediate dir feature before that work on NG.

<Bert> That 'X' on the intermediate dir is produced to 'not show it as
unversioned dir'. Each and every (dir) external is reported separately
after the primary status output.

<jcorvel> Bert: X-feature ... strange. But the individual externals
below "unversioned" are not reported with 'X'. Is dat normal?

<jcorvel> Do you know why this feature was designed that way? Any way
to find out the rationale behind this? If we wanted to "not show it as
an unversioned dir" we might as well just have suppressed it ...

<Bert> We just don't recurse into unversioned dirs... we only show the root.

<jcorvel> Hm, okay, guess that makes sense from the status-walk logic
side of things ...

<jcorvel> it's still strange to see the unversioned
externals-parent-dir being reported with X ... as a user I'd expect
'X' to show the actual externals roots. Confusing ... but okay
]]]

Andrey, you might be able to parse the externals from the "Performing
status on external ..." lines as a workaround.
--
Johan
Andry
2017-07-01 18:45:28 UTC
Permalink
Hello Johan,

Friday, June 30, 2017, 11:20:11 PM, you wrote:

JC> Andrey, you might be able to parse the externals from the "Performing
JC> status on external ..." lines as a workaround.
It would be excessive that way. Better just to read the EXTERNALS
table from the wc.db directly.
--
Best regards,
Andry mailto:***@inbox.ru
Daniel Shahaf
2017-07-02 04:08:00 UTC
Permalink
Post by Andry
Hello Johan,
JC> Andrey, you might be able to parse the externals from the "Performing
JC> status on external ..." lines as a workaround.
It would be excessive that way. Better just to read the EXTERNALS
table from the wc.db directly.
The db schema may change arbitrarily between versions. If you insist
on this approach, the right way to do it is to check `pragma user_version;`
first and bail out if it's a newer value than your code knows how to handle.

The public API is what Johan suggested, or to use the libsvn_client bindings
in the language of your choice (C/java/python/perl/ruby).
Andry
2017-07-02 11:11:57 UTC
Permalink
Hello Daniel,
Post by Andry
Hello Johan,
JC> Andrey, you might be able to parse the externals from the "Performing
JC> status on external ..." lines as a workaround.
It would be excessive that way. Better just to read the EXTERNALS
table from the wc.db directly.
DS> The db schema may change arbitrarily between versions. If you insist
DS> on this approach, the right way to do it is to check `pragma user_version;`
DS> first and bail out if it's a newer value than your code knows how to handle.
Yes i know, thanx for the tip
--
Best regards,
Andry mailto:***@inbox.ru
Loading...