Support <remove-project name="X"> in manifest to remove/replace X

The manifest files now permit removing a project so the user can
either keep it out of their client, or replace it with a different
project using an entirely different configuration.

Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 5c014d6..562e66e 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -22,6 +22,7 @@
 <!DOCTYPE manifest [
   <!ELEMENT manifest (remote*,
                       default?,
+                      remove-project*,
                       project*,
                       add-remote*)>
 
@@ -47,6 +48,9 @@
   <!ATTLIST add-remote fetch        CDATA #REQUIRED>
   <!ATTLIST add-remote review       CDATA #IMPLIED>
   <!ATTLIST add-remote project-name CDATA #IMPLIED>
+
+  <!ELEMENT remove-project (EMPTY)>
+  <!ATTLIST remove-project name  CDATA #REQUIRED>
 ]>
 
 A description of the elements and their attributes follows.
@@ -155,6 +159,18 @@
 these additional remotes.
 
 
+Element remove-project
+----------------------
+
+Deletes the named project from the internal manifest table, possibly
+allowing a subsequent project element in the same manifest file to
+replace the project with a different source.
+
+This element is mostly useful in the local_manifest.xml, where
+the user can remove a project, and possibly replace it with their
+own definition.
+
+
 Local Manifest
 ==============
 
diff --git a/manifest.py b/manifest.py
index 9137371..32a7e51 100644
--- a/manifest.py
+++ b/manifest.py
@@ -138,6 +138,16 @@
             self.manifestFile
 
     for node in config.childNodes:
+      if node.nodeName == 'remove-project':
+        name = self._reqatt(node, 'name')
+        try:
+          del self._projects[name]
+        except KeyError:
+          raise ManifestParseError, \
+                'project %s not found' % \
+                (name)
+
+    for node in config.childNodes:
       if node.nodeName == 'remote':
         remote = self._ParseRemote(node)
         if self._remotes.get(remote.name):