2007-07-16

Restore .svn in Keynote/Pages documents

Subversion stores its metadata in a directory called ".svn" that lies in every directory under version control. Keynote, Pages, and some other applications on Mac OS X store their documents in directories that look like files in the Finder. However, for Subversion they are normal directories and as such contain a ".svn" when under Subversion control.

Unfortunately, Keynote/Pages delete the ".svn" metadata-directories when a document is saved. This breaks Subversion: on the next commit or update you get the error "containing working copy admin area is missing". This bug is known since years but has not been fixed.

As a workaround, I've written a shellscript that restores the deleted ".svn" files. You can download it here.


Update 2008-09-16: I fixed a bug that could lead to the deletion of all contents of folders with extended privileges.

Update 2008-04-09: I created an Automator workflow so that the .svn folder recovery can be started from a document's context menu in Finder.

Update 2008-04-09: I improved error handling when the document is not under version control or has been an ordinary file before.

Update 2008-02-19: I incorporated the improvements from the comments. Thank you!

Kommentare:

Petri.Sirkkala hat gesagt…

Great work! This issue really should be addressed in Subversion. Thanks for this workaround.

On the other hand, it would be interesting to implement a folder action or such, that would keep the .svn in place.

Or a filesystem that would allow zip files as folders. :)

Petri.Sirkkala hat gesagt…

It might be nice to have double quotes around all $1 variables. This would allow using svnRestore in folders that have spaces in their name.

Here is a diff for them:
[1]Petri@laavu-zapto-org:bin $ diff -e svnRecover.1 svnRecover
19,20c
rm -rf "$1" && \
mv -f ___temp_svnRecover___ "$1"
.
16c
mv "$1/$i" ___temp_svnRecover___/$i
.
13,14c
svn update "$1" && \
(for i in `(cd "$1"; find . -name ".svn" -type d; cd ..)`; do
.
11c
mv "$1" ___temp_svnRecover___ && \
.

Percy hat gesagt…

I made my own script after having similar problems, should have just Googled first and found yours. I think we both are doing virtually the same work. I believe mine can handle spaces inside of the "packge" folder, if there happens to be any. It also handles spaces in the root folder.

The IFS variable is a BASH system variable for splitting words. I tried \n but that didn't seem to work as expected. It also has status messages echo'd out, which are totally unnecessary, but I like having them. Mine also checks to make sure that the recently updated path is still a directory, in case for some odd reason it doesn't exist in the latest revision or isn't a dir anymore (probably quite rare, I know, but just an extra step in checking).

Take what you want from it...

#!/bin/bash
IFS="
"

# must be dir!
if [ ! -d "$1" ]
then
echo Path is not a directory.
exit
fi

# get info
dir=`dirname "$1"`
base=`basename "$1"`

# go to dir
cd "$dir"

# prefix
prefix="tmp"
prefixi=1

# does it exist?
while [ -x "$prefix.$base" ]
do
prefix="tmp$prefixi"
prefixi=$(( prefixi + 1 ))
done

# move to temp
echo Moving to temp location
mv "$base" "$prefix.$base"

# update
echo SVN Update
svn update -q "$base"

# check to make sure it's a dir!
if [ ! -d "$base" ]
then
echo Updated path is not a folder! Restoring original!
mv "$prefix.$base" "$base"
exit
fi

# go to dir
echo Moving .svn directories
cd "$base"

# find .svn dirs
for foo in `find . -type d -name .svn`
do
if [ -d ../"$prefix.$base"/"`dirname "$foo"`" ]
then
# only move it if the folder exists in the modified version
mv "$foo" ../"$prefix.$base"/"`dirname "$foo"`"
fi
done

# replace
echo Replacing
cd ..
rm -Rf "$base"
mv "$prefix.$base" "$base"

Michael Czeiszperger hat gesagt…

Has anyone really gotten this to work? I tried running it on an updated pages document directory, and only got errors :-(

[Tempelhuter:Documents/Services/Samples] czei% svnrecover wpi_load_testing_prices.pages
A wpi_load_testing_prices.pages
A wpi_load_testing_prices.pages/thumbs
A wpi_load_testing_prices.pages/thumbs/page_thumb_1-1.tiff
A wpi_load_testing_prices.pages/user_capacity.tiff
A wpi_load_testing_prices.pages/web_performance_baseline_bandwidth.jpg
A wpi_load_testing_prices.pages/index.xml.gz
A wpi_load_testing_prices.pages/web_perf_sample_summary.jpg
A wpi_load_testing_prices.pages/.typeAttributes.dict
A wpi_load_testing_prices.pages/Contents
A wpi_load_testing_prices.pages/Contents/PkgInfo
Updated to revision 195.
mv: rename wpi_load_testing_prices.pages/./thumbs/.svn to ___temp_svnRecover___/./thumbs/.svn: No such file or directory

Daniel Sadilek hat gesagt…

Michael, you could try the updated version.

oferrer hat gesagt…
Dieser Kommentar wurde vom Autor entfernt.
oferrer hat gesagt…

Excellent work! thank you much for sharing this, it saved me quite a long time of researching. It works great, however if you have an svn repository with many different files in Pages, Keynote, and Numbers, all in different directories, specifying each file that has been changed every time a commit is needed is not very practical.

I have modified your script to take care of this. What I do is I have the script on the 'root' of my svn checkout, and I just call the script from there and it will find every file that needs to be fixed inside of the checkout directory. At the top of the script is a variable called fix_extensions in which you can add more extensions that have this problem should anyone find anymore, the default is:

fix_extensions=(pages key numbers)

That takes care of everything from iWork, but I don't know if any other software has the same bug, so that way it's easy to add more extensions.

You can find the revised script here:

http://misc.oscarferrer.com/fix_svn.sh

Feel free to use it or modify it as you wish. Thanks again, and I hope my changes help someone else.

Oscar.

joe S. hat gesagt…

Thanks to Daniel!

I had a couple issues when I used his code:

1.) there were leftover svn files that needed to be cleaned up before his code could restore the svn directories.

2.) the version of subversion I was using was outdated and his code wasn't compatible.

Daniel was incredibly helpful and generous in assisting me with my problems (which likely arise from my lack of knowledge, rather than anything to do with his code).

The following is an excerpt of our dialogue:

Daniel:

"for the first problem you can look here: http://sadilek.blogspot.com/2008/02/remove-svn-folders.html.
The problem is that there are still some .svn folders inside the document folder.

Regarding the second problem, I assume that Cornerstone is a graphical client? The script uses the command line version of svn which seems to be outdated on your machine. You should update it. (I use the svn that comes with http://www.macports.org/)"

I actually ended up getting a new subversion from collab: http://www.collab.net/downloads/subversion/

Regarding the svn cleanup code he provided, I am currently trying to learn more about incorporating the terminal in my subversion workflow (I use Cornerstone as a gui), so I haven't successfully cleaned my folders yet, but am confident I will be able to after a little bit of study.

Thanks again Daniel!

-Joe S.