mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
merge with crew.
This commit is contained in:
commit
dd7442a4f4
@ -2,7 +2,7 @@ include hg
|
||||
recursive-include mercurial *.py
|
||||
include hgweb.cgi hgwebdir.cgi
|
||||
include hgeditor rewrite-log
|
||||
include tests/README tests/run-tests tests/md5sum.py tests/test-*[a-z0-9] tests/*.out
|
||||
include tests/README tests/coverage.py tests/run-tests.py tests/md5sum.py tests/test-*[a-z0-9] tests/*.out
|
||||
prune tests/*.err
|
||||
include *.txt
|
||||
include templates/map templates/map-*[a-z0-9]
|
||||
|
4
Makefile
4
Makefile
@ -16,10 +16,10 @@ dist: tests doc
|
||||
TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py sdist --force-manifest
|
||||
|
||||
tests:
|
||||
cd tests && ./run-tests
|
||||
cd tests && $(PYTHON) run-tests.py
|
||||
|
||||
test-%:
|
||||
cd tests && ./run-tests $@
|
||||
cd tests && $(PYTHON) run-tests.py $@
|
||||
|
||||
doc:
|
||||
$(MAKE) -C doc
|
||||
|
24
README
24
README
@ -11,13 +11,16 @@ Setting up Mercurial:
|
||||
$ tar xvzf mercurial-<ver>.tar.gz
|
||||
$ cd mercurial-<ver>
|
||||
|
||||
When installing, change python to python2.3 or python2.4 if 2.2 is the
|
||||
default on your system.
|
||||
|
||||
To install system-wide:
|
||||
|
||||
$ python setup.py install # change python to python2.3 if 2.2 is default
|
||||
$ python setup.py install --force
|
||||
|
||||
To install in your home directory (~/bin and ~/lib, actually), run:
|
||||
|
||||
$ python2.3 setup.py install --home=~
|
||||
$ python setup.py install --home=${HOME} --force
|
||||
$ export PYTHONPATH=${HOME}/lib/python # (or lib64/ on some systems)
|
||||
$ export PATH=${HOME}/bin:$PATH # add these to your .bashrc
|
||||
|
||||
@ -30,10 +33,12 @@ Setting up Mercurial:
|
||||
|
||||
Setting up a Mercurial project:
|
||||
|
||||
$ cd project/
|
||||
$ hg init # creates .hg
|
||||
$ hg addremove # add all unknown files and remove all missing files
|
||||
$ hg commit # commit all changes, edit changelog entry
|
||||
$ hg init project # creates project directory
|
||||
$ cd project
|
||||
# copy files in, edit them
|
||||
$ hg add # add all unknown files
|
||||
$ hg remove --after # remove deleted files
|
||||
$ hg commit # commit all changes, edit changelog entry
|
||||
|
||||
Mercurial will look for a file named .hgignore in the root of your
|
||||
repository which contains a set of regular expressions to ignore in
|
||||
@ -47,7 +52,7 @@ Branching and merging:
|
||||
$ hg commit
|
||||
$ cd ../linux
|
||||
$ hg pull ../linux-work # pull changesets from linux-work
|
||||
$ hg update -m # merge the new tip from linux-work into
|
||||
$ hg merge # merge the new tip from linux-work into
|
||||
# our working directory
|
||||
$ hg commit # commit the result of the merge
|
||||
|
||||
@ -55,8 +60,7 @@ Importing patches:
|
||||
|
||||
Fast:
|
||||
$ patch < ../p/foo.patch
|
||||
$ hg addremove
|
||||
$ hg commit
|
||||
$ hg commit -A
|
||||
|
||||
Faster:
|
||||
$ patch < ../p/foo.patch
|
||||
@ -87,7 +91,7 @@ Network support:
|
||||
|
||||
# merge changes from a remote machine
|
||||
bar$ hg pull http://foo/
|
||||
bar$ hg update -m # merge changes into your working directory
|
||||
bar$ hg merge # merge changes into your working directory
|
||||
|
||||
# Set up a CGI server on your webserver
|
||||
foo$ cp hgweb.cgi ~/public_html/hg/index.cgi
|
||||
|
@ -14,7 +14,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Mercurial version 0.8 for Windows</h1>
|
||||
<h1>Mercurial version 0.8.1 for Windows</h1>
|
||||
|
||||
<p>Welcome to Mercurial for Windows!</p>
|
||||
|
||||
@ -117,7 +117,7 @@ hg
|
||||
href="http://www.serpentine.com/blog">Bryan
|
||||
O'Sullivan</a>.</p>
|
||||
|
||||
<p>Mercurial is Copyright 2005 Matt Mackall and others. See the
|
||||
<p>Mercurial is Copyright 2005, 2006 Matt Mackall and others. See the
|
||||
<tt>Contributors.txt</tt> file for a list of contributors.</p>
|
||||
|
||||
<p>Mercurial is free software; you can redistribute it and/or
|
||||
|
@ -2,9 +2,9 @@
|
||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
[Setup]
|
||||
AppCopyright=Copyright 2005 Matt Mackall and others
|
||||
AppCopyright=Copyright 2005, 2006 Matt Mackall and others
|
||||
AppName=Mercurial
|
||||
AppVerName=Mercurial version 0.8
|
||||
AppVerName=Mercurial version 0.8.1
|
||||
InfoAfterFile=contrib/win32/postinstall.txt
|
||||
LicenseFile=COPYING
|
||||
ShowLanguageDialog=yes
|
||||
@ -14,12 +14,12 @@ AppSupportURL=http://www.selenic.com/mercurial
|
||||
AppUpdatesURL=http://www.selenic.com/mercurial
|
||||
AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}
|
||||
AppContact=mercurial@selenic.com
|
||||
OutputBaseFilename=Mercurial-0.8
|
||||
OutputBaseFilename=Mercurial-0.8.1
|
||||
DefaultDirName={sd}\Mercurial
|
||||
SourceDir=C:\hg\hg-release
|
||||
VersionInfoVersion=0.8
|
||||
VersionInfoVersion=0.8.1
|
||||
VersionInfoDescription=Mercurial distributed SCM
|
||||
VersionInfoCopyright=Copyright 2005 Matt Mackall and others
|
||||
VersionInfoCopyright=Copyright 2005, 2006 Matt Mackall and others
|
||||
VersionInfoCompany=Matt Mackall and others
|
||||
InternalCompressLevel=max
|
||||
SolidCompression=true
|
||||
|
@ -8,6 +8,22 @@ file that comes with this package.
|
||||
Release Notes
|
||||
-------------
|
||||
|
||||
2006-04-07 v0.8.1
|
||||
|
||||
* Major changes from 0.8 to 0.8.1:
|
||||
|
||||
- new extensions:
|
||||
mq (manage a queue of patches, like quilt only better)
|
||||
email (send changes as series of email patches)
|
||||
- new command: merge (replaces "update -m")
|
||||
- improved commands: log (--limit option added), pull/push ("-r" works
|
||||
on specific revisions), revert (rewritten, much better)
|
||||
- comprehensive hook support
|
||||
- output templating added, supporting e.g. GNU changelog style
|
||||
- Windows, Mac OS X: prebuilt binary packages, better support
|
||||
- many reliability, performance, and memory usage improvements
|
||||
|
||||
|
||||
2006-01-29 v0.8
|
||||
|
||||
* Upgrade notes:
|
||||
|
@ -180,7 +180,7 @@ FILES
|
||||
-----
|
||||
.hgignore::
|
||||
This file contains regular expressions (one per line) that describe file
|
||||
names that should be ignored by hg.
|
||||
names that should be ignored by hg. For details, see hgignore(5).
|
||||
|
||||
.hgtags::
|
||||
This file contains changeset hash values and text tag names (one of each
|
||||
@ -200,7 +200,7 @@ when you find them.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
hgrc(5)
|
||||
hgignore(5), hgrc(5)
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
|
92
doc/hgignore.5.txt
Normal file
92
doc/hgignore.5.txt
Normal file
@ -0,0 +1,92 @@
|
||||
HGIGNORE(5)
|
||||
===========
|
||||
Vadim Gelfer <vadim.gelfer@gmail.com>
|
||||
|
||||
NAME
|
||||
----
|
||||
hgignore - syntax for Mercurial ignore files
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
|
||||
The Mercurial system uses a file called .hgignore in the root
|
||||
directory of a repository to control its behavior when it finds files
|
||||
that it is not currently managing.
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Mercurial ignores every unmanaged file that matches any pattern in an
|
||||
ignore file. The patterns in an ignore file do not apply to files
|
||||
managed by Mercurial. To control Mercurial's handling of files that
|
||||
it manages, see the hg(1) man page. Look for the "-I" and "-X"
|
||||
options.
|
||||
|
||||
In addition, a Mercurial configuration file can point to a set of
|
||||
per-user or global ignore files. See the hgrc(5) man page for details
|
||||
of how to configure these files. Look for the "ignore" entry in the
|
||||
"ui" section.
|
||||
|
||||
SYNTAX
|
||||
------
|
||||
|
||||
An ignore file is a plain text file consisting of a list of patterns,
|
||||
with one pattern per line. Empty lines are skipped. The "#"
|
||||
character is treated as a comment character, and the "\" character is
|
||||
treated as an escape character.
|
||||
|
||||
Mercurial supports several pattern syntaxes. The default syntax used
|
||||
is Python/Perl-style regular expressions.
|
||||
|
||||
To change the syntax used, use a line of the following form:
|
||||
|
||||
syntax: NAME
|
||||
|
||||
where NAME is one of the following:
|
||||
|
||||
regexp::
|
||||
Regular expression, Python/Perl syntax.
|
||||
glob::
|
||||
Shell-style glob.
|
||||
|
||||
The chosen syntax stays in effect when parsing all patterns that
|
||||
follow, until another syntax is selected.
|
||||
|
||||
Neither glob nor regexp patterns are rooted. A glob-syntax pattern of
|
||||
the form "*.c" will match a file ending in ".c" in any directory, and
|
||||
a regexp pattern of the form "\.c$" will do the same. To root a
|
||||
regexp pattern, start it with "^".
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
|
||||
Here is an example ignore file.
|
||||
|
||||
# use glob syntax.
|
||||
syntax: glob
|
||||
|
||||
*.elc
|
||||
*.pyc
|
||||
*~
|
||||
.*.swp
|
||||
|
||||
# switch to regexp syntax.
|
||||
syntax: regexp
|
||||
^\.pc/
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
Vadim Gelfer <vadim.gelfer@gmail.com>
|
||||
|
||||
Mercurial was written by Matt Mackall <mpm@selenic.com>.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
hg(1), hgrc(5)
|
||||
|
||||
COPYING
|
||||
-------
|
||||
This manual page is copyright 2006 Vadim Gelfer.
|
||||
Mercurial is copyright 2005, 2006 Matt Mackall.
|
||||
Free use of this software is granted under the terms of the GNU General
|
||||
Public License (GPL).
|
@ -130,6 +130,24 @@ decode/encode::
|
||||
# them to the working dir
|
||||
**.txt = tempfile: unix2dos -n INFILE OUTFILE
|
||||
|
||||
email::
|
||||
Settings for extensions that send email messages.
|
||||
from;;
|
||||
Optional. Email address to use in "From" header and SMTP envelope
|
||||
of outgoing messages.
|
||||
|
||||
extensions::
|
||||
Mercurial has an extension mechanism for adding new features. To
|
||||
enable an extension, create an entry for it in this section.
|
||||
|
||||
If you know that the extension is already in Python's search path,
|
||||
you can give the name of the module, followed by "=", with nothing
|
||||
after the "=".
|
||||
|
||||
Otherwise, give a name that you choose, followed by "=", followed by
|
||||
the path to the ".py" file (including the file name extension) that
|
||||
defines the extension.
|
||||
|
||||
hooks::
|
||||
Commands or Python functions that get automatically executed by
|
||||
various actions such as starting or finishing a commit. Multiple
|
||||
@ -240,6 +258,24 @@ http_proxy::
|
||||
user;;
|
||||
Optional. User name to authenticate with at the proxy server.
|
||||
|
||||
smtp::
|
||||
Configuration for extensions that need to send email messages.
|
||||
host;;
|
||||
Optional. Host name of mail server. Default: "mail".
|
||||
port;;
|
||||
Optional. Port to connect to on mail server. Default: 25.
|
||||
tls;;
|
||||
Optional. Whether to connect to mail server using TLS. True or
|
||||
False. Default: False.
|
||||
username;;
|
||||
Optional. User name to authenticate to SMTP server with.
|
||||
If username is specified, password must also be specified.
|
||||
Default: none.
|
||||
password;;
|
||||
Optional. Password to authenticate to SMTP server with.
|
||||
If username is specified, password must also be specified.
|
||||
Default: none.
|
||||
|
||||
paths::
|
||||
Assigns symbolic names to repositories. The left side is the
|
||||
symbolic name, and the right gives the directory or URL that is the
|
||||
@ -256,7 +292,8 @@ ui::
|
||||
the same format as a repository-wide .hgignore file. This option
|
||||
supports hook syntax, so if you want to specify multiple ignore
|
||||
files, you can do so by setting something like
|
||||
"ignore.other = ~/.hgignore2".
|
||||
"ignore.other = ~/.hgignore2". For details of the ignore file
|
||||
format, see the hgignore(5) man page.
|
||||
interactive;;
|
||||
Allow to prompt the user. True or False. Default is True.
|
||||
logtemplate;;
|
||||
@ -300,6 +337,10 @@ web::
|
||||
allowzip;;
|
||||
Whether to allow .zip downloading of repo revisions. Default is false.
|
||||
This feature creates temporary files.
|
||||
baseurl;;
|
||||
Base URL to use when publishing URLs in other locations, so
|
||||
third-party tools like email notification hooks can construct URLs.
|
||||
Example: "http://hgserver/repos/"
|
||||
description;;
|
||||
Textual description of the repository's purpose or contents.
|
||||
Default is "unknown".
|
||||
@ -330,11 +371,11 @@ Mercurial was written by Matt Mackall <mpm@selenic.com>.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
hg(1)
|
||||
hg(1), hgignore(5)
|
||||
|
||||
COPYING
|
||||
-------
|
||||
This manual page is copyright 2005 Bryan O'Sullivan.
|
||||
Mercurial is copyright 2005 Matt Mackall.
|
||||
Mercurial is copyright 2005, 2006 Matt Mackall.
|
||||
Free use of this software is granted under the terms of the GNU General
|
||||
Public License (GPL).
|
||||
|
@ -30,7 +30,6 @@
|
||||
# OPTIONAL:
|
||||
# bzuser = ... # bugzilla user id to record comments with
|
||||
# db = bugs # database to connect to
|
||||
# hgweb = http:// # root of hg web site for browsing commits
|
||||
# notify = ... # command to run to get bugzilla to send mail
|
||||
# regexp = ... # regexp to match bug ids (must contain one "()" group)
|
||||
# strip = 0 # number of slashes to strip for url paths
|
||||
@ -38,11 +37,13 @@
|
||||
# template = ... # template to use when formatting comments
|
||||
# timeout = 5 # database connection timeout (seconds)
|
||||
# user = bugs # user to connect to database as
|
||||
# [web]
|
||||
# baseurl = http://hgserver/... # root of hg web site for browsing commits
|
||||
|
||||
from mercurial.demandload import *
|
||||
from mercurial.i18n import gettext as _
|
||||
from mercurial.node import *
|
||||
demandload(globals(), 'cStringIO mercurial:templater,util os re time')
|
||||
demandload(globals(), 'mercurial:templater,util os re time')
|
||||
|
||||
MySQLdb = None
|
||||
|
||||
@ -237,23 +238,9 @@ class bugzilla(object):
|
||||
count -= 1
|
||||
return root
|
||||
|
||||
class stringio(object):
|
||||
'''wrap cStringIO.'''
|
||||
def __init__(self):
|
||||
self.fp = cStringIO.StringIO()
|
||||
|
||||
def write(self, *args):
|
||||
for a in args:
|
||||
self.fp.write(a)
|
||||
|
||||
write_header = write
|
||||
|
||||
def getvalue(self):
|
||||
return self.fp.getvalue()
|
||||
|
||||
mapfile = self.ui.config('bugzilla', 'style')
|
||||
tmpl = self.ui.config('bugzilla', 'template')
|
||||
sio = stringio()
|
||||
sio = templater.stringio()
|
||||
t = templater.changeset_templater(self.ui, self.repo, mapfile, sio)
|
||||
if not mapfile and not tmpl:
|
||||
tmpl = _('changeset {node|short} in repo {root} refers '
|
||||
@ -263,7 +250,7 @@ class bugzilla(object):
|
||||
t.use_template(tmpl)
|
||||
t.show(changenode=node, changes=changes,
|
||||
bug=str(bugid),
|
||||
hgweb=self.ui.config('bugzilla', 'hgweb'),
|
||||
hgweb=self.ui.config('web', 'baseurl'),
|
||||
root=self.repo.root,
|
||||
webroot=webroot(self.repo.root))
|
||||
self.add_comment(bugid, sio.getvalue(), templater.email(changes[1]))
|
||||
|
258
hgext/notify.py
Normal file
258
hgext/notify.py
Normal file
@ -0,0 +1,258 @@
|
||||
# notify.py - email notifications for mercurial
|
||||
#
|
||||
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
|
||||
#
|
||||
# This software may be used and distributed according to the terms
|
||||
# of the GNU General Public License, incorporated herein by reference.
|
||||
#
|
||||
# hook extension to email notifications to people when changesets are
|
||||
# committed to a repo they subscribe to.
|
||||
#
|
||||
# default mode is to print messages to stdout, for testing and
|
||||
# configuring.
|
||||
#
|
||||
# to use, configure notify extension and enable in hgrc like this:
|
||||
#
|
||||
# [extensions]
|
||||
# hgext.notify =
|
||||
#
|
||||
# [hooks]
|
||||
# # one email for each incoming changeset
|
||||
# incoming.notify = python:hgext.notify.hook
|
||||
# # batch emails when many changesets incoming at one time
|
||||
# changegroup.notify = python:hgext.notify.hook
|
||||
#
|
||||
# [notify]
|
||||
# # config items go in here
|
||||
#
|
||||
# config items:
|
||||
#
|
||||
# REQUIRED:
|
||||
# config = /path/to/file # file containing subscriptions
|
||||
#
|
||||
# OPTIONAL:
|
||||
# test = True # print messages to stdout for testing
|
||||
# strip = 3 # number of slashes to strip for url paths
|
||||
# domain = example.com # domain to use if committer missing domain
|
||||
# style = ... # style file to use when formatting email
|
||||
# template = ... # template to use when formatting email
|
||||
# incoming = ... # template to use when run as incoming hook
|
||||
# changegroup = ... # template when run as changegroup hook
|
||||
# maxdiff = 300 # max lines of diffs to include (0=none, -1=all)
|
||||
# maxsubject = 67 # truncate subject line longer than this
|
||||
# [email]
|
||||
# from = user@host.com # email address to send as if none given
|
||||
# [web]
|
||||
# baseurl = http://hgserver/... # root of hg web site for browsing commits
|
||||
#
|
||||
# notify config file has same format as regular hgrc. it has two
|
||||
# sections so you can express subscriptions in whatever way is handier
|
||||
# for you.
|
||||
#
|
||||
# [usersubs]
|
||||
# # key is subscriber email, value is ","-separated list of glob patterns
|
||||
# user@host = pattern
|
||||
#
|
||||
# [reposubs]
|
||||
# # key is glob pattern, value is ","-separated list of subscriber emails
|
||||
# pattern = user@host
|
||||
#
|
||||
# glob patterns are matched against path to repo root.
|
||||
#
|
||||
# if you like, you can put notify config file in repo that users can
|
||||
# push changes to, they can manage their own subscriptions.
|
||||
|
||||
from mercurial.demandload import *
|
||||
from mercurial.i18n import gettext as _
|
||||
from mercurial.node import *
|
||||
demandload(globals(), 'email.Parser mercurial:commands,templater,util')
|
||||
demandload(globals(), 'fnmatch socket time')
|
||||
|
||||
# template for single changeset can include email headers.
|
||||
single_template = '''
|
||||
Subject: changeset in {webroot}: {desc|firstline|strip}
|
||||
From: {author}
|
||||
|
||||
changeset {node|short} in {root}
|
||||
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
|
||||
description:
|
||||
\t{desc|tabindent|strip}
|
||||
'''.lstrip()
|
||||
|
||||
# template for multiple changesets should not contain email headers,
|
||||
# because only first set of headers will be used and result will look
|
||||
# strange.
|
||||
multiple_template = '''
|
||||
changeset {node|short} in {root}
|
||||
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
|
||||
summary: {desc|firstline}
|
||||
'''
|
||||
|
||||
deftemplates = {
|
||||
'changegroup': multiple_template,
|
||||
}
|
||||
|
||||
class notifier(object):
|
||||
'''email notification class.'''
|
||||
|
||||
def __init__(self, ui, repo, hooktype):
|
||||
self.ui = ui
|
||||
self.ui.readconfig(self.ui.config('notify', 'config'))
|
||||
self.repo = repo
|
||||
self.stripcount = int(self.ui.config('notify', 'strip', 0))
|
||||
self.root = self.strip(self.repo.root)
|
||||
self.domain = self.ui.config('notify', 'domain')
|
||||
self.sio = templater.stringio()
|
||||
self.subs = self.subscribers()
|
||||
|
||||
mapfile = self.ui.config('notify', 'style')
|
||||
template = (self.ui.config('notify', hooktype) or
|
||||
self.ui.config('notify', 'template'))
|
||||
self.t = templater.changeset_templater(self.ui, self.repo, mapfile,
|
||||
self.sio)
|
||||
if not mapfile and not template:
|
||||
template = deftemplates.get(hooktype) or single_template
|
||||
if template:
|
||||
template = templater.parsestring(template, quoted=False)
|
||||
self.t.use_template(template)
|
||||
|
||||
def strip(self, path):
|
||||
'''strip leading slashes from local path, turn into web-safe path.'''
|
||||
|
||||
path = util.pconvert(path)
|
||||
count = self.stripcount
|
||||
while path and count >= 0:
|
||||
c = path.find('/')
|
||||
if c == -1:
|
||||
break
|
||||
path = path[c+1:]
|
||||
count -= 1
|
||||
return path
|
||||
|
||||
def fixmail(self, addr):
|
||||
'''try to clean up email addresses.'''
|
||||
|
||||
addr = templater.email(addr.strip())
|
||||
a = addr.find('@localhost')
|
||||
if a != -1:
|
||||
addr = addr[:a]
|
||||
if '@' not in addr:
|
||||
return addr + '@' + self.domain
|
||||
return addr
|
||||
|
||||
def subscribers(self):
|
||||
'''return list of email addresses of subscribers to this repo.'''
|
||||
|
||||
subs = {}
|
||||
for user, pats in self.ui.configitems('usersubs'):
|
||||
for pat in pats.split(','):
|
||||
if fnmatch.fnmatch(self.repo.root, pat.strip()):
|
||||
subs[self.fixmail(user)] = 1
|
||||
for pat, users in self.ui.configitems('reposubs'):
|
||||
if fnmatch.fnmatch(self.repo.root, pat):
|
||||
for user in users.split(','):
|
||||
subs[self.fixmail(user)] = 1
|
||||
subs = subs.keys()
|
||||
subs.sort()
|
||||
return subs
|
||||
|
||||
def url(self, path=None):
|
||||
return self.ui.config('web', 'baseurl') + (path or self.root)
|
||||
|
||||
def node(self, node):
|
||||
'''format one changeset.'''
|
||||
|
||||
self.t.show(changenode=node, changes=self.repo.changelog.read(node),
|
||||
baseurl=self.ui.config('web', 'baseurl'),
|
||||
root=self.repo.root,
|
||||
webroot=self.root)
|
||||
|
||||
def send(self, node, count):
|
||||
'''send message.'''
|
||||
|
||||
p = email.Parser.Parser()
|
||||
self.sio.seek(0)
|
||||
msg = p.parse(self.sio)
|
||||
|
||||
def fix_subject():
|
||||
'''try to make subject line exist and be useful.'''
|
||||
|
||||
subject = msg['Subject']
|
||||
if not subject:
|
||||
if count > 1:
|
||||
subject = _('%s: %d new changesets') % (self.root, count)
|
||||
else:
|
||||
changes = self.repo.changelog.read(node)
|
||||
s = changes[4].lstrip().split('\n', 1)[0].rstrip()
|
||||
subject = '%s: %s' % (self.root, s)
|
||||
maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
|
||||
if maxsubject and len(subject) > maxsubject:
|
||||
subject = subject[:maxsubject-3] + '...'
|
||||
del msg['Subject']
|
||||
msg['Subject'] = subject
|
||||
|
||||
def fix_sender():
|
||||
'''try to make message have proper sender.'''
|
||||
|
||||
sender = msg['From']
|
||||
if not sender:
|
||||
sender = self.ui.config('email', 'from') or self.ui.username()
|
||||
if '@' not in sender or '@localhost' in sender:
|
||||
sender = self.fixmail(sender)
|
||||
del msg['From']
|
||||
msg['From'] = sender
|
||||
|
||||
fix_subject()
|
||||
fix_sender()
|
||||
|
||||
msg['X-Hg-Notification'] = 'changeset ' + short(node)
|
||||
if not msg['Message-Id']:
|
||||
msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
|
||||
(short(node), int(time.time()),
|
||||
hash(self.repo.root), socket.getfqdn()))
|
||||
|
||||
msgtext = msg.as_string(0)
|
||||
if self.ui.configbool('notify', 'test', True):
|
||||
self.ui.write(msgtext)
|
||||
if not msgtext.endswith('\n'):
|
||||
self.ui.write('\n')
|
||||
else:
|
||||
mail = self.ui.sendmail()
|
||||
mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
|
||||
|
||||
def diff(self, node):
|
||||
maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
|
||||
if maxdiff == 0:
|
||||
return
|
||||
fp = templater.stringio()
|
||||
commands.dodiff(fp, self.ui, self.repo, node,
|
||||
self.repo.changelog.tip())
|
||||
difflines = fp.getvalue().splitlines(1)
|
||||
if maxdiff > 0 and len(difflines) > maxdiff:
|
||||
self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
|
||||
(len(difflines), maxdiff))
|
||||
difflines = difflines[:maxdiff]
|
||||
elif difflines:
|
||||
self.sio.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
|
||||
self.sio.write(*difflines)
|
||||
|
||||
def hook(ui, repo, hooktype, node=None, **kwargs):
|
||||
'''send email notifications to interested subscribers.
|
||||
|
||||
if used as changegroup hook, send one email for all changesets in
|
||||
changegroup. else send one email per changeset.'''
|
||||
n = notifier(ui, repo, hooktype)
|
||||
if not n.subs: return True
|
||||
node = bin(node)
|
||||
if hooktype == 'changegroup':
|
||||
start = repo.changelog.rev(node)
|
||||
end = repo.changelog.count()
|
||||
count = end - start
|
||||
for rev in xrange(start, end):
|
||||
n.node(repo.changelog.node(rev))
|
||||
else:
|
||||
count = 1
|
||||
n.node(node)
|
||||
n.diff(node)
|
||||
n.send(node, count)
|
||||
return True
|
@ -31,20 +31,10 @@
|
||||
# the messages directly. This can be reviewed e.g. with "mutt -R -f mbox",
|
||||
# and finally sent with "formail -s sendmail -bm -t < mbox".
|
||||
#
|
||||
# To configure a default mail host, add a section like this to your
|
||||
# hgrc file:
|
||||
#
|
||||
# [smtp]
|
||||
# host = my_mail_host
|
||||
# port = 1025
|
||||
# tls = yes # or omit if not needed
|
||||
# username = user # if SMTP authentication required
|
||||
# password = password # if SMTP authentication required - PLAINTEXT
|
||||
#
|
||||
# To configure other defaults, add a section like this to your hgrc
|
||||
# file:
|
||||
#
|
||||
# [patchbomb]
|
||||
# [email]
|
||||
# from = My Name <my@email>
|
||||
# to = recipient1, recipient2, ...
|
||||
# cc = cc1, cc2, ...
|
||||
@ -52,7 +42,7 @@
|
||||
from mercurial.demandload import *
|
||||
demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
|
||||
mercurial:commands,hg,ui
|
||||
os errno popen2 smtplib socket sys tempfile time''')
|
||||
os errno popen2 socket sys tempfile time''')
|
||||
from mercurial.i18n import gettext as _
|
||||
|
||||
try:
|
||||
@ -183,11 +173,13 @@ def patchbomb(ui, repo, *revs, **opts):
|
||||
jumbo.extend(p)
|
||||
msgs.append(makepatch(p, i + 1, len(patches)))
|
||||
|
||||
sender = (opts['from'] or ui.config('patchbomb', 'from') or
|
||||
sender = (opts['from'] or ui.config('email', 'from') or
|
||||
ui.config('patchbomb', 'from') or
|
||||
prompt('From', ui.username()))
|
||||
|
||||
def getaddrs(opt, prpt, default = None):
|
||||
addrs = opts[opt] or (ui.config('patchbomb', opt) or
|
||||
addrs = opts[opt] or (ui.config('email', opt) or
|
||||
ui.config('patchbomb', opt) or
|
||||
prompt(prpt, default = default)).split(',')
|
||||
return [a.strip() for a in addrs if a.strip()]
|
||||
to = getaddrs('to', 'To')
|
||||
@ -223,17 +215,7 @@ def patchbomb(ui, repo, *revs, **opts):
|
||||
ui.write('\n')
|
||||
|
||||
if not opts['test'] and not opts['mbox']:
|
||||
s = smtplib.SMTP()
|
||||
s.connect(host = ui.config('smtp', 'host', 'mail'),
|
||||
port = int(ui.config('smtp', 'port', 25)))
|
||||
if ui.configbool('smtp', 'tls'):
|
||||
s.ehlo()
|
||||
s.starttls()
|
||||
s.ehlo()
|
||||
username = ui.config('smtp', 'username')
|
||||
password = ui.config('smtp', 'password')
|
||||
if username and password:
|
||||
s.login(username, password)
|
||||
mail = ui.sendmail()
|
||||
parent = None
|
||||
tz = time.strftime('%z')
|
||||
sender_addr = email.Utils.parseaddr(sender)[1]
|
||||
@ -271,9 +253,9 @@ def patchbomb(ui, repo, *revs, **opts):
|
||||
fp.close()
|
||||
else:
|
||||
ui.status('Sending ', m['Subject'], ' ...\n')
|
||||
s.sendmail(sender, to + cc, m.as_string(0))
|
||||
mail.sendmail(sender, to + cc, m.as_string(0))
|
||||
if not opts['test'] and not opts['mbox']:
|
||||
s.close()
|
||||
mail.close()
|
||||
|
||||
cmdtable = {
|
||||
'email':
|
||||
|
@ -2232,21 +2232,26 @@ def rename(ui, repo, *pats, **opts):
|
||||
return errs
|
||||
|
||||
def revert(ui, repo, *pats, **opts):
|
||||
"""revert modified files or dirs back to their unmodified states
|
||||
"""revert modified files or dirs to their states as of some revision
|
||||
|
||||
In its default mode, it reverts any uncommitted modifications made
|
||||
to the named files or directories. This restores the contents of
|
||||
the affected files to an unmodified state.
|
||||
With no revision specified, revert the named files or directories
|
||||
to the contents they had in the parent of the working directory.
|
||||
This restores the contents of the affected files to an unmodified
|
||||
state. If the working directory has two parents, you must
|
||||
explicitly specify the revision to revert to.
|
||||
|
||||
Modified files are saved with a .orig suffix before reverting.
|
||||
To disable these backups, use --no-backup.
|
||||
|
||||
Using the -r option, it reverts the given files or directories to
|
||||
their state as of an earlier revision. This can be helpful to "roll
|
||||
Using the -r option, revert the given files or directories to
|
||||
their contents as of a specific revision. This can be helpful to"roll
|
||||
back" some or all of a change that should not have been committed.
|
||||
|
||||
Revert modifies the working directory. It does not commit any
|
||||
changes, or change the parent of the current working directory.
|
||||
changes, or change the parent of the working directory. If you
|
||||
revert to a revision other than the parent of the working
|
||||
directory, the reverted files will thus appear modified
|
||||
afterwards.
|
||||
|
||||
If a file has been deleted, it is recreated. If the executable
|
||||
mode of a file was changed, it is reset.
|
||||
@ -2255,8 +2260,14 @@ def revert(ui, repo, *pats, **opts):
|
||||
|
||||
If no arguments are given, all files in the repository are reverted.
|
||||
"""
|
||||
parent = repo.dirstate.parents()[0]
|
||||
node = opts['rev'] and repo.lookup(opts['rev']) or parent
|
||||
parent, p2 = repo.dirstate.parents()
|
||||
if opts['rev']:
|
||||
node = repo.lookup(opts['rev'])
|
||||
elif p2 != nullid:
|
||||
raise util.Abort(_('working dir has two parents; '
|
||||
'you must specify the revision to revert to'))
|
||||
else:
|
||||
node = parent
|
||||
mf = repo.manifest.read(repo.changelog.read(node)[0])
|
||||
|
||||
wlock = repo.wlock()
|
||||
|
@ -499,3 +499,17 @@ class changeset_templater(object):
|
||||
inst.args[0]))
|
||||
except SyntaxError, inst:
|
||||
raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
|
||||
|
||||
class stringio(object):
|
||||
'''wrap cStringIO for use by changeset_templater.'''
|
||||
def __init__(self):
|
||||
self.fp = cStringIO.StringIO()
|
||||
|
||||
def write(self, *args):
|
||||
for a in args:
|
||||
self.fp.write(a)
|
||||
|
||||
write_header = write
|
||||
|
||||
def __getattr__(self, key):
|
||||
return getattr(self.fp, key)
|
||||
|
@ -8,7 +8,7 @@
|
||||
import ConfigParser
|
||||
from i18n import gettext as _
|
||||
from demandload import *
|
||||
demandload(globals(), "errno os re socket sys tempfile util")
|
||||
demandload(globals(), "errno os re smtplib socket sys tempfile util")
|
||||
|
||||
class ui(object):
|
||||
def __init__(self, verbose=False, debug=False, quiet=False,
|
||||
@ -242,7 +242,8 @@ class ui(object):
|
||||
def debug(self, *msg):
|
||||
if self.debugflag: self.write(*msg)
|
||||
def edit(self, text, user):
|
||||
(fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt")
|
||||
(fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
|
||||
text=True)
|
||||
try:
|
||||
f = os.fdopen(fd, "w")
|
||||
f.write(text)
|
||||
@ -264,3 +265,17 @@ class ui(object):
|
||||
os.unlink(name)
|
||||
|
||||
return t
|
||||
|
||||
def sendmail(self):
|
||||
s = smtplib.SMTP()
|
||||
s.connect(host = self.config('smtp', 'host', 'mail'),
|
||||
port = int(self.config('smtp', 'port', 25)))
|
||||
if self.configbool('smtp', 'tls'):
|
||||
s.ehlo()
|
||||
s.starttls()
|
||||
s.ehlo()
|
||||
username = self.config('smtp', 'username')
|
||||
password = self.config('smtp', 'password')
|
||||
if username and password:
|
||||
s.login(username, password)
|
||||
return s
|
||||
|
@ -231,7 +231,7 @@ def canonpath(root, cwd, myname):
|
||||
name_st = os.stat(name)
|
||||
except OSError:
|
||||
break
|
||||
if os.path.samestat(name_st, root_st):
|
||||
if samestat(name_st, root_st):
|
||||
rel.reverse()
|
||||
name = os.path.join(*rel)
|
||||
audit_path(name)
|
||||
@ -561,6 +561,9 @@ if os.name == 'nt':
|
||||
makelock = _makelock_file
|
||||
readlock = _readlock_file
|
||||
|
||||
def samestat(s1, s2):
|
||||
return False
|
||||
|
||||
def explain_exit(code):
|
||||
return _("exited with status %d") % code, code
|
||||
|
||||
@ -627,6 +630,7 @@ else:
|
||||
return path
|
||||
|
||||
normpath = os.path.normpath
|
||||
samestat = os.path.samestat
|
||||
|
||||
def makelock(info, pathname):
|
||||
try:
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<a class="title" href="?cmd=changeset;node=#node#;style=gitweb"><span class="age">#date|age# ago</span>#desc|firstline|escape#</a>
|
||||
<a class="title" href="?cmd=changeset;node=#node#;style=gitweb"><span class="age">#date|age# ago</span>#desc|strip|firstline|escape#</a>
|
||||
</div>
|
||||
<div class="title_text">
|
||||
<div class="log_link">
|
||||
@ -8,7 +8,7 @@
|
||||
<i>#author|obfuscate# [#date|rfc822date#] rev #rev#</i><br/>
|
||||
</div>
|
||||
<div class="log_body">
|
||||
#desc|escape|addbreaks#
|
||||
#desc|strip|escape|addbreaks#
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a class="title" href="?cmd=changeset;node=#node#;style=raw">#desc|escape|firstline#</a>
|
||||
<a class="title" href="?cmd=changeset;node=#node#;style=raw">#desc|strip|escape|firstline#</a>
|
||||
</div>
|
||||
<div class="title_text">
|
||||
<table cellspacing="0">
|
||||
@ -28,7 +28,7 @@
|
||||
</table></div>
|
||||
|
||||
<div class="title_text">
|
||||
#desc|escape|addbreaks#
|
||||
#desc|strip|escape|addbreaks#
|
||||
</div>
|
||||
|
||||
<div class="title_text">
|
||||
|
@ -45,6 +45,6 @@ filelogparent = '<tr><td align="right">parent #rev#: </td><td><a href="?cmd
|
||||
filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>'
|
||||
filelogchild = '<tr><td align="right">child #rev#: </td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>'
|
||||
shortlog = shortlog-gitweb.tmpl
|
||||
shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=manifest;manifest=#manifest|short#;path=/;style=gitweb">manifest</a></td></tr>'
|
||||
filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><!-- FIXME: <a href="?fd=#node|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a> #rename%filelogrename#</td></tr>'
|
||||
shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=manifest;manifest=#manifest|short#;path=/;style=gitweb">manifest</a></td></tr>'
|
||||
filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><!-- FIXME: <a href="?fd=#node|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a> #rename%filelogrename#</td></tr>'
|
||||
archiveentry = ' | <a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> '
|
||||
|
@ -3,7 +3,7 @@ A simple testing framework
|
||||
To run the tests, do:
|
||||
|
||||
cd tests/
|
||||
./run-tests
|
||||
python run-tests.py
|
||||
|
||||
This finds all scripts in the test directory named test-* and executes
|
||||
them. The scripts can be either shell scripts or Python. Each test is
|
||||
|
197
tests/run-tests
197
tests/run-tests
@ -1,197 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# environment variables:
|
||||
#
|
||||
# TEST_COVERAGE - set non-empty if you want to print test coverage report
|
||||
# COVERAGE_STDLIB - set non-empty to report coverage of standard library
|
||||
|
||||
LANG="C"; export LANG
|
||||
LC_CTYPE="C"; export LC_CTYPE
|
||||
LC_NUMERIC="C"; export LC_NUMERIC
|
||||
LC_TIME="C"; export LC_TIME
|
||||
LC_COLLATE="C"; export LC_COLLATE
|
||||
LC_MONETARY="C"; export LC_MONETARY
|
||||
LC_MESSAGES="C"; export LC_MESSAGES
|
||||
LC_PAPER="C"; export LC_PAPER
|
||||
LC_NAME="C"; export LC_NAME
|
||||
LC_ADDRESS="C"; export LC_ADDRESS
|
||||
LC_TELEPHONE="C"; export LC_TELEPHONE
|
||||
LC_MEASUREMENT="C"; export LC_MEASUREMENT
|
||||
LC_IDENTIFICATION="C"; export LC_IDENTIFICATION
|
||||
LC_ALL=""; export LC_ALL
|
||||
TZ=GMT; export TZ
|
||||
HGEDITOR=true; export HGEDITOR
|
||||
HGMERGE=true; export HGMERGE
|
||||
HGUSER="test"; export HGUSER
|
||||
HGRCPATH=""; export HGRCPATH
|
||||
OS=`uname`
|
||||
|
||||
case "$OS" in
|
||||
HP-UX|SunOS)
|
||||
DIFFOPTS=
|
||||
;;
|
||||
*)
|
||||
DIFFOPTS=-u
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ `echo -n HG` = "-n HG" ]
|
||||
then
|
||||
ECHO_N=echo
|
||||
NNL="\c"
|
||||
else
|
||||
ECHO_N="echo -n"
|
||||
NNL=
|
||||
fi
|
||||
|
||||
umask 022
|
||||
|
||||
tests=0
|
||||
failed=0
|
||||
|
||||
HGTMP=""
|
||||
cleanup_exit() {
|
||||
rm -rf "$HGTMP"
|
||||
}
|
||||
|
||||
# Remove temporary files even if we get interrupted
|
||||
trap "cleanup_exit" 0 # normal exit
|
||||
trap "exit 255" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
|
||||
|
||||
HGTMP="${TMPDIR-/tmp}/hgtests.$RANDOM.$RANDOM.$RANDOM.$$"
|
||||
(umask 077 && mkdir "$HGTMP") || {
|
||||
echo "Could not create temporary directory! Exiting." 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
TESTDIR="`pwd`"
|
||||
export TESTDIR
|
||||
INST="$HGTMP/install"
|
||||
PYTHONDIR="$INST/lib/python"
|
||||
cd ..
|
||||
if ${PYTHON-python} setup.py clean --all install --force --home="$INST" \
|
||||
--install-lib="$PYTHONDIR" > tests/install.err 2>&1
|
||||
then
|
||||
rm tests/install.err
|
||||
else
|
||||
cat tests/install.err
|
||||
exit 1
|
||||
fi
|
||||
cd "$TESTDIR"
|
||||
|
||||
BINDIR="$INST/bin"; export BINDIR
|
||||
if [ -n "$TEST_COVERAGE" ]; then
|
||||
COVERAGE_FILE="$TESTDIR/.coverage"; export COVERAGE_FILE
|
||||
rm -f "$COVERAGE_FILE"
|
||||
mv "$BINDIR/hg" "$BINDIR/hg.py"
|
||||
{
|
||||
echo '#!/bin/sh'
|
||||
echo "exec \"${PYTHON-python}\" \"$TESTDIR/coverage.py\"" \
|
||||
"-x \"$BINDIR/hg.py\" \"\$@\""
|
||||
} > "$BINDIR/hg"
|
||||
chmod 700 "$BINDIR/hg"
|
||||
fi
|
||||
|
||||
PATH="$BINDIR:$PATH"; export PATH
|
||||
if [ -n "$PYTHON" ]; then
|
||||
{
|
||||
echo "#!/bin/sh"
|
||||
echo "exec \"$PYTHON"'" "$@"'
|
||||
} > "$BINDIR/python"
|
||||
chmod 755 "$BINDIR/python"
|
||||
fi
|
||||
|
||||
PYTHONPATH="$PYTHONDIR"; export PYTHONPATH
|
||||
|
||||
run_one() {
|
||||
rm -f "$1.err"
|
||||
|
||||
mkdir "$HGTMP/$1"
|
||||
cd "$HGTMP/$1"
|
||||
fail=0
|
||||
HOME="$HGTMP/$1"; export HOME
|
||||
OUT="$HGTMP/$1.out"
|
||||
OUTOK="$TESTDIR/$1.out"
|
||||
ERR="$TESTDIR/$1.err"
|
||||
|
||||
if "$TESTDIR/$1" > "$OUT" 2>&1; then
|
||||
: no error
|
||||
else
|
||||
echo "$1 failed with error code $?"
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ -s "$OUT" -a ! -s "$OUTOK" ] ; then
|
||||
cp "$OUT" "$ERR"
|
||||
echo
|
||||
echo "$1 generated unexpected output:"
|
||||
cat "$ERR"
|
||||
fail=1
|
||||
elif [ -r "$OUTOK" ]; then
|
||||
if diff $DIFFOPTS "$OUTOK" "$OUT" > /dev/null; then
|
||||
: no differences
|
||||
else
|
||||
cp "$OUT" "$ERR"
|
||||
echo
|
||||
echo "$1 output changed:"
|
||||
diff $DIFFOPTS "$OUTOK" "$ERR" || true
|
||||
fail=1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$TESTDIR"
|
||||
rm -f "$HGTMP/$1.out"
|
||||
rm -rf "$HGTMP/$1"
|
||||
return $fail
|
||||
}
|
||||
|
||||
# list of prerequisite programs
|
||||
# stuff from coreutils (cat, rm, etc) are not tested
|
||||
prereqs="python merge diff grep unzip gunzip bunzip2 sed"
|
||||
missing=''
|
||||
for pre in $prereqs ; do
|
||||
if type $pre > /dev/null 2>&1 ; then
|
||||
: prereq exists
|
||||
else
|
||||
missing="$pre $missing"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$missing" != '' ] ; then
|
||||
echo "ERROR: the test suite needs some programs to execute correctly."
|
||||
echo "The following programs are missing: "
|
||||
for pre in $missing; do
|
||||
echo " $pre"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TESTS="$*"
|
||||
if [ -z "$TESTS" ] ; then
|
||||
TESTS=`ls test-* | grep -v "[.~]"`
|
||||
fi
|
||||
|
||||
for f in $TESTS ; do
|
||||
$ECHO_N ".${NNL}"
|
||||
run_one $f || failed=`expr $failed + 1`
|
||||
tests=`expr $tests + 1`
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Ran $tests tests, $failed failed."
|
||||
|
||||
if [ -n "$TEST_COVERAGE" ]; then
|
||||
unset PYTHONPATH
|
||||
$ECHO_N "$BINDIR,$TESTDIR,$HGTMP/test-," > "$HGTMP/omit"
|
||||
if [ -z "$COVERAGE_STDLIB" ]; then
|
||||
"${PYTHON-python}" -c 'import sys; print ",".join(sys.path)' \
|
||||
>> "$HGTMP/omit"
|
||||
fi
|
||||
cd "$PYTHONDIR"
|
||||
"${PYTHON-python}" "$TESTDIR/coverage.py" -r --omit="`cat \"$HGTMP/omit\"`"
|
||||
fi
|
||||
|
||||
if [ $failed -gt 0 ] ; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
@ -176,18 +176,20 @@ def run_one(test):
|
||||
ret, out = run(cmd)
|
||||
vlog("# Ret was:", ret)
|
||||
|
||||
if ret == 0:
|
||||
# If reference output file exists, check test output against it
|
||||
if os.path.exists(ref):
|
||||
f = open(ref, "r")
|
||||
ref_out = f.read().splitlines()
|
||||
f.close()
|
||||
if out != ref_out:
|
||||
ret = 1
|
||||
print "\nERROR: %s output changed" % (test)
|
||||
show_diff(ref_out, out)
|
||||
else:
|
||||
diffret = 0
|
||||
# If reference output file exists, check test output against it
|
||||
if os.path.exists(ref):
|
||||
f = open(ref, "r")
|
||||
ref_out = f.read().splitlines()
|
||||
f.close()
|
||||
if out != ref_out:
|
||||
diffret = 1
|
||||
print "\nERROR: %s output changed" % (test)
|
||||
show_diff(ref_out, out)
|
||||
if ret:
|
||||
print "\nERROR: %s failed with error code %d" % (test, ret)
|
||||
elif diffret:
|
||||
ret = diffret
|
||||
|
||||
if ret != 0: # Save errors to a file for diagnosis
|
||||
f = open(err, "w")
|
||||
|
@ -41,9 +41,12 @@ hg remove a
|
||||
echo "%%% should show a removed and b added"
|
||||
hg status
|
||||
|
||||
echo "reverting..."
|
||||
echo "%%% revert should fail"
|
||||
hg revert
|
||||
|
||||
echo "%%% revert should be ok now"
|
||||
hg revert -r2
|
||||
|
||||
echo "%%% should show b unknown and a marked modified (merged)"
|
||||
hg status
|
||||
|
||||
|
@ -16,7 +16,9 @@ foo-b
|
||||
%%% should show a removed and b added
|
||||
A b
|
||||
R a
|
||||
reverting...
|
||||
%%% revert should fail
|
||||
abort: working dir has two parents; you must specify the revision to revert to
|
||||
%%% revert should be ok now
|
||||
undeleting a
|
||||
forgetting b
|
||||
%%% should show b unknown and a marked modified (merged)
|
||||
|
@ -14,7 +14,7 @@ basic commands (use "hg help" for the full list or option "-v" for details):
|
||||
pull pull changes from the specified source
|
||||
push push changes to the specified destination
|
||||
remove remove the specified files on the next commit
|
||||
revert revert modified files or dirs back to their unmodified states
|
||||
revert revert modified files or dirs to their states as of some revision
|
||||
serve export the repository via HTTP
|
||||
status show changed files in the working directory
|
||||
update update or merge working directory
|
||||
@ -30,7 +30,7 @@ basic commands (use "hg help" for the full list or option "-v" for details):
|
||||
pull pull changes from the specified source
|
||||
push push changes to the specified destination
|
||||
remove remove the specified files on the next commit
|
||||
revert revert modified files or dirs back to their unmodified states
|
||||
revert revert modified files or dirs to their states as of some revision
|
||||
serve export the repository via HTTP
|
||||
status show changed files in the working directory
|
||||
update update or merge working directory
|
||||
@ -68,7 +68,7 @@ list of commands (use "hg help -v" to show aliases and global options):
|
||||
recover roll back an interrupted transaction
|
||||
remove remove the specified files on the next commit
|
||||
rename rename files; equivalent of copy + remove
|
||||
revert revert modified files or dirs back to their unmodified states
|
||||
revert revert modified files or dirs to their states as of some revision
|
||||
root print the root (top) of the current working dir
|
||||
serve export the repository via HTTP
|
||||
status show changed files in the working directory
|
||||
@ -110,7 +110,7 @@ list of commands (use "hg help -v" to show aliases and global options):
|
||||
recover roll back an interrupted transaction
|
||||
remove remove the specified files on the next commit
|
||||
rename rename files; equivalent of copy + remove
|
||||
revert revert modified files or dirs back to their unmodified states
|
||||
revert revert modified files or dirs to their states as of some revision
|
||||
root print the root (top) of the current working dir
|
||||
serve export the repository via HTTP
|
||||
status show changed files in the working directory
|
||||
@ -226,7 +226,7 @@ basic commands (use "hg help" for the full list or option "-v" for details):
|
||||
pull pull changes from the specified source
|
||||
push push changes to the specified destination
|
||||
remove remove the specified files on the next commit
|
||||
revert revert modified files or dirs back to their unmodified states
|
||||
revert revert modified files or dirs to their states as of some revision
|
||||
serve export the repository via HTTP
|
||||
status show changed files in the working directory
|
||||
update update or merge working directory
|
||||
@ -247,7 +247,7 @@ basic commands (use "hg help" for the full list or option "-v" for details):
|
||||
pull pull changes from the specified source
|
||||
push push changes to the specified destination
|
||||
remove remove the specified files on the next commit
|
||||
revert revert modified files or dirs back to their unmodified states
|
||||
revert revert modified files or dirs to their states as of some revision
|
||||
serve export the repository via HTTP
|
||||
status show changed files in the working directory
|
||||
update update or merge working directory
|
||||
|
Loading…
Reference in New Issue
Block a user