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
following DTD:
<!DOCTYPE manifest [
<!ELEMENT manifest (remote*,
default?,
remove-project*,
project*,
add-remote*)>
<!ELEMENT remote (EMPTY)>
<!ATTLIST remote name ID #REQUIRED>
<!ATTLIST remote fetch CDATA #REQUIRED>
<!ATTLIST remote review CDATA #IMPLIED>
<!ATTLIST remote project-name CDATA #IMPLIED>
<!ELEMENT default (EMPTY)>
<!ATTLIST default remote IDREF #IMPLIED>
<!ATTLIST default revision CDATA #IMPLIED>
<!ELEMENT project (remote*)>
<!ATTLIST project name CDATA #REQUIRED>
<!ATTLIST project path CDATA #IMPLIED>
<!ATTLIST project remote IDREF #IMPLIED>
<!ATTLIST project revision CDATA #IMPLIED>
<!ELEMENT add-remote (EMPTY)>
<!ATTLIST add-remote to-project ID #REQUIRED>
<!ATTLIST add-remote name ID #REQUIRED>
<!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>
]>
<!DOCTYPE manifest [
<!ELEMENT manifest (remote*,
default?,
remove-project*,
project*,
add-remote*)>
<!ELEMENT remote (EMPTY)>
<!ATTLIST remote name ID #REQUIRED>
<!ATTLIST remote fetch CDATA #REQUIRED>
<!ATTLIST remote review CDATA #IMPLIED>
<!ATTLIST remote project-name CDATA #IMPLIED>
<!ELEMENT default (EMPTY)>
<!ATTLIST default remote IDREF #IMPLIED>
<!ATTLIST default revision CDATA #IMPLIED>
<!ELEMENT project (remote*)>
<!ATTLIST project name CDATA #REQUIRED>
<!ATTLIST project path CDATA #IMPLIED>
<!ATTLIST project remote IDREF #IMPLIED>
<!ATTLIST project revision CDATA #IMPLIED>
<!ELEMENT add-remote (EMPTY)>
<!ATTLIST add-remote to-project ID #REQUIRED>
<!ATTLIST add-remote name ID #REQUIRED>
<!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.
@ -179,16 +179,14 @@ manifest, stored in `$TOP_DIR/.repo/local_manifest.xml`.
For example:
----
$ cat .repo/local_manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<project path="manifest"
name="tools/manifest" />
<project path="platform-manifest"
name="platform/manifest" />
</manifest>
----
$ cat .repo/local_manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<project path="manifest"
name="tools/manifest" />
<project path="platform-manifest"
name="platform/manifest" />
</manifest>
Users may add projects to the local manifest prior to a `repo sync`
invocation, instructing repo to automatically download and manage

View File

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

View File

@ -18,7 +18,7 @@ import sys
import xml.dom.minidom
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 error import ManifestParseError
@ -73,6 +73,76 @@ class Manifest(object):
except OSError, e:
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
def projects(self):
self._Load()
@ -324,7 +394,7 @@ class Manifest(object):
if not self.IsMirror:
# src is project relative;
# 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):
name = node.getAttribute('remote')

View File

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

View File

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

View File

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

View File

@ -89,8 +89,9 @@ default.xml will be used.
def _SyncManifest(self, opt):
m = self.manifest.manifestProject
is_new = not m.Exists
if not m.Exists:
if is_new:
if not opt.manifest_url:
print >>sys.stderr, 'fatal: manifest url (-u) is required.'
sys.exit(1)
@ -117,11 +118,20 @@ default.xml will be used.
r.Save()
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.StartBranch('default')
if is_new or m.CurrentBranch is None:
m.StartBranch('default')
def _LinkManifest(self, 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)