Пример #1
0
def checkreadonly(ui, repo, op):
    try:
        reporeason = repo.vfs.read('readonlyreason')

        ui.warn(_('repository is read only\n'))
        if reporeason:
            ui.warn(reporeason.strip() + '\n')

        ui.warn(_('refusing to %s\n') % op)
        return True
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise

    # Repo local file does not exist. Check global file.
    rf = ui.config('readonly', 'globalreasonfile')
    if rf:
        try:
            with util.posixfile(rf, 'rb') as fh:
                globalreason = fh.read()

            ui.warn(_('all repositories currently read only\n'))
            if globalreason:
                ui.warn(globalreason.strip() + '\n')

            ui.warn(_('refusing to %s\n') % op)
            return True
        except IOError as e:
            if e.errno != errno.ENOENT:
                raise

    return False
Пример #2
0
    def setfile(self, fname, data):
        if fname in self._popped:
            raise EditingError('trying to set a popped file %s' % fname)

        if fname in self._data:
            self._size -= len(self._data[fname])
            del self._data[fname]

        if fname in self._files:
            del self._files[fname]

        if self._maxsize < 0 or (len(data) + self._size) <= self._maxsize:
            self._data[fname] = data
            self._size += len(data)
        else:
            if self._tempdir is None:
                self._tempdir = tempfile.mkdtemp(prefix='hg-subversion-')
            # Avoid filename issues with these simple names
            fn = str(self._created)
            fp = hgutil.posixfile(os.path.join(self._tempdir, fn), 'wb')
            try:
                fp.write(data)
            finally:
                fp.close()
            self._created += 1
            self._files[fname] = fn
Пример #3
0
def _generateoutputparts(head, bundlerepo, bundleroots, bundlefile):
    '''generates bundle that will be send to the user

    returns tuple with raw bundle string and bundle type
    '''
    parts = []
    if not _needsrebundling(head, bundlerepo):
        with util.posixfile(bundlefile, "rb") as f:
            unbundler = exchange.readbundle(bundlerepo.ui, f, bundlefile)
            if isinstance(unbundler, changegroup.cg1unpacker):
                part = bundle2.bundlepart('changegroup',
                                          data=unbundler._stream.read())
                part.addparam('version', '01')
                parts.append(part)
            elif isinstance(unbundler, bundle2.unbundle20):
                haschangegroup = False
                for part in unbundler.iterparts():
                    if part.type == 'changegroup':
                        haschangegroup = True
                    newpart = bundle2.bundlepart(part.type, data=part.read())
                    for key, value in part.params.iteritems():
                        newpart.addparam(key, value)
                    parts.append(newpart)

                if not haschangegroup:
                    raise error.Abort(
                        'unexpected bundle without changegroup part, ' +
                        'head: %s' % hex(head),
                        hint='report to administrator')
            else:
                raise error.Abort('unknown bundle type')
    else:
        parts = _rebundle(bundlerepo, bundleroots, head)

    return parts
Пример #4
0
def checkreadonly(ui, repo, op):
    try:
        reporeason = repo.vfs.read('readonlyreason')

        ui.warn(_('repository is read only\n'))
        if reporeason:
            ui.warn(reporeason.strip() + '\n')

        ui.warn(_('refusing to %s\n') % op)
        return True
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise

    # Repo local file does not exist. Check global file.
    rf = ui.config('readonly', 'globalreasonfile')
    if rf:
        try:
            with util.posixfile(rf, 'rb') as fh:
                globalreason = fh.read()

            ui.warn(_('all repositories currently read only\n'))
            if globalreason:
                ui.warn(globalreason.strip() + '\n')

            ui.warn(_('refusing to %s\n') % op)
            return True
        except IOError as e:
            if e.errno != errno.ENOENT:
                raise

    return False
Пример #5
0
    def _readini(self):
        """Create iniparse object by reading every file"""
        if len(self._readfiles) > 1:
            raise NotImplementedError("wconfig does not support read() more than once")

        def newini(fp=None):
            # TODO: optionxformvalue isn't used by INIConfig ?
            return INIConfig(fp=fp, optionxformvalue=None)

        if not self._readfiles:
            return newini()

        path, fp, sections, remap = self._readfiles[0]
        if sections:
            raise NotImplementedError("wconfig does not support 'sections'")
        if remap:
            raise NotImplementedError("wconfig does not support 'remap'")

        if fp:
            fp.seek(0)
            return newini(fp)
        else:
            fp = util.posixfile(path, 'rb')
            try:
                return newini(fp)
            finally:
                fp.close()
Пример #6
0
def _import(ui, repo, files, opts, force=False):
    with repo.wlock():
        # load union of current active profile
        revs = [repo.changelog.rev(node) for node in
                repo.dirstate.parents() if node != nullid]

        # read current configuration
        raw = ''
        if repo.vfs.exists('sparse'):
            raw = repo.vfs.read('sparse')
        oincludes, oexcludes, oprofiles = repo.readsparseconfig(raw)
        includes, excludes, profiles = map(
                set, (oincludes, oexcludes, oprofiles))

        # all active rules
        aincludes, aexcludes, aprofiles = set(), set(), set()
        for rev in revs:
            rincludes, rexcludes, rprofiles = repo.getsparsepatterns(rev)
            aincludes.update(rincludes)
            aexcludes.update(rexcludes)
            aprofiles.update(rprofiles)

        # import rules on top; only take in rules that are not yet
        # part of the active rules.
        changed = False
        for file in files:
            with util.posixfile(util.expandpath(file)) as importfile:
                iincludes, iexcludes, iprofiles = repo.readsparseconfig(
                    importfile.read())
                oldsize = len(includes) + len(excludes) + len(profiles)
                includes.update(iincludes - aincludes)
                excludes.update(iexcludes - aexcludes)
                profiles.update(set(iprofiles) - aprofiles)
                if len(includes) + len(excludes) + len(profiles) > oldsize:
                    changed = True

        profilecount = includecount = excludecount = 0
        fcounts = (0, 0, 0)

        if changed:
            profilecount = len(profiles - aprofiles)
            includecount = len(includes - aincludes)
            excludecount = len(excludes - aexcludes)

            oldstatus = repo.status()
            oldsparsematch = repo.sparsematch()
            repo.writesparseconfig(includes, excludes, profiles)

            try:
                fcounts = map(
                    len, _refresh(ui, repo, oldstatus, oldsparsematch, force))
            except Exception:
                repo.writesparseconfig(oincludes, oexcludes, oprofiles)
                raise

        _verbose_output(ui, opts, profilecount, includecount, excludecount,
                        *fcounts)
Пример #7
0
    def getfile(self, fname):
        if fname in self._popped:
            raise EditingError('trying to get a popped file %s' % fname)

        if fname in self._data:
            return self._data[fname]
        if self._tempdir is None or fname not in self._files:
            raise IOError
        path = os.path.join(self._tempdir, self._files[fname])
        fp = hgutil.posixfile(path, 'rb')
        try:
            return fp.read()
        finally:
            fp.close()
Пример #8
0
def writefile(path, content, readonly=False):
    dirname, filename = os.path.split(path)
    if not os.path.exists(dirname):
        try:
            os.makedirs(dirname)
        except OSError as ex:
            if ex.errno != errno.EEXIST:
                raise

    fd, temp = tempfile.mkstemp(prefix='.%s-' % filename, dir=dirname)
    os.close(fd)

    try:
        f = util.posixfile(temp, 'wb')
        f.write(content)
        f.close()

        if readonly:
            mode = 0o444
        else:
            # tempfiles are created with 0o600, so we need to manually set the
            # mode.
            oldumask = os.umask(0)
            # there's no way to get the umask without modifying it, so set it
            # back
            os.umask(oldumask)
            mode = ~oldumask

        renamefile(temp, path)
        os.chmod(path, mode)
    except Exception:
        try:
            unlinkfile(temp)
        except OSError:
            pass
        raise
Пример #9
0
def writefile(path, content, readonly=False):
    dirname, filename = os.path.split(path)
    if not os.path.exists(dirname):
        try:
            os.makedirs(dirname)
        except OSError as ex:
            if ex.errno != errno.EEXIST:
                raise

    fd, temp = tempfile.mkstemp(prefix='.%s-' % filename, dir=dirname)
    os.close(fd)

    try:
        f = util.posixfile(temp, 'wb')
        f.write(content)
        f.close()

        if readonly:
            mode = 0o444
        else:
            # tempfiles are created with 0o600, so we need to manually set the
            # mode.
            oldumask = os.umask(0)
            # there's no way to get the umask without modifying it, so set it
            # back
            os.umask(oldumask)
            mode = ~oldumask

        renamefile(temp, path)
        os.chmod(path, mode)
    except Exception:
        try:
            unlinkfile(temp)
        except OSError:
            pass
        raise
Пример #10
0
    def _readStatus(self, ctx, ctx2, wfile, status, changeselect, force):
        def getstatus(repo, n1, n2, wfile):
            m = match.exact(repo.root, repo.getcwd(), [wfile])
            modified, added, removed = repo.status(n1, n2, match=m)[:3]
            if wfile in modified:
                return 'M'
            if wfile in added:
                return 'A'
            if wfile in removed:
                return 'R'
            if wfile in ctx:
                return 'C'
            return None

        isbfile = False
        repo = ctx._repo
        maxdiff = repo.maxdiff
        self.flabel = u'<b>%s</b>' % self.filePath()

        if ctx2:
            # If a revision to compare to was provided, we must put it in
            # the context of the subrepo as well
            if ctx2._repo.root != ctx._repo.root:
                wsub2, wfileinsub2, sctx2 = \
                    hglib.getDeepestSubrepoContainingFile(wfile, ctx2)
                if wsub2:
                    ctx2 = sctx2

        absfile = repo.wjoin(wfile)
        if (wfile in ctx and 'l' in ctx.flags(wfile)) or \
           os.path.islink(absfile):
            if wfile in ctx:
                data = ctx[wfile].data()
            else:
                data = os.readlink(absfile)
            self.contents = data
            self.flabel += _(' <i>(is a symlink)</i>')
            return

        if ctx2 is None:
            ctx2 = ctx.p1()
        if status is None:
            status = getstatus(repo, ctx2.node(), ctx.node(), wfile)

        mde = _('File or diffs not displayed: '
                'File is larger than the specified max size.\n'
                'maxdiff = %s KB') % (maxdiff // 1024)

        if status in ('R', '!'):
            if wfile in ctx.p1():
                fctx = ctx.p1()[wfile]
                if fctx._filelog.rawsize(fctx.filerev()) > maxdiff:
                    self.error = mde
                else:
                    olddata = fctx.data()
                    if '\0' in olddata:
                        self.error = 'binary file'
                    else:
                        self.contents = olddata
                self.flabel += _(' <i>(was deleted)</i>')
            elif hasattr(ctx.p1(), 'hasStandin') and ctx.p1().hasStandin(wfile):
                self.error = 'binary file'
                self.flabel += _(' <i>(was deleted)</i>')
            else:
                self.flabel += _(' <i>(was added, now missing)</i>')
            return

        if status in ('I', '?'):
            assert ctx.rev() is None
            self.flabel += _(' <i>(is unversioned)</i>')
            if os.path.getsize(absfile) > maxdiff:
                self.error = mde
                return
            data = util.posixfile(absfile, 'r').read()
            if not force and '\0' in data:
                self.error = 'binary file'
            else:
                self.contents = data
            return

        if status in ('M', 'A', 'C'):
            if ctx.hasStandin(wfile):
                wfile = ctx.findStandin(wfile)
                isbfile = True
            try:
                fctx, newdata = self._checkMaxDiff(ctx, wfile, maxdiff, force)
            except _BadContent:
                if status == 'A':
                    self._checkRenamed(repo, ctx, ctx2, wfile)
                raise
            self.contents = newdata
            if status == 'C':
                # no further comparison is necessary
                return
            for pctx in ctx.parents():
                if 'x' in fctx.flags() and 'x' not in pctx.flags(wfile):
                    self.elabel = _("exec mode has been "
                                    "<font color='red'>set</font>")
                elif 'x' not in fctx.flags() and 'x' in pctx.flags(wfile):
                    self.elabel = _("exec mode has been "
                                    "<font color='red'>unset</font>")

        if status == 'A':
            oldname = self._checkRenamed(repo, ctx, ctx2, wfile)
            if not oldname:
                return
            olddata = ctx2[oldname].data()
        elif status == 'M':
            if wfile not in ctx2:
                # merge situation where file was added in other branch
                self.flabel += _(' <i>(was added)</i>')
                return
            oldname = wfile
            olddata = ctx2[wfile].data()
        else:
            return

        self.olddata = olddata
        if changeselect:
            diffopts = patch.diffopts(repo.ui, {})
            diffopts.git = True
            m = match.exact(repo.root, repo.root, [wfile])
            fp = cStringIO.StringIO()

            copy = {}
            if oldname != wfile:
                copy[wfile] = oldname
            patches = patch.diff(repo, ctx.node(), None, match=m,
                                 opts=diffopts, copy=copy)

            for c in patches:
                fp.write(c)
            fp.seek(0)

            # feed diffs through parsepatch() for more fine grained
            # chunk selection
            filediffs = patch.parsepatch(fp)
            if filediffs and filediffs[0].hunks:
                self.changes = filediffs[0]
            else:
                self.diff = ''
                return
            self.changes.excludecount = 0
            values = []
            lines = 0
            for chunk in self.changes.hunks:
                buf = cStringIO.StringIO()
                chunk.write(buf)
                chunk.excluded = False
                val = buf.getvalue()
                values.append(val)
                chunk.lineno = lines
                chunk.linecount = len(val.splitlines())
                lines += chunk.linecount
            self.diff = ''.join(values)
        else:
            diffopts = patch.diffopts(repo.ui, {})
            diffopts.git = False
            newdate = util.datestr(ctx.date())
            olddate = util.datestr(ctx2.date())
            if isbfile:
                olddata += '\0'
                newdata += '\0'
            difftext = hglib.unidifftext(olddata, olddate, newdata, newdate,
                                         oldname, wfile, opts=diffopts)
            if difftext:
                self.diff = ('diff -r %s -r %s %s\n' % (ctx, ctx2, oldname)
                             + difftext)
            else:
                self.diff = ''
Пример #11
0
                         'hasStandin') and ctx.p1().hasStandin(wfile):
                self.error = 'binary file'
                self.flabel += _(' <i>(was deleted)</i>')
            else:
                self.flabel += _(' <i>(was added, now missing)</i>')
            return

        if status in ('I', '?', 'C'):
            if ctx.rev() is None:
                if status in ('I', '?'):
                    self.flabel += _(' <i>(is unversioned)</i>')
                if os.path.getsize(absfile) > maxdiff:
                    self.error = mde
                    return
                else:
                    data = util.posixfile(absfile, 'r').read()
            elif ctx.hasStandin(wfile):
                data = '\0'
            else:
                data = ctx.filectx(wfile).data()
            if '\0' in data:
                self.error = 'binary file'
            else:
                self.contents = data
            return

        if status in ('M', 'A'):
            if ctx.hasStandin(wfile):
                wfile = ctx.findStandin(wfile)
                isbfile = True
            res = self.checkMaxDiff(ctx, wfile, maxdiff, status)
Пример #12
0
                raise error.ParseError(err.message.splitlines()[0], loc)

        if not self._readfiles:
            return newini()

        path, fp, sections, remap = self._readfiles[0]
        if sections:
            raise NotImplementedError("wconfig does not support 'sections'")
        if remap:
            raise NotImplementedError("wconfig does not support 'remap'")

        if fp:
            fp.seek(0)
            return newini(fp)
        else:
            fp = util.posixfile(path, 'rb')
            try:
                return newini(fp)
            finally:
                fp.close()

    def _replaylogs(self, ini):
        def getsection(ini, section):
            if section in ini:
                return ini[section]
            else:
                newns = getattr(ini, '_new_namespace',
                                getattr(ini, 'new_namespace'))
                return newns(section)

        for k, v in self._sections.iteritems():
Пример #13
0
            elif hasattr(ctx.p1(), 'hasStandin') and ctx.p1().hasStandin(wfile):
                self.error = 'binary file'
                self.flabel += _(' <i>(was deleted)</i>')
            else:
                self.flabel += _(' <i>(was added, now missing)</i>')
            return

        if status in ('I', '?', 'C'):
            if ctx.rev() is None:
                if status in ('I', '?'):
                    self.flabel += _(' <i>(is unversioned)</i>')
                if os.path.getsize(absfile) > maxdiff:
                    self.error = mde
                    return
                else:
                    data = util.posixfile(absfile, 'r').read()
            elif ctx.hasStandin(wfile):
                data = '\0'
            else:
                data = ctx.filectx(wfile).data()
            if not force and '\0' in data:
                self.error = 'binary file'
            else:
                self.contents = data
            return

        if status in ('M', 'A'):
            if ctx.hasStandin(wfile):
                wfile = ctx.findStandin(wfile)
                isbfile = True
            res = self.checkMaxDiff(ctx, wfile, maxdiff, status, force)
Пример #14
0
class _wconfig(object):
    """Wrapper for config.config to replay changes to iniparse on write

    This records set/del operations and replays them on write().
    Source file is reloaded before replaying changes, so that it doesn't
    override changes for another part of file made by somebody else:

    - A "set foo = bar", B "set baz = bax" => "foo = bar, baz = bax"
    - A "set foo = bar", B "set foo = baz" => "foo = baz" (last one wins)
    - A "del foo", B "set foo = baz" => "foo = baz" (last one wins)
    - A "set foo = bar", B "del foo" => "" (last one wins)
    """
    def __init__(self, data=None):
        self._config = config_mod.config(data)
        self._readfiles = []  # list of read (path, fp, sections, remap)
        self._sections = {}

        if isinstance(data, self.__class__):  # keep log
            self._readfiles.extend(data._readfiles)
            self._sections.update(data._sections)
        elif data:  # record as changes
            self._logupdates(data)

    def copy(self):
        return self.__class__(self)

    def __contains__(self, section):
        return section in self._config

    def __getitem__(self, section):
        try:
            return self._sections[section]
        except KeyError:
            if self._config[section]:
                self._sections[section] = _wsortdict(self._config[section])
                return self._sections[section]
            else:
                return {}

    def __iter__(self):
        return iter(self._config)

    def update(self, src):
        self._config.update(src)
        self._logupdates(src)

    def _logupdates(self, src):
        for s in src:
            self[s]._logupdate(src[s])

    def set(self, section, item, value, source=''):
        self._setconfig(section, item, value, source)
        self[section]._logset(item, value)

    def _setconfig(self, section, item, value, source):
        if item not in self._config[section]:
            # need to handle 'source'
            self._config.set(section, item, value, source)
        else:
            self[section][item] = value

    def remove(self, section, item):
        del self[section][item]
        self[section]._logdel(item)

    def read(self, path, fp=None, sections=None, remap=None):
        self._config.read(path, fp, sections, remap)
        self._readfiles.append((path, fp, sections, remap))

    def write(self, dest):
        ini = self._readini()
        self._replaylogs(ini)
        dest.write(str(ini))

    def _readini(self):
        """Create iniparse object by reading every file"""
        if len(self._readfiles) > 1:
            raise NotImplementedError(
                "wconfig does not support read() more than once")

        def newini(fp=None):
            try:
                # TODO: optionxformvalue isn't used by INIConfig ?
                return INIConfig(fp=fp, optionxformvalue=None)
            except ConfigParser.ParsingError, err:
                raise error.ParseError(err.message.splitlines()[0],
                                       '%s:%d' % (err.filename, err.lineno))

        if not self._readfiles:
            return newini()

        path, fp, sections, remap = self._readfiles[0]
        if sections:
            raise NotImplementedError("wconfig does not support 'sections'")
        if remap:
            raise NotImplementedError("wconfig does not support 'remap'")

        if fp:
            fp.seek(0)
            return newini(fp)
        else:
            fp = util.posixfile(path, 'rb')
            try:
                return newini(fp)
            finally:
                fp.close()
Пример #15
0
                raise error.ParseError(err.message.splitlines()[0], loc)

        if not self._readfiles:
            return newini()

        path, fp, sections, remap = self._readfiles[0]
        if sections:
            raise NotImplementedError("wconfig does not support 'sections'")
        if remap:
            raise NotImplementedError("wconfig does not support 'remap'")

        if fp:
            fp.seek(0)
            return newini(fp)
        else:
            fp = util.posixfile(path, 'rb')
            try:
                return newini(fp)
            finally:
                fp.close()

    def _replaylogs(self, ini):
        def getsection(ini, section):
            if section in ini:
                return ini[section]
            else:
                newns = getattr(ini, '_new_namespace',
                                getattr(ini, 'new_namespace'))
                return newns(section)

        for k, v in self._sections.iteritems():
Пример #16
0
    def _readStatus(self, ctx, ctx2, wfile, status, changeselect, force):
        def getstatus(repo, n1, n2, wfile):
            m = match.exact(repo.root, repo.getcwd(), [wfile])
            modified, added, removed = repo.status(n1, n2, match=m)[:3]
            if wfile in modified:
                return 'M'
            if wfile in added:
                return 'A'
            if wfile in removed:
                return 'R'
            if wfile in ctx:
                return 'C'
            return None

        isbfile = False
        repo = ctx._repo
        maxdiff = repo.maxdiff
        self.flabel = u'<b>%s</b>' % self.filePath()

        if ctx2:
            # If a revision to compare to was provided, we must put it in
            # the context of the subrepo as well
            if ctx2._repo.root != ctx._repo.root:
                wsub2, wfileinsub2, sctx2 = \
                    hglib.getDeepestSubrepoContainingFile(wfile, ctx2)
                if wsub2:
                    ctx2 = sctx2

        absfile = repo.wjoin(wfile)
        if (wfile in ctx and 'l' in ctx.flags(wfile)) or \
           os.path.islink(absfile):
            if wfile in ctx:
                data = ctx[wfile].data()
            else:
                data = os.readlink(absfile)
            self.contents = data
            self.flabel += _(' <i>(is a symlink)</i>')
            return

        if ctx2 is None:
            ctx2 = ctx.p1()
        if status is None:
            status = getstatus(repo, ctx2.node(), ctx.node(), wfile)

        mde = _('File or diffs not displayed: '
                'File is larger than the specified max size.\n'
                'maxdiff = %s KB') % (maxdiff // 1024)

        if status in ('R', '!'):
            if wfile in ctx.p1():
                fctx = ctx.p1()[wfile]
                if fctx._filelog.rawsize(fctx.filerev()) > maxdiff:
                    self.error = mde
                else:
                    olddata = fctx.data()
                    if '\0' in olddata:
                        self.error = 'binary file'
                    else:
                        self.contents = olddata
                self.flabel += _(' <i>(was deleted)</i>')
            elif hasattr(ctx.p1(), 'hasStandin') and ctx.p1().hasStandin(wfile):
                self.error = 'binary file'
                self.flabel += _(' <i>(was deleted)</i>')
            else:
                self.flabel += _(' <i>(was added, now missing)</i>')
            return

        if status in ('I', '?'):
            assert ctx.rev() is None
            self.flabel += _(' <i>(is unversioned)</i>')
            if os.path.getsize(absfile) > maxdiff:
                self.error = mde
                return
            data = util.posixfile(absfile, 'r').read()
            if not force and '\0' in data:
                self.error = 'binary file'
            else:
                self.contents = data
            return

        if status in ('M', 'A', 'C'):
            if ctx.hasStandin(wfile):
                wfile = ctx.findStandin(wfile)
                isbfile = True
            try:
                fctx, newdata = self._checkMaxDiff(ctx, wfile, maxdiff, force)
            except _BadContent:
                if status == 'A':
                    self._checkRenamed(repo, ctx, ctx2, wfile)
                raise
            self.contents = newdata
            if status == 'C':
                # no further comparison is necessary
                return
            for pctx in ctx.parents():
                if 'x' in fctx.flags() and 'x' not in pctx.flags(wfile):
                    self.elabel = _("exec mode has been "
                                    "<font color='red'>set</font>")
                elif 'x' not in fctx.flags() and 'x' in pctx.flags(wfile):
                    self.elabel = _("exec mode has been "
                                    "<font color='red'>unset</font>")

        if status == 'A':
            oldname = self._checkRenamed(repo, ctx, ctx2, wfile)
            if not oldname:
                return
            olddata = ctx2[oldname].data()
        elif status == 'M':
            if wfile not in ctx2:
                # merge situation where file was added in other branch
                self.flabel += _(' <i>(was added)</i>')
                return
            oldname = wfile
            olddata = ctx2[wfile].data()
        else:
            return

        self.olddata = olddata
        if changeselect:
            diffopts = patch.diffopts(repo.ui, {})
            diffopts.git = True
            m = match.exact(repo.root, repo.root, [wfile])
            fp = cStringIO.StringIO()
            for c in patch.diff(repo, ctx.node(), None, match=m, opts=diffopts):
                fp.write(c)
            fp.seek(0)

            # feed diffs through parsepatch() for more fine grained
            # chunk selection
            filediffs = patch.parsepatch(fp)
            if filediffs and filediffs[0].hunks:
                self.changes = filediffs[0]
            else:
                self.diff = ''
                return
            self.changes.excludecount = 0
            values = []
            lines = 0
            for chunk in self.changes.hunks:
                buf = cStringIO.StringIO()
                chunk.write(buf)
                chunk.excluded = False
                val = buf.getvalue()
                values.append(val)
                chunk.lineno = lines
                chunk.linecount = len(val.splitlines())
                lines += chunk.linecount
            self.diff = ''.join(values)
        else:
            diffopts = patch.diffopts(repo.ui, {})
            diffopts.git = False
            newdate = util.datestr(ctx.date())
            olddate = util.datestr(ctx2.date())
            if isbfile:
                olddata += '\0'
                newdata += '\0'
            difftext = mdiff.unidiff(olddata, olddate, newdata, newdate,
                                     oldname, wfile, opts=diffopts)
            if difftext:
                self.diff = ('diff -r %s -r %s %s\n' % (ctx, ctx2, oldname)
                             + difftext)
            else:
                self.diff = ''