Compare commits

...

9 Commits

Author SHA1 Message Date
df01883f9b Allow repo init to restart if URL was initially invalid
This allows the user to run "repo init -u" again after an
initial attempt failed due to an invalid URL.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-17 08:15:27 -07:00
1fc99f4e47 Give a more friendly error in 'repo init' if manifest url is invalid
Instead of a stack trace ending in origin/master not existing we
now tell the user the manifest url is invalid if 'git fetch' has
failed out early.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-17 08:11:51 -07:00
1775dbe176 Set forall environment variables to empty string if None
If the value obtained is None we now set the variable to
'' instead, in an attempt to make execve() happier about
our 3rd argument, the env dictionary.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-17 08:03:04 -07:00
521cd3ce67 Support "repo init -b foo && repo sync" to switch baselines
We now correctly support re-initializing an existing client to point
to a different branch of the same manifest repository, effectively
allowing the client to switch the baseline it is operating on.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-09 18:53:20 -07:00
5470df6219 Don't permit "repo init --mirror" in an existing client
Simply setting repo.mirror true doesn't make a client into a mirror.
The on-disk layout is completely wrong for a mirror repository,
and until we fix our layout for a non-mirror client to more closely
resemble the upstream we can't do anything to easily turn on or
turn off the mirror status flag.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-09 18:51:58 -07:00
0ed2bd1d95 Add global --trace command line option
This has the same effect as saying "export REPO_TRACE=1" in
your shell prior to starting repo, but is documented in the
command usage and perhaps easier to use.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-09 18:26:31 -07:00
c7a4eefa7e Add repo manifest -o to save a manifest
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>
2009-03-05 10:32:38 -08:00
43c3d9ea17 Add a 'repo manifest' command whose help is the manifest file format
This should make it easier for users to discover the file format
on their own, and read about it.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-04 14:26:50 -08:00
4259b8a2ac Tell users how to see the complete list of commands
Using "repo help --all" may not be obvious.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-04 14:03:16 -08:00
8 changed files with 245 additions and 65 deletions

View File

@ -19,39 +19,39 @@ XML File Format
A manifest XML file (e.g. 'default.xml') roughly conforms to the A manifest XML file (e.g. 'default.xml') roughly conforms to the
following DTD: following DTD:
<!DOCTYPE manifest [ <!DOCTYPE manifest [
<!ELEMENT manifest (remote*, <!ELEMENT manifest (remote*,
default?, default?,
remove-project*, remove-project*,
project*, project*,
add-remote*)> add-remote*)>
<!ELEMENT remote (EMPTY)> <!ELEMENT remote (EMPTY)>
<!ATTLIST remote name ID #REQUIRED> <!ATTLIST remote name ID #REQUIRED>
<!ATTLIST remote fetch CDATA #REQUIRED> <!ATTLIST remote fetch CDATA #REQUIRED>
<!ATTLIST remote review CDATA #IMPLIED> <!ATTLIST remote review CDATA #IMPLIED>
<!ATTLIST remote project-name CDATA #IMPLIED> <!ATTLIST remote project-name CDATA #IMPLIED>
<!ELEMENT default (EMPTY)> <!ELEMENT default (EMPTY)>
<!ATTLIST default remote IDREF #IMPLIED> <!ATTLIST default remote IDREF #IMPLIED>
<!ATTLIST default revision CDATA #IMPLIED> <!ATTLIST default revision CDATA #IMPLIED>
<!ELEMENT project (remote*)> <!ELEMENT project (remote*)>
<!ATTLIST project name CDATA #REQUIRED> <!ATTLIST project name CDATA #REQUIRED>
<!ATTLIST project path CDATA #IMPLIED> <!ATTLIST project path CDATA #IMPLIED>
<!ATTLIST project remote IDREF #IMPLIED> <!ATTLIST project remote IDREF #IMPLIED>
<!ATTLIST project revision CDATA #IMPLIED> <!ATTLIST project revision CDATA #IMPLIED>
<!ELEMENT add-remote (EMPTY)> <!ELEMENT add-remote (EMPTY)>
<!ATTLIST add-remote to-project ID #REQUIRED> <!ATTLIST add-remote to-project ID #REQUIRED>
<!ATTLIST add-remote name ID #REQUIRED> <!ATTLIST add-remote name ID #REQUIRED>
<!ATTLIST add-remote fetch CDATA #REQUIRED> <!ATTLIST add-remote fetch CDATA #REQUIRED>
<!ATTLIST add-remote review CDATA #IMPLIED> <!ATTLIST add-remote review CDATA #IMPLIED>
<!ATTLIST add-remote project-name CDATA #IMPLIED> <!ATTLIST add-remote project-name CDATA #IMPLIED>
<!ELEMENT remove-project (EMPTY)> <!ELEMENT remove-project (EMPTY)>
<!ATTLIST remove-project name CDATA #REQUIRED> <!ATTLIST remove-project name CDATA #REQUIRED>
]> ]>
A description of the elements and their attributes follows. A description of the elements and their attributes follows.
@ -179,16 +179,14 @@ manifest, stored in `$TOP_DIR/.repo/local_manifest.xml`.
For example: For example:
---- $ cat .repo/local_manifest.xml
$ cat .repo/local_manifest.xml <?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?> <manifest>
<manifest> <project path="manifest"
<project path="manifest" name="tools/manifest" />
name="tools/manifest" /> <project path="platform-manifest"
<project path="platform-manifest" name="platform/manifest" />
name="platform/manifest" /> </manifest>
</manifest>
----
Users may add projects to the local manifest prior to a `repo sync` Users may add projects to the local manifest prior to a `repo sync`
invocation, instructing repo to automatically download and manage invocation, instructing repo to automatically download and manage

View File

@ -27,6 +27,7 @@ import os
import re import re
import sys import sys
import git_command
from command import InteractiveCommand from command import InteractiveCommand
from command import MirrorSafeCommand from command import MirrorSafeCommand
from command import PagedCommand from command import PagedCommand
@ -48,6 +49,9 @@ global_options.add_option('-p', '--paginate',
global_options.add_option('--no-pager', global_options.add_option('--no-pager',
dest='no_pager', action='store_true', dest='no_pager', action='store_true',
help='disable the pager') help='disable the pager')
global_options.add_option('--trace',
dest='trace', action='store_true',
help='trace git command execution')
global_options.add_option('--version', global_options.add_option('--version',
dest='show_version', action='store_true', dest='show_version', action='store_true',
help='display this version of repo') help='display this version of repo')
@ -74,6 +78,8 @@ class _Repo(object):
argv = [] argv = []
gopts, gargs = global_options.parse_args(glob) gopts, gargs = global_options.parse_args(glob)
if gopts.trace:
git_command.TRACE = True
if gopts.show_version: if gopts.show_version:
if name == 'help': if name == 'help':
name = 'version' name = 'version'

View File

@ -18,7 +18,7 @@ import sys
import xml.dom.minidom import xml.dom.minidom
from git_config import GitConfig, IsId from git_config import GitConfig, IsId
from project import Project, MetaProject, R_HEADS from project import Project, MetaProject, R_HEADS, HEAD
from remote import Remote from remote import Remote
from error import ManifestParseError from error import ManifestParseError
@ -73,6 +73,76 @@ class Manifest(object):
except OSError, e: except OSError, e:
raise ManifestParseError('cannot link manifest %s' % name) raise ManifestParseError('cannot link manifest %s' % name)
def _RemoteToXml(self, r, doc, root):
e = doc.createElement('remote')
root.appendChild(e)
e.setAttribute('name', r.name)
e.setAttribute('fetch', r.fetchUrl)
if r.reviewUrl is not None:
e.setAttribute('review', r.reviewUrl)
if r.projectName is not None:
e.setAttribute('project-name', r.projectName)
def Save(self, fd, peg_rev=False):
"""Write the current manifest out to the given file descriptor.
"""
doc = xml.dom.minidom.Document()
root = doc.createElement('manifest')
doc.appendChild(root)
d = self.default
sort_remotes = list(self.remotes.keys())
sort_remotes.sort()
for r in sort_remotes:
self._RemoteToXml(self.remotes[r], doc, root)
if self.remotes:
root.appendChild(doc.createTextNode(''))
have_default = False
e = doc.createElement('default')
if d.remote:
have_default = True
e.setAttribute('remote', d.remote.name)
if d.revision:
have_default = True
e.setAttribute('revision', d.revision)
if have_default:
root.appendChild(e)
root.appendChild(doc.createTextNode(''))
sort_projects = list(self.projects.keys())
sort_projects.sort()
for p in sort_projects:
p = self.projects[p]
e = doc.createElement('project')
root.appendChild(e)
e.setAttribute('name', p.name)
if p.relpath != p.name:
e.setAttribute('path', p.relpath)
if not d.remote or p.remote.name != d.remote.name:
e.setAttribute('remote', p.remote.name)
if peg_rev:
if self.IsMirror:
e.setAttribute('revision',
p.bare_git.rev_parse(p.revision + '^0'))
else:
e.setAttribute('revision',
p.work_git.rev_parse(HEAD + '^0'))
elif not d.revision or p.revision != d.revision:
e.setAttribute('revision', p.revision)
for r in p.extraRemotes:
self._RemoteToXml(p.extraRemotes[r], doc, e)
for c in p.copyfiles:
ce = doc.createElement('copyfile')
ce.setAttribute('src', c.src)
ce.setAttribute('dest', c.dest)
e.appendChild(ce)
doc.writexml(fd, '', ' ', '\n', 'UTF-8')
@property @property
def projects(self): def projects(self):
self._Load() self._Load()
@ -324,7 +394,7 @@ class Manifest(object):
if not self.IsMirror: if not self.IsMirror:
# src is project relative; # src is project relative;
# dest is relative to the top of the tree # dest is relative to the top of the tree
project.AddCopyFile(src, os.path.join(self.topdir, dest)) project.AddCopyFile(src, dest, os.path.join(self.topdir, dest))
def _get_remote(self, node): def _get_remote(self, node):
name = node.getAttribute('remote') name = node.getAttribute('remote')

View File

@ -178,13 +178,15 @@ class DiffColoring(Coloring):
class _CopyFile: class _CopyFile:
def __init__(self, src, dest): def __init__(self, src, dest, abssrc, absdest):
self.src = src self.src = src
self.dest = dest self.dest = dest
self.abs_src = abssrc
self.abs_dest = absdest
def _Copy(self): def _Copy(self):
src = self.src src = self.abs_src
dest = self.dest dest = self.abs_dest
# copy file if it does not exist or is out of date # copy file if it does not exist or is out of date
if not os.path.exists(dest) or not filecmp.cmp(src, dest): if not os.path.exists(dest) or not filecmp.cmp(src, dest):
try: try:
@ -691,11 +693,11 @@ class Project(object):
self._CopyFiles() self._CopyFiles()
return True return True
def AddCopyFile(self, src, dest): def AddCopyFile(self, src, dest, absdest):
# dest should already be an absolute path, but src is project relative # dest should already be an absolute path, but src is project relative
# make src an absolute path # make src an absolute path
src = os.path.join(self.worktree, src) abssrc = os.path.join(self.worktree, src)
self.copyfiles.append(_CopyFile(src, dest)) self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest))
def DownloadPatchSet(self, change_id, patch_id): def DownloadPatchSet(self, change_id, patch_id):
"""Download a single patch set of a single change to FETCH_HEAD. """Download a single patch set of a single change to FETCH_HEAD.

View File

@ -82,16 +82,21 @@ not redirected.
rc = 0 rc = 0
for project in self.GetProjects(args): for project in self.GetProjects(args):
env = dict(os.environ.iteritems()) env = dict(os.environ.iteritems())
env['REPO_PROJECT'] = project.name def setenv(name, val):
env['REPO_PATH'] = project.relpath if val is None:
env['REPO_REMOTE'] = project.remote.name val = ''
env['REPO_LREV'] = project\ env[name] = val
setenv('REPO_PROJECT', project.name)
setenv('REPO_PATH', project.relpath)
setenv('REPO_REMOTE', project.remote.name)
setenv('REPO_LREV', project\
.GetRemote(project.remote.name)\ .GetRemote(project.remote.name)\
.ToLocal(project.revision) .ToLocal(project.revision))
env['REPO_RREV'] = project.revision setenv('REPO_RREV', project.revision)
if mirror: if mirror:
env['GIT_DIR'] = project.gitdir setenv('GIT_DIR', project.gitdir)
cwd = project.gitdir cwd = project.gitdir
else: else:
cwd = project.worktree cwd = project.worktree

View File

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import re
import sys import sys
from formatter import AbstractFormatter, DumbWriter from formatter import AbstractFormatter, DumbWriter
@ -77,6 +78,7 @@ The most commonly used repo commands are:
print fmt % (name, summary) print fmt % (name, summary)
print """ print """
See 'repo help <command>' for more information on a specific command. See 'repo help <command>' for more information on a specific command.
See 'repo help --all' for a complete list of recognized commands.
""" """
def _PrintCommandHelp(self, cmd): def _PrintCommandHelp(self, cmd):
@ -105,14 +107,24 @@ See 'repo help <command>' for more information on a specific command.
body = body.strip() body = body.strip()
body = body.replace('%prog', me) body = body.replace('%prog', me)
asciidoc_hdr = re.compile(r'^\n?([^\n]{1,})\n(={2,}|-{2,})$')
for para in body.split("\n\n"): for para in body.split("\n\n"):
if para.startswith(' '): if para.startswith(' '):
self.write('%s', para) self.write('%s', para)
self.nl() self.nl()
self.nl() self.nl()
else: continue
self.wrap.add_flowing_data(para)
self.wrap.end_paragraph(1) m = asciidoc_hdr.match(para)
if m:
self.heading('%s', m.group(1))
self.nl()
self.heading('%s', ''.ljust(len(m.group(1)),'-'))
self.nl()
continue
self.wrap.add_flowing_data(para)
self.wrap.end_paragraph(1)
self.wrap.end_paragraph(0) self.wrap.end_paragraph(0)
out = _Out(self.manifest.globalConfig) out = _Out(self.manifest.globalConfig)

View File

@ -89,8 +89,9 @@ default.xml will be used.
def _SyncManifest(self, opt): def _SyncManifest(self, opt):
m = self.manifest.manifestProject m = self.manifest.manifestProject
is_new = not m.Exists
if not m.Exists: if is_new:
if not opt.manifest_url: if not opt.manifest_url:
print >>sys.stderr, 'fatal: manifest url (-u) is required.' print >>sys.stderr, 'fatal: manifest url (-u) is required.'
sys.exit(1) sys.exit(1)
@ -117,11 +118,20 @@ default.xml will be used.
r.Save() r.Save()
if opt.mirror: if opt.mirror:
m.config.SetString('repo.mirror', 'true') if is_new:
m.config.SetString('repo.mirror', 'true')
else:
print >>sys.stderr, 'fatal: --mirror not supported on existing client'
sys.exit(1)
if not m.Sync_NetworkHalf():
r = m.GetRemote(m.remote.name)
print >>sys.stderr, 'fatal: cannot obtain manifest %s' % r.url
sys.exit(1)
m.Sync_NetworkHalf()
m.Sync_LocalHalf() m.Sync_LocalHalf()
m.StartBranch('default') if is_new or m.CurrentBranch is None:
m.StartBranch('default')
def _LinkManifest(self, name): def _LinkManifest(self, name):
if not name: if not name:

77
subcmds/manifest.py Normal file
View File

@ -0,0 +1,77 @@
#
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from command import PagedCommand
class Manifest(PagedCommand):
common = False
helpSummary = "Manifest inspection utility"
helpUsage = """
%prog [-o {-|NAME.xml} [-r]]
"""
_helpDescription = """
With the -o option, exports the current manifest for inspection.
The manifest and (if present) local_manifest.xml are combined
together to produce a single manifest file. This file can be stored
in a Git repository for use during future 'repo init' invocations.
"""
@property
def helpDescription(self):
help = self._helpDescription + '\n'
r = os.path.dirname(__file__)
r = os.path.dirname(r)
fd = open(os.path.join(r, 'docs', 'manifest-format.txt'))
for line in fd:
help += line
fd.close()
return help
def _Options(self, p):
p.add_option('-r', '--revision-as-HEAD',
dest='peg_rev', action='store_true',
help='Save revisions as current HEAD')
p.add_option('-o', '--output-file',
dest='output_file',
help='File to save the manifest to',
metavar='-|NAME.xml')
def _Output(self, opt):
if opt.output_file == '-':
fd = sys.stdout
else:
fd = open(opt.output_file, 'w')
self.manifest.Save(fd,
peg_rev = opt.peg_rev)
fd.close()
if opt.output_file != '-':
print >>sys.stderr, 'Saved manifest to %s' % opt.output_file
def Execute(self, opt, args):
if args:
self.Usage()
if opt.output_file is not None:
self._Output(opt)
return
print >>sys.stderr, 'error: no operation to perform'
print >>sys.stderr, 'error: see repo help manifest'
sys.exit(1)