Remove import_tar, import_zip and the <snapshot> elements
Now that repo relies only on the git data stream (as it is much
faster to download through) we don't really need to be parsing the
<snapshot> elements within manifest. Its a lot of complex code to
convert the tar (or zip) through to a fast import stream, and we
just aren't calling it anymore.
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/import_ext.py b/import_ext.py
deleted file mode 100644
index 2a1ebf8..0000000
--- a/import_ext.py
+++ /dev/null
@@ -1,422 +0,0 @@
-#
-# Copyright (C) 2008 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 random
-import stat
-import sys
-import urllib2
-import StringIO
-
-from error import GitError, ImportError
-from git_command import GitCommand
-
-class ImportExternal(object):
- """Imports a single revision from a non-git data source.
- Suitable for use to import a tar or zip based snapshot.
- """
- def __init__(self):
- self._marks = 0
- self._files = {}
- self._tempref = 'refs/repo-external/import'
-
- self._urls = []
- self._remap = []
- self.parent = None
- self._user_name = 'Upstream'
- self._user_email = 'upstream-import@none'
- self._user_when = 1000000
-
- self.commit = None
-
- def Clone(self):
- r = self.__class__()
-
- r.project = self.project
- for u in self._urls:
- r._urls.append(u)
- for p in self._remap:
- r._remap.append(_PathMap(r, p._old, p._new))
-
- return r
-
- def SetProject(self, project):
- self.project = project
-
- def SetVersion(self, version):
- self.version = version
-
- def AddUrl(self, url):
- self._urls.append(url)
-
- def SetParent(self, commit_hash):
- self.parent = commit_hash
-
- def SetCommit(self, commit_hash):
- self.commit = commit_hash
-
- def RemapPath(self, old, new, replace_version=True):
- self._remap.append(_PathMap(self, old, new))
-
- @property
- def TagName(self):
- v = ''
- for c in self.version:
- if c >= '0' and c <= '9':
- v += c
- elif c >= 'A' and c <= 'Z':
- v += c
- elif c >= 'a' and c <= 'z':
- v += c
- elif c in ('-', '_', '.', '/', '+', '@'):
- v += c
- return 'upstream/%s' % v
-
- @property
- def PackageName(self):
- n = self.project.name
- if n.startswith('platform/'):
- # This was not my finest moment...
- #
- n = n[len('platform/'):]
- return n
-
- def Import(self):
- self._need_graft = False
- if self.parent:
- try:
- self.project.bare_git.cat_file('-e', self.parent)
- except GitError:
- self._need_graft = True
-
- gfi = GitCommand(self.project,
- ['fast-import', '--force', '--quiet'],
- bare = True,
- provide_stdin = True)
- try:
- self._out = gfi.stdin
-
- try:
- self._UnpackFiles()
- self._MakeCommit()
- self._out.flush()
- finally:
- rc = gfi.Wait()
- if rc != 0:
- raise ImportError('fast-import failed')
-
- if self._need_graft:
- id = self._GraftCommit()
- else:
- id = self.project.bare_git.rev_parse('%s^0' % self._tempref)
-
- if self.commit and self.commit != id:
- raise ImportError('checksum mismatch: %s expected,'
- ' %s imported' % (self.commit, id))
-
- self._MakeTag(id)
- return id
- finally:
- try:
- self.project.bare_git.DeleteRef(self._tempref)
- except GitError:
- pass
-
- def _PickUrl(self, failed):
- u = map(lambda x: x.replace('%version%', self.version), self._urls)
- for f in failed:
- if f in u:
- u.remove(f)
- if len(u) == 0:
- return None
- return random.choice(u)
-
- def _OpenUrl(self):
- failed = {}
- while True:
- url = self._PickUrl(failed.keys())
- if url is None:
- why = 'Cannot download %s' % self.project.name
-
- if failed:
- why += ': one or more mirrors are down\n'
- bad_urls = list(failed.keys())
- bad_urls.sort()
- for url in bad_urls:
- why += ' %s: %s\n' % (url, failed[url])
- else:
- why += ': no mirror URLs'
- raise ImportError(why)
-
- print >>sys.stderr, "Getting %s ..." % url
- try:
- return urllib2.urlopen(url), url
- except urllib2.HTTPError, e:
- failed[url] = e.code
- except urllib2.URLError, e:
- failed[url] = e.reason[1]
- except OSError, e:
- failed[url] = e.strerror
-
- def _UnpackFiles(self):
- raise NotImplementedError
-
- def _NextMark(self):
- self._marks += 1
- return self._marks
-
- def _UnpackOneFile(self, mode, size, name, fd):
- if stat.S_ISDIR(mode): # directory
- return
- else:
- mode = self._CleanMode(mode, name)
-
- old_name = name
- name = self._CleanName(name)
-
- if stat.S_ISLNK(mode) and self._remap:
- # The link is relative to the old_name, and may need to
- # be rewritten according to our remap rules if it goes
- # up high enough in the tree structure.
- #
- dest = self._RewriteLink(fd.read(size), old_name, name)
- fd = StringIO.StringIO(dest)
- size = len(dest)
-
- fi = _File(mode, name, self._NextMark())
-
- self._out.write('blob\n')
- self._out.write('mark :%d\n' % fi.mark)
- self._out.write('data %d\n' % size)
- while size > 0:
- n = min(2048, size)
- self._out.write(fd.read(n))
- size -= n
- self._out.write('\n')
- self._files[fi.name] = fi
-
- def _SetFileMode(self, name, mode):
- if not stat.S_ISDIR(mode):
- mode = self._CleanMode(mode, name)
- name = self._CleanName(name)
- try:
- fi = self._files[name]
- except KeyError:
- raise ImportError('file %s was not unpacked' % name)
- fi.mode = mode
-
- def _RewriteLink(self, dest, relto_old, relto_new):
- # Drop the last components of the symlink itself
- # as the dest is relative to the directory its in.
- #
- relto_old = _TrimPath(relto_old)
- relto_new = _TrimPath(relto_new)
-
- # Resolve the link to be absolute from the top of
- # the archive, so we can remap its destination.
- #
- while dest.find('/./') >= 0 or dest.find('//') >= 0:
- dest = dest.replace('/./', '/')
- dest = dest.replace('//', '/')
-
- if dest.startswith('../') or dest.find('/../') > 0:
- dest = _FoldPath('%s/%s' % (relto_old, dest))
-
- for pm in self._remap:
- if pm.Matches(dest):
- dest = pm.Apply(dest)
- break
-
- dest, relto_new = _StripCommonPrefix(dest, relto_new)
- while relto_new:
- i = relto_new.find('/')
- if i > 0:
- relto_new = relto_new[i + 1:]
- else:
- relto_new = ''
- dest = '../' + dest
- return dest
-
- def _CleanMode(self, mode, name):
- if stat.S_ISREG(mode): # regular file
- if (mode & 0111) == 0:
- return 0644
- else:
- return 0755
- elif stat.S_ISLNK(mode): # symlink
- return stat.S_IFLNK
- else:
- raise ImportError('invalid mode %o in %s' % (mode, name))
-
- def _CleanName(self, name):
- old_name = name
- for pm in self._remap:
- if pm.Matches(name):
- name = pm.Apply(name)
- break
- while name.startswith('/'):
- name = name[1:]
- if not name:
- raise ImportError('path %s is empty after remap' % old_name)
- if name.find('/./') >= 0 or name.find('/../') >= 0:
- raise ImportError('path %s contains relative parts' % name)
- return name
-
- def _MakeCommit(self):
- msg = '%s %s\n' % (self.PackageName, self.version)
-
- self._out.write('commit %s\n' % self._tempref)
- self._out.write('committer %s <%s> %d +0000\n' % (
- self._user_name,
- self._user_email,
- self._user_when))
- self._out.write('data %d\n' % len(msg))
- self._out.write(msg)
- self._out.write('\n')
- if self.parent and not self._need_graft:
- self._out.write('from %s^0\n' % self.parent)
- self._out.write('deleteall\n')
-
- for f in self._files.values():
- self._out.write('M %o :%d %s\n' % (f.mode, f.mark, f.name))
- self._out.write('\n')
-
- def _GraftCommit(self):
- raw = self.project.bare_git.cat_file('commit', self._tempref)
- raw = raw.split("\n")
- while raw[1].startswith('parent '):
- del raw[1]
- raw.insert(1, 'parent %s' % self.parent)
- id = self._WriteObject('commit', "\n".join(raw))
-
- graft_file = os.path.join(self.project.gitdir, 'info/grafts')
- if os.path.exists(graft_file):
- graft_list = open(graft_file, 'rb').read().split("\n")
- if graft_list and graft_list[-1] == '':
- del graft_list[-1]
- else:
- graft_list = []
-
- exists = False
- for line in graft_list:
- if line == id:
- exists = True
- break
-
- if not exists:
- graft_list.append(id)
- graft_list.append('')
- fd = open(graft_file, 'wb')
- fd.write("\n".join(graft_list))
- fd.close()
-
- return id
-
- def _MakeTag(self, id):
- name = self.TagName
-
- raw = []
- raw.append('object %s' % id)
- raw.append('type commit')
- raw.append('tag %s' % name)
- raw.append('tagger %s <%s> %d +0000' % (
- self._user_name,
- self._user_email,
- self._user_when))
- raw.append('')
- raw.append('%s %s\n' % (self.PackageName, self.version))
-
- tagid = self._WriteObject('tag', "\n".join(raw))
- self.project.bare_git.UpdateRef('refs/tags/%s' % name, tagid)
-
- def _WriteObject(self, type, data):
- wo = GitCommand(self.project,
- ['hash-object', '-t', type, '-w', '--stdin'],
- bare = True,
- provide_stdin = True,
- capture_stdout = True,
- capture_stderr = True)
- wo.stdin.write(data)
- if wo.Wait() != 0:
- raise GitError('cannot create %s from (%s)' % (type, data))
- return wo.stdout[:-1]
-
-
-def _TrimPath(path):
- i = path.rfind('/')
- if i > 0:
- path = path[0:i]
- return ''
-
-def _StripCommonPrefix(a, b):
- while True:
- ai = a.find('/')
- bi = b.find('/')
- if ai > 0 and bi > 0 and a[0:ai] == b[0:bi]:
- a = a[ai + 1:]
- b = b[bi + 1:]
- else:
- break
- return a, b
-
-def _FoldPath(path):
- while True:
- if path.startswith('../'):
- return path
-
- i = path.find('/../')
- if i <= 0:
- if path.startswith('/'):
- return path[1:]
- return path
-
- lhs = path[0:i]
- rhs = path[i + 4:]
-
- i = lhs.rfind('/')
- if i > 0:
- path = lhs[0:i + 1] + rhs
- else:
- path = rhs
-
-class _File(object):
- def __init__(self, mode, name, mark):
- self.mode = mode
- self.name = name
- self.mark = mark
-
-
-class _PathMap(object):
- def __init__(self, imp, old, new):
- self._imp = imp
- self._old = old
- self._new = new
-
- def _r(self, p):
- return p.replace('%version%', self._imp.version)
-
- @property
- def old(self):
- return self._r(self._old)
-
- @property
- def new(self):
- return self._r(self._new)
-
- def Matches(self, name):
- return name.startswith(self.old)
-
- def Apply(self, name):
- return self.new + name[len(self.old):]
diff --git a/import_tar.py b/import_tar.py
deleted file mode 100644
index d7ce14d..0000000
--- a/import_tar.py
+++ /dev/null
@@ -1,206 +0,0 @@
-#
-# Copyright (C) 2008 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 bz2
-import stat
-import tarfile
-import zlib
-import StringIO
-
-from import_ext import ImportExternal
-from error import ImportError
-
-class ImportTar(ImportExternal):
- """Streams a (optionally compressed) tar file from the network
- directly into a Project's Git repository.
- """
- @classmethod
- def CanAccept(cls, url):
- """Can this importer read and unpack the data stored at url?
- """
- if url.endswith('.tar.gz') or url.endswith('.tgz'):
- return True
- if url.endswith('.tar.bz2'):
- return True
- if url.endswith('.tar'):
- return True
- return False
-
- def _UnpackFiles(self):
- url_fd, url = self._OpenUrl()
- try:
- if url.endswith('.tar.gz') or url.endswith('.tgz'):
- tar_fd = _Gzip(url_fd)
- elif url.endswith('.tar.bz2'):
- tar_fd = _Bzip2(url_fd)
- elif url.endswith('.tar'):
- tar_fd = _Raw(url_fd)
- else:
- raise ImportError('non-tar file extension: %s' % url)
-
- try:
- tar = tarfile.TarFile(name = url,
- mode = 'r',
- fileobj = tar_fd)
- try:
- for entry in tar:
- mode = entry.mode
-
- if (mode & 0170000) == 0:
- if entry.isdir():
- mode |= stat.S_IFDIR
- elif entry.isfile() or entry.islnk(): # hard links as files
- mode |= stat.S_IFREG
- elif entry.issym():
- mode |= stat.S_IFLNK
-
- if stat.S_ISLNK(mode): # symlink
- data_fd = StringIO.StringIO(entry.linkname)
- data_sz = len(entry.linkname)
- elif stat.S_ISDIR(mode): # directory
- data_fd = StringIO.StringIO('')
- data_sz = 0
- else:
- data_fd = tar.extractfile(entry)
- data_sz = entry.size
-
- self._UnpackOneFile(mode, data_sz, entry.name, data_fd)
- finally:
- tar.close()
- finally:
- tar_fd.close()
- finally:
- url_fd.close()
-
-
-
-class _DecompressStream(object):
- """file like object to decompress a tar stream
- """
- def __init__(self, fd):
- self._fd = fd
- self._pos = 0
- self._buf = None
-
- def tell(self):
- return self._pos
-
- def seek(self, offset):
- d = offset - self._pos
- if d > 0:
- self.read(d)
- elif d == 0:
- pass
- else:
- raise NotImplementedError, 'seek backwards'
-
- def close(self):
- self._fd = None
-
- def read(self, size = -1):
- if not self._fd:
- raise EOFError, 'Reached EOF'
-
- r = []
- try:
- if size >= 0:
- self._ReadChunk(r, size)
- else:
- while True:
- self._ReadChunk(r, 2048)
- except EOFError:
- pass
-
- if len(r) == 1:
- r = r[0]
- else:
- r = ''.join(r)
- self._pos += len(r)
- return r
-
- def _ReadChunk(self, r, size):
- b = self._buf
- try:
- while size > 0:
- if b is None or len(b) == 0:
- b = self._Decompress(self._fd.read(2048))
- continue
-
- use = min(size, len(b))
- r.append(b[:use])
- b = b[use:]
- size -= use
- finally:
- self._buf = b
-
- def _Decompress(self, b):
- raise NotImplementedError, '_Decompress'
-
-
-class _Raw(_DecompressStream):
- """file like object for an uncompressed stream
- """
- def __init__(self, fd):
- _DecompressStream.__init__(self, fd)
-
- def _Decompress(self, b):
- return b
-
-
-class _Bzip2(_DecompressStream):
- """file like object to decompress a .bz2 stream
- """
- def __init__(self, fd):
- _DecompressStream.__init__(self, fd)
- self._bz = bz2.BZ2Decompressor()
-
- def _Decompress(self, b):
- return self._bz.decompress(b)
-
-
-_FHCRC, _FEXTRA, _FNAME, _FCOMMENT = 2, 4, 8, 16
-class _Gzip(_DecompressStream):
- """file like object to decompress a .gz stream
- """
- def __init__(self, fd):
- _DecompressStream.__init__(self, fd)
- self._z = zlib.decompressobj(-zlib.MAX_WBITS)
-
- magic = fd.read(2)
- if magic != '\037\213':
- raise IOError, 'Not a gzipped file'
-
- method = ord(fd.read(1))
- if method != 8:
- raise IOError, 'Unknown compression method'
-
- flag = ord(fd.read(1))
- fd.read(6)
-
- if flag & _FEXTRA:
- xlen = ord(fd.read(1))
- xlen += 256 * ord(fd.read(1))
- fd.read(xlen)
- if flag & _FNAME:
- while fd.read(1) != '\0':
- pass
- if flag & _FCOMMENT:
- while fd.read(1) != '\0':
- pass
- if flag & _FHCRC:
- fd.read(2)
-
- def _Decompress(self, b):
- return self._z.decompress(b)
diff --git a/import_zip.py b/import_zip.py
deleted file mode 100644
index 08aff32..0000000
--- a/import_zip.py
+++ /dev/null
@@ -1,345 +0,0 @@
-#
-# Copyright (C) 2008 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 stat
-import struct
-import zlib
-import cStringIO
-
-from import_ext import ImportExternal
-from error import ImportError
-
-class ImportZip(ImportExternal):
- """Streams a zip file from the network directly into a Project's
- Git repository.
- """
- @classmethod
- def CanAccept(cls, url):
- """Can this importer read and unpack the data stored at url?
- """
- if url.endswith('.zip') or url.endswith('.jar'):
- return True
- return False
-
- def _UnpackFiles(self):
- url_fd, url = self._OpenUrl()
- try:
- if not self.__class__.CanAccept(url):
- raise ImportError('non-zip file extension: %s' % url)
-
- zip = _ZipFile(url_fd)
- for entry in zip.FileRecords():
- data = zip.Open(entry).read()
- sz = len(data)
-
- if data and _SafeCRLF(data):
- data = data.replace('\r\n', '\n')
- sz = len(data)
-
- fd = cStringIO.StringIO(data)
- self._UnpackOneFile(entry.mode, sz, entry.name, fd)
- zip.Close(entry)
-
- for entry in zip.CentralDirectory():
- self._SetFileMode(entry.name, entry.mode)
-
- zip.CheckTail()
- finally:
- url_fd.close()
-
-
-def _SafeCRLF(data):
- """Is it reasonably safe to perform a CRLF->LF conversion?
-
- If the stream contains a NUL byte it is likely binary,
- and thus a CRLF->LF conversion may damage the stream.
-
- If the only NUL is in the last position of the stream,
- but it otherwise can do a CRLF<->LF conversion we do
- the CRLF conversion anyway. At least one source ZIP
- file has this structure in its source code.
-
- If every occurrance of a CR and LF is paired up as a
- CRLF pair then the conversion is safely bi-directional.
- s/\r\n/\n/g == s/\n/\r\\n/g can convert between them.
- """
- nul = data.find('\0')
- if 0 <= nul and nul < (len(data) - 1):
- return False
-
- n_lf = 0
- last = 0
- while True:
- lf = data.find('\n', last)
- if lf < 0:
- break
- if lf == 0 or data[lf - 1] != '\r':
- return False
- last = lf + 1
- n_lf += 1
- return n_lf > 0
-
-class _ZipFile(object):
- """Streaming iterator to parse a zip file on the fly.
- """
- def __init__(self, fd):
- self._fd = _UngetStream(fd)
-
- def FileRecords(self):
- return _FileIter(self._fd)
-
- def CentralDirectory(self):
- return _CentIter(self._fd)
-
- def CheckTail(self):
- type_buf = self._fd.read(4)
- type = struct.unpack('<I', type_buf)[0]
- if type != 0x06054b50: # end of central directory
- raise ImportError('zip record %x unsupported' % type)
-
- def Open(self, entry):
- if entry.is_compressed:
- return _InflateStream(self._fd)
- else:
- if entry.has_trailer:
- raise ImportError('unable to extract streamed zip')
- return _FixedLengthStream(self._fd, entry.uncompressed_size)
-
- def Close(self, entry):
- if entry.has_trailer:
- type = struct.unpack('<I', self._fd.read(4))[0]
- if type == 0x08074b50:
- # Not a formal type marker, but commonly seen in zips
- # as the data descriptor signature.
- #
- struct.unpack('<3I', self._fd.read(12))
- else:
- # No signature for the data descriptor, so read the
- # remaining fields out of the stream
- #
- self._fd.read(8)
-
-
-class _FileIter(object):
- def __init__(self, fd):
- self._fd = fd
-
- def __iter__(self):
- return self
-
- def next(self):
- fd = self._fd
-
- type_buf = fd.read(4)
- type = struct.unpack('<I', type_buf)[0]
-
- if type != 0x04034b50: # local file header
- fd.unread(type_buf)
- raise StopIteration()
-
- rec = _FileHeader(fd.read(26))
- rec.name = fd.read(rec.name_len)
- fd.read(rec.extra_len)
-
- if rec.name.endswith('/'):
- rec.name = rec.name[:-1]
- rec.mode = stat.S_IFDIR | 0777
- return rec
-
-
-class _FileHeader(object):
- """Information about a single file in the archive.
- 0 version needed to extract 2 bytes
- 1 general purpose bit flag 2 bytes
- 2 compression method 2 bytes
- 3 last mod file time 2 bytes
- 4 last mod file date 2 bytes
- 5 crc-32 4 bytes
- 6 compressed size 4 bytes
- 7 uncompressed size 4 bytes
- 8 file name length 2 bytes
- 9 extra field length 2 bytes
- """
- def __init__(self, raw_bin):
- rec = struct.unpack('<5H3I2H', raw_bin)
-
- if rec[2] == 8:
- self.is_compressed = True
- elif rec[2] == 0:
- self.is_compressed = False
- else:
- raise ImportError('unrecognized compression format')
-
- if rec[1] & (1 << 3):
- self.has_trailer = True
- else:
- self.has_trailer = False
-
- self.compressed_size = rec[6]
- self.uncompressed_size = rec[7]
- self.name_len = rec[8]
- self.extra_len = rec[9]
- self.mode = stat.S_IFREG | 0644
-
-
-class _CentIter(object):
- def __init__(self, fd):
- self._fd = fd
-
- def __iter__(self):
- return self
-
- def next(self):
- fd = self._fd
-
- type_buf = fd.read(4)
- type = struct.unpack('<I', type_buf)[0]
-
- if type != 0x02014b50: # central directory
- fd.unread(type_buf)
- raise StopIteration()
-
- rec = _CentHeader(fd.read(42))
- rec.name = fd.read(rec.name_len)
- fd.read(rec.extra_len)
- fd.read(rec.comment_len)
-
- if rec.name.endswith('/'):
- rec.name = rec.name[:-1]
- rec.mode = stat.S_IFDIR | 0777
- return rec
-
-
-class _CentHeader(object):
- """Information about a single file in the archive.
- 0 version made by 2 bytes
- 1 version needed to extract 2 bytes
- 2 general purpose bit flag 2 bytes
- 3 compression method 2 bytes
- 4 last mod file time 2 bytes
- 5 last mod file date 2 bytes
- 6 crc-32 4 bytes
- 7 compressed size 4 bytes
- 8 uncompressed size 4 bytes
- 9 file name length 2 bytes
- 10 extra field length 2 bytes
- 11 file comment length 2 bytes
- 12 disk number start 2 bytes
- 13 internal file attributes 2 bytes
- 14 external file attributes 4 bytes
- 15 relative offset of local header 4 bytes
- """
- def __init__(self, raw_bin):
- rec = struct.unpack('<6H3I5H2I', raw_bin)
- self.name_len = rec[9]
- self.extra_len = rec[10]
- self.comment_len = rec[11]
-
- if (rec[0] & 0xff00) == 0x0300: # UNIX
- self.mode = rec[14] >> 16
- else:
- self.mode = stat.S_IFREG | 0644
-
-
-class _UngetStream(object):
- """File like object to read and rewind a stream.
- """
- def __init__(self, fd):
- self._fd = fd
- self._buf = None
-
- def read(self, size = -1):
- r = []
- try:
- if size >= 0:
- self._ReadChunk(r, size)
- else:
- while True:
- self._ReadChunk(r, 2048)
- except EOFError:
- pass
-
- if len(r) == 1:
- return r[0]
- return ''.join(r)
-
- def unread(self, buf):
- b = self._buf
- if b is None or len(b) == 0:
- self._buf = buf
- else:
- self._buf = buf + b
-
- def _ReadChunk(self, r, size):
- b = self._buf
- try:
- while size > 0:
- if b is None or len(b) == 0:
- b = self._Inflate(self._fd.read(2048))
- if not b:
- raise EOFError()
- continue
-
- use = min(size, len(b))
- r.append(b[:use])
- b = b[use:]
- size -= use
- finally:
- self._buf = b
-
- def _Inflate(self, b):
- return b
-
-
-class _FixedLengthStream(_UngetStream):
- """File like object to read a fixed length stream.
- """
- def __init__(self, fd, have):
- _UngetStream.__init__(self, fd)
- self._have = have
-
- def _Inflate(self, b):
- n = self._have
- if n == 0:
- self._fd.unread(b)
- return None
-
- if len(b) > n:
- self._fd.unread(b[n:])
- b = b[:n]
- self._have -= len(b)
- return b
-
-
-class _InflateStream(_UngetStream):
- """Inflates the stream as it reads input.
- """
- def __init__(self, fd):
- _UngetStream.__init__(self, fd)
- self._z = zlib.decompressobj(-zlib.MAX_WBITS)
-
- def _Inflate(self, b):
- z = self._z
- if not z:
- self._fd.unread(b)
- return None
-
- b = z.decompress(b)
- if z.unconsumed_tail != '':
- self._fd.unread(z.unconsumed_tail)
- elif z.unused_data != '':
- self._fd.unread(z.unused_data)
- self._z = None
- return b
diff --git a/manifest.py b/manifest.py
index 8c5a8d6..ffff14a 100644
--- a/manifest.py
+++ b/manifest.py
@@ -18,8 +18,6 @@
import xml.dom.minidom
from git_config import GitConfig, IsId
-from import_tar import ImportTar
-from import_zip import ImportZip
from project import Project, MetaProject, R_TAGS
from remote import Remote
from error import ManifestParseError
@@ -245,78 +243,8 @@
elif n.nodeName == 'copyfile':
self._ParseCopyFile(project, n)
- to_resolve = []
- by_version = {}
-
- for n in node.childNodes:
- if n.nodeName == 'import':
- self._ParseImport(project, n, to_resolve, by_version)
-
- for pair in to_resolve:
- sn, pr = pair
- try:
- sn.SetParent(by_version[pr].commit)
- except KeyError:
- raise ManifestParseError, \
- 'snapshot %s not in project %s in %s' % \
- (pr, project.name, self.manifestFile)
-
return project
- def _ParseImport(self, project, import_node, to_resolve, by_version):
- first_url = None
- for node in import_node.childNodes:
- if node.nodeName == 'mirror':
- first_url = self._reqatt(node, 'url')
- break
- if not first_url:
- raise ManifestParseError, \
- 'mirror url required for project %s in %s' % \
- (project.name, self.manifestFile)
-
- imp = None
- for cls in [ImportTar, ImportZip]:
- if cls.CanAccept(first_url):
- imp = cls()
- break
- if not imp:
- raise ManifestParseError, \
- 'snapshot %s unsupported for project %s in %s' % \
- (first_url, project.name, self.manifestFile)
-
- imp.SetProject(project)
-
- for node in import_node.childNodes:
- if node.nodeName == 'remap':
- old = node.getAttribute('strip')
- new = node.getAttribute('insert')
- imp.RemapPath(old, new)
-
- elif node.nodeName == 'mirror':
- imp.AddUrl(self._reqatt(node, 'url'))
-
- for node in import_node.childNodes:
- if node.nodeName == 'snapshot':
- sn = imp.Clone()
- sn.SetVersion(self._reqatt(node, 'version'))
- sn.SetCommit(node.getAttribute('check'))
-
- pr = node.getAttribute('prior')
- if pr:
- if IsId(pr):
- sn.SetParent(pr)
- else:
- to_resolve.append((sn, pr))
-
- rev = R_TAGS + sn.TagName
-
- if rev in project.snapshots:
- raise ManifestParseError, \
- 'duplicate snapshot %s for project %s in %s' % \
- (sn.version, project.name, self.manifestFile)
- project.snapshots[rev] = sn
- by_version[sn.version] = sn
-
def _ParseCopyFile(self, project, node):
src = self._reqatt(node, 'src')
dest = self._reqatt(node, 'dest')
diff --git a/subcmds/compute_snapshot_check.py b/subcmds/compute_snapshot_check.py
deleted file mode 100644
index 82db359..0000000
--- a/subcmds/compute_snapshot_check.py
+++ /dev/null
@@ -1,169 +0,0 @@
-#
-# Copyright (C) 2008 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
-import tempfile
-
-from command import Command
-from error import GitError, NoSuchProjectError
-from git_config import IsId
-from import_tar import ImportTar
-from import_zip import ImportZip
-from project import Project
-from remote import Remote
-
-def _ToCommit(project, rev):
- return project.bare_git.rev_parse('--verify', '%s^0' % rev)
-
-def _Missing(project, rev):
- return project._revlist('--objects', rev, '--not', '--all')
-
-
-class ComputeSnapshotCheck(Command):
- common = False
- helpSummary = "Compute the check value for a new snapshot"
- helpUsage = """
-%prog -p NAME -v VERSION -s FILE [options]
-"""
- helpDescription = """
-%prog computes and then displays the proper check value for a
-snapshot, so it can be pasted into the manifest file for a project.
-"""
-
- def _Options(self, p):
- g = p.add_option_group('Snapshot description options')
- g.add_option('-p', '--project',
- dest='project', metavar='NAME',
- help='destination project name')
- g.add_option('-v', '--version',
- dest='version', metavar='VERSION',
- help='upstream version/revision identifier')
- g.add_option('-s', '--snapshot',
- dest='snapshot', metavar='PATH',
- help='local tarball path')
- g.add_option('--new-project',
- dest='new_project', action='store_true',
- help='destinition is a new project')
- g.add_option('--keep',
- dest='keep_git', action='store_true',
- help='keep the temporary git repository')
-
- g = p.add_option_group('Base revision grafting options')
- g.add_option('--prior',
- dest='prior', metavar='COMMIT',
- help='prior revision checksum')
-
- g = p.add_option_group('Path mangling options')
- g.add_option('--strip-prefix',
- dest='strip_prefix', metavar='PREFIX',
- help='remove prefix from all paths on import')
- g.add_option('--insert-prefix',
- dest='insert_prefix', metavar='PREFIX',
- help='insert prefix before all paths on import')
-
-
- def _Compute(self, opt):
- try:
- real_project = self.GetProjects([opt.project])[0]
- except NoSuchProjectError:
- if opt.new_project:
- print >>sys.stderr, \
- "warning: project '%s' does not exist" % opt.project
- else:
- raise NoSuchProjectError(opt.project)
-
- self._tmpdir = tempfile.mkdtemp()
- project = Project(manifest = self.manifest,
- name = opt.project,
- remote = Remote('origin'),
- gitdir = os.path.join(self._tmpdir, '.git'),
- worktree = self._tmpdir,
- relpath = opt.project,
- revision = 'refs/heads/master')
- project._InitGitDir()
-
- url = 'file://%s' % os.path.abspath(opt.snapshot)
-
- imp = None
- for cls in [ImportTar, ImportZip]:
- if cls.CanAccept(url):
- imp = cls()
- break
- if not imp:
- print >>sys.stderr, 'error: %s unsupported' % opt.snapshot
- sys.exit(1)
-
- imp.SetProject(project)
- imp.SetVersion(opt.version)
- imp.AddUrl(url)
-
- if opt.prior:
- if opt.new_project:
- if not IsId(opt.prior):
- print >>sys.stderr, 'error: --prior=%s not valid' % opt.prior
- sys.exit(1)
- else:
- try:
- opt.prior = _ToCommit(real_project, opt.prior)
- missing = _Missing(real_project, opt.prior)
- except GitError, e:
- print >>sys.stderr,\
- 'error: --prior=%s not valid\n%s' \
- % (opt.prior, e)
- sys.exit(1)
- if missing:
- print >>sys.stderr,\
- 'error: --prior=%s is valid, but is not reachable' \
- % opt.prior
- sys.exit(1)
- imp.SetParent(opt.prior)
-
- src = opt.strip_prefix
- dst = opt.insert_prefix
- if src or dst:
- if src is None:
- src = ''
- if dst is None:
- dst = ''
- imp.RemapPath(src, dst)
- commitId = imp.Import()
-
- print >>sys.stderr,"%s\t%s" % (commitId, imp.version)
- return project
-
- def Execute(self, opt, args):
- if args \
- or not opt.project \
- or not opt.version \
- or not opt.snapshot:
- self.Usage()
-
- success = False
- project = None
- try:
- self._tmpdir = None
- project = self._Compute(opt)
- finally:
- if project and opt.keep_git:
- print 'GIT_DIR = %s' % (project.gitdir)
- elif self._tmpdir:
- for root, dirs, files in os.walk(self._tmpdir, topdown=False):
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- os.rmdir(os.path.join(root, name))
- os.rmdir(self._tmpdir)
-