Wednesday, August 1, 2007

An awesome xargs option and cleaning up SVN accidents

I started using a wonderfully helpful option for xargs recently, after Master Ian showed me its use in a particularly thorny case. Before seeing the cool option, I will give the case as an example of its use:

I am still learning about the best (or even proper) way to use some aspects of SVN. In this particular case, I need to take all the files in a directory that was in the repo, move them into a new directory in the same directory, add another new directory, and copy new files into that.

To better explain the example, here is the structure I had in place, initially:
  • Directory 1 (In SVN)
    • FilesetA
And this is what I wanted in the end:
  • Directory 1
    • Directory1.1
      • FilesetA
    • Directory1.2
      • FilesetB
What I should have done is: made the 2 new directories (1.1 and 1.2) within the first one, copied the new files into one (FilesetB), add and commit both new directories and their contents. Then I should have run svn mv on the files in the top directory (FilesetA) into the second new directory.

What I actually did was: created the two new directories, simply mv'ed FilesetA into one, copied in FilesetB into the other, and then svn add'ed the two new directories and their contents. Then I had a problem. I still had FilesetA in Directory 1 in the repo, but not locally. So I needed to svn rm those, but I could not since they did not exist locally any more!

In the end, I copied the FilesetA out into a temp directory, when up to the directory above my repository, check the entire thing out again, svn rm'ed the FilesetA in Directory 1, and then needed to add FilesetA back into Directory 1.1. This was why I moved it to a temp directory. The problem was that that set had several nested directories with .svn directories in them. I had to remove these before adding them into the SVN'ed directories, else mass confusion would result. So I ran:
find . -type d | xargs -I % rm -rf %/.svn

This gem found all directories from the current directory down, and passed them to rm -rf. However, I could not just pipe the results and use xargs, as I needed to append "/.svn" to specify the right directories to remove. This is where -I comes in handy. This option replaces all instances of the string following it with the results of the first command (before the pipe). In this case the string was "%", for similarity to Python syntax, but any string could be used. The man page uses "replace-str". So in this particular case, if FilesetA included Directory 1.1.1 and 1.1.2, the command would resolve to: "rm -rf Directory1.1.1/.svn Directory1.1.2/.svn", which is precisely what was needed!

For some reason, I had a hard time understanding the option from the man page, but Ian translated it to Python for me:
for dir in [find . -type d]:
cmd = "rm -rf %s/.svn" % dir
os.popen(cmd)
This was much clearer to me. What it basically comes down to is:
OPERATION1 | xargs -I replaceme ANOTHEROPERATION replaceme OTHERTHINGS

translates into
ANOTHEROPERATION OPERATIO1RESULTS OTHERTHINGS
.

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home