summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2009-03-05 10:32:38 -0800
committerShawn O. Pearce <sop@google.com>2009-03-05 10:32:38 -0800
commitc7a4eefa7e775b64916a66b52ca6c5f31e2cf5c8 (patch)
tree49451ef2767128c809e48f980766c1a02d6504aa
parent43c3d9ea17f1436a6b3b2e7e7827da6f48a21da9 (diff)
downloadgit-repo-c7a4eefa7e775b64916a66b52ca6c5f31e2cf5c8.tar.gz
Add repo manifest -o to save a manifestv1.6.2
This can be useful to create a new manifest from an existing client, especially if the client wants to use the "-r" option to set each project's revision to the current commit SHA-1, making a sort of a tag file that can be used to recreate this exact state elsewhere. Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--manifest.py74
-rw-r--r--project.py14
-rw-r--r--subcmds/manifest.py43
3 files changed, 118 insertions, 13 deletions
diff --git a/manifest.py b/manifest.py
index 32a7e513..da2bb25f 100644
--- a/manifest.py
+++ b/manifest.py
@@ -18,7 +18,7 @@ import sys
18import xml.dom.minidom 18import xml.dom.minidom
19 19
20from git_config import GitConfig, IsId 20from git_config import GitConfig, IsId
21from project import Project, MetaProject, R_HEADS 21from project import Project, MetaProject, R_HEADS, HEAD
22from remote import Remote 22from remote import Remote
23from error import ManifestParseError 23from error import ManifestParseError
24 24
@@ -73,6 +73,76 @@ class Manifest(object):
73 except OSError, e: 73 except OSError, e:
74 raise ManifestParseError('cannot link manifest %s' % name) 74 raise ManifestParseError('cannot link manifest %s' % name)
75 75
76 def _RemoteToXml(self, r, doc, root):
77 e = doc.createElement('remote')
78 root.appendChild(e)
79 e.setAttribute('name', r.name)
80 e.setAttribute('fetch', r.fetchUrl)
81 if r.reviewUrl is not None:
82 e.setAttribute('review', r.reviewUrl)
83 if r.projectName is not None:
84 e.setAttribute('project-name', r.projectName)
85
86 def Save(self, fd, peg_rev=False):
87 """Write the current manifest out to the given file descriptor.
88 """
89 doc = xml.dom.minidom.Document()
90 root = doc.createElement('manifest')
91 doc.appendChild(root)
92
93 d = self.default
94 sort_remotes = list(self.remotes.keys())
95 sort_remotes.sort()
96
97 for r in sort_remotes:
98 self._RemoteToXml(self.remotes[r], doc, root)
99 if self.remotes:
100 root.appendChild(doc.createTextNode(''))
101
102 have_default = False
103 e = doc.createElement('default')
104 if d.remote:
105 have_default = True
106 e.setAttribute('remote', d.remote.name)
107 if d.revision:
108 have_default = True
109 e.setAttribute('revision', d.revision)
110 if have_default:
111 root.appendChild(e)
112 root.appendChild(doc.createTextNode(''))
113
114 sort_projects = list(self.projects.keys())
115 sort_projects.sort()
116
117 for p in sort_projects:
118 p = self.projects[p]
119 e = doc.createElement('project')
120 root.appendChild(e)
121 e.setAttribute('name', p.name)
122 if p.relpath != p.name:
123 e.setAttribute('path', p.relpath)
124 if not d.remote or p.remote.name != d.remote.name:
125 e.setAttribute('remote', p.remote.name)
126 if peg_rev:
127 if self.IsMirror:
128 e.setAttribute('revision',
129 p.bare_git.rev_parse(p.revision + '^0'))
130 else:
131 e.setAttribute('revision',
132 p.work_git.rev_parse(HEAD + '^0'))
133 elif not d.revision or p.revision != d.revision:
134 e.setAttribute('revision', p.revision)
135
136 for r in p.extraRemotes:
137 self._RemoteToXml(p.extraRemotes[r], doc, e)
138 for c in p.copyfiles:
139 ce = doc.createElement('copyfile')
140 ce.setAttribute('src', c.src)
141 ce.setAttribute('dest', c.dest)
142 e.appendChild(ce)
143
144 doc.writexml(fd, '', ' ', '\n', 'UTF-8')
145
76 @property 146 @property
77 def projects(self): 147 def projects(self):
78 self._Load() 148 self._Load()
@@ -324,7 +394,7 @@ class Manifest(object):
324 if not self.IsMirror: 394 if not self.IsMirror:
325 # src is project relative; 395 # src is project relative;
326 # dest is relative to the top of the tree 396 # dest is relative to the top of the tree
327 project.AddCopyFile(src, os.path.join(self.topdir, dest)) 397 project.AddCopyFile(src, dest, os.path.join(self.topdir, dest))
328 398
329 def _get_remote(self, node): 399 def _get_remote(self, node):
330 name = node.getAttribute('remote') 400 name = node.getAttribute('remote')
diff --git a/project.py b/project.py
index b9792523..8ed61551 100644
--- a/project.py
+++ b/project.py
@@ -178,13 +178,15 @@ class DiffColoring(Coloring):
178 178
179 179
180class _CopyFile: 180class _CopyFile:
181 def __init__(self, src, dest): 181 def __init__(self, src, dest, abssrc, absdest):
182 self.src = src 182 self.src = src
183 self.dest = dest 183 self.dest = dest
184 self.abs_src = abssrc
185 self.abs_dest = absdest
184 186
185 def _Copy(self): 187 def _Copy(self):
186 src = self.src 188 src = self.abs_src
187 dest = self.dest 189 dest = self.abs_dest
188 # copy file if it does not exist or is out of date 190 # copy file if it does not exist or is out of date
189 if not os.path.exists(dest) or not filecmp.cmp(src, dest): 191 if not os.path.exists(dest) or not filecmp.cmp(src, dest):
190 try: 192 try:
@@ -691,11 +693,11 @@ class Project(object):
691 self._CopyFiles() 693 self._CopyFiles()
692 return True 694 return True
693 695
694 def AddCopyFile(self, src, dest): 696 def AddCopyFile(self, src, dest, absdest):
695 # dest should already be an absolute path, but src is project relative 697 # dest should already be an absolute path, but src is project relative
696 # make src an absolute path 698 # make src an absolute path
697 src = os.path.join(self.worktree, src) 699 abssrc = os.path.join(self.worktree, src)
698 self.copyfiles.append(_CopyFile(src, dest)) 700 self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest))
699 701
700 def DownloadPatchSet(self, change_id, patch_id): 702 def DownloadPatchSet(self, change_id, patch_id):
701 """Download a single patch set of a single change to FETCH_HEAD. 703 """Download a single patch set of a single change to FETCH_HEAD.
diff --git a/subcmds/manifest.py b/subcmds/manifest.py
index 69906faa..4374a9d0 100644
--- a/subcmds/manifest.py
+++ b/subcmds/manifest.py
@@ -16,16 +16,21 @@
16import os 16import os
17import sys 17import sys
18 18
19from command import Command 19from command import PagedCommand
20 20
21class Manifest(Command): 21class Manifest(PagedCommand):
22 common = False 22 common = False
23 helpSummary = "Manifest file" 23 helpSummary = "Manifest inspection utility"
24 helpUsage = """ 24 helpUsage = """
25%prog 25%prog [-o {-|NAME.xml} [-r]]
26""" 26"""
27 _helpDescription = """ 27 _helpDescription = """
28The repo manifest file describes the projects mapped into the client. 28
29With the -o option, exports the current manifest for inspection.
30The manifest and (if present) local_manifest.xml are combined
31together to produce a single manifest file. This file can be stored
32in a Git repository for use during future 'repo init' invocations.
33
29""" 34"""
30 35
31 @property 36 @property
@@ -39,6 +44,34 @@ The repo manifest file describes the projects mapped into the client.
39 fd.close() 44 fd.close()
40 return help 45 return help
41 46
47 def _Options(self, p):
48 p.add_option('-r', '--revision-as-HEAD',
49 dest='peg_rev', action='store_true',
50 help='Save revisions as current HEAD')
51 p.add_option('-o', '--output-file',
52 dest='output_file',
53 help='File to save the manifest to',
54 metavar='-|NAME.xml')
55
56 def _Output(self, opt):
57 if opt.output_file == '-':
58 fd = sys.stdout
59 else:
60 fd = open(opt.output_file, 'w')
61 self.manifest.Save(fd,
62 peg_rev = opt.peg_rev)
63 fd.close()
64 if opt.output_file != '-':
65 print >>sys.stderr, 'Saved manifest to %s' % opt.output_file
66
42 def Execute(self, opt, args): 67 def Execute(self, opt, args):
68 if args:
69 self.Usage()
70
71 if opt.output_file is not None:
72 self._Output(opt)
73 return
74
75 print >>sys.stderr, 'error: no operation to perform'
43 print >>sys.stderr, 'error: see repo help manifest' 76 print >>sys.stderr, 'error: see repo help manifest'
44 sys.exit(1) 77 sys.exit(1)