Show More
@@ -0,0 +1,179 b'' | |||||
|
1 | # churn.py - create a graph showing who changed the most lines | |||
|
2 | # | |||
|
3 | # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | # | |||
|
8 | # | |||
|
9 | # Aliases map file format is simple one alias per line in the following | |||
|
10 | # format: | |||
|
11 | # | |||
|
12 | # <alias email> <actual email> | |||
|
13 | ||||
|
14 | from mercurial.demandload import * | |||
|
15 | from mercurial.i18n import gettext as _ | |||
|
16 | demandload(globals(), 'time sys signal os') | |||
|
17 | demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node') | |||
|
18 | ||||
|
19 | def __gather(ui, repo, node1, node2): | |||
|
20 | def dirtywork(f, mmap1, mmap2): | |||
|
21 | lines = 0 | |||
|
22 | ||||
|
23 | to = mmap1 and repo.file(f).read(mmap1[f]) or None | |||
|
24 | tn = mmap2 and repo.file(f).read(mmap2[f]) or None | |||
|
25 | ||||
|
26 | diff = mdiff.unidiff(to, "", tn, "", f).split("\n") | |||
|
27 | ||||
|
28 | for line in diff: | |||
|
29 | if not line: | |||
|
30 | continue # skip EOF | |||
|
31 | if line.startswith(" "): | |||
|
32 | continue # context line | |||
|
33 | if line.startswith("--- ") or line.startswith("+++ "): | |||
|
34 | continue # begining of diff | |||
|
35 | if line.startswith("@@ "): | |||
|
36 | continue # info line | |||
|
37 | ||||
|
38 | # changed lines | |||
|
39 | lines += 1 | |||
|
40 | ||||
|
41 | return lines | |||
|
42 | ||||
|
43 | ## | |||
|
44 | ||||
|
45 | lines = 0 | |||
|
46 | ||||
|
47 | changes = repo.status(node1, node2, None, util.always)[:5] | |||
|
48 | ||||
|
49 | modified, added, removed, deleted, unknown = changes | |||
|
50 | ||||
|
51 | who = repo.changelog.read(node2)[1] | |||
|
52 | who = templater.email(who) # get the email of the person | |||
|
53 | ||||
|
54 | mmap1 = repo.manifest.read(repo.changelog.read(node1)[0]) | |||
|
55 | mmap2 = repo.manifest.read(repo.changelog.read(node2)[0]) | |||
|
56 | for f in modified: | |||
|
57 | lines += dirtywork(f, mmap1, mmap2) | |||
|
58 | ||||
|
59 | for f in added: | |||
|
60 | lines += dirtywork(f, None, mmap2) | |||
|
61 | ||||
|
62 | for f in removed: | |||
|
63 | lines += dirtywork(f, mmap1, None) | |||
|
64 | ||||
|
65 | for f in deleted: | |||
|
66 | lines += dirtywork(f, mmap1, mmap2) | |||
|
67 | ||||
|
68 | for f in unknown: | |||
|
69 | lines += dirtywork(f, mmap1, mmap2) | |||
|
70 | ||||
|
71 | return (who, lines) | |||
|
72 | ||||
|
73 | def gather_stats(ui, repo, amap, revs=None, progress=False): | |||
|
74 | stats = {} | |||
|
75 | ||||
|
76 | cl = repo.changelog | |||
|
77 | ||||
|
78 | if not revs: | |||
|
79 | revs = range(0, cl.count()) | |||
|
80 | ||||
|
81 | nr_revs = len(revs) | |||
|
82 | cur_rev = 0 | |||
|
83 | ||||
|
84 | for rev in revs: | |||
|
85 | cur_rev += 1 # next revision | |||
|
86 | ||||
|
87 | node2 = cl.node(rev) | |||
|
88 | node1 = cl.parents(node2)[0] | |||
|
89 | ||||
|
90 | if cl.parents(node2)[1] != node.nullid: | |||
|
91 | ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,)) | |||
|
92 | continue | |||
|
93 | ||||
|
94 | who, lines = __gather(ui, repo, node1, node2) | |||
|
95 | ||||
|
96 | # remap the owner if possible | |||
|
97 | if amap.has_key(who): | |||
|
98 | ui.note("using '%s' alias for '%s'\n" % (amap[who], who)) | |||
|
99 | who = amap[who] | |||
|
100 | ||||
|
101 | if not stats.has_key(who): | |||
|
102 | stats[who] = 0 | |||
|
103 | stats[who] += lines | |||
|
104 | ||||
|
105 | ui.note("rev %d: %d lines by %s\n" % (rev, lines, who)) | |||
|
106 | ||||
|
107 | if progress: | |||
|
108 | if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs): | |||
|
109 | ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),)) | |||
|
110 | sys.stdout.flush() | |||
|
111 | ||||
|
112 | if progress: | |||
|
113 | ui.write("done\n") | |||
|
114 | sys.stdout.flush() | |||
|
115 | ||||
|
116 | return stats | |||
|
117 | ||||
|
118 | def churn(ui, repo, **opts): | |||
|
119 | "Graphs the number of lines changed" | |||
|
120 | ||||
|
121 | def pad(s, l): | |||
|
122 | if len(s) < l: | |||
|
123 | return s + " " * (l-len(s)) | |||
|
124 | return s[0:l] | |||
|
125 | ||||
|
126 | def graph(n, maximum, width, char): | |||
|
127 | n = int(n * width / float(maximum)) | |||
|
128 | ||||
|
129 | return char * (n) | |||
|
130 | ||||
|
131 | def get_aliases(f): | |||
|
132 | aliases = {} | |||
|
133 | ||||
|
134 | for l in f.readlines(): | |||
|
135 | l = l.strip() | |||
|
136 | alias, actual = l.split(" ") | |||
|
137 | aliases[alias] = actual | |||
|
138 | ||||
|
139 | return aliases | |||
|
140 | ||||
|
141 | amap = {} | |||
|
142 | aliases = opts.get('aliases') | |||
|
143 | if aliases: | |||
|
144 | try: | |||
|
145 | f = open(aliases,"r") | |||
|
146 | except OSError, e: | |||
|
147 | print "Error: " + e | |||
|
148 | return | |||
|
149 | ||||
|
150 | amap = get_aliases(f) | |||
|
151 | f.close() | |||
|
152 | ||||
|
153 | revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])] | |||
|
154 | revs.sort() | |||
|
155 | stats = gather_stats(ui, repo, amap, revs, opts.get('progress')) | |||
|
156 | ||||
|
157 | # make a list of tuples (name, lines) and sort it in descending order | |||
|
158 | ordered = stats.items() | |||
|
159 | ordered.sort(lambda x, y: cmp(y[1], x[1])) | |||
|
160 | ||||
|
161 | maximum = ordered[0][1] | |||
|
162 | ||||
|
163 | ui.note("Assuming 80 character terminal\n") | |||
|
164 | width = 80 - 1 | |||
|
165 | ||||
|
166 | for i in ordered: | |||
|
167 | person = i[0] | |||
|
168 | lines = i[1] | |||
|
169 | print "%s %6d %s" % (pad(person, 20), lines, | |||
|
170 | graph(lines, maximum, width - 20 - 1 - 6 - 2 - 2, '*')) | |||
|
171 | ||||
|
172 | cmdtable = { | |||
|
173 | "churn": | |||
|
174 | (churn, | |||
|
175 | [('r', 'rev', [], _('limit statistics to the specified revisions')), | |||
|
176 | ('', 'aliases', '', _('file with email aliases')), | |||
|
177 | ('', 'progress', None, _('show progress'))], | |||
|
178 | 'hg churn [-r revision range] [-a file] [--progress]'), | |||
|
179 | } |
@@ -0,0 +1,281 b'' | |||||
|
1 | ;;; mq.el --- Emacs support for Mercurial Queues | |||
|
2 | ||||
|
3 | ;; Copyright (C) 2006 Bryan O'Sullivan | |||
|
4 | ||||
|
5 | ;; Author: Bryan O'Sullivan <bos@serpentine.com> | |||
|
6 | ||||
|
7 | ;; mq.el is free software; you can redistribute it and/or modify it | |||
|
8 | ;; under the terms of version 2 of the GNU General Public License as | |||
|
9 | ;; published by the Free Software Foundation. | |||
|
10 | ||||
|
11 | ;; mq.el is distributed in the hope that it will be useful, but | |||
|
12 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
|
14 | ;; General Public License for more details. | |||
|
15 | ||||
|
16 | ;; You should have received a copy of the GNU General Public License | |||
|
17 | ;; along with mq.el, GNU Emacs, or XEmacs; see the file COPYING (`C-h | |||
|
18 | ;; C-l'). If not, write to the Free Software Foundation, Inc., 59 | |||
|
19 | ;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
|
20 | ||||
|
21 | (require 'mercurial) | |||
|
22 | ||||
|
23 | ||||
|
24 | (defcustom mq-mode-hook nil | |||
|
25 | "Hook run when a buffer enters mq-mode." | |||
|
26 | :type 'sexp | |||
|
27 | :group 'mercurial) | |||
|
28 | ||||
|
29 | (defcustom mq-global-prefix "\C-cq" | |||
|
30 | "The global prefix for Mercurial Queues keymap bindings." | |||
|
31 | :type 'sexp | |||
|
32 | :group 'mercurial) | |||
|
33 | ||||
|
34 | (defcustom mq-edit-mode-hook nil | |||
|
35 | "Hook run after a buffer is populated to edit a patch description." | |||
|
36 | :type 'sexp | |||
|
37 | :group 'mercurial) | |||
|
38 | ||||
|
39 | ||||
|
40 | ;;; Internal variables. | |||
|
41 | ||||
|
42 | (defvar mq-patch-history nil) | |||
|
43 | ||||
|
44 | (defvar mq-prev-buffer nil) | |||
|
45 | (make-variable-buffer-local 'mq-prev-buffer) | |||
|
46 | (put 'mq-prev-buffer 'permanent-local t) | |||
|
47 | ||||
|
48 | ||||
|
49 | ;;; Global keymap. | |||
|
50 | ||||
|
51 | (defvar mq-global-map (make-sparse-keymap)) | |||
|
52 | (fset 'mq-global-map mq-global-map) | |||
|
53 | (global-set-key mq-global-prefix 'mq-global-map) | |||
|
54 | (define-key mq-global-map "." 'mq-push) | |||
|
55 | (define-key mq-global-map ">" 'mq-push-all) | |||
|
56 | (define-key mq-global-map "," 'mq-pop) | |||
|
57 | (define-key mq-global-map "<" 'mq-pop-all) | |||
|
58 | (define-key mq-global-map "r" 'mq-refresh) | |||
|
59 | (define-key mq-global-map "e" 'mq-refresh-edit) | |||
|
60 | (define-key mq-global-map "n" 'mq-next) | |||
|
61 | (define-key mq-global-map "p" 'mq-previous) | |||
|
62 | (define-key mq-global-map "t" 'mq-top) | |||
|
63 | ||||
|
64 | ||||
|
65 | ;;; Refresh edit mode keymap. | |||
|
66 | ||||
|
67 | (defvar mq-edit-mode-map (make-sparse-keymap)) | |||
|
68 | (define-key mq-edit-mode-map "\C-c\C-c" 'mq-edit-finish) | |||
|
69 | (define-key mq-edit-mode-map "\C-c\C-k" 'mq-edit-kill) | |||
|
70 | ||||
|
71 | ||||
|
72 | ;;; Helper functions. | |||
|
73 | ||||
|
74 | (defun mq-read-patch-name (&optional source prompt) | |||
|
75 | "Read a patch name to use with a command. | |||
|
76 | May return nil, meaning \"use the default\"." | |||
|
77 | (let ((patches (split-string | |||
|
78 | (hg-chomp (hg-run0 (or source "qseries"))) "\n"))) | |||
|
79 | (when current-prefix-arg | |||
|
80 | (completing-read (format "Patch%s: " (or prompt "")) | |||
|
81 | (map 'list 'cons patches patches) | |||
|
82 | nil | |||
|
83 | nil | |||
|
84 | nil | |||
|
85 | 'mq-patch-history)))) | |||
|
86 | ||||
|
87 | (defun mq-refresh-buffers (root) | |||
|
88 | (save-excursion | |||
|
89 | (dolist (buf (hg-buffers-visiting-repo root)) | |||
|
90 | (when (not (verify-visited-file-modtime buf)) | |||
|
91 | (set-buffer buf) | |||
|
92 | (let ((ctx (hg-buffer-context))) | |||
|
93 | (message "Refreshing %s..." (buffer-name)) | |||
|
94 | (revert-buffer t t t) | |||
|
95 | (hg-restore-context ctx) | |||
|
96 | (message "Refreshing %s...done" (buffer-name)))))) | |||
|
97 | (hg-update-mode-lines root)) | |||
|
98 | ||||
|
99 | (defun mq-last-line () | |||
|
100 | (goto-char (point-max)) | |||
|
101 | (beginning-of-line) | |||
|
102 | (when (looking-at "^$") | |||
|
103 | (forward-line -1)) | |||
|
104 | (let ((bol (point))) | |||
|
105 | (end-of-line) | |||
|
106 | (let ((line (buffer-substring bol (point)))) | |||
|
107 | (when (> (length line) 0) | |||
|
108 | line)))) | |||
|
109 | ||||
|
110 | (defun mq-push (&optional patch) | |||
|
111 | "Push patches until PATCH is reached. | |||
|
112 | If PATCH is nil, push at most one patch." | |||
|
113 | (interactive (list (mq-read-patch-name "qunapplied" " to push"))) | |||
|
114 | (let ((root (hg-root)) | |||
|
115 | (prev-buf (current-buffer)) | |||
|
116 | last-line ok) | |||
|
117 | (unless root | |||
|
118 | (error "Cannot push outside a repository!")) | |||
|
119 | (hg-sync-buffers root) | |||
|
120 | (let ((buf-name (format "MQ: Push %s" (or patch "next patch")))) | |||
|
121 | (kill-buffer (get-buffer-create buf-name)) | |||
|
122 | (split-window-vertically) | |||
|
123 | (other-window 1) | |||
|
124 | (switch-to-buffer (get-buffer-create buf-name)) | |||
|
125 | (cd root) | |||
|
126 | (message "Pushing...") | |||
|
127 | (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpush" | |||
|
128 | (if patch (list patch)))) | |||
|
129 | last-line (mq-last-line)) | |||
|
130 | (let ((lines (count-lines (point-min) (point-max)))) | |||
|
131 | (if (and (equal lines 2) (string-match "Now at:" last-line)) | |||
|
132 | (progn | |||
|
133 | (kill-buffer (current-buffer)) | |||
|
134 | (delete-window)) | |||
|
135 | (hg-view-mode prev-buf)))) | |||
|
136 | (mq-refresh-buffers root) | |||
|
137 | (sit-for 0) | |||
|
138 | (when last-line | |||
|
139 | (if ok | |||
|
140 | (message "Pushing... %s" last-line) | |||
|
141 | (error "Pushing... %s" last-line))))) | |||
|
142 | ||||
|
143 | (defun mq-push-all () | |||
|
144 | "Push patches until all are applied." | |||
|
145 | (interactive) | |||
|
146 | (mq-push "-a")) | |||
|
147 | ||||
|
148 | (defun mq-pop (&optional patch) | |||
|
149 | "Pop patches until PATCH is reached. | |||
|
150 | If PATCH is nil, pop at most one patch." | |||
|
151 | (interactive (list (mq-read-patch-name "qapplied" " to pop to"))) | |||
|
152 | (let ((root (hg-root)) | |||
|
153 | last-line ok) | |||
|
154 | (unless root | |||
|
155 | (error "Cannot pop outside a repository!")) | |||
|
156 | (hg-sync-buffers root) | |||
|
157 | (set-buffer (generate-new-buffer "qpop")) | |||
|
158 | (cd root) | |||
|
159 | (message "Popping...") | |||
|
160 | (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpop" | |||
|
161 | (if patch (list patch)))) | |||
|
162 | last-line (mq-last-line)) | |||
|
163 | (kill-buffer (current-buffer)) | |||
|
164 | (mq-refresh-buffers root) | |||
|
165 | (sit-for 0) | |||
|
166 | (when last-line | |||
|
167 | (if ok | |||
|
168 | (message "Popping... %s" last-line) | |||
|
169 | (error "Popping... %s" last-line))))) | |||
|
170 | ||||
|
171 | (defun mq-pop-all () | |||
|
172 | "Push patches until none are applied." | |||
|
173 | (interactive) | |||
|
174 | (mq-pop "-a")) | |||
|
175 | ||||
|
176 | (defun mq-refresh-internal (root &rest args) | |||
|
177 | (hg-sync-buffers root) | |||
|
178 | (let ((patch (mq-patch-info "qtop"))) | |||
|
179 | (message "Refreshing %s..." patch) | |||
|
180 | (let ((ret (apply 'hg-run "qrefresh" args))) | |||
|
181 | (if (equal (car ret) 0) | |||
|
182 | (message "Refreshing %s... done." patch) | |||
|
183 | (error "Refreshing %s... %s" patch (hg-chomp (cdr ret))))))) | |||
|
184 | ||||
|
185 | (defun mq-refresh () | |||
|
186 | "Refresh the topmost applied patch." | |||
|
187 | (interactive) | |||
|
188 | (let ((root (hg-root))) | |||
|
189 | (unless root | |||
|
190 | (error "Cannot refresh outside of a repository!")) | |||
|
191 | (mq-refresh-internal root))) | |||
|
192 | ||||
|
193 | (defun mq-patch-info (cmd &optional msg) | |||
|
194 | (let* ((ret (hg-run cmd)) | |||
|
195 | (info (hg-chomp (cdr ret)))) | |||
|
196 | (if (equal (car ret) 0) | |||
|
197 | (if msg | |||
|
198 | (message "%s patch: %s" msg info) | |||
|
199 | info) | |||
|
200 | (error "%s" info)))) | |||
|
201 | ||||
|
202 | (defun mq-top () | |||
|
203 | "Print the name of the topmost applied patch." | |||
|
204 | (interactive) | |||
|
205 | (mq-patch-info "qtop" "Top")) | |||
|
206 | ||||
|
207 | (defun mq-next () | |||
|
208 | "Print the name of the next patch to be pushed." | |||
|
209 | (interactive) | |||
|
210 | (mq-patch-info "qnext" "Next")) | |||
|
211 | ||||
|
212 | (defun mq-previous () | |||
|
213 | "Print the name of the first patch below the topmost applied patch. | |||
|
214 | This would become the active patch if popped to." | |||
|
215 | (interactive) | |||
|
216 | (mq-patch-info "qprev" "Previous")) | |||
|
217 | ||||
|
218 | (defun mq-edit-finish () | |||
|
219 | "Finish editing the description of this patch, and refresh the patch." | |||
|
220 | (interactive) | |||
|
221 | (unless (equal (mq-patch-info "qtop") mq-top) | |||
|
222 | (error "Topmost patch has changed!")) | |||
|
223 | (hg-sync-buffers hg-root) | |||
|
224 | (mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max))) | |||
|
225 | (let ((buf mq-prev-buffer)) | |||
|
226 | (kill-buffer nil) | |||
|
227 | (switch-to-buffer buf))) | |||
|
228 | ||||
|
229 | (defun mq-edit-kill () | |||
|
230 | "Kill the edit currently being prepared." | |||
|
231 | (interactive) | |||
|
232 | (when (or (not (buffer-modified-p)) (y-or-n-p "Really kill this edit? ")) | |||
|
233 | (let ((buf mq-prev-buffer)) | |||
|
234 | (kill-buffer nil) | |||
|
235 | (switch-to-buffer buf)))) | |||
|
236 | ||||
|
237 | (defun mq-edit-mode () | |||
|
238 | "Mode for editing the description of a patch. | |||
|
239 | ||||
|
240 | Key bindings | |||
|
241 | ------------ | |||
|
242 | \\[mq-edit-finish] use this description | |||
|
243 | \\[mq-edit-kill] abandon this description" | |||
|
244 | (interactive) | |||
|
245 | (use-local-map mq-edit-mode-map) | |||
|
246 | (set-syntax-table text-mode-syntax-table) | |||
|
247 | (setq local-abbrev-table text-mode-abbrev-table | |||
|
248 | major-mode 'mq-edit-mode | |||
|
249 | mode-name "MQ-Edit") | |||
|
250 | (set-buffer-modified-p nil) | |||
|
251 | (setq buffer-undo-list nil) | |||
|
252 | (run-hooks 'text-mode-hook 'mq-edit-mode-hook)) | |||
|
253 | ||||
|
254 | (defun mq-refresh-edit () | |||
|
255 | "Refresh the topmost applied patch, editing the patch description." | |||
|
256 | (interactive) | |||
|
257 | (while mq-prev-buffer | |||
|
258 | (set-buffer mq-prev-buffer)) | |||
|
259 | (let ((root (hg-root)) | |||
|
260 | (prev-buffer (current-buffer)) | |||
|
261 | (patch (mq-patch-info "qtop"))) | |||
|
262 | (hg-sync-buffers root) | |||
|
263 | (let ((buf-name (format "*MQ: Edit description of %s*" patch))) | |||
|
264 | (switch-to-buffer (get-buffer-create buf-name)) | |||
|
265 | (when (= (point-min) (point-max)) | |||
|
266 | (set (make-local-variable 'hg-root) root) | |||
|
267 | (set (make-local-variable 'mq-top) patch) | |||
|
268 | (setq mq-prev-buffer prev-buffer) | |||
|
269 | (insert (hg-run0 "qheader")) | |||
|
270 | (goto-char (point-min))) | |||
|
271 | (mq-edit-mode) | |||
|
272 | (cd root))) | |||
|
273 | (message "Type `C-c C-c' to finish editing and refresh the patch.")) | |||
|
274 | ||||
|
275 | ||||
|
276 | (provide 'mq) | |||
|
277 | ||||
|
278 | ||||
|
279 | ;;; Local Variables: | |||
|
280 | ;;; prompt-to-byte-compile: nil | |||
|
281 | ;;; end: |
@@ -0,0 +1,9 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | echo 'syntax error' > badext.py | |||
|
4 | abspath=`pwd`/badext.py | |||
|
5 | ||||
|
6 | echo '[extensions]' >> $HGRCPATH | |||
|
7 | echo "badext = $abspath" >> $HGRCPATH | |||
|
8 | ||||
|
9 | hg -q help help |
@@ -0,0 +1,4 b'' | |||||
|
1 | *** failed to import extension badext: invalid syntax (badext.py, line 1) | |||
|
2 | hg help [COMMAND] | |||
|
3 | ||||
|
4 | show help for a command, extension, or list of commands |
@@ -0,0 +1,34 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | # | |||
|
3 | # test for branch handling | |||
|
4 | # | |||
|
5 | # XXX: need more tests | |||
|
6 | ||||
|
7 | hg init | |||
|
8 | echo a > a | |||
|
9 | echo b > b | |||
|
10 | hg ci -A -m 0 -d "1000000 0" | |||
|
11 | echo aa > a | |||
|
12 | echo bb > b | |||
|
13 | hg ci -m 1 -d "1000000 0" | |||
|
14 | hg tag -l foo | |||
|
15 | hg update 0 | |||
|
16 | hg parents -b | |||
|
17 | ||||
|
18 | # test update | |||
|
19 | hg update -b foo | |||
|
20 | hg parents | |||
|
21 | ||||
|
22 | # test merge | |||
|
23 | hg update 0 | |||
|
24 | echo c > c | |||
|
25 | hg ci -A -m 0.0 -d "1000000 0" | |||
|
26 | hg merge -b foo | |||
|
27 | hg parents -b | |||
|
28 | ||||
|
29 | # re-test with more branches | |||
|
30 | hg update -C 0 | |||
|
31 | echo d > d | |||
|
32 | hg ci -A -m 0.0 -d "1000000 0" | |||
|
33 | hg merge -b foo | |||
|
34 | hg parents -b |
@@ -0,0 +1,55 b'' | |||||
|
1 | adding a | |||
|
2 | adding b | |||
|
3 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
4 | changeset: 0:b544c4ac4389 | |||
|
5 | user: test | |||
|
6 | date: Mon Jan 12 13:46:40 1970 +0000 | |||
|
7 | summary: 0 | |||
|
8 | ||||
|
9 | Using head f4ac749470f2 for branch foo | |||
|
10 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
11 | changeset: 1:f4ac749470f2 | |||
|
12 | tag: foo | |||
|
13 | tag: tip | |||
|
14 | user: test | |||
|
15 | date: Mon Jan 12 13:46:40 1970 +0000 | |||
|
16 | summary: 1 | |||
|
17 | ||||
|
18 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
19 | adding c | |||
|
20 | Using head f4ac749470f2 for branch foo | |||
|
21 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
22 | (branch merge, don't forget to commit) | |||
|
23 | changeset: 2:1505d56ee00e | |||
|
24 | tag: tip | |||
|
25 | parent: 0:b544c4ac4389 | |||
|
26 | user: test | |||
|
27 | date: Mon Jan 12 13:46:40 1970 +0000 | |||
|
28 | summary: 0.0 | |||
|
29 | ||||
|
30 | changeset: 1:f4ac749470f2 | |||
|
31 | tag: foo | |||
|
32 | branch: foo | |||
|
33 | user: test | |||
|
34 | date: Mon Jan 12 13:46:40 1970 +0000 | |||
|
35 | summary: 1 | |||
|
36 | ||||
|
37 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
38 | adding d | |||
|
39 | Using head f4ac749470f2 for branch foo | |||
|
40 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
41 | (branch merge, don't forget to commit) | |||
|
42 | changeset: 3:53b72df12ae5 | |||
|
43 | tag: tip | |||
|
44 | parent: 0:b544c4ac4389 | |||
|
45 | user: test | |||
|
46 | date: Mon Jan 12 13:46:40 1970 +0000 | |||
|
47 | summary: 0.0 | |||
|
48 | ||||
|
49 | changeset: 1:f4ac749470f2 | |||
|
50 | tag: foo | |||
|
51 | branch: foo | |||
|
52 | user: test | |||
|
53 | date: Mon Jan 12 13:46:40 1970 +0000 | |||
|
54 | summary: 1 | |||
|
55 |
@@ -0,0 +1,35 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | echo "[extensions]" >> $HGRCPATH | |||
|
4 | echo "mq=" >> $HGRCPATH | |||
|
5 | ||||
|
6 | hg init a | |||
|
7 | cd a | |||
|
8 | ||||
|
9 | echo 'base' > base | |||
|
10 | hg ci -Ambase -d '1 0' | |||
|
11 | ||||
|
12 | hg qnew a | |||
|
13 | hg qnew b | |||
|
14 | hg qnew c | |||
|
15 | ||||
|
16 | hg qdel c | |||
|
17 | hg qpop | |||
|
18 | hg qdel c | |||
|
19 | hg qseries | |||
|
20 | ls .hg/patches | |||
|
21 | hg qpop | |||
|
22 | hg qdel -k b | |||
|
23 | ls .hg/patches | |||
|
24 | hg qdel -f a | |||
|
25 | hg qapplied | |||
|
26 | hg log --template '{rev} {desc}\n' | |||
|
27 | ||||
|
28 | hg qnew d | |||
|
29 | hg qnew e | |||
|
30 | hg qnew f | |||
|
31 | ||||
|
32 | hg qdel -f e | |||
|
33 | hg qdel -f d e | |||
|
34 | hg qapplied | |||
|
35 | hg log --template '{rev} {desc}\n' |
@@ -0,0 +1,23 b'' | |||||
|
1 | adding base | |||
|
2 | abort: cannot delete applied patch c | |||
|
3 | Now at: b | |||
|
4 | a | |||
|
5 | b | |||
|
6 | a | |||
|
7 | b | |||
|
8 | series | |||
|
9 | status | |||
|
10 | Now at: a | |||
|
11 | a | |||
|
12 | b | |||
|
13 | series | |||
|
14 | status | |||
|
15 | 1 New patch: a | |||
|
16 | 0 base | |||
|
17 | abort: patch e not at base | |||
|
18 | f | |||
|
19 | 4 New patch: f | |||
|
20 | 3 New patch: e | |||
|
21 | 2 New patch: d | |||
|
22 | 1 New patch: a | |||
|
23 | 0 base |
@@ -0,0 +1,25 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | echo "[extensions]" >> $HGRCPATH | |||
|
4 | echo "mq=" >> $HGRCPATH | |||
|
5 | ||||
|
6 | hg init a | |||
|
7 | cd a | |||
|
8 | ||||
|
9 | echo 'base' > base | |||
|
10 | hg ci -Ambase -d '1 0' | |||
|
11 | ||||
|
12 | hg qnew -mmqbase mqbase | |||
|
13 | hg qrename mqbase renamed | |||
|
14 | mkdir .hg/patches/foo | |||
|
15 | hg qrename renamed foo | |||
|
16 | hg qseries | |||
|
17 | ls .hg/patches/foo | |||
|
18 | mkdir .hg/patches/bar | |||
|
19 | hg qrename foo/renamed bar | |||
|
20 | hg qseries | |||
|
21 | ls .hg/patches/bar | |||
|
22 | hg qrename bar/renamed baz | |||
|
23 | hg qseries | |||
|
24 | ls .hg/patches/baz | |||
|
25 |
@@ -0,0 +1,7 b'' | |||||
|
1 | adding base | |||
|
2 | foo/renamed | |||
|
3 | renamed | |||
|
4 | bar/renamed | |||
|
5 | renamed | |||
|
6 | baz | |||
|
7 | .hg/patches/baz |
@@ -0,0 +1,18 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init | |||
|
4 | ||||
|
5 | echo a > a | |||
|
6 | hg ci -d '0 0' -Ama | |||
|
7 | ||||
|
8 | hg an a | |||
|
9 | ||||
|
10 | echo "[ui]" >> $HGRCPATH | |||
|
11 | echo "strict=True" >> $HGRCPATH | |||
|
12 | ||||
|
13 | hg an a | |||
|
14 | hg annotate a | |||
|
15 | ||||
|
16 | echo % should succeed - up is an alias, not an abbreviation | |||
|
17 | ||||
|
18 | hg up |
@@ -0,0 +1,26 b'' | |||||
|
1 | adding a | |||
|
2 | 0: a | |||
|
3 | hg: unknown command 'an' | |||
|
4 | Mercurial Distributed SCM | |||
|
5 | ||||
|
6 | basic commands (use "hg help" for the full list or option "-v" for details): | |||
|
7 | ||||
|
8 | add add the specified files on the next commit | |||
|
9 | annotate show changeset information per file line | |||
|
10 | clone make a copy of an existing repository | |||
|
11 | commit commit the specified files or all outstanding changes | |||
|
12 | diff diff repository (or selected files) | |||
|
13 | export dump the header and diffs for one or more changesets | |||
|
14 | init create a new repository in the given directory | |||
|
15 | log show revision history of entire repository or files | |||
|
16 | parents show the parents of the working dir or revision | |||
|
17 | pull pull changes from the specified source | |||
|
18 | push push changes to the specified destination | |||
|
19 | remove remove the specified files on the next commit | |||
|
20 | revert revert files or dirs to their states as of some revision | |||
|
21 | serve export the repository via HTTP | |||
|
22 | status show changed files in the working directory | |||
|
23 | update update or merge working directory | |||
|
24 | 0: a | |||
|
25 | % should succeed - up is an alias, not an abbreviation | |||
|
26 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
@@ -0,0 +1,112 b'' | |||||
|
1 | #!/usr/bin/env python | |||
|
2 | # Since it's not easy to write a test that portably deals | |||
|
3 | # with files from different users/groups, we cheat a bit by | |||
|
4 | # monkey-patching some functions in the util module | |||
|
5 | ||||
|
6 | import os | |||
|
7 | from mercurial import ui, util | |||
|
8 | ||||
|
9 | hgrc = os.environ['HGRCPATH'] | |||
|
10 | ||||
|
11 | def testui(user='foo', group='bar', tusers=(), tgroups=(), | |||
|
12 | cuser='foo', cgroup='bar'): | |||
|
13 | # user, group => owners of the file | |||
|
14 | # tusers, tgroups => trusted users/groups | |||
|
15 | # cuser, cgroup => user/group of the current process | |||
|
16 | ||||
|
17 | # write a global hgrc with the list of trusted users/groups and | |||
|
18 | # some setting so that we can be sure it was read | |||
|
19 | f = open(hgrc, 'w') | |||
|
20 | f.write('[paths]\n') | |||
|
21 | f.write('global = /some/path\n\n') | |||
|
22 | ||||
|
23 | if tusers or tgroups: | |||
|
24 | f.write('[trusted]\n') | |||
|
25 | if tusers: | |||
|
26 | f.write('users = %s\n' % ', '.join(tusers)) | |||
|
27 | if tgroups: | |||
|
28 | f.write('groups = %s\n' % ', '.join(tgroups)) | |||
|
29 | f.close() | |||
|
30 | ||||
|
31 | # override the functions that give names to uids and gids | |||
|
32 | def username(uid=None): | |||
|
33 | if uid is None: | |||
|
34 | return cuser | |||
|
35 | return user | |||
|
36 | util.username = username | |||
|
37 | ||||
|
38 | def groupname(gid=None): | |||
|
39 | if gid is None: | |||
|
40 | return 'bar' | |||
|
41 | return group | |||
|
42 | util.groupname = groupname | |||
|
43 | ||||
|
44 | # try to read everything | |||
|
45 | #print '# File belongs to user %s, group %s' % (user, group) | |||
|
46 | #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups) | |||
|
47 | kind = ('different', 'same') | |||
|
48 | who = ('', 'user', 'group', 'user and the group') | |||
|
49 | trusted = who[(user in tusers) + 2*(group in tgroups)] | |||
|
50 | if trusted: | |||
|
51 | trusted = ', but we trust the ' + trusted | |||
|
52 | print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup], | |||
|
53 | trusted) | |||
|
54 | ||||
|
55 | parentui = ui.ui() | |||
|
56 | u = ui.ui(parentui=parentui) | |||
|
57 | u.readconfig('.hg/hgrc') | |||
|
58 | for name, path in u.configitems('paths'): | |||
|
59 | print name, '=', path | |||
|
60 | ||||
|
61 | ||||
|
62 | return u | |||
|
63 | ||||
|
64 | os.mkdir('repo') | |||
|
65 | os.chdir('repo') | |||
|
66 | os.mkdir('.hg') | |||
|
67 | f = open('.hg/hgrc', 'w') | |||
|
68 | f.write('[paths]\n') | |||
|
69 | f.write('local = /another/path\n\n') | |||
|
70 | f.close() | |||
|
71 | ||||
|
72 | #print '# Everything is run by user foo, group bar\n' | |||
|
73 | ||||
|
74 | # same user, same group | |||
|
75 | testui() | |||
|
76 | # same user, different group | |||
|
77 | testui(group='def') | |||
|
78 | # different user, same group | |||
|
79 | testui(user='abc') | |||
|
80 | # ... but we trust the group | |||
|
81 | testui(user='abc', tgroups=['bar']) | |||
|
82 | # different user, different group | |||
|
83 | testui(user='abc', group='def') | |||
|
84 | # ... but we trust the user | |||
|
85 | testui(user='abc', group='def', tusers=['abc']) | |||
|
86 | # ... but we trust the group | |||
|
87 | testui(user='abc', group='def', tgroups=['def']) | |||
|
88 | # ... but we trust the user and the group | |||
|
89 | testui(user='abc', group='def', tusers=['abc'], tgroups=['def']) | |||
|
90 | # ... but we trust all users | |||
|
91 | print '# we trust all users' | |||
|
92 | testui(user='abc', group='def', tusers=['*']) | |||
|
93 | # ... but we trust all groups | |||
|
94 | print '# we trust all groups' | |||
|
95 | testui(user='abc', group='def', tgroups=['*']) | |||
|
96 | # ... but we trust the whole universe | |||
|
97 | print '# we trust all users and groups' | |||
|
98 | testui(user='abc', group='def', tusers=['*'], tgroups=['*']) | |||
|
99 | # ... check that users and groups are in different namespaces | |||
|
100 | print "# we don't get confused by users and groups with the same name" | |||
|
101 | testui(user='abc', group='def', tusers=['def'], tgroups=['abc']) | |||
|
102 | # ... lists of user names work | |||
|
103 | print "# list of user names" | |||
|
104 | testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'], | |||
|
105 | tgroups=['bar', 'baz', 'qux']) | |||
|
106 | # ... lists of group names work | |||
|
107 | print "# list of group names" | |||
|
108 | testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'], | |||
|
109 | tgroups=['bar', 'def', 'baz', 'qux']) | |||
|
110 | ||||
|
111 | print "# Can't figure out the name of the user running this process" | |||
|
112 | testui(user='abc', group='def', cuser=None) |
@@ -0,0 +1,67 b'' | |||||
|
1 | # same user, same group | |||
|
2 | global = /some/path | |||
|
3 | local = /another/path | |||
|
4 | ||||
|
5 | # same user, different group | |||
|
6 | global = /some/path | |||
|
7 | local = /another/path | |||
|
8 | ||||
|
9 | # different user, same group | |||
|
10 | not reading file .hg/hgrc from untrusted user abc, group bar | |||
|
11 | global = /some/path | |||
|
12 | ||||
|
13 | # different user, same group, but we trust the group | |||
|
14 | global = /some/path | |||
|
15 | local = /another/path | |||
|
16 | ||||
|
17 | # different user, different group | |||
|
18 | not reading file .hg/hgrc from untrusted user abc, group def | |||
|
19 | global = /some/path | |||
|
20 | ||||
|
21 | # different user, different group, but we trust the user | |||
|
22 | global = /some/path | |||
|
23 | local = /another/path | |||
|
24 | ||||
|
25 | # different user, different group, but we trust the group | |||
|
26 | global = /some/path | |||
|
27 | local = /another/path | |||
|
28 | ||||
|
29 | # different user, different group, but we trust the user and the group | |||
|
30 | global = /some/path | |||
|
31 | local = /another/path | |||
|
32 | ||||
|
33 | # we trust all users | |||
|
34 | # different user, different group | |||
|
35 | global = /some/path | |||
|
36 | local = /another/path | |||
|
37 | ||||
|
38 | # we trust all groups | |||
|
39 | # different user, different group | |||
|
40 | global = /some/path | |||
|
41 | local = /another/path | |||
|
42 | ||||
|
43 | # we trust all users and groups | |||
|
44 | # different user, different group | |||
|
45 | global = /some/path | |||
|
46 | local = /another/path | |||
|
47 | ||||
|
48 | # we don't get confused by users and groups with the same name | |||
|
49 | # different user, different group | |||
|
50 | not reading file .hg/hgrc from untrusted user abc, group def | |||
|
51 | global = /some/path | |||
|
52 | ||||
|
53 | # list of user names | |||
|
54 | # different user, different group, but we trust the user | |||
|
55 | global = /some/path | |||
|
56 | local = /another/path | |||
|
57 | ||||
|
58 | # list of group names | |||
|
59 | # different user, different group, but we trust the group | |||
|
60 | global = /some/path | |||
|
61 | local = /another/path | |||
|
62 | ||||
|
63 | # Can't figure out the name of the user running this process | |||
|
64 | # different user, different group | |||
|
65 | global = /some/path | |||
|
66 | local = /another/path | |||
|
67 |
@@ -21,6 +21,7 b' doc/*.[0-9].{x,ht}ml' | |||||
21 | MANIFEST |
|
21 | MANIFEST | |
22 | patches |
|
22 | patches | |
23 | mercurial/__version__.py |
|
23 | mercurial/__version__.py | |
|
24 | .DS_Store | |||
24 |
|
25 | |||
25 | syntax: regexp |
|
26 | syntax: regexp | |
26 | ^\.pc/ |
|
27 | ^\.pc/ |
@@ -30,15 +30,29 b' proc getcommits {rargs} {' | |||||
30 | set startmsecs [clock clicks -milliseconds] |
|
30 | set startmsecs [clock clicks -milliseconds] | |
31 | set nextupdate [expr $startmsecs + 100] |
|
31 | set nextupdate [expr $startmsecs + 100] | |
32 | set ncmupdate 1 |
|
32 | set ncmupdate 1 | |
|
33 | set limit 0 | |||
|
34 | set revargs {} | |||
|
35 | for {set i 0} {$i < [llength $rargs]} {incr i} { | |||
|
36 | set opt [lindex $rargs $i] | |||
|
37 | if {$opt == "--limit"} { | |||
|
38 | incr i | |||
|
39 | set limit [lindex $rargs $i] | |||
|
40 | } else { | |||
|
41 | lappend revargs $opt | |||
|
42 | } | |||
|
43 | } | |||
33 | if [catch { |
|
44 | if [catch { | |
34 | set parse_args [concat --default HEAD $rargs] |
|
45 | set parse_args [concat --default HEAD $revargs] | |
35 | set parsed_args [split [eval exec hg debug-rev-parse $parse_args] "\n"] |
|
46 | set parsed_args [split [eval exec hg debug-rev-parse $parse_args] "\n"] | |
36 | }] { |
|
47 | } err] { | |
37 | # if git-rev-parse failed for some reason... |
|
48 | # if git-rev-parse failed for some reason... | |
38 | if {$rargs == {}} { |
|
49 | if {$rargs == {}} { | |
39 | set rargs HEAD |
|
50 | set revargs HEAD | |
40 | } |
|
51 | } | |
41 | set parsed_args $rargs |
|
52 | set parsed_args $revargs | |
|
53 | } | |||
|
54 | if {$limit > 0} { | |||
|
55 | set parsed_args [concat -n $limit $parsed_args] | |||
42 | } |
|
56 | } | |
43 | if [catch { |
|
57 | if [catch { | |
44 | set commfd [open "|hg debug-rev-list --header --topo-order --parents $parsed_args" r] |
|
58 | set commfd [open "|hg debug-rev-list --header --topo-order --parents $parsed_args" r] | |
@@ -100,7 +114,7 b' to allow selection of commits to be disp' | |||||
100 | set ids [string range $cmit 0 [expr {$j - 1}]] |
|
114 | set ids [string range $cmit 0 [expr {$j - 1}]] | |
101 | set ok 1 |
|
115 | set ok 1 | |
102 | foreach id $ids { |
|
116 | foreach id $ids { | |
103 |
if {![regexp {^[0-9a-f]{ |
|
117 | if {![regexp {^[0-9a-f]{12}$} $id]} { | |
104 | set ok 0 |
|
118 | set ok 0 | |
105 | break |
|
119 | break | |
106 | } |
|
120 | } | |
@@ -176,6 +190,7 b' proc parsecommit {id contents listed old' | |||||
176 | set audate {} |
|
190 | set audate {} | |
177 | set comname {} |
|
191 | set comname {} | |
178 | set comdate {} |
|
192 | set comdate {} | |
|
193 | set rev {} | |||
179 | if {![info exists nchildren($id)]} { |
|
194 | if {![info exists nchildren($id)]} { | |
180 | set children($id) {} |
|
195 | set children($id) {} | |
181 | set nchildren($id) 0 |
|
196 | set nchildren($id) 0 | |
@@ -209,6 +224,8 b' proc parsecommit {id contents listed old' | |||||
209 | set x [expr {[llength $line] - 2}] |
|
224 | set x [expr {[llength $line] - 2}] | |
210 | set comdate [lindex $line $x] |
|
225 | set comdate [lindex $line $x] | |
211 | set comname [join [lrange $line 1 [expr {$x - 1}]]] |
|
226 | set comname [join [lrange $line 1 [expr {$x - 1}]]] | |
|
227 | } elseif {$tag == "revision"} { | |||
|
228 | set rev [lindex $line 1] | |||
212 | } |
|
229 | } | |
213 | } |
|
230 | } | |
214 | } else { |
|
231 | } else { | |
@@ -233,7 +250,7 b' proc parsecommit {id contents listed old' | |||||
233 | set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] |
|
250 | set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] | |
234 | } |
|
251 | } | |
235 | set commitinfo($id) [list $headline $auname $audate \ |
|
252 | set commitinfo($id) [list $headline $auname $audate \ | |
236 | $comname $comdate $comment] |
|
253 | $comname $comdate $comment $rev] | |
237 | } |
|
254 | } | |
238 |
|
255 | |||
239 | proc readrefs {} { |
|
256 | proc readrefs {} { | |
@@ -261,7 +278,7 b' proc readotherrefs {base dname excl} {' | |||||
261 | catch { |
|
278 | catch { | |
262 | set fd [open $f r] |
|
279 | set fd [open $f r] | |
263 | set line [read $fd 40] |
|
280 | set line [read $fd 40] | |
264 |
if {[regexp {^[0-9a-f]{ |
|
281 | if {[regexp {^[0-9a-f]{12}} $line id]} { | |
265 | set name "$dname[file tail $f]" |
|
282 | set name "$dname[file tail $f]" | |
266 | set otherrefids($name) $id |
|
283 | set otherrefids($name) $id | |
267 | lappend idotherrefs($id) $name |
|
284 | lappend idotherrefs($id) $name | |
@@ -1743,7 +1760,7 b' proc readfindproc {} {' | |||||
1743 | } |
|
1760 | } | |
1744 | return |
|
1761 | return | |
1745 | } |
|
1762 | } | |
1746 |
if {![regexp {^[0-9a-f]{ |
|
1763 | if {![regexp {^[0-9a-f]{12}} $line id]} { | |
1747 | error_popup "Can't parse git-diff-tree output: $line" |
|
1764 | error_popup "Can't parse git-diff-tree output: $line" | |
1748 | stopfindproc |
|
1765 | stopfindproc | |
1749 | return |
|
1766 | return | |
@@ -1856,7 +1873,7 b' proc readfilediffs {df} {' | |||||
1856 | } |
|
1873 | } | |
1857 | return |
|
1874 | return | |
1858 | } |
|
1875 | } | |
1859 |
if {[regexp {^([0-9a-f]{ |
|
1876 | if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} { | |
1860 | # start of a new string of diffs |
|
1877 | # start of a new string of diffs | |
1861 | donefilediff |
|
1878 | donefilediff | |
1862 | set fdiffids [list $id $p] |
|
1879 | set fdiffids [list $id $p] | |
@@ -2002,8 +2019,9 b' proc commit_descriptor {p} {' | |||||
2002 | set l "..." |
|
2019 | set l "..." | |
2003 | if {[info exists commitinfo($p)]} { |
|
2020 | if {[info exists commitinfo($p)]} { | |
2004 | set l [lindex $commitinfo($p) 0] |
|
2021 | set l [lindex $commitinfo($p) 0] | |
|
2022 | set r [lindex $commitinfo($p) 6] | |||
2005 | } |
|
2023 | } | |
2006 | return "$p ($l)" |
|
2024 | return "$r:$p ($l)" | |
2007 | } |
|
2025 | } | |
2008 |
|
2026 | |||
2009 | # append some text to the ctext widget, and make any SHA1 ID |
|
2027 | # append some text to the ctext widget, and make any SHA1 ID | |
@@ -2014,7 +2032,7 b' proc appendwithlinks {text} {' | |||||
2014 | set start [$ctext index "end - 1c"] |
|
2032 | set start [$ctext index "end - 1c"] | |
2015 | $ctext insert end $text |
|
2033 | $ctext insert end $text | |
2016 | $ctext insert end "\n" |
|
2034 | $ctext insert end "\n" | |
2017 |
set links [regexp -indices -all -inline {[0-9a-f]{ |
|
2035 | set links [regexp -indices -all -inline {[0-9a-f]{12}} $text] | |
2018 | foreach l $links { |
|
2036 | foreach l $links { | |
2019 | set s [lindex $l 0] |
|
2037 | set s [lindex $l 0] | |
2020 | set e [lindex $l 1] |
|
2038 | set e [lindex $l 1] | |
@@ -2107,6 +2125,7 b' proc selectline {l isnew} {' | |||||
2107 | $ctext mark set fmark.0 0.0 |
|
2125 | $ctext mark set fmark.0 0.0 | |
2108 | $ctext mark gravity fmark.0 left |
|
2126 | $ctext mark gravity fmark.0 left | |
2109 | set info $commitinfo($id) |
|
2127 | set info $commitinfo($id) | |
|
2128 | $ctext insert end "Revision: [lindex $info 6]\n" | |||
2110 | $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" |
|
2129 | $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" | |
2111 | $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" |
|
2130 | $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" | |
2112 | if {[info exists idtags($id)]} { |
|
2131 | if {[info exists idtags($id)]} { |
@@ -1,6 +1,6 b'' | |||||
1 | ;;; mercurial.el --- Emacs support for the Mercurial distributed SCM |
|
1 | ;;; mercurial.el --- Emacs support for the Mercurial distributed SCM | |
2 |
|
2 | |||
3 | ;; Copyright (C) 2005 Bryan O'Sullivan |
|
3 | ;; Copyright (C) 2005, 2006 Bryan O'Sullivan | |
4 |
|
4 | |||
5 | ;; Author: Bryan O'Sullivan <bos@serpentine.com> |
|
5 | ;; Author: Bryan O'Sullivan <bos@serpentine.com> | |
6 |
|
6 | |||
@@ -289,7 +289,7 b' XEmacs and GNU Emacs."' | |||||
289 |
|
289 | |||
290 | (defsubst hg-chomp (str) |
|
290 | (defsubst hg-chomp (str) | |
291 | "Strip trailing newlines from a string." |
|
291 | "Strip trailing newlines from a string." | |
292 | (hg-replace-in-string str "[\r\n]+\'" "")) |
|
292 | (hg-replace-in-string str "[\r\n]+\\'" "")) | |
293 |
|
293 | |||
294 | (defun hg-run-command (command &rest args) |
|
294 | (defun hg-run-command (command &rest args) | |
295 | "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT). |
|
295 | "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT). | |
@@ -502,6 +502,43 b' directory names from the file system. W' | |||||
502 | (or default "tip"))) |
|
502 | (or default "tip"))) | |
503 | rev)))) |
|
503 | rev)))) | |
504 |
|
504 | |||
|
505 | (defun hg-parents-for-mode-line (root) | |||
|
506 | "Format the parents of the working directory for the mode line." | |||
|
507 | (let ((parents (split-string (hg-chomp | |||
|
508 | (hg-run0 "--cwd" root "parents" "--template" | |||
|
509 | "{rev}\n")) "\n"))) | |||
|
510 | (mapconcat 'identity parents "+"))) | |||
|
511 | ||||
|
512 | (defun hg-buffers-visiting-repo (&optional path) | |||
|
513 | "Return a list of buffers visiting the repository containing PATH." | |||
|
514 | (let ((root-name (hg-root (or path (buffer-file-name)))) | |||
|
515 | bufs) | |||
|
516 | (save-excursion | |||
|
517 | (dolist (buf (buffer-list) bufs) | |||
|
518 | (set-buffer buf) | |||
|
519 | (let ((name (buffer-file-name))) | |||
|
520 | (when (and hg-status name (equal (hg-root name) root-name)) | |||
|
521 | (setq bufs (cons buf bufs)))))))) | |||
|
522 | ||||
|
523 | (defun hg-update-mode-lines (path) | |||
|
524 | "Update the mode lines of all buffers visiting the same repository as PATH." | |||
|
525 | (let* ((root (hg-root path)) | |||
|
526 | (parents (hg-parents-for-mode-line root))) | |||
|
527 | (save-excursion | |||
|
528 | (dolist (info (hg-path-status | |||
|
529 | root | |||
|
530 | (mapcar | |||
|
531 | (function | |||
|
532 | (lambda (buf) | |||
|
533 | (substring (buffer-file-name buf) (length root)))) | |||
|
534 | (hg-buffers-visiting-repo root)))) | |||
|
535 | (let* ((name (car info)) | |||
|
536 | (status (cdr info)) | |||
|
537 | (buf (find-buffer-visiting (concat root name)))) | |||
|
538 | (when buf | |||
|
539 | (set-buffer buf) | |||
|
540 | (hg-mode-line-internal status parents))))))) | |||
|
541 | ||||
505 | (defmacro hg-do-across-repo (path &rest body) |
|
542 | (defmacro hg-do-across-repo (path &rest body) | |
506 | (let ((root-name (gensym "root-")) |
|
543 | (let ((root-name (gensym "root-")) | |
507 | (buf-name (gensym "buf-"))) |
|
544 | (buf-name (gensym "buf-"))) | |
@@ -548,13 +585,31 b' current frame."' | |||||
548 | '(("M " . modified) |
|
585 | '(("M " . modified) | |
549 | ("A " . added) |
|
586 | ("A " . added) | |
550 | ("R " . removed) |
|
587 | ("R " . removed) | |
|
588 | ("! " . deleted) | |||
551 | ("? " . nil))))) |
|
589 | ("? " . nil))))) | |
552 | (if state |
|
590 | (if state | |
553 | (cdr state) |
|
591 | (cdr state) | |
554 | 'normal))))) |
|
592 | 'normal))))) | |
555 |
|
593 | |||
556 | (defun hg-tip () |
|
594 | (defun hg-path-status (root paths) | |
557 | (split-string (hg-chomp (hg-run0 "-q" "tip")) ":")) |
|
595 | "Return status of PATHS in repo ROOT as an alist. | |
|
596 | Each entry is a pair (FILE-NAME . STATUS)." | |||
|
597 | (let ((s (apply 'hg-run "--cwd" root "status" "-marduc" paths)) | |||
|
598 | result) | |||
|
599 | (dolist (entry (split-string (hg-chomp (cdr s)) "\n") (nreverse result)) | |||
|
600 | (let (state name) | |||
|
601 | (if (equal (substring entry 1 2) " ") | |||
|
602 | (setq state (cdr (assoc (substring entry 0 2) | |||
|
603 | '(("M " . modified) | |||
|
604 | ("A " . added) | |||
|
605 | ("R " . removed) | |||
|
606 | ("! " . deleted) | |||
|
607 | ("C " . normal) | |||
|
608 | ("I " . ignored) | |||
|
609 | ("? " . nil)))) | |||
|
610 | name (substring entry 2)) | |||
|
611 | (setq name (substring entry 0 (search ": " entry :from-end t)))) | |||
|
612 | (setq result (cons (cons name state) result)))))) | |||
558 |
|
613 | |||
559 | (defmacro hg-view-output (args &rest body) |
|
614 | (defmacro hg-view-output (args &rest body) | |
560 | "Execute BODY in a clean buffer, then quickly display that buffer. |
|
615 | "Execute BODY in a clean buffer, then quickly display that buffer. | |
@@ -589,7 +644,7 b' being viewed."' | |||||
589 |
|
644 | |||
590 | (put 'hg-view-output 'lisp-indent-function 1) |
|
645 | (put 'hg-view-output 'lisp-indent-function 1) | |
591 |
|
646 | |||
592 | ;;; Context save and restore across revert. |
|
647 | ;;; Context save and restore across revert and other operations. | |
593 |
|
648 | |||
594 | (defun hg-position-context (pos) |
|
649 | (defun hg-position-context (pos) | |
595 | "Return information to help find the given position again." |
|
650 | "Return information to help find the given position again." | |
@@ -631,22 +686,28 b' Always returns a valid, hopefully sane, ' | |||||
631 |
|
686 | |||
632 | ;;; Hooks. |
|
687 | ;;; Hooks. | |
633 |
|
688 | |||
|
689 | (defun hg-mode-line-internal (status parents) | |||
|
690 | (setq hg-status status | |||
|
691 | hg-mode (and status (concat " Hg:" | |||
|
692 | parents | |||
|
693 | (cdr (assq status | |||
|
694 | '((normal . "") | |||
|
695 | (removed . "r") | |||
|
696 | (added . "a") | |||
|
697 | (deleted . "!") | |||
|
698 | (modified . "m")))))))) | |||
|
699 | ||||
634 | (defun hg-mode-line (&optional force) |
|
700 | (defun hg-mode-line (&optional force) | |
635 | "Update the modeline with the current status of a file. |
|
701 | "Update the modeline with the current status of a file. | |
636 | An update occurs if optional argument FORCE is non-nil, |
|
702 | An update occurs if optional argument FORCE is non-nil, | |
637 | hg-update-modeline is non-nil, or we have not yet checked the state of |
|
703 | hg-update-modeline is non-nil, or we have not yet checked the state of | |
638 | the file." |
|
704 | the file." | |
639 | (when (and (hg-root) (or force hg-update-modeline (not hg-mode))) |
|
705 | (let ((root (hg-root))) | |
640 | (let ((status (hg-file-status buffer-file-name))) |
|
706 | (when (and root (or force hg-update-modeline (not hg-mode))) | |
641 | (setq hg-status status |
|
707 | (let ((status (hg-file-status buffer-file-name)) | |
642 | hg-mode (and status (concat " Hg:" |
|
708 | (parents (hg-parents-for-mode-line root))) | |
643 | (car (hg-tip)) |
|
709 | (hg-mode-line-internal status parents) | |
644 | (cdr (assq status |
|
710 | status)))) | |
645 | '((normal . "") |
|
|||
646 | (removed . "r") |
|
|||
647 | (added . "a") |
|
|||
648 | (modified . "m"))))))) |
|
|||
649 | status))) |
|
|||
650 |
|
711 | |||
651 | (defun hg-mode (&optional toggle) |
|
712 | (defun hg-mode (&optional toggle) | |
652 | "Minor mode for Mercurial distributed SCM integration. |
|
713 | "Minor mode for Mercurial distributed SCM integration. | |
@@ -724,6 +785,13 b' code by typing `M-x find-library mercuri' | |||||
724 | default-directory) |
|
785 | default-directory) | |
725 | (cd hg-root-dir))))) |
|
786 | (cd hg-root-dir))))) | |
726 |
|
787 | |||
|
788 | (defun hg-fix-paths () | |||
|
789 | "Fix paths reported by some Mercurial commands." | |||
|
790 | (save-excursion | |||
|
791 | (goto-char (point-min)) | |||
|
792 | (while (re-search-forward " \\.\\.." nil t) | |||
|
793 | (replace-match " " nil nil)))) | |||
|
794 | ||||
727 | (defun hg-add (path) |
|
795 | (defun hg-add (path) | |
728 | "Add PATH to the Mercurial repository on the next commit. |
|
796 | "Add PATH to the Mercurial repository on the next commit. | |
729 | With a prefix argument, prompt for the path to add." |
|
797 | With a prefix argument, prompt for the path to add." | |
@@ -732,9 +800,8 b' With a prefix argument, prompt for the p' | |||||
732 | (update (equal buffer-file-name path))) |
|
800 | (update (equal buffer-file-name path))) | |
733 | (hg-view-output (hg-output-buffer-name) |
|
801 | (hg-view-output (hg-output-buffer-name) | |
734 | (apply 'call-process (hg-binary) nil t nil (list "add" path)) |
|
802 | (apply 'call-process (hg-binary) nil t nil (list "add" path)) | |
735 | ;; "hg add" shows pathes relative NOT TO ROOT BUT TO REPOSITORY |
|
803 | (hg-fix-paths) | |
736 | (replace-regexp " \\.\\.." " " nil 0 (buffer-size)) |
|
804 | (goto-char (point-min)) | |
737 | (goto-char 0) |
|
|||
738 | (cd (hg-root path))) |
|
805 | (cd (hg-root path))) | |
739 | (when update |
|
806 | (when update | |
740 | (unless vc-make-backup-files |
|
807 | (unless vc-make-backup-files | |
@@ -820,8 +887,7 b' hg-commit-allow-empty-file-list is nil, ' | |||||
820 | (let ((buf hg-prev-buffer)) |
|
887 | (let ((buf hg-prev-buffer)) | |
821 | (kill-buffer nil) |
|
888 | (kill-buffer nil) | |
822 | (switch-to-buffer buf)) |
|
889 | (switch-to-buffer buf)) | |
823 | (hg-do-across-repo root |
|
890 | (hg-update-mode-lines root)))) | |
824 | (hg-mode-line))))) |
|
|||
825 |
|
891 | |||
826 | (defun hg-commit-mode () |
|
892 | (defun hg-commit-mode () | |
827 | "Mode for describing a commit of changes to a Mercurial repository. |
|
893 | "Mode for describing a commit of changes to a Mercurial repository. | |
@@ -973,8 +1039,8 b' With a prefix argument, prompt for the p' | |||||
973 | (hg-view-output (hg-output-buffer-name) |
|
1039 | (hg-view-output (hg-output-buffer-name) | |
974 | (apply 'call-process (hg-binary) nil t nil (list "forget" path)) |
|
1040 | (apply 'call-process (hg-binary) nil t nil (list "forget" path)) | |
975 | ;; "hg forget" shows pathes relative NOT TO ROOT BUT TO REPOSITORY |
|
1041 | ;; "hg forget" shows pathes relative NOT TO ROOT BUT TO REPOSITORY | |
976 | (replace-regexp " \\.\\.." " " nil 0 (buffer-size)) |
|
1042 | (hg-fix-paths) | |
977 |
(goto-char |
|
1043 | (goto-char (point-min)) | |
978 | (cd (hg-root path))) |
|
1044 | (cd (hg-root path))) | |
979 | (when update |
|
1045 | (when update | |
980 | (with-current-buffer buf |
|
1046 | (with-current-buffer buf | |
@@ -1148,6 +1214,21 b' prompts for a path to check."' | |||||
1148 | root) |
|
1214 | root) | |
1149 | hg-root)) |
|
1215 | hg-root)) | |
1150 |
|
1216 | |||
|
1217 | (defun hg-cwd (&optional path) | |||
|
1218 | "Return the current directory of PATH within the repository." | |||
|
1219 | (do ((stack nil (cons (file-name-nondirectory | |||
|
1220 | (directory-file-name dir)) | |||
|
1221 | stack)) | |||
|
1222 | (prev nil dir) | |||
|
1223 | (dir (file-name-directory (or path buffer-file-name | |||
|
1224 | (expand-file-name default-directory))) | |||
|
1225 | (file-name-directory (directory-file-name dir)))) | |||
|
1226 | ((equal prev dir)) | |||
|
1227 | (when (file-directory-p (concat dir ".hg")) | |||
|
1228 | (let ((cwd (mapconcat 'identity stack "/"))) | |||
|
1229 | (unless (equal cwd "") | |||
|
1230 | (return (file-name-as-directory cwd))))))) | |||
|
1231 | ||||
1151 | (defun hg-status (path) |
|
1232 | (defun hg-status (path) | |
1152 | "Print revision control status of a file or directory. |
|
1233 | "Print revision control status of a file or directory. | |
1153 | With prefix argument, prompt for the path to give status for. |
|
1234 | With prefix argument, prompt for the path to give status for. |
@@ -193,6 +193,10 b' FILES' | |||||
193 | global /etc/mercurial/hgrc configuration. See hgrc(5) for details of |
|
193 | global /etc/mercurial/hgrc configuration. See hgrc(5) for details of | |
194 | the contents and format of these files. |
|
194 | the contents and format of these files. | |
195 |
|
195 | |||
|
196 | Some commands (e.g. revert) produce backup files ending in .orig, if | |||
|
197 | the .orig file already exists and is not tracked by Mercurial, it | |||
|
198 | will be overwritten. | |||
|
199 | ||||
196 | BUGS |
|
200 | BUGS | |
197 | ---- |
|
201 | ---- | |
198 | Probably lots, please post them to the mailing list (See Resources below) |
|
202 | Probably lots, please post them to the mailing list (See Resources below) |
@@ -50,6 +50,8 b' installed.' | |||||
50 | particular repository. This file is not version-controlled, and |
|
50 | particular repository. This file is not version-controlled, and | |
51 | will not get transferred during a "clone" operation. Options in |
|
51 | will not get transferred during a "clone" operation. Options in | |
52 | this file override options in all other configuration files. |
|
52 | this file override options in all other configuration files. | |
|
53 | On Unix, this file is only read if it belongs to a trusted user | |||
|
54 | or to a trusted group. | |||
53 |
|
55 | |||
54 | SYNTAX |
|
56 | SYNTAX | |
55 | ------ |
|
57 | ------ | |
@@ -133,6 +135,21 b' decode/encode::' | |||||
133 | # them to the working dir |
|
135 | # them to the working dir | |
134 | **.txt = tempfile: unix2dos -n INFILE OUTFILE |
|
136 | **.txt = tempfile: unix2dos -n INFILE OUTFILE | |
135 |
|
137 | |||
|
138 | defaults:: | |||
|
139 | Use the [defaults] section to define command defaults, i.e. the | |||
|
140 | default options/arguments to pass to the specified commands. | |||
|
141 | ||||
|
142 | The following example makes 'hg log' run in verbose mode, and | |||
|
143 | 'hg status' show only the modified files, by default. | |||
|
144 | ||||
|
145 | [defaults] | |||
|
146 | log = -v | |||
|
147 | status = -m | |||
|
148 | ||||
|
149 | The actual commands, instead of their aliases, must be used when | |||
|
150 | defining command defaults. The command defaults will also be | |||
|
151 | applied to the aliases of the commands defined. | |||
|
152 | ||||
136 | email:: |
|
153 | email:: | |
137 | Settings for extensions that send email messages. |
|
154 | Settings for extensions that send email messages. | |
138 | from;; |
|
155 | from;; | |
@@ -349,6 +366,16 b' server::' | |||||
349 | 6Mbps), uncompressed streaming is slower, because of the extra |
|
366 | 6Mbps), uncompressed streaming is slower, because of the extra | |
350 | data transfer overhead. Default is False. |
|
367 | data transfer overhead. Default is False. | |
351 |
|
368 | |||
|
369 | trusted:: | |||
|
370 | Mercurial will only read the .hg/hgrc file from a repository if | |||
|
371 | it belongs to a trusted user or to a trusted group. This section | |||
|
372 | specifies what users and groups are trusted. To trust everybody, | |||
|
373 | list a user or a group with name "*". | |||
|
374 | users;; | |||
|
375 | Comma-separated list of trusted users. | |||
|
376 | groups;; | |||
|
377 | Comma-separated list of trusted groups. | |||
|
378 | ||||
352 | ui:: |
|
379 | ui:: | |
353 | User interface controls. |
|
380 | User interface controls. | |
354 | debug;; |
|
381 | debug;; | |
@@ -377,6 +404,9 b' ui::' | |||||
377 | remote command to use for clone/push/pull operations. Default is 'hg'. |
|
404 | remote command to use for clone/push/pull operations. Default is 'hg'. | |
378 | ssh;; |
|
405 | ssh;; | |
379 | command to use for SSH connections. Default is 'ssh'. |
|
406 | command to use for SSH connections. Default is 'ssh'. | |
|
407 | strict;; | |||
|
408 | Require exact command names, instead of allowing unambiguous | |||
|
409 | abbreviations. True or False. Default is False. | |||
380 | timeout;; |
|
410 | timeout;; | |
381 | The timeout used when a lock is held (in seconds), a negative value |
|
411 | The timeout used when a lock is held (in seconds), a negative value | |
382 | means no timeout. Default is 600. |
|
412 | means no timeout. Default is 600. |
@@ -41,13 +41,15 b' HGTMP="${TMPDIR-/tmp}/hgeditor.$RANDOM.$' | |||||
41 |
|
41 | |||
42 | cat "$1" > "$HGTMP/msg" |
|
42 | cat "$1" > "$HGTMP/msg" | |
43 |
|
43 | |||
44 | CHECKSUM=`md5sum "$HGTMP/msg"` |
|
44 | MD5=$(which md5sum 2>/dev/null) || \ | |
|
45 | MD5=$(which md5 2>/dev/null) | |||
|
46 | [ -x "${MD5}" ] && CHECKSUM=`${MD5} "$HGTMP/msg"` | |||
45 | if [ -s "$HGTMP/diff" ]; then |
|
47 | if [ -s "$HGTMP/diff" ]; then | |
46 | $EDITOR "$HGTMP/msg" "$HGTMP/diff" || exit $? |
|
48 | $EDITOR "$HGTMP/msg" "$HGTMP/diff" || exit $? | |
47 | else |
|
49 | else | |
48 | $EDITOR "$HGTMP/msg" || exit $? |
|
50 | $EDITOR "$HGTMP/msg" || exit $? | |
49 | fi |
|
51 | fi | |
50 |
echo "$CHECKSUM" | |
|
52 | [ -x "${MD5}" ] && (echo "$CHECKSUM" | ${MD5} -c >/dev/null 2>&1 && exit 13) | |
51 |
|
53 | |||
52 | mv "$HGTMP/msg" "$1" |
|
54 | mv "$HGTMP/msg" "$1" | |
53 |
|
55 |
@@ -60,8 +60,8 b' class checker(object):' | |||||
60 | return None, False |
|
60 | return None, False | |
61 |
|
61 | |||
62 | thisuser = self.getuser() |
|
62 | thisuser = self.getuser() | |
63 | pats = [pat for pat, user in self.ui.configitems(key) |
|
63 | pats = [pat for pat, users in self.ui.configitems(key) | |
64 | if user == thisuser] |
|
64 | if thisuser in users.replace(',', ' ').split()] | |
65 | self.ui.debug(_('acl: %s enabled, %d entries for user %s\n') % |
|
65 | self.ui.debug(_('acl: %s enabled, %d entries for user %s\n') % | |
66 | (key, len(pats), thisuser)) |
|
66 | (key, len(pats), thisuser)) | |
67 | if pats: |
|
67 | if pats: |
@@ -45,7 +45,7 b'' | |||||
45 | from mercurial.demandload import demandload |
|
45 | from mercurial.demandload import demandload | |
46 | from mercurial.i18n import gettext as _ |
|
46 | from mercurial.i18n import gettext as _ | |
47 | from mercurial.node import * |
|
47 | from mercurial.node import * | |
48 |
demandload(globals(), 'mercurial:c |
|
48 | demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile') | |
49 |
|
49 | |||
50 | def dodiff(ui, repo, diffcmd, diffopts, pats, opts): |
|
50 | def dodiff(ui, repo, diffcmd, diffopts, pats, opts): | |
51 | def snapshot_node(files, node): |
|
51 | def snapshot_node(files, node): | |
@@ -90,7 +90,7 b' def dodiff(ui, repo, diffcmd, diffopts, ' | |||||
90 | fp.write(chunk) |
|
90 | fp.write(chunk) | |
91 | return dirname |
|
91 | return dirname | |
92 |
|
92 | |||
93 |
node1, node2 = c |
|
93 | node1, node2 = cmdutil.revpair(ui, repo, opts['rev']) | |
94 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
|
94 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
95 | modified, added, removed, deleted, unknown = repo.status( |
|
95 | modified, added, removed, deleted, unknown = repo.status( | |
96 | node1, node2, files, match=matchfn)[:5] |
|
96 | node1, node2, files, match=matchfn)[:5] | |
@@ -105,8 +105,7 b' def dodiff(ui, repo, diffcmd, diffopts, ' | |||||
105 | else: |
|
105 | else: | |
106 | dir2 = snapshot_wdir(modified + added) |
|
106 | dir2 = snapshot_wdir(modified + added) | |
107 | cmdline = ('%s %s %s %s' % |
|
107 | cmdline = ('%s %s %s %s' % | |
108 | (util.shellquote(diffcmd), |
|
108 | (util.shellquote(diffcmd), ' '.join(diffopts), | |
109 | ' '.join(map(util.shellquote, diffopts)), |
|
|||
110 | util.shellquote(dir1), util.shellquote(dir2))) |
|
109 | util.shellquote(dir1), util.shellquote(dir2))) | |
111 | ui.debug('running %r in %s\n' % (cmdline, tmproot)) |
|
110 | ui.debug('running %r in %s\n' % (cmdline, tmproot)) | |
112 | util.system(cmdline, cwd=tmproot) |
|
111 | util.system(cmdline, cwd=tmproot) |
@@ -7,90 +7,39 b'' | |||||
7 |
|
7 | |||
8 | from mercurial.demandload import * |
|
8 | from mercurial.demandload import * | |
9 | demandload(globals(), 'time sys signal os') |
|
9 | demandload(globals(), 'time sys signal os') | |
10 |
demandload(globals(), 'mercurial:hg, |
|
10 | demandload(globals(), 'mercurial:hg,fancyopts,commands,ui,util,patch,revlog') | |
11 |
|
||||
12 | def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, |
|
|||
13 | changes=None, text=False): |
|
|||
14 | def date(c): |
|
|||
15 | return time.asctime(time.gmtime(c[2][0])) |
|
|||
16 |
|
||||
17 | if not changes: |
|
|||
18 | changes = repo.status(node1, node2, files, match=match)[:5] |
|
|||
19 | modified, added, removed, deleted, unknown = changes |
|
|||
20 | if files: |
|
|||
21 | modified, added, removed = map(lambda x: filterfiles(files, x), |
|
|||
22 | (modified, added, removed)) |
|
|||
23 |
|
||||
24 | if not modified and not added and not removed: |
|
|||
25 | return |
|
|||
26 |
|
11 | |||
27 | if node2: |
|
12 | def difftree(ui, repo, node1=None, node2=None, *files, **opts): | |
28 | change = repo.changelog.read(node2) |
|
|||
29 | mmap2 = repo.manifest.read(change[0]) |
|
|||
30 | date2 = date(change) |
|
|||
31 | def read(f): |
|
|||
32 | return repo.file(f).read(mmap2[f]) |
|
|||
33 | else: |
|
|||
34 | date2 = time.asctime() |
|
|||
35 | if not node1: |
|
|||
36 | node1 = repo.dirstate.parents()[0] |
|
|||
37 | def read(f): |
|
|||
38 | return repo.wfile(f).read() |
|
|||
39 |
|
||||
40 | change = repo.changelog.read(node1) |
|
|||
41 | mmap = repo.manifest.read(change[0]) |
|
|||
42 | date1 = date(change) |
|
|||
43 |
|
||||
44 | for f in modified: |
|
|||
45 | to = None |
|
|||
46 | if f in mmap: |
|
|||
47 | to = repo.file(f).read(mmap[f]) |
|
|||
48 | tn = read(f) |
|
|||
49 | fp.write("diff --git a/%s b/%s\n" % (f, f)) |
|
|||
50 | fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text)) |
|
|||
51 | for f in added: |
|
|||
52 | to = None |
|
|||
53 | tn = read(f) |
|
|||
54 | fp.write("diff --git /dev/null b/%s\n" % (f)) |
|
|||
55 | fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text)) |
|
|||
56 | for f in removed: |
|
|||
57 | to = repo.file(f).read(mmap[f]) |
|
|||
58 | tn = None |
|
|||
59 | fp.write("diff --git a/%s /dev/null\n" % (f)) |
|
|||
60 | fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text)) |
|
|||
61 |
|
||||
62 | def difftree(ui, repo, node1=None, node2=None, **opts): |
|
|||
63 | """diff trees from two commits""" |
|
13 | """diff trees from two commits""" | |
64 | def __difftree(repo, node1, node2): |
|
14 | def __difftree(repo, node1, node2, files=[]): | |
65 | def date(c): |
|
|||
66 | return time.asctime(time.gmtime(c[2][0])) |
|
|||
67 |
|
||||
68 | if node2: |
|
15 | if node2: | |
69 | change = repo.changelog.read(node2) |
|
16 | change = repo.changelog.read(node2) | |
70 | mmap2 = repo.manifest.read(change[0]) |
|
17 | mmap2 = repo.manifest.read(change[0]) | |
71 |
|
|
18 | status = repo.status(node1, node2, files=files)[:5] | |
72 | def read(f): return repo.file(f).read(mmap2[f]) |
|
19 | modified, added, removed, deleted, unknown = status | |
73 | date2 = date(change) |
|
|||
74 | else: |
|
20 | else: | |
75 | date2 = time.asctime() |
|
21 | status = repo.status(node1, files=files)[:5] | |
76 |
modified, added, removed, deleted, unknown = |
|
22 | modified, added, removed, deleted, unknown = status | |
77 | if not node1: |
|
23 | if not node1: | |
78 | node1 = repo.dirstate.parents()[0] |
|
24 | node1 = repo.dirstate.parents()[0] | |
79 | def read(f): return file(os.path.join(repo.root, f)).read() |
|
|||
80 |
|
25 | |||
81 | change = repo.changelog.read(node1) |
|
26 | change = repo.changelog.read(node1) | |
82 | mmap = repo.manifest.read(change[0]) |
|
27 | mmap = repo.manifest.read(change[0]) | |
83 | date1 = date(change) |
|
28 | empty = hg.short(hg.nullid) | |
84 | empty = "0" * 40; |
|
|||
85 |
|
29 | |||
86 | for f in modified: |
|
30 | for f in modified: | |
87 | # TODO get file permissions |
|
31 | # TODO get file permissions | |
88 |
print ":100664 100664 %s %s M\t%s\t%s" % (hg. |
|
32 | print ":100664 100664 %s %s M\t%s\t%s" % (hg.short(mmap[f]), | |
89 |
hg. |
|
33 | hg.short(mmap2[f]), | |
|
34 | f, f) | |||
90 | for f in added: |
|
35 | for f in added: | |
91 |
print ":000000 100664 %s %s N\t%s\t%s" % (empty, |
|
36 | print ":000000 100664 %s %s N\t%s\t%s" % (empty, | |
|
37 | hg.short(mmap2[f]), | |||
|
38 | f, f) | |||
92 | for f in removed: |
|
39 | for f in removed: | |
93 |
print ":100664 000000 %s %s D\t%s\t%s" % (hg. |
|
40 | print ":100664 000000 %s %s D\t%s\t%s" % (hg.short(mmap[f]), | |
|
41 | empty, | |||
|
42 | f, f) | |||
94 | ## |
|
43 | ## | |
95 |
|
44 | |||
96 | while True: |
|
45 | while True: | |
@@ -113,20 +62,22 b' def difftree(ui, repo, node1=None, node2' | |||||
113 | if opts['patch']: |
|
62 | if opts['patch']: | |
114 | if opts['pretty']: |
|
63 | if opts['pretty']: | |
115 | catcommit(repo, node2, "") |
|
64 | catcommit(repo, node2, "") | |
116 |
|
|
65 | patch.diff(repo, node1, node2, | |
|
66 | files=files, | |||
|
67 | opts=patch.diffopts(ui, {'git': True})) | |||
117 | else: |
|
68 | else: | |
118 | __difftree(repo, node1, node2) |
|
69 | __difftree(repo, node1, node2, files=files) | |
119 | if not opts['stdin']: |
|
70 | if not opts['stdin']: | |
120 | break |
|
71 | break | |
121 |
|
72 | |||
122 | def catcommit(repo, n, prefix, changes=None): |
|
73 | def catcommit(repo, n, prefix, changes=None): | |
123 | nlprefix = '\n' + prefix; |
|
74 | nlprefix = '\n' + prefix; | |
124 | (p1, p2) = repo.changelog.parents(n) |
|
75 | (p1, p2) = repo.changelog.parents(n) | |
125 |
(h, h1, h2) = map(hg. |
|
76 | (h, h1, h2) = map(hg.short, (n, p1, p2)) | |
126 | (i1, i2) = map(repo.changelog.rev, (p1, p2)) |
|
77 | (i1, i2) = map(repo.changelog.rev, (p1, p2)) | |
127 | if not changes: |
|
78 | if not changes: | |
128 | changes = repo.changelog.read(n) |
|
79 | changes = repo.changelog.read(n) | |
129 |
print "tree %s" % (hg. |
|
80 | print "tree %s" % (hg.short(changes[0])) | |
130 | if i1 != -1: print "parent %s" % (h1) |
|
81 | if i1 != -1: print "parent %s" % (h1) | |
131 | if i2 != -1: print "parent %s" % (h2) |
|
82 | if i2 != -1: print "parent %s" % (h2) | |
132 | date_ar = changes[2] |
|
83 | date_ar = changes[2] | |
@@ -139,6 +90,7 b' def catcommit(repo, n, prefix, changes=N' | |||||
139 |
|
90 | |||
140 | print "author %s %s %s" % (changes[1], date, date_ar[1]) |
|
91 | print "author %s %s %s" % (changes[1], date, date_ar[1]) | |
141 | print "committer %s %s %s" % (committer, date, date_ar[1]) |
|
92 | print "committer %s %s %s" % (committer, date, date_ar[1]) | |
|
93 | print "revision %d" % repo.changelog.rev(n) | |||
142 | print "" |
|
94 | print "" | |
143 | if prefix != "": |
|
95 | if prefix != "": | |
144 | print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip()) |
|
96 | print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip()) | |
@@ -152,7 +104,7 b' def base(ui, repo, node1, node2):' | |||||
152 | node1 = repo.lookup(node1) |
|
104 | node1 = repo.lookup(node1) | |
153 | node2 = repo.lookup(node2) |
|
105 | node2 = repo.lookup(node2) | |
154 | n = repo.changelog.ancestor(node1, node2) |
|
106 | n = repo.changelog.ancestor(node1, node2) | |
155 |
print hg. |
|
107 | print hg.short(n) | |
156 |
|
108 | |||
157 | def catfile(ui, repo, type=None, r=None, **opts): |
|
109 | def catfile(ui, repo, type=None, r=None, **opts): | |
158 | """cat a specific revision""" |
|
110 | """cat a specific revision""" | |
@@ -265,7 +217,6 b' def revtree(args, repo, full="tree", max' | |||||
265 |
|
217 | |||
266 | # walk the repository looking for commits that are in our |
|
218 | # walk the repository looking for commits that are in our | |
267 | # reachability graph |
|
219 | # reachability graph | |
268 | #for i in range(repo.changelog.count()-1, -1, -1): |
|
|||
269 | for i, changes in chlogwalk(): |
|
220 | for i, changes in chlogwalk(): | |
270 | n = repo.changelog.node(i) |
|
221 | n = repo.changelog.node(i) | |
271 | mask = is_reachable(want_sha1, reachable, n) |
|
222 | mask = is_reachable(want_sha1, reachable, n) | |
@@ -274,17 +225,17 b' def revtree(args, repo, full="tree", max' | |||||
274 | if parents: |
|
225 | if parents: | |
275 | pp = repo.changelog.parents(n) |
|
226 | pp = repo.changelog.parents(n) | |
276 | if pp[0] != hg.nullid: |
|
227 | if pp[0] != hg.nullid: | |
277 |
parentstr += " " + hg. |
|
228 | parentstr += " " + hg.short(pp[0]) | |
278 | if pp[1] != hg.nullid: |
|
229 | if pp[1] != hg.nullid: | |
279 |
parentstr += " " + hg. |
|
230 | parentstr += " " + hg.short(pp[1]) | |
280 | if not full: |
|
231 | if not full: | |
281 |
print hg. |
|
232 | print hg.short(n) + parentstr | |
282 |
elif full |
|
233 | elif full == "commit": | |
283 |
print hg. |
|
234 | print hg.short(n) + parentstr | |
284 | catcommit(repo, n, ' ', changes) |
|
235 | catcommit(repo, n, ' ', changes) | |
285 | else: |
|
236 | else: | |
286 | (p1, p2) = repo.changelog.parents(n) |
|
237 | (p1, p2) = repo.changelog.parents(n) | |
287 |
(h, h1, h2) = map(hg. |
|
238 | (h, h1, h2) = map(hg.short, (n, p1, p2)) | |
288 | (i1, i2) = map(repo.changelog.rev, (p1, p2)) |
|
239 | (i1, i2) = map(repo.changelog.rev, (p1, p2)) | |
289 |
|
240 | |||
290 | date = changes[2][0] |
|
241 | date = changes[2][0] | |
@@ -300,6 +251,19 b' def revtree(args, repo, full="tree", max' | |||||
300 | break |
|
251 | break | |
301 | count += 1 |
|
252 | count += 1 | |
302 |
|
253 | |||
|
254 | def revparse(ui, repo, *revs, **opts): | |||
|
255 | """Parse given revisions""" | |||
|
256 | def revstr(rev): | |||
|
257 | if rev == 'HEAD': | |||
|
258 | rev = 'tip' | |||
|
259 | return revlog.hex(repo.lookup(rev)) | |||
|
260 | ||||
|
261 | for r in revs: | |||
|
262 | revrange = r.split(':', 1) | |||
|
263 | ui.write('%s\n' % revstr(revrange[0])) | |||
|
264 | if len(revrange) == 2: | |||
|
265 | ui.write('^%s\n' % revstr(revrange[1])) | |||
|
266 | ||||
303 | # git rev-list tries to order things by date, and has the ability to stop |
|
267 | # git rev-list tries to order things by date, and has the ability to stop | |
304 | # at a given commit without walking the whole repo. TODO add the stop |
|
268 | # at a given commit without walking the whole repo. TODO add the stop | |
305 | # parameter |
|
269 | # parameter | |
@@ -312,23 +276,29 b' def revlist(ui, repo, *revs, **opts):' | |||||
312 | copy = [x for x in revs] |
|
276 | copy = [x for x in revs] | |
313 | revtree(copy, repo, full, opts['max_count'], opts['parents']) |
|
277 | revtree(copy, repo, full, opts['max_count'], opts['parents']) | |
314 |
|
278 | |||
315 | def view(ui, repo, *etc): |
|
279 | def view(ui, repo, *etc, **opts): | |
316 | "start interactive history viewer" |
|
280 | "start interactive history viewer" | |
317 | os.chdir(repo.root) |
|
281 | os.chdir(repo.root) | |
318 | os.system(ui.config("hgk", "path", "hgk") + " " + " ".join(etc)) |
|
282 | optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems()]) | |
|
283 | os.system(ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))) | |||
319 |
|
284 | |||
320 | cmdtable = { |
|
285 | cmdtable = { | |
321 |
"view": (view, |
|
286 | "view": (view, | |
|
287 | [('l', 'limit', '', 'limit number of changes displayed')], | |||
|
288 | 'hg view [-l LIMIT] [REVRANGE]'), | |||
322 | "debug-diff-tree": (difftree, [('p', 'patch', None, 'generate patch'), |
|
289 | "debug-diff-tree": (difftree, [('p', 'patch', None, 'generate patch'), | |
323 | ('r', 'recursive', None, 'recursive'), |
|
290 | ('r', 'recursive', None, 'recursive'), | |
324 | ('P', 'pretty', None, 'pretty'), |
|
291 | ('P', 'pretty', None, 'pretty'), | |
325 | ('s', 'stdin', None, 'stdin'), |
|
292 | ('s', 'stdin', None, 'stdin'), | |
326 | ('C', 'copy', None, 'detect copies'), |
|
293 | ('C', 'copy', None, 'detect copies'), | |
327 | ('S', 'search', "", 'search')], |
|
294 | ('S', 'search', "", 'search')], | |
328 | "hg git-diff-tree [options] node1 node2"), |
|
295 | "hg git-diff-tree [options] node1 node2 [files...]"), | |
329 | "debug-cat-file": (catfile, [('s', 'stdin', None, 'stdin')], |
|
296 | "debug-cat-file": (catfile, [('s', 'stdin', None, 'stdin')], | |
330 | "hg debug-cat-file [options] type file"), |
|
297 | "hg debug-cat-file [options] type file"), | |
331 | "debug-merge-base": (base, [], "hg debug-merge-base node node"), |
|
298 | "debug-merge-base": (base, [], "hg debug-merge-base node node"), | |
|
299 | 'debug-rev-parse': (revparse, | |||
|
300 | [('', 'default', '', 'ignored')], | |||
|
301 | "hg debug-rev-parse rev"), | |||
332 | "debug-rev-list": (revlist, [('H', 'header', None, 'header'), |
|
302 | "debug-rev-list": (revlist, [('H', 'header', None, 'header'), | |
333 | ('t', 'topo-order', None, 'topo-order'), |
|
303 | ('t', 'topo-order', None, 'topo-order'), | |
334 | ('p', 'parents', None, 'parents'), |
|
304 | ('p', 'parents', None, 'parents'), |
@@ -31,15 +31,16 b' refresh contents of top applied patch ' | |||||
31 |
|
31 | |||
32 | from mercurial.demandload import * |
|
32 | from mercurial.demandload import * | |
33 | from mercurial.i18n import gettext as _ |
|
33 | from mercurial.i18n import gettext as _ | |
|
34 | from mercurial import commands | |||
34 | demandload(globals(), "os sys re struct traceback errno bz2") |
|
35 | demandload(globals(), "os sys re struct traceback errno bz2") | |
35 |
demandload(globals(), "mercurial:cmdutil, |
|
36 | demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,ui,util") | |
36 |
|
37 | |||
37 | commands.norepo += " qclone qversion" |
|
38 | commands.norepo += " qclone qversion" | |
38 |
|
39 | |||
39 | class statusentry: |
|
40 | class statusentry: | |
40 | def __init__(self, rev, name=None): |
|
41 | def __init__(self, rev, name=None): | |
41 | if not name: |
|
42 | if not name: | |
42 | fields = rev.split(':') |
|
43 | fields = rev.split(':', 1) | |
43 | if len(fields) == 2: |
|
44 | if len(fields) == 2: | |
44 | self.rev, self.name = fields |
|
45 | self.rev, self.name = fields | |
45 | else: |
|
46 | else: | |
@@ -482,24 +483,35 b' class queue:' | |||||
482 | tr.close() |
|
483 | tr.close() | |
483 | return (err, n) |
|
484 | return (err, n) | |
484 |
|
485 | |||
485 |
def delete(self, repo, patches, |
|
486 | def delete(self, repo, patches, opts): | |
486 | realpatches = [] |
|
487 | realpatches = [] | |
|
488 | appliedbase = 0 | |||
|
489 | forget = opts.get('forget') | |||
487 | for patch in patches: |
|
490 | for patch in patches: | |
488 | patch = self.lookup(patch, strict=True) |
|
491 | patch = self.lookup(patch, strict=True) | |
489 | info = self.isapplied(patch) |
|
492 | info = self.isapplied(patch) | |
490 | if info: |
|
493 | if info and not forget: | |
491 | raise util.Abort(_("cannot delete applied patch %s") % patch) |
|
494 | raise util.Abort(_("cannot delete applied patch %s") % patch) | |
492 | if patch not in self.series: |
|
495 | if patch not in self.series: | |
493 | raise util.Abort(_("patch %s not in series file") % patch) |
|
496 | raise util.Abort(_("patch %s not in series file") % patch) | |
|
497 | if forget: | |||
|
498 | if not info: | |||
|
499 | raise util.Abort(_("cannot forget unapplied patch %s") % patch) | |||
|
500 | if info[0] != appliedbase: | |||
|
501 | raise util.Abort(_("patch %s not at base") % patch) | |||
|
502 | appliedbase += 1 | |||
494 | realpatches.append(patch) |
|
503 | realpatches.append(patch) | |
495 |
|
504 | |||
496 | if not keep: |
|
505 | if not opts.get('keep'): | |
497 | r = self.qrepo() |
|
506 | r = self.qrepo() | |
498 | if r: |
|
507 | if r: | |
499 | r.remove(realpatches, True) |
|
508 | r.remove(realpatches, True) | |
500 | else: |
|
509 | else: | |
501 | os.unlink(self.join(patch)) |
|
510 | os.unlink(self.join(patch)) | |
502 |
|
511 | |||
|
512 | if forget: | |||
|
513 | del self.applied[:appliedbase] | |||
|
514 | self.applied_dirty = 1 | |||
503 | indices = [self.find_series(p) for p in realpatches] |
|
515 | indices = [self.find_series(p) for p in realpatches] | |
504 | indices.sort() |
|
516 | indices.sort() | |
505 | for i in indices[-1::-1]: |
|
517 | for i in indices[-1::-1]: | |
@@ -693,8 +705,8 b' class queue:' | |||||
693 | stripall(rev, revnum) |
|
705 | stripall(rev, revnum) | |
694 |
|
706 | |||
695 | change = chlog.read(rev) |
|
707 | change = chlog.read(rev) | |
|
708 | chlog.strip(revnum, revnum) | |||
696 | repo.manifest.strip(repo.manifest.rev(change[0]), revnum) |
|
709 | repo.manifest.strip(repo.manifest.rev(change[0]), revnum) | |
697 | chlog.strip(revnum, revnum) |
|
|||
698 | if saveheads: |
|
710 | if saveheads: | |
699 | self.ui.status("adding branch\n") |
|
711 | self.ui.status("adding branch\n") | |
700 | commands.unbundle(self.ui, repo, chgrpfile, update=False) |
|
712 | commands.unbundle(self.ui, repo, chgrpfile, update=False) | |
@@ -756,25 +768,25 b' class queue:' | |||||
756 | # return any partial match made above |
|
768 | # return any partial match made above | |
757 | if res: |
|
769 | if res: | |
758 | return res |
|
770 | return res | |
759 |
minus = patch.r |
|
771 | minus = patch.rfind('-') | |
760 |
if |
|
772 | if minus >= 0: | |
761 |
res = partial_name(minus |
|
773 | res = partial_name(patch[:minus]) | |
762 | if res: |
|
774 | if res: | |
763 | i = self.series.index(res) |
|
775 | i = self.series.index(res) | |
764 | try: |
|
776 | try: | |
765 |
off = int(minus |
|
777 | off = int(patch[minus+1:] or 1) | |
766 | except(ValueError, OverflowError): |
|
778 | except(ValueError, OverflowError): | |
767 | pass |
|
779 | pass | |
768 | else: |
|
780 | else: | |
769 | if i - off >= 0: |
|
781 | if i - off >= 0: | |
770 | return self.series[i - off] |
|
782 | return self.series[i - off] | |
771 |
plus = patch.r |
|
783 | plus = patch.rfind('+') | |
772 |
if |
|
784 | if plus >= 0: | |
773 |
res = partial_name(plus |
|
785 | res = partial_name(patch[:plus]) | |
774 | if res: |
|
786 | if res: | |
775 | i = self.series.index(res) |
|
787 | i = self.series.index(res) | |
776 | try: |
|
788 | try: | |
777 |
off = int(plus |
|
789 | off = int(patch[plus+1:] or 1) | |
778 | except(ValueError, OverflowError): |
|
790 | except(ValueError, OverflowError): | |
779 | pass |
|
791 | pass | |
780 | else: |
|
792 | else: | |
@@ -915,16 +927,16 b' class queue:' | |||||
915 | def refresh(self, repo, pats=None, **opts): |
|
927 | def refresh(self, repo, pats=None, **opts): | |
916 | if len(self.applied) == 0: |
|
928 | if len(self.applied) == 0: | |
917 | self.ui.write("No patches applied\n") |
|
929 | self.ui.write("No patches applied\n") | |
918 | return |
|
930 | return 1 | |
919 | wlock = repo.wlock() |
|
931 | wlock = repo.wlock() | |
920 | self.check_toppatch(repo) |
|
932 | self.check_toppatch(repo) | |
921 | (top, patch) = (self.applied[-1].rev, self.applied[-1].name) |
|
933 | (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name) | |
922 | top = revlog.bin(top) |
|
934 | top = revlog.bin(top) | |
923 | cparents = repo.changelog.parents(top) |
|
935 | cparents = repo.changelog.parents(top) | |
924 | patchparent = self.qparents(repo, top) |
|
936 | patchparent = self.qparents(repo, top) | |
925 | message, comments, user, date, patchfound = self.readheaders(patch) |
|
937 | message, comments, user, date, patchfound = self.readheaders(patchfn) | |
926 |
|
938 | |||
927 | patchf = self.opener(patch, "w") |
|
939 | patchf = self.opener(patchfn, "w") | |
928 | msg = opts.get('msg', '').rstrip() |
|
940 | msg = opts.get('msg', '').rstrip() | |
929 | if msg: |
|
941 | if msg: | |
930 | if comments: |
|
942 | if comments: | |
@@ -994,8 +1006,11 b' class queue:' | |||||
994 | r = list(util.unique(dd)) |
|
1006 | r = list(util.unique(dd)) | |
995 | a = list(util.unique(aa)) |
|
1007 | a = list(util.unique(aa)) | |
996 | filelist = filter(matchfn, util.unique(m + r + a)) |
|
1008 | filelist = filter(matchfn, util.unique(m + r + a)) | |
997 | self.printdiff(repo, patchparent, files=filelist, |
|
1009 | if opts.get('git'): | |
998 | changes=(m, a, r, [], u), fp=patchf) |
|
1010 | self.diffopts().git = True | |
|
1011 | patch.diff(repo, patchparent, files=filelist, match=matchfn, | |||
|
1012 | fp=patchf, changes=(m, a, r, [], u), | |||
|
1013 | opts=self.diffopts()) | |||
999 | patchf.close() |
|
1014 | patchf.close() | |
1000 |
|
1015 | |||
1001 | changes = repo.changelog.read(tip) |
|
1016 | changes = repo.changelog.read(tip) | |
@@ -1018,7 +1033,7 b' class queue:' | |||||
1018 |
|
1033 | |||
1019 | if not msg: |
|
1034 | if not msg: | |
1020 | if not message: |
|
1035 | if not message: | |
1021 | message = "patch queue: %s\n" % patch |
|
1036 | message = "patch queue: %s\n" % patchfn | |
1022 | else: |
|
1037 | else: | |
1023 | message = "\n".join(message) |
|
1038 | message = "\n".join(message) | |
1024 | else: |
|
1039 | else: | |
@@ -1026,7 +1041,7 b' class queue:' | |||||
1026 |
|
1041 | |||
1027 | self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
|
1042 | self.strip(repo, top, update=False, backup='strip', wlock=wlock) | |
1028 | n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) |
|
1043 | n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) | |
1029 | self.applied[-1] = statusentry(revlog.hex(n), patch) |
|
1044 | self.applied[-1] = statusentry(revlog.hex(n), patchfn) | |
1030 | self.applied_dirty = 1 |
|
1045 | self.applied_dirty = 1 | |
1031 | else: |
|
1046 | else: | |
1032 | self.printdiff(repo, patchparent, fp=patchf) |
|
1047 | self.printdiff(repo, patchparent, fp=patchf) | |
@@ -1237,11 +1252,13 b' class queue:' | |||||
1237 | self.ui.write(p + '\n') |
|
1252 | self.ui.write(p + '\n') | |
1238 | else: |
|
1253 | else: | |
1239 | self.ui.write("No patches applied\n") |
|
1254 | self.ui.write("No patches applied\n") | |
|
1255 | return 1 | |||
1240 |
|
1256 | |||
1241 | def next(self, repo): |
|
1257 | def next(self, repo): | |
1242 | end = self.series_end() |
|
1258 | end = self.series_end() | |
1243 | if end == len(self.series): |
|
1259 | if end == len(self.series): | |
1244 | self.ui.write("All patches applied\n") |
|
1260 | self.ui.write("All patches applied\n") | |
|
1261 | return 1 | |||
1245 | else: |
|
1262 | else: | |
1246 | p = self.series[end] |
|
1263 | p = self.series[end] | |
1247 | if self.ui.verbose: |
|
1264 | if self.ui.verbose: | |
@@ -1254,8 +1271,10 b' class queue:' | |||||
1254 | self.ui.write(p + '\n') |
|
1271 | self.ui.write(p + '\n') | |
1255 | elif len(self.applied) == 1: |
|
1272 | elif len(self.applied) == 1: | |
1256 | self.ui.write("Only one patch applied\n") |
|
1273 | self.ui.write("Only one patch applied\n") | |
|
1274 | return 1 | |||
1257 | else: |
|
1275 | else: | |
1258 | self.ui.write("No patches applied\n") |
|
1276 | self.ui.write("No patches applied\n") | |
|
1277 | return 1 | |||
1259 |
|
1278 | |||
1260 | def qimport(self, repo, files, patch=None, existing=None, force=None): |
|
1279 | def qimport(self, repo, files, patch=None, existing=None, force=None): | |
1261 | if len(files) > 1 and patch: |
|
1280 | if len(files) > 1 and patch: | |
@@ -1298,10 +1317,15 b' class queue:' | |||||
1298 | def delete(ui, repo, patch, *patches, **opts): |
|
1317 | def delete(ui, repo, patch, *patches, **opts): | |
1299 | """remove patches from queue |
|
1318 | """remove patches from queue | |
1300 |
|
1319 | |||
1301 | The patches must not be applied. |
|
1320 | With --forget, mq will stop managing the named patches. The | |
1302 | With -k, the patch files are preserved in the patch directory.""" |
|
1321 | patches must be applied and at the base of the stack. This option | |
|
1322 | is useful when the patches have been applied upstream. | |||
|
1323 | ||||
|
1324 | Otherwise, the patches must not be applied. | |||
|
1325 | ||||
|
1326 | With --keep, the patch files are preserved in the patch directory.""" | |||
1303 | q = repo.mq |
|
1327 | q = repo.mq | |
1304 |
q.delete(repo, (patch,) + patches, |
|
1328 | q.delete(repo, (patch,) + patches, opts) | |
1305 | q.save_dirty() |
|
1329 | q.save_dirty() | |
1306 | return 0 |
|
1330 | return 0 | |
1307 |
|
1331 | |||
@@ -1402,18 +1426,15 b' def series(ui, repo, **opts):' | |||||
1402 |
|
1426 | |||
1403 | def top(ui, repo, **opts): |
|
1427 | def top(ui, repo, **opts): | |
1404 | """print the name of the current patch""" |
|
1428 | """print the name of the current patch""" | |
1405 | repo.mq.top(repo) |
|
1429 | return repo.mq.top(repo) | |
1406 | return 0 |
|
|||
1407 |
|
1430 | |||
1408 | def next(ui, repo, **opts): |
|
1431 | def next(ui, repo, **opts): | |
1409 | """print the name of the next patch""" |
|
1432 | """print the name of the next patch""" | |
1410 | repo.mq.next(repo) |
|
1433 | return repo.mq.next(repo) | |
1411 | return 0 |
|
|||
1412 |
|
1434 | |||
1413 | def prev(ui, repo, **opts): |
|
1435 | def prev(ui, repo, **opts): | |
1414 | """print the name of the previous patch""" |
|
1436 | """print the name of the previous patch""" | |
1415 | repo.mq.prev(repo) |
|
1437 | return repo.mq.prev(repo) | |
1416 | return 0 |
|
|||
1417 |
|
1438 | |||
1418 | def new(ui, repo, patch, **opts): |
|
1439 | def new(ui, repo, patch, **opts): | |
1419 | """create a new patch |
|
1440 | """create a new patch | |
@@ -1449,9 +1470,9 b' def refresh(ui, repo, *pats, **opts):' | |||||
1449 | patch = q.applied[-1].name |
|
1470 | patch = q.applied[-1].name | |
1450 | (message, comment, user, date, hasdiff) = q.readheaders(patch) |
|
1471 | (message, comment, user, date, hasdiff) = q.readheaders(patch) | |
1451 | message = ui.edit('\n'.join(message), user or ui.username()) |
|
1472 | message = ui.edit('\n'.join(message), user or ui.username()) | |
1452 | q.refresh(repo, pats, msg=message, **opts) |
|
1473 | ret = q.refresh(repo, pats, msg=message, **opts) | |
1453 | q.save_dirty() |
|
1474 | q.save_dirty() | |
1454 |
return |
|
1475 | return ret | |
1455 |
|
1476 | |||
1456 | def diff(ui, repo, *pats, **opts): |
|
1477 | def diff(ui, repo, *pats, **opts): | |
1457 | """diff of the current patch""" |
|
1478 | """diff of the current patch""" | |
@@ -1476,7 +1497,7 b' def fold(ui, repo, *files, **opts):' | |||||
1476 | if not files: |
|
1497 | if not files: | |
1477 | raise util.Abort(_('qfold requires at least one patch name')) |
|
1498 | raise util.Abort(_('qfold requires at least one patch name')) | |
1478 | if not q.check_toppatch(repo): |
|
1499 | if not q.check_toppatch(repo): | |
1479 |
raise util.Abort(_('No patches applied |
|
1500 | raise util.Abort(_('No patches applied')) | |
1480 |
|
1501 | |||
1481 | message = commands.logmessage(opts) |
|
1502 | message = commands.logmessage(opts) | |
1482 | if opts['edit']: |
|
1503 | if opts['edit']: | |
@@ -1571,7 +1592,7 b' def header(ui, repo, patch=None):' | |||||
1571 | else: |
|
1592 | else: | |
1572 | if not q.applied: |
|
1593 | if not q.applied: | |
1573 | ui.write('No patches applied\n') |
|
1594 | ui.write('No patches applied\n') | |
1574 | return |
|
1595 | return 1 | |
1575 | patch = q.lookup('qtip') |
|
1596 | patch = q.lookup('qtip') | |
1576 | message = repo.mq.readheaders(patch)[0] |
|
1597 | message = repo.mq.readheaders(patch)[0] | |
1577 |
|
1598 | |||
@@ -1648,13 +1669,6 b' def rename(ui, repo, patch, name=None, *' | |||||
1648 | name = patch |
|
1669 | name = patch | |
1649 | patch = None |
|
1670 | patch = None | |
1650 |
|
1671 | |||
1651 | if name in q.series: |
|
|||
1652 | raise util.Abort(_('A patch named %s already exists in the series file') % name) |
|
|||
1653 |
|
||||
1654 | absdest = q.join(name) |
|
|||
1655 | if os.path.exists(absdest): |
|
|||
1656 | raise util.Abort(_('%s already exists') % absdest) |
|
|||
1657 |
|
||||
1658 | if patch: |
|
1672 | if patch: | |
1659 | patch = q.lookup(patch) |
|
1673 | patch = q.lookup(patch) | |
1660 | else: |
|
1674 | else: | |
@@ -1662,6 +1676,15 b' def rename(ui, repo, patch, name=None, *' | |||||
1662 | ui.write(_('No patches applied\n')) |
|
1676 | ui.write(_('No patches applied\n')) | |
1663 | return |
|
1677 | return | |
1664 | patch = q.lookup('qtip') |
|
1678 | patch = q.lookup('qtip') | |
|
1679 | absdest = q.join(name) | |||
|
1680 | if os.path.isdir(absdest): | |||
|
1681 | name = os.path.join(name, os.path.basename(patch)) | |||
|
1682 | absdest = q.join(name) | |||
|
1683 | if os.path.exists(absdest): | |||
|
1684 | raise util.Abort(_('%s already exists') % absdest) | |||
|
1685 | ||||
|
1686 | if name in q.series: | |||
|
1687 | raise util.Abort(_('A patch named %s already exists in the series file') % name) | |||
1665 |
|
1688 | |||
1666 | if ui.verbose: |
|
1689 | if ui.verbose: | |
1667 | ui.write('Renaming %s to %s\n' % (patch, name)) |
|
1690 | ui.write('Renaming %s to %s\n' % (patch, name)) | |
@@ -1733,7 +1756,8 b' def strip(ui, repo, rev, **opts):' | |||||
1733 | backup = 'strip' |
|
1756 | backup = 'strip' | |
1734 | elif opts['nobackup']: |
|
1757 | elif opts['nobackup']: | |
1735 | backup = 'none' |
|
1758 | backup = 'none' | |
1736 | repo.mq.strip(repo, rev, backup=backup) |
|
1759 | update = repo.dirstate.parents()[0] != revlog.nullid | |
|
1760 | repo.mq.strip(repo, rev, backup=backup, update=update) | |||
1737 | return 0 |
|
1761 | return 0 | |
1738 |
|
1762 | |||
1739 | def select(ui, repo, *args, **opts): |
|
1763 | def select(ui, repo, *args, **opts): | |
@@ -1909,8 +1933,9 b' cmdtable = {' | |||||
1909 | 'hg qdiff [-I] [-X] [FILE]...'), |
|
1933 | 'hg qdiff [-I] [-X] [FILE]...'), | |
1910 | "qdelete|qremove|qrm": |
|
1934 | "qdelete|qremove|qrm": | |
1911 | (delete, |
|
1935 | (delete, | |
1912 |
[(' |
|
1936 | [('f', 'forget', None, _('stop managing an applied patch')), | |
1913 | 'hg qdelete [-k] PATCH'), |
|
1937 | ('k', 'keep', None, _('keep patch file'))], | |
|
1938 | 'hg qdelete [-f] [-k] PATCH'), | |||
1914 | 'qfold': |
|
1939 | 'qfold': | |
1915 | (fold, |
|
1940 | (fold, | |
1916 | [('e', 'edit', None, _('edit patch header')), |
|
1941 | [('e', 'edit', None, _('edit patch header')), | |
@@ -1961,6 +1986,7 b' cmdtable = {' | |||||
1961 | [('e', 'edit', None, _('edit commit message')), |
|
1986 | [('e', 'edit', None, _('edit commit message')), | |
1962 | ('m', 'message', '', _('change commit message with <text>')), |
|
1987 | ('m', 'message', '', _('change commit message with <text>')), | |
1963 | ('l', 'logfile', '', _('change commit message with <file> content')), |
|
1988 | ('l', 'logfile', '', _('change commit message with <file> content')), | |
|
1989 | ('g', 'git', None, _('use git extended diff format')), | |||
1964 | ('s', 'short', None, 'short refresh'), |
|
1990 | ('s', 'short', None, 'short refresh'), | |
1965 | ('I', 'include', [], _('include names matching the given patterns')), |
|
1991 | ('I', 'include', [], _('include names matching the given patterns')), | |
1966 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
|
1992 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |
@@ -1992,7 +2018,7 b' cmdtable = {' | |||||
1992 | (series, |
|
2018 | (series, | |
1993 | [('m', 'missing', None, 'print patches not in series'), |
|
2019 | [('m', 'missing', None, 'print patches not in series'), | |
1994 | ('s', 'summary', None, _('print first line of patch header'))], |
|
2020 | ('s', 'summary', None, _('print first line of patch header'))], | |
1995 | 'hg qseries [-m]'), |
|
2021 | 'hg qseries [-ms]'), | |
1996 | "^strip": |
|
2022 | "^strip": | |
1997 | (strip, |
|
2023 | (strip, | |
1998 | [('f', 'force', None, 'force multi-head removal'), |
|
2024 | [('f', 'force', None, 'force multi-head removal'), |
@@ -238,8 +238,11 b' class notifier(object):' | |||||
238 | return |
|
238 | return | |
239 | fp = templater.stringio() |
|
239 | fp = templater.stringio() | |
240 | prev = self.repo.changelog.parents(node)[0] |
|
240 | prev = self.repo.changelog.parents(node)[0] | |
241 |
patch.diff(self.repo, |
|
241 | patch.diff(self.repo, prev, ref, fp=fp) | |
242 | difflines = fp.getvalue().splitlines(1) |
|
242 | difflines = fp.getvalue().splitlines(1) | |
|
243 | if self.ui.configbool('notify', 'diffstat', True): | |||
|
244 | s = patch.diffstat(difflines) | |||
|
245 | self.sio.write('\ndiffstat:\n\n' + s) | |||
243 | if maxdiff > 0 and len(difflines) > maxdiff: |
|
246 | if maxdiff > 0 and len(difflines) > maxdiff: | |
244 | self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % |
|
247 | self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % | |
245 | (len(difflines), maxdiff)) |
|
248 | (len(difflines), maxdiff)) |
@@ -65,7 +65,7 b'' | |||||
65 |
|
65 | |||
66 | from mercurial.demandload import * |
|
66 | from mercurial.demandload import * | |
67 | demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils |
|
67 | demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils | |
68 | mercurial:commands,hg,mail,ui |
|
68 | mercurial:commands,hg,mail,ui,patch | |
69 | os errno popen2 socket sys tempfile time''') |
|
69 | os errno popen2 socket sys tempfile time''') | |
70 | from mercurial.i18n import gettext as _ |
|
70 | from mercurial.i18n import gettext as _ | |
71 | from mercurial.node import * |
|
71 | from mercurial.node import * | |
@@ -76,27 +76,6 b' try:' | |||||
76 | import readline |
|
76 | import readline | |
77 | except ImportError: pass |
|
77 | except ImportError: pass | |
78 |
|
78 | |||
79 | def diffstat(patch): |
|
|||
80 | fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt") |
|
|||
81 | try: |
|
|||
82 | p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) |
|
|||
83 | try: |
|
|||
84 | for line in patch: print >> p.tochild, line |
|
|||
85 | p.tochild.close() |
|
|||
86 | if p.wait(): return |
|
|||
87 | fp = os.fdopen(fd, 'r') |
|
|||
88 | stat = [] |
|
|||
89 | for line in fp: stat.append(line.lstrip()) |
|
|||
90 | last = stat.pop() |
|
|||
91 | stat.insert(0, last) |
|
|||
92 | stat = ''.join(stat) |
|
|||
93 | if stat.startswith('0 files'): raise ValueError |
|
|||
94 | return stat |
|
|||
95 | except: raise |
|
|||
96 | finally: |
|
|||
97 | try: os.unlink(name) |
|
|||
98 | except: pass |
|
|||
99 |
|
||||
100 | def patchbomb(ui, repo, *revs, **opts): |
|
79 | def patchbomb(ui, repo, *revs, **opts): | |
101 | '''send changesets as a series of patch emails |
|
80 | '''send changesets as a series of patch emails | |
102 |
|
81 | |||
@@ -123,8 +102,8 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
123 | if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'): |
|
102 | if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'): | |
124 | raise ValueError |
|
103 | raise ValueError | |
125 |
|
104 | |||
126 | def cdiffstat(summary, patch): |
|
105 | def cdiffstat(summary, patchlines): | |
127 | s = diffstat(patch) |
|
106 | s = patch.diffstat(patchlines) | |
128 | if s: |
|
107 | if s: | |
129 | if summary: |
|
108 | if summary: | |
130 | ui.write(summary, '\n') |
|
109 | ui.write(summary, '\n') | |
@@ -140,7 +119,9 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
140 | if line.startswith('#'): |
|
119 | if line.startswith('#'): | |
141 | if line.startswith('# Node ID'): node = line.split()[-1] |
|
120 | if line.startswith('# Node ID'): node = line.split()[-1] | |
142 | continue |
|
121 | continue | |
143 |
if line.startswith('diff -r') |
|
122 | if (line.startswith('diff -r') | |
|
123 | or line.startswith('diff --git')): | |||
|
124 | break | |||
144 | desc.append(line) |
|
125 | desc.append(line) | |
145 | if not node: raise ValueError |
|
126 | if not node: raise ValueError | |
146 |
|
127 | |||
@@ -205,7 +186,8 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
205 |
|
186 | |||
206 | commands.export(ui, repo, *revs, **{'output': exportee(patches), |
|
187 | commands.export(ui, repo, *revs, **{'output': exportee(patches), | |
207 | 'switch_parent': False, |
|
188 | 'switch_parent': False, | |
208 |
'text': None |
|
189 | 'text': None, | |
|
190 | 'git': opts.get('git')}) | |||
209 |
|
191 | |||
210 | jumbo = [] |
|
192 | jumbo = [] | |
211 | msgs = [] |
|
193 | msgs = [] | |
@@ -322,6 +304,7 b' cmdtable = {' | |||||
322 | ('', 'bcc', [], 'email addresses of blind copy recipients'), |
|
304 | ('', 'bcc', [], 'email addresses of blind copy recipients'), | |
323 | ('c', 'cc', [], 'email addresses of copy recipients'), |
|
305 | ('c', 'cc', [], 'email addresses of copy recipients'), | |
324 | ('d', 'diffstat', None, 'add diffstat output to messages'), |
|
306 | ('d', 'diffstat', None, 'add diffstat output to messages'), | |
|
307 | ('g', 'git', None, _('use git extended diff format')), | |||
325 | ('f', 'from', '', 'email address of sender'), |
|
308 | ('f', 'from', '', 'email address of sender'), | |
326 | ('', 'plain', None, 'omit hg patch header'), |
|
309 | ('', 'plain', None, 'omit hg patch header'), | |
327 | ('n', 'test', None, 'print messages that would be sent'), |
|
310 | ('n', 'test', None, 'print messages that would be sent'), |
@@ -16,6 +16,14 b' class changelog(revlog):' | |||||
16 | defversion) |
|
16 | defversion) | |
17 |
|
17 | |||
18 | def extract(self, text): |
|
18 | def extract(self, text): | |
|
19 | """ | |||
|
20 | format used: | |||
|
21 | nodeid\n : manifest node in ascii | |||
|
22 | user\n : user, no \n or \r allowed | |||
|
23 | time tz\n : date (time is int or float, timezone is int) | |||
|
24 | files\n\n : files modified by the cset, no \n or \r allowed | |||
|
25 | (.*) : comment (free text, ideally utf-8) | |||
|
26 | """ | |||
19 | if not text: |
|
27 | if not text: | |
20 | return (nullid, "", (0, 0), [], "") |
|
28 | return (nullid, "", (0, 0), [], "") | |
21 | last = text.index("\n\n") |
|
29 | last = text.index("\n\n") |
@@ -11,6 +11,76 b' from i18n import gettext as _' | |||||
11 | demandload(globals(), 'mdiff util') |
|
11 | demandload(globals(), 'mdiff util') | |
12 | demandload(globals(), 'os sys') |
|
12 | demandload(globals(), 'os sys') | |
13 |
|
13 | |||
|
14 | revrangesep = ':' | |||
|
15 | ||||
|
16 | def revfix(repo, val, defval): | |||
|
17 | '''turn user-level id of changeset into rev number. | |||
|
18 | user-level id can be tag, changeset, rev number, or negative rev | |||
|
19 | number relative to number of revs (-1 is tip, etc).''' | |||
|
20 | if not val: | |||
|
21 | return defval | |||
|
22 | try: | |||
|
23 | num = int(val) | |||
|
24 | if str(num) != val: | |||
|
25 | raise ValueError | |||
|
26 | if num < 0: | |||
|
27 | num += repo.changelog.count() | |||
|
28 | if num < 0: | |||
|
29 | num = 0 | |||
|
30 | elif num >= repo.changelog.count(): | |||
|
31 | raise ValueError | |||
|
32 | except ValueError: | |||
|
33 | try: | |||
|
34 | num = repo.changelog.rev(repo.lookup(val)) | |||
|
35 | except KeyError: | |||
|
36 | raise util.Abort(_('invalid revision identifier %s') % val) | |||
|
37 | return num | |||
|
38 | ||||
|
39 | def revpair(ui, repo, revs): | |||
|
40 | '''return pair of nodes, given list of revisions. second item can | |||
|
41 | be None, meaning use working dir.''' | |||
|
42 | if not revs: | |||
|
43 | return repo.dirstate.parents()[0], None | |||
|
44 | end = None | |||
|
45 | if len(revs) == 1: | |||
|
46 | start = revs[0] | |||
|
47 | if revrangesep in start: | |||
|
48 | start, end = start.split(revrangesep, 1) | |||
|
49 | start = revfix(repo, start, 0) | |||
|
50 | end = revfix(repo, end, repo.changelog.count() - 1) | |||
|
51 | else: | |||
|
52 | start = revfix(repo, start, None) | |||
|
53 | elif len(revs) == 2: | |||
|
54 | if revrangesep in revs[0] or revrangesep in revs[1]: | |||
|
55 | raise util.Abort(_('too many revisions specified')) | |||
|
56 | start = revfix(repo, revs[0], None) | |||
|
57 | end = revfix(repo, revs[1], None) | |||
|
58 | else: | |||
|
59 | raise util.Abort(_('too many revisions specified')) | |||
|
60 | if end is not None: end = repo.lookup(str(end)) | |||
|
61 | return repo.lookup(str(start)), end | |||
|
62 | ||||
|
63 | def revrange(ui, repo, revs): | |||
|
64 | """Yield revision as strings from a list of revision specifications.""" | |||
|
65 | seen = {} | |||
|
66 | for spec in revs: | |||
|
67 | if revrangesep in spec: | |||
|
68 | start, end = spec.split(revrangesep, 1) | |||
|
69 | start = revfix(repo, start, 0) | |||
|
70 | end = revfix(repo, end, repo.changelog.count() - 1) | |||
|
71 | step = start > end and -1 or 1 | |||
|
72 | for rev in xrange(start, end+step, step): | |||
|
73 | if rev in seen: | |||
|
74 | continue | |||
|
75 | seen[rev] = 1 | |||
|
76 | yield str(rev) | |||
|
77 | else: | |||
|
78 | rev = revfix(repo, spec, None) | |||
|
79 | if rev in seen: | |||
|
80 | continue | |||
|
81 | seen[rev] = 1 | |||
|
82 | yield str(rev) | |||
|
83 | ||||
14 | def make_filename(repo, pat, node, |
|
84 | def make_filename(repo, pat, node, | |
15 | total=None, seqno=None, revwidth=None, pathname=None): |
|
85 | total=None, seqno=None, revwidth=None, pathname=None): | |
16 | node_expander = { |
|
86 | node_expander = { | |
@@ -53,8 +123,8 b' def make_filename(repo, pat, node,' | |||||
53 | i += 1 |
|
123 | i += 1 | |
54 | return ''.join(newname) |
|
124 | return ''.join(newname) | |
55 | except KeyError, inst: |
|
125 | except KeyError, inst: | |
56 |
raise util.Abort(_("invalid format spec '%%%s' in output file name") |
|
126 | raise util.Abort(_("invalid format spec '%%%s' in output file name") % | |
57 | inst.args[0]) |
|
127 | inst.args[0]) | |
58 |
|
128 | |||
59 | def make_file(repo, pat, node=None, |
|
129 | def make_file(repo, pat, node=None, | |
60 | total=None, seqno=None, revwidth=None, mode='wb', pathname=None): |
|
130 | total=None, seqno=None, revwidth=None, mode='wb', pathname=None): |
@@ -8,7 +8,7 b'' | |||||
8 | from demandload import demandload |
|
8 | from demandload import demandload | |
9 | from node import * |
|
9 | from node import * | |
10 | from i18n import gettext as _ |
|
10 | from i18n import gettext as _ | |
11 | demandload(globals(), "os re sys signal shutil imp urllib pdb") |
|
11 | demandload(globals(), "os re sys signal shutil imp urllib pdb shlex") | |
12 | demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") |
|
12 | demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") | |
13 | demandload(globals(), "fnmatch difflib patch random signal tempfile time") |
|
13 | demandload(globals(), "fnmatch difflib patch random signal tempfile time") | |
14 | demandload(globals(), "traceback errno socket version struct atexit sets bz2") |
|
14 | demandload(globals(), "traceback errno socket version struct atexit sets bz2") | |
@@ -50,6 +50,21 b' def logmessage(opts):' | |||||
50 | (logfile, inst.strerror)) |
|
50 | (logfile, inst.strerror)) | |
51 | return message |
|
51 | return message | |
52 |
|
52 | |||
|
53 | def defaultrev(repo, rev=None, default='tip'): | |||
|
54 | """returns rev if it is specified, otherwise the working dir | |||
|
55 | parent if there is only one, or tip if there is no working | |||
|
56 | dir""" | |||
|
57 | if rev: | |||
|
58 | return rev | |||
|
59 | ||||
|
60 | p1, p2 = repo.dirstate.parents() | |||
|
61 | if p2 != nullid: | |||
|
62 | raise util.Abort(_('uncommitted merge - please provide a ' | |||
|
63 | 'specific revision')) | |||
|
64 | if p1 != nullid: | |||
|
65 | return hex(p1) | |||
|
66 | return default | |||
|
67 | ||||
53 | def walkchangerevs(ui, repo, pats, opts): |
|
68 | def walkchangerevs(ui, repo, pats, opts): | |
54 | '''Iterate over files and the revs they changed in. |
|
69 | '''Iterate over files and the revs they changed in. | |
55 |
|
70 | |||
@@ -99,16 +114,10 b' def walkchangerevs(ui, repo, pats, opts)' | |||||
99 | return [], False, matchfn |
|
114 | return [], False, matchfn | |
100 |
|
115 | |||
101 | if follow: |
|
116 | if follow: | |
102 | p = repo.dirstate.parents()[0] |
|
117 | defrange = '%s:0' % defaultrev(repo) | |
103 | if p == nullid: |
|
|||
104 | ui.warn(_('No working directory revision; defaulting to tip\n')) |
|
|||
105 | start = 'tip' |
|
|||
106 | else: |
|
|||
107 | start = repo.changelog.rev(p) |
|
|||
108 | defrange = '%s:0' % start |
|
|||
109 | else: |
|
118 | else: | |
110 | defrange = 'tip:0' |
|
119 | defrange = 'tip:0' | |
111 | revs = map(int, revrange(ui, repo, opts['rev'] or [defrange])) |
|
120 | revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange])) | |
112 | wanted = {} |
|
121 | wanted = {} | |
113 | slowpath = anypats |
|
122 | slowpath = anypats | |
114 | fncache = {} |
|
123 | fncache = {} | |
@@ -252,76 +261,6 b' def walkchangerevs(ui, repo, pats, opts)' | |||||
252 | yield 'iter', rev, None |
|
261 | yield 'iter', rev, None | |
253 | return iterate(), getchange, matchfn |
|
262 | return iterate(), getchange, matchfn | |
254 |
|
263 | |||
255 | revrangesep = ':' |
|
|||
256 |
|
||||
257 | def revfix(repo, val, defval): |
|
|||
258 | '''turn user-level id of changeset into rev number. |
|
|||
259 | user-level id can be tag, changeset, rev number, or negative rev |
|
|||
260 | number relative to number of revs (-1 is tip, etc).''' |
|
|||
261 | if not val: |
|
|||
262 | return defval |
|
|||
263 | try: |
|
|||
264 | num = int(val) |
|
|||
265 | if str(num) != val: |
|
|||
266 | raise ValueError |
|
|||
267 | if num < 0: |
|
|||
268 | num += repo.changelog.count() |
|
|||
269 | if num < 0: |
|
|||
270 | num = 0 |
|
|||
271 | elif num >= repo.changelog.count(): |
|
|||
272 | raise ValueError |
|
|||
273 | except ValueError: |
|
|||
274 | try: |
|
|||
275 | num = repo.changelog.rev(repo.lookup(val)) |
|
|||
276 | except KeyError: |
|
|||
277 | raise util.Abort(_('invalid revision identifier %s'), val) |
|
|||
278 | return num |
|
|||
279 |
|
||||
280 | def revpair(ui, repo, revs): |
|
|||
281 | '''return pair of nodes, given list of revisions. second item can |
|
|||
282 | be None, meaning use working dir.''' |
|
|||
283 | if not revs: |
|
|||
284 | return repo.dirstate.parents()[0], None |
|
|||
285 | end = None |
|
|||
286 | if len(revs) == 1: |
|
|||
287 | start = revs[0] |
|
|||
288 | if revrangesep in start: |
|
|||
289 | start, end = start.split(revrangesep, 1) |
|
|||
290 | start = revfix(repo, start, 0) |
|
|||
291 | end = revfix(repo, end, repo.changelog.count() - 1) |
|
|||
292 | else: |
|
|||
293 | start = revfix(repo, start, None) |
|
|||
294 | elif len(revs) == 2: |
|
|||
295 | if revrangesep in revs[0] or revrangesep in revs[1]: |
|
|||
296 | raise util.Abort(_('too many revisions specified')) |
|
|||
297 | start = revfix(repo, revs[0], None) |
|
|||
298 | end = revfix(repo, revs[1], None) |
|
|||
299 | else: |
|
|||
300 | raise util.Abort(_('too many revisions specified')) |
|
|||
301 | if end is not None: end = repo.lookup(str(end)) |
|
|||
302 | return repo.lookup(str(start)), end |
|
|||
303 |
|
||||
304 | def revrange(ui, repo, revs): |
|
|||
305 | """Yield revision as strings from a list of revision specifications.""" |
|
|||
306 | seen = {} |
|
|||
307 | for spec in revs: |
|
|||
308 | if revrangesep in spec: |
|
|||
309 | start, end = spec.split(revrangesep, 1) |
|
|||
310 | start = revfix(repo, start, 0) |
|
|||
311 | end = revfix(repo, end, repo.changelog.count() - 1) |
|
|||
312 | step = start > end and -1 or 1 |
|
|||
313 | for rev in xrange(start, end+step, step): |
|
|||
314 | if rev in seen: |
|
|||
315 | continue |
|
|||
316 | seen[rev] = 1 |
|
|||
317 | yield str(rev) |
|
|||
318 | else: |
|
|||
319 | rev = revfix(repo, spec, None) |
|
|||
320 | if rev in seen: |
|
|||
321 | continue |
|
|||
322 | seen[rev] = 1 |
|
|||
323 | yield str(rev) |
|
|||
324 |
|
||||
325 | def write_bundle(cg, filename=None, compress=True): |
|
264 | def write_bundle(cg, filename=None, compress=True): | |
326 | """Write a bundle file and return its filename. |
|
265 | """Write a bundle file and return its filename. | |
327 |
|
266 | |||
@@ -341,7 +280,7 b' def write_bundle(cg, filename=None, comp' | |||||
341 | try: |
|
280 | try: | |
342 | if filename: |
|
281 | if filename: | |
343 | if os.path.exists(filename): |
|
282 | if os.path.exists(filename): | |
344 |
raise util.Abort(_("file '%s' already exists") |
|
283 | raise util.Abort(_("file '%s' already exists") % filename) | |
345 | fh = open(filename, "wb") |
|
284 | fh = open(filename, "wb") | |
346 | else: |
|
285 | else: | |
347 | fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg") |
|
286 | fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg") | |
@@ -505,7 +444,7 b' def help_(ui, name=None, with_version=Fa' | |||||
505 | if with_version: |
|
444 | if with_version: | |
506 | show_version(ui) |
|
445 | show_version(ui) | |
507 | ui.write('\n') |
|
446 | ui.write('\n') | |
508 | aliases, i = findcmd(name) |
|
447 | aliases, i = findcmd(ui, name) | |
509 | # synopsis |
|
448 | # synopsis | |
510 | ui.write("%s\n\n" % i[2]) |
|
449 | ui.write("%s\n\n" % i[2]) | |
511 |
|
450 | |||
@@ -707,7 +646,7 b' def annotate(ui, repo, *pats, **opts):' | |||||
707 | if not opts['user'] and not opts['changeset'] and not opts['date']: |
|
646 | if not opts['user'] and not opts['changeset'] and not opts['date']: | |
708 | opts['number'] = 1 |
|
647 | opts['number'] = 1 | |
709 |
|
648 | |||
710 |
ctx = repo.changectx(opts['rev'] |
|
649 | ctx = repo.changectx(defaultrev(repo, opts['rev'])) | |
711 |
|
650 | |||
712 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, |
|
651 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, | |
713 | node=ctx.node()): |
|
652 | node=ctx.node()): | |
@@ -754,14 +693,7 b' def archive(ui, repo, dest, **opts):' | |||||
754 | The default is the basename of the archive, with suffixes removed. |
|
693 | The default is the basename of the archive, with suffixes removed. | |
755 | ''' |
|
694 | ''' | |
756 |
|
695 | |||
757 | if opts['rev']: |
|
696 | node = repo.lookup(defaultrev(repo, opts['rev'])) | |
758 | node = repo.lookup(opts['rev']) |
|
|||
759 | else: |
|
|||
760 | node, p2 = repo.dirstate.parents() |
|
|||
761 | if p2 != nullid: |
|
|||
762 | raise util.Abort(_('uncommitted merge - please provide a ' |
|
|||
763 | 'specific revision')) |
|
|||
764 |
|
||||
765 | dest = cmdutil.make_filename(repo, dest, node) |
|
697 | dest = cmdutil.make_filename(repo, dest, node) | |
766 | if os.path.realpath(dest) == repo.root: |
|
698 | if os.path.realpath(dest) == repo.root: | |
767 | raise util.Abort(_('repository root cannot be destination')) |
|
699 | raise util.Abort(_('repository root cannot be destination')) | |
@@ -818,6 +750,7 b' def backout(ui, repo, rev, **opts):' | |||||
818 | parent = p1 |
|
750 | parent = p1 | |
819 | hg.clean(repo, node, show_stats=False) |
|
751 | hg.clean(repo, node, show_stats=False) | |
820 | revert_opts = opts.copy() |
|
752 | revert_opts = opts.copy() | |
|
753 | revert_opts['all'] = True | |||
821 | revert_opts['rev'] = hex(parent) |
|
754 | revert_opts['rev'] = hex(parent) | |
822 | revert(ui, repo, **revert_opts) |
|
755 | revert(ui, repo, **revert_opts) | |
823 | commit_opts = opts.copy() |
|
756 | commit_opts = opts.copy() | |
@@ -866,7 +799,8 b' def cat(ui, repo, file1, *pats, **opts):' | |||||
866 | """output the latest or given revisions of files |
|
799 | """output the latest or given revisions of files | |
867 |
|
800 | |||
868 | Print the specified files as they were at the given revision. |
|
801 | Print the specified files as they were at the given revision. | |
869 |
If no revision is given then |
|
802 | If no revision is given then working dir parent is used, or tip | |
|
803 | if no revision is checked out. | |||
870 |
|
804 | |||
871 | Output may be to a file, in which case the name of the file is |
|
805 | Output may be to a file, in which case the name of the file is | |
872 | given using a format string. The formatting rules are the same as |
|
806 | given using a format string. The formatting rules are the same as | |
@@ -876,7 +810,7 b' def cat(ui, repo, file1, *pats, **opts):' | |||||
876 | %d dirname of file being printed, or '.' if in repo root |
|
810 | %d dirname of file being printed, or '.' if in repo root | |
877 | %p root-relative path name of file being printed |
|
811 | %p root-relative path name of file being printed | |
878 | """ |
|
812 | """ | |
879 |
ctx = repo.changectx(opts['rev'] |
|
813 | ctx = repo.changectx(defaultrev(repo, opts['rev'])) | |
880 | for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, |
|
814 | for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, | |
881 | ctx.node()): |
|
815 | ctx.node()): | |
882 | fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) |
|
816 | fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) | |
@@ -1151,7 +1085,7 b" def debugcomplete(ui, cmd='', **opts):" | |||||
1151 | options = [] |
|
1085 | options = [] | |
1152 | otables = [globalopts] |
|
1086 | otables = [globalopts] | |
1153 | if cmd: |
|
1087 | if cmd: | |
1154 | aliases, entry = findcmd(cmd) |
|
1088 | aliases, entry = findcmd(ui, cmd) | |
1155 | otables.append(entry[1]) |
|
1089 | otables.append(entry[1]) | |
1156 | for t in otables: |
|
1090 | for t in otables: | |
1157 | for o in t: |
|
1091 | for o in t: | |
@@ -1161,7 +1095,7 b" def debugcomplete(ui, cmd='', **opts):" | |||||
1161 | ui.write("%s\n" % "\n".join(options)) |
|
1095 | ui.write("%s\n" % "\n".join(options)) | |
1162 | return |
|
1096 | return | |
1163 |
|
1097 | |||
1164 | clist = findpossible(cmd).keys() |
|
1098 | clist = findpossible(ui, cmd).keys() | |
1165 | clist.sort() |
|
1099 | clist.sort() | |
1166 | ui.write("%s\n" % "\n".join(clist)) |
|
1100 | ui.write("%s\n" % "\n".join(clist)) | |
1167 |
|
1101 | |||
@@ -1268,7 +1202,7 b' def debugdata(ui, file_, rev):' | |||||
1268 | try: |
|
1202 | try: | |
1269 | ui.write(r.revision(r.lookup(rev))) |
|
1203 | ui.write(r.revision(r.lookup(rev))) | |
1270 | except KeyError: |
|
1204 | except KeyError: | |
1271 |
raise util.Abort(_('invalid revision identifier %s') |
|
1205 | raise util.Abort(_('invalid revision identifier %s') % rev) | |
1272 |
|
1206 | |||
1273 | def debugindex(ui, file_): |
|
1207 | def debugindex(ui, file_): | |
1274 | """dump the contents of an index file""" |
|
1208 | """dump the contents of an index file""" | |
@@ -1343,7 +1277,7 b' def diff(ui, repo, *pats, **opts):' | |||||
1343 | it detects as binary. With -a, diff will generate a diff anyway, |
|
1277 | it detects as binary. With -a, diff will generate a diff anyway, | |
1344 | probably with undesirable results. |
|
1278 | probably with undesirable results. | |
1345 | """ |
|
1279 | """ | |
1346 | node1, node2 = revpair(ui, repo, opts['rev']) |
|
1280 | node1, node2 = cmdutil.revpair(ui, repo, opts['rev']) | |
1347 |
|
1281 | |||
1348 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
|
1282 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
1349 |
|
1283 | |||
@@ -1379,7 +1313,7 b' def export(ui, repo, *changesets, **opts' | |||||
1379 | """ |
|
1313 | """ | |
1380 | if not changesets: |
|
1314 | if not changesets: | |
1381 | raise util.Abort(_("export requires at least one changeset")) |
|
1315 | raise util.Abort(_("export requires at least one changeset")) | |
1382 | revs = list(revrange(ui, repo, changesets)) |
|
1316 | revs = list(cmdutil.revrange(ui, repo, changesets)) | |
1383 | if len(revs) > 1: |
|
1317 | if len(revs) > 1: | |
1384 | ui.note(_('exporting patches:\n')) |
|
1318 | ui.note(_('exporting patches:\n')) | |
1385 | else: |
|
1319 | else: | |
@@ -1939,7 +1873,7 b' def merge(ui, repo, node=None, force=Non' | |||||
1939 | revision to merge with must be provided. |
|
1873 | revision to merge with must be provided. | |
1940 | """ |
|
1874 | """ | |
1941 |
|
1875 | |||
1942 | if node: |
|
1876 | if node or branch: | |
1943 | node = _lookup(repo, node, branch) |
|
1877 | node = _lookup(repo, node, branch) | |
1944 | else: |
|
1878 | else: | |
1945 | heads = repo.heads() |
|
1879 | heads = repo.heads() | |
@@ -2271,8 +2205,8 b' def revert(ui, repo, *pats, **opts):' | |||||
2271 | Modified files are saved with a .orig suffix before reverting. |
|
2205 | Modified files are saved with a .orig suffix before reverting. | |
2272 | To disable these backups, use --no-backup. |
|
2206 | To disable these backups, use --no-backup. | |
2273 |
|
2207 | |||
2274 | Using the -r option, revert the given files or directories to |
|
2208 | Using the -r option, revert the given files or directories to their | |
2275 |
|
|
2209 | contents as of a specific revision. This can be helpful to "roll | |
2276 | back" some or all of a change that should not have been committed. |
|
2210 | back" some or all of a change that should not have been committed. | |
2277 |
|
2211 | |||
2278 | Revert modifies the working directory. It does not commit any |
|
2212 | Revert modifies the working directory. It does not commit any | |
@@ -2286,16 +2220,15 b' def revert(ui, repo, *pats, **opts):' | |||||
2286 |
|
2220 | |||
2287 | If names are given, all files matching the names are reverted. |
|
2221 | If names are given, all files matching the names are reverted. | |
2288 |
|
2222 | |||
2289 |
If no arguments are given, |
|
2223 | If no arguments are given, no files are reverted. | |
2290 | """ |
|
2224 | """ | |
|
2225 | ||||
|
2226 | if not pats and not opts['all']: | |||
|
2227 | raise util.Abort(_('no files or directories specified; ' | |||
|
2228 | 'use --all to revert the whole repo')) | |||
|
2229 | ||||
2291 | parent, p2 = repo.dirstate.parents() |
|
2230 | parent, p2 = repo.dirstate.parents() | |
2292 | if opts['rev']: |
|
2231 | node = repo.lookup(defaultrev(repo, opts['rev'])) | |
2293 | node = repo.lookup(opts['rev']) |
|
|||
2294 | elif p2 != nullid: |
|
|||
2295 | raise util.Abort(_('working dir has two parents; ' |
|
|||
2296 | 'you must specify the revision to revert to')) |
|
|||
2297 | else: |
|
|||
2298 | node = parent |
|
|||
2299 | mf = repo.manifest.read(repo.changelog.read(node)[0]) |
|
2232 | mf = repo.manifest.read(repo.changelog.read(node)[0]) | |
2300 | if node == parent: |
|
2233 | if node == parent: | |
2301 | pmf = mf |
|
2234 | pmf = mf | |
@@ -2452,7 +2385,8 b' def serve(ui, repo, **opts):' | |||||
2452 |
|
2385 | |||
2453 | if opts["stdio"]: |
|
2386 | if opts["stdio"]: | |
2454 | if repo is None: |
|
2387 | if repo is None: | |
2455 |
raise hg.RepoError(_( |
|
2388 | raise hg.RepoError(_("There is no Mercurial repository here" | |
|
2389 | " (.hg not found)")) | |||
2456 | s = sshserver.sshserver(ui, repo) |
|
2390 | s = sshserver.sshserver(ui, repo) | |
2457 | s.serve_forever() |
|
2391 | s.serve_forever() | |
2458 |
|
2392 | |||
@@ -2463,7 +2397,8 b' def serve(ui, repo, **opts):' | |||||
2463 | ui.setconfig("web", o, opts[o]) |
|
2397 | ui.setconfig("web", o, opts[o]) | |
2464 |
|
2398 | |||
2465 | if repo is None and not ui.config("web", "webdir_conf"): |
|
2399 | if repo is None and not ui.config("web", "webdir_conf"): | |
2466 |
raise hg.RepoError(_( |
|
2400 | raise hg.RepoError(_("There is no Mercurial repository here" | |
|
2401 | " (.hg not found)")) | |||
2467 |
|
2402 | |||
2468 | if opts['daemon'] and not opts['daemon_pipefds']: |
|
2403 | if opts['daemon'] and not opts['daemon_pipefds']: | |
2469 | rfd, wfd = os.pipe() |
|
2404 | rfd, wfd = os.pipe() | |
@@ -2478,7 +2413,7 b' def serve(ui, repo, **opts):' | |||||
2478 | try: |
|
2413 | try: | |
2479 | httpd = hgweb.server.create_server(ui, repo) |
|
2414 | httpd = hgweb.server.create_server(ui, repo) | |
2480 | except socket.error, inst: |
|
2415 | except socket.error, inst: | |
2481 |
raise util.Abort(_('cannot start server: ') |
|
2416 | raise util.Abort(_('cannot start server: %s') % inst.args[1]) | |
2482 |
|
2417 | |||
2483 | if ui.verbose: |
|
2418 | if ui.verbose: | |
2484 | addr, port = httpd.socket.getsockname() |
|
2419 | addr, port = httpd.socket.getsockname() | |
@@ -2593,15 +2528,10 b' def tag(ui, repo, name, rev_=None, **opt' | |||||
2593 | raise util.Abort(_("use only one form to specify the revision")) |
|
2528 | raise util.Abort(_("use only one form to specify the revision")) | |
2594 | if opts['rev']: |
|
2529 | if opts['rev']: | |
2595 | rev_ = opts['rev'] |
|
2530 | rev_ = opts['rev'] | |
2596 | if rev_: |
|
2531 | r = defaultrev(repo, rev_, nullid) | |
2597 | r = repo.lookup(rev_) |
|
2532 | if r == nullid: | |
2598 | else: |
|
2533 | raise util.Abort(_('no revision to tag')) | |
2599 | p1, p2 = repo.dirstate.parents() |
|
2534 | r = repo.lookup(r) | |
2600 | if p1 == nullid: |
|
|||
2601 | raise util.Abort(_('no revision to tag')) |
|
|||
2602 | if p2 != nullid: |
|
|||
2603 | raise util.Abort(_('outstanding uncommitted merges')) |
|
|||
2604 | r = p1 |
|
|||
2605 |
|
2535 | |||
2606 | message = opts['message'] |
|
2536 | message = opts['message'] | |
2607 | if not message: |
|
2537 | if not message: | |
@@ -2728,7 +2658,7 b' def _lookup(repo, node, branch=None):' | |||||
2728 | repo.ui.warn(_("Using head %s for branch %s\n") |
|
2658 | repo.ui.warn(_("Using head %s for branch %s\n") | |
2729 | % (short(node), branch)) |
|
2659 | % (short(node), branch)) | |
2730 | else: |
|
2660 | else: | |
2731 |
raise util.Abort(_("branch %s not found |
|
2661 | raise util.Abort(_("branch %s not found") % branch) | |
2732 | else: |
|
2662 | else: | |
2733 | node = node and repo.lookup(node) or repo.changelog.tip() |
|
2663 | node = node and repo.lookup(node) or repo.changelog.tip() | |
2734 | return node |
|
2664 | return node | |
@@ -2881,6 +2811,7 b' table = {' | |||||
2881 | (export, |
|
2811 | (export, | |
2882 | [('o', 'output', '', _('print output to file with formatted name')), |
|
2812 | [('o', 'output', '', _('print output to file with formatted name')), | |
2883 | ('a', 'text', None, _('treat all files as text')), |
|
2813 | ('a', 'text', None, _('treat all files as text')), | |
|
2814 | ('g', 'git', None, _('use git extended diff format')), | |||
2884 | ('', 'switch-parent', None, _('diff against the second parent'))], |
|
2815 | ('', 'switch-parent', None, _('diff against the second parent'))], | |
2885 | _('hg export [-a] [-o OUTFILESPEC] REV...')), |
|
2816 | _('hg export [-a] [-o OUTFILESPEC] REV...')), | |
2886 | "debugforget|forget": |
|
2817 | "debugforget|forget": | |
@@ -3046,7 +2977,8 b' table = {' | |||||
3046 | _('hg rename [OPTION]... SOURCE... DEST')), |
|
2977 | _('hg rename [OPTION]... SOURCE... DEST')), | |
3047 | "^revert": |
|
2978 | "^revert": | |
3048 | (revert, |
|
2979 | (revert, | |
3049 | [('r', 'rev', '', _('revision to revert to')), |
|
2980 | [('a', 'all', None, _('revert all changes when no arguments given')), | |
|
2981 | ('r', 'rev', '', _('revision to revert to')), | |||
3050 | ('', 'no-backup', None, _('do not save backup copies of files')), |
|
2982 | ('', 'no-backup', None, _('do not save backup copies of files')), | |
3051 | ('I', 'include', [], _('include names matching given patterns')), |
|
2983 | ('I', 'include', [], _('include names matching given patterns')), | |
3052 | ('X', 'exclude', [], _('exclude names matching given patterns')), |
|
2984 | ('X', 'exclude', [], _('exclude names matching given patterns')), | |
@@ -3145,7 +3077,7 b' norepo = ("clone init version help debug' | |||||
3145 | " debugindex debugindexdot") |
|
3077 | " debugindex debugindexdot") | |
3146 | optionalrepo = ("paths serve debugconfig") |
|
3078 | optionalrepo = ("paths serve debugconfig") | |
3147 |
|
3079 | |||
3148 | def findpossible(cmd): |
|
3080 | def findpossible(ui, cmd): | |
3149 | """ |
|
3081 | """ | |
3150 | Return cmd -> (aliases, command table entry) |
|
3082 | Return cmd -> (aliases, command table entry) | |
3151 | for each matching command. |
|
3083 | for each matching command. | |
@@ -3158,7 +3090,7 b' def findpossible(cmd):' | |||||
3158 | found = None |
|
3090 | found = None | |
3159 | if cmd in aliases: |
|
3091 | if cmd in aliases: | |
3160 | found = cmd |
|
3092 | found = cmd | |
3161 | else: |
|
3093 | elif not ui.config("ui", "strict"): | |
3162 | for a in aliases: |
|
3094 | for a in aliases: | |
3163 | if a.startswith(cmd): |
|
3095 | if a.startswith(cmd): | |
3164 | found = a |
|
3096 | found = a | |
@@ -3174,9 +3106,9 b' def findpossible(cmd):' | |||||
3174 |
|
3106 | |||
3175 | return choice |
|
3107 | return choice | |
3176 |
|
3108 | |||
3177 | def findcmd(cmd): |
|
3109 | def findcmd(ui, cmd): | |
3178 | """Return (aliases, command table entry) for command string.""" |
|
3110 | """Return (aliases, command table entry) for command string.""" | |
3179 | choice = findpossible(cmd) |
|
3111 | choice = findpossible(ui, cmd) | |
3180 |
|
3112 | |||
3181 | if choice.has_key(cmd): |
|
3113 | if choice.has_key(cmd): | |
3182 | return choice[cmd] |
|
3114 | return choice[cmd] | |
@@ -3211,11 +3143,11 b' def parse(ui, args):' | |||||
3211 |
|
3143 | |||
3212 | if args: |
|
3144 | if args: | |
3213 | cmd, args = args[0], args[1:] |
|
3145 | cmd, args = args[0], args[1:] | |
3214 | aliases, i = findcmd(cmd) |
|
3146 | aliases, i = findcmd(ui, cmd) | |
3215 | cmd = aliases[0] |
|
3147 | cmd = aliases[0] | |
3216 | defaults = ui.config("defaults", cmd) |
|
3148 | defaults = ui.config("defaults", cmd) | |
3217 | if defaults: |
|
3149 | if defaults: | |
3218 |
args = |
|
3150 | args = shlex.split(defaults) + args | |
3219 | c = list(i[1]) |
|
3151 | c = list(i[1]) | |
3220 | else: |
|
3152 | else: | |
3221 | cmd = None |
|
3153 | cmd = None | |
@@ -3299,12 +3231,14 b' def dispatch(args):' | |||||
3299 | if num: signal.signal(num, catchterm) |
|
3231 | if num: signal.signal(num, catchterm) | |
3300 |
|
3232 | |||
3301 | try: |
|
3233 | try: | |
3302 |
u = ui.ui(traceback='--traceback' in sys.argv[1:] |
|
3234 | u = ui.ui(traceback='--traceback' in sys.argv[1:]) | |
3303 | readhooks=[load_extensions]) |
|
|||
3304 | except util.Abort, inst: |
|
3235 | except util.Abort, inst: | |
3305 | sys.stderr.write(_("abort: %s\n") % inst) |
|
3236 | sys.stderr.write(_("abort: %s\n") % inst) | |
3306 | return -1 |
|
3237 | return -1 | |
3307 |
|
3238 | |||
|
3239 | load_extensions(u) | |||
|
3240 | u.addreadhook(load_extensions) | |||
|
3241 | ||||
3308 | try: |
|
3242 | try: | |
3309 | cmd, func, args, options, cmdoptions = parse(u, args) |
|
3243 | cmd, func, args, options, cmdoptions = parse(u, args) | |
3310 | if options["time"]: |
|
3244 | if options["time"]: | |
@@ -3439,7 +3373,7 b' def dispatch(args):' | |||||
3439 | u.warn(_("abort: could not lock %s: %s\n") % |
|
3373 | u.warn(_("abort: could not lock %s: %s\n") % | |
3440 | (inst.desc or inst.filename, inst.strerror)) |
|
3374 | (inst.desc or inst.filename, inst.strerror)) | |
3441 | except revlog.RevlogError, inst: |
|
3375 | except revlog.RevlogError, inst: | |
3442 |
u.warn(_("abort: |
|
3376 | u.warn(_("abort: %s!\n") % inst) | |
3443 | except util.SignalInterrupt: |
|
3377 | except util.SignalInterrupt: | |
3444 | u.warn(_("killed!\n")) |
|
3378 | u.warn(_("killed!\n")) | |
3445 | except KeyboardInterrupt: |
|
3379 | except KeyboardInterrupt: | |
@@ -3461,18 +3395,18 b' def dispatch(args):' | |||||
3461 | u.warn(_("broken pipe\n")) |
|
3395 | u.warn(_("broken pipe\n")) | |
3462 | elif getattr(inst, "strerror", None): |
|
3396 | elif getattr(inst, "strerror", None): | |
3463 | if getattr(inst, "filename", None): |
|
3397 | if getattr(inst, "filename", None): | |
3464 |
u.warn(_("abort: %s |
|
3398 | u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename)) | |
3465 | else: |
|
3399 | else: | |
3466 | u.warn(_("abort: %s\n") % inst.strerror) |
|
3400 | u.warn(_("abort: %s\n") % inst.strerror) | |
3467 | else: |
|
3401 | else: | |
3468 | raise |
|
3402 | raise | |
3469 | except OSError, inst: |
|
3403 | except OSError, inst: | |
3470 |
if |
|
3404 | if getattr(inst, "filename", None): | |
3471 | u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename)) |
|
3405 | u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename)) | |
3472 | else: |
|
3406 | else: | |
3473 | u.warn(_("abort: %s\n") % inst.strerror) |
|
3407 | u.warn(_("abort: %s\n") % inst.strerror) | |
3474 | except util.Abort, inst: |
|
3408 | except util.Abort, inst: | |
3475 |
u.warn(_( |
|
3409 | u.warn(_("abort: %s\n") % inst) | |
3476 | except TypeError, inst: |
|
3410 | except TypeError, inst: | |
3477 | # was this an argument error? |
|
3411 | # was this an argument error? | |
3478 | tb = traceback.extract_tb(sys.exc_info()[2]) |
|
3412 | tb = traceback.extract_tb(sys.exc_info()[2]) |
@@ -115,7 +115,7 b' def clone(ui, source, dest=None, pull=Fa' | |||||
115 | source = localpath(source) |
|
115 | source = localpath(source) | |
116 |
|
116 | |||
117 | if os.path.exists(dest): |
|
117 | if os.path.exists(dest): | |
118 |
raise util.Abort(_("destination '%s' already exists") |
|
118 | raise util.Abort(_("destination '%s' already exists") % dest) | |
119 |
|
119 | |||
120 | class DirCleanup(object): |
|
120 | class DirCleanup(object): | |
121 | def __init__(self, dir_): |
|
121 | def __init__(self, dir_): | |
@@ -127,12 +127,7 b' def clone(ui, source, dest=None, pull=Fa' | |||||
127 | if self.dir_: |
|
127 | if self.dir_: | |
128 | self.rmtree(self.dir_, True) |
|
128 | self.rmtree(self.dir_, True) | |
129 |
|
129 | |||
130 | dest_repo = None |
|
130 | dest_repo = repository(ui, dest, create=True) | |
131 | try: |
|
|||
132 | dest_repo = repository(ui, dest) |
|
|||
133 | raise util.Abort(_("destination '%s' already exists." % dest)) |
|
|||
134 | except RepoError: |
|
|||
135 | dest_repo = repository(ui, dest, create=True) |
|
|||
136 |
|
131 | |||
137 | dest_path = None |
|
132 | dest_path = None | |
138 | dir_cleanup = None |
|
133 | dir_cleanup = None |
@@ -207,7 +207,8 b' def create_server(ui, repo):' | |||||
207 | hgwebobj = self.repoviewmaker(repo.__class__(repo.ui, |
|
207 | hgwebobj = self.repoviewmaker(repo.__class__(repo.ui, | |
208 | repo.origroot)) |
|
208 | repo.origroot)) | |
209 | else: |
|
209 | else: | |
210 |
raise hg.RepoError(_( |
|
210 | raise hg.RepoError(_("There is no Mercurial repository here" | |
|
211 | " (.hg not found)")) | |||
211 | return hgwebobj |
|
212 | return hgwebobj | |
212 |
|
213 | |||
213 | class IPv6HTTPServer(MercurialHTTPServer): |
|
214 | class IPv6HTTPServer(MercurialHTTPServer): |
@@ -325,7 +325,7 b' class httprepository(remoterepository):' | |||||
325 | rfp.close() |
|
325 | rfp.close() | |
326 | except socket.error, err: |
|
326 | except socket.error, err: | |
327 | if err[0] in (errno.ECONNRESET, errno.EPIPE): |
|
327 | if err[0] in (errno.ECONNRESET, errno.EPIPE): | |
328 |
raise util.Abort(_('push failed: %s') |
|
328 | raise util.Abort(_('push failed: %s') % err[1]) | |
329 | raise util.Abort(err[1]) |
|
329 | raise util.Abort(err[1]) | |
330 | finally: |
|
330 | finally: | |
331 | fp.close() |
|
331 | fp.close() |
@@ -27,12 +27,21 b' class localrepository(repo.repository):' | |||||
27 | oldp = p |
|
27 | oldp = p | |
28 | p = os.path.dirname(p) |
|
28 | p = os.path.dirname(p) | |
29 | if p == oldp: |
|
29 | if p == oldp: | |
30 |
raise repo.RepoError(_(" |
|
30 | raise repo.RepoError(_("There is no Mercurial repository" | |
|
31 | " here (.hg not found)")) | |||
31 | path = p |
|
32 | path = p | |
32 | self.path = os.path.join(path, ".hg") |
|
33 | self.path = os.path.join(path, ".hg") | |
33 |
|
34 | |||
34 |
if |
|
35 | if not os.path.isdir(self.path): | |
35 | raise repo.RepoError(_("repository %s not found") % path) |
|
36 | if create: | |
|
37 | if not os.path.exists(path): | |||
|
38 | os.mkdir(path) | |||
|
39 | os.mkdir(self.path) | |||
|
40 | os.mkdir(self.join("data")) | |||
|
41 | else: | |||
|
42 | raise repo.RepoError(_("repository %s not found") % path) | |||
|
43 | elif create: | |||
|
44 | raise repo.RepoError(_("repository %s already exists") % path) | |||
36 |
|
45 | |||
37 | self.root = os.path.abspath(path) |
|
46 | self.root = os.path.abspath(path) | |
38 | self.origroot = path |
|
47 | self.origroot = path | |
@@ -75,12 +84,6 b' class localrepository(repo.repository):' | |||||
75 | self.decodepats = None |
|
84 | self.decodepats = None | |
76 | self.transhandle = None |
|
85 | self.transhandle = None | |
77 |
|
86 | |||
78 | if create: |
|
|||
79 | if not os.path.exists(path): |
|
|||
80 | os.mkdir(path) |
|
|||
81 | os.mkdir(self.path) |
|
|||
82 | os.mkdir(self.join("data")) |
|
|||
83 |
|
||||
84 | self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) |
|
87 | self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) | |
85 |
|
88 | |||
86 | def url(self): |
|
89 | def url(self): | |
@@ -131,7 +134,7 b' class localrepository(repo.repository):' | |||||
131 | except Exception, exc: |
|
134 | except Exception, exc: | |
132 | if isinstance(exc, util.Abort): |
|
135 | if isinstance(exc, util.Abort): | |
133 | self.ui.warn(_('error: %s hook failed: %s\n') % |
|
136 | self.ui.warn(_('error: %s hook failed: %s\n') % | |
134 |
(hname, exc.args[0] |
|
137 | (hname, exc.args[0])) | |
135 | else: |
|
138 | else: | |
136 | self.ui.warn(_('error: %s hook raised an exception: ' |
|
139 | self.ui.warn(_('error: %s hook raised an exception: ' | |
137 | '%s\n') % (hname, exc)) |
|
140 | '%s\n') % (hname, exc)) | |
@@ -641,7 +644,11 b' class localrepository(repo.repository):' | |||||
641 | if node: |
|
644 | if node: | |
642 | fdict = dict.fromkeys(files) |
|
645 | fdict = dict.fromkeys(files) | |
643 | for fn in self.manifest.read(self.changelog.read(node)[0]): |
|
646 | for fn in self.manifest.read(self.changelog.read(node)[0]): | |
644 |
fdict |
|
647 | for ffn in fdict: | |
|
648 | # match if the file is the exact name or a directory | |||
|
649 | if ffn == fn or fn.startswith("%s/" % ffn): | |||
|
650 | del fdict[ffn] | |||
|
651 | break | |||
645 | if match(fn): |
|
652 | if match(fn): | |
646 | yield 'm', fn |
|
653 | yield 'm', fn | |
647 | for fn in fdict: |
|
654 | for fn in fdict: |
@@ -50,6 +50,9 b' class diffopts(object):' | |||||
50 | defaultopts = diffopts() |
|
50 | defaultopts = diffopts() | |
51 |
|
51 | |||
52 | def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts): |
|
52 | def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts): | |
|
53 | def datetag(date): | |||
|
54 | return opts.git and '\n' or '\t%s\n' % date | |||
|
55 | ||||
53 | if not a and not b: return "" |
|
56 | if not a and not b: return "" | |
54 | epoch = util.datestr((0, 0)) |
|
57 | epoch = util.datestr((0, 0)) | |
55 |
|
58 | |||
@@ -58,19 +61,19 b' def unidiff(a, ad, b, bd, fn, r=None, op' | |||||
58 | elif not a: |
|
61 | elif not a: | |
59 | b = splitnewlines(b) |
|
62 | b = splitnewlines(b) | |
60 | if a is None: |
|
63 | if a is None: | |
61 |
l1 = |
|
64 | l1 = '--- /dev/null%s' % datetag(epoch) | |
62 | else: |
|
65 | else: | |
63 |
l1 = "--- %s |
|
66 | l1 = "--- %s%s" % ("a/" + fn, datetag(ad)) | |
64 |
l2 = "+++ %s |
|
67 | l2 = "+++ %s%s" % ("b/" + fn, datetag(bd)) | |
65 | l3 = "@@ -0,0 +1,%d @@\n" % len(b) |
|
68 | l3 = "@@ -0,0 +1,%d @@\n" % len(b) | |
66 | l = [l1, l2, l3] + ["+" + e for e in b] |
|
69 | l = [l1, l2, l3] + ["+" + e for e in b] | |
67 | elif not b: |
|
70 | elif not b: | |
68 | a = splitnewlines(a) |
|
71 | a = splitnewlines(a) | |
69 |
l1 = "--- %s |
|
72 | l1 = "--- %s%s" % ("a/" + fn, datetag(ad)) | |
70 | if b is None: |
|
73 | if b is None: | |
71 |
l2 = |
|
74 | l2 = '+++ /dev/null%s' % datetag(epoch) | |
72 | else: |
|
75 | else: | |
73 |
l2 = "+++ %s |
|
76 | l2 = "+++ %s%s" % ("b/" + fn, datetag(bd)) | |
74 | l3 = "@@ -1,%d +0,0 @@\n" % len(a) |
|
77 | l3 = "@@ -1,%d +0,0 @@\n" % len(a) | |
75 | l = [l1, l2, l3] + ["-" + e for e in a] |
|
78 | l = [l1, l2, l3] + ["-" + e for e in a] | |
76 | else: |
|
79 | else: | |
@@ -79,8 +82,8 b' def unidiff(a, ad, b, bd, fn, r=None, op' | |||||
79 | l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts)) |
|
82 | l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts)) | |
80 | if not l: return "" |
|
83 | if not l: return "" | |
81 | # difflib uses a space, rather than a tab |
|
84 | # difflib uses a space, rather than a tab | |
82 |
l[0] = "%s |
|
85 | l[0] = "%s%s" % (l[0][:-2], datetag(ad)) | |
83 |
l[1] = "%s |
|
86 | l[1] = "%s%s" % (l[1][:-2], datetag(bd)) | |
84 |
|
87 | |||
85 | for ln in xrange(len(l)): |
|
88 | for ln in xrange(len(l)): | |
86 | if l[ln][-1] != '\n': |
|
89 | if l[ln][-1] != '\n': |
@@ -8,7 +8,7 b'' | |||||
8 | from node import * |
|
8 | from node import * | |
9 | from i18n import gettext as _ |
|
9 | from i18n import gettext as _ | |
10 | from demandload import * |
|
10 | from demandload import * | |
11 | demandload(globals(), "util os tempfile") |
|
11 | demandload(globals(), "errno util os tempfile") | |
12 |
|
12 | |||
13 | def fmerge(f, local, other, ancestor): |
|
13 | def fmerge(f, local, other, ancestor): | |
14 | """merge executable flags""" |
|
14 | """merge executable flags""" | |
@@ -166,7 +166,8 b' def update(repo, node, branchmerge=False' | |||||
166 | repo.ui.debug(_(" updating permissions for %s\n") % f) |
|
166 | repo.ui.debug(_(" updating permissions for %s\n") % f) | |
167 | util.set_exec(repo.wjoin(f), m2.execf(f)) |
|
167 | util.set_exec(repo.wjoin(f), m2.execf(f)) | |
168 | else: |
|
168 | else: | |
169 |
|
|
169 | mode = fmerge(f, m1, m2, ma) | |
|
170 | if mode != m1.execf(f): | |||
170 | repo.ui.debug(_(" updating permissions for %s\n") |
|
171 | repo.ui.debug(_(" updating permissions for %s\n") | |
171 | % f) |
|
172 | % f) | |
172 | util.set_exec(repo.wjoin(f), mode) |
|
173 | util.set_exec(repo.wjoin(f), mode) |
@@ -26,6 +26,7 b' def demandload(scope, modules):' | |||||
26 | foo import foo |
|
26 | foo import foo | |
27 | foo bar import foo, bar |
|
27 | foo bar import foo, bar | |
28 | foo.bar import foo.bar |
|
28 | foo.bar import foo.bar | |
|
29 | foo@bar import foo as bar | |||
29 | foo:bar from foo import bar |
|
30 | foo:bar from foo import bar | |
30 | foo:bar,quux from foo import bar, quux |
|
31 | foo:bar,quux from foo import bar, quux | |
31 | foo.bar:quux from foo.bar import quux""" |
|
32 | foo.bar:quux from foo.bar import quux""" | |
@@ -38,6 +39,9 b' def demandload(scope, modules):' | |||||
38 | except: |
|
39 | except: | |
39 | module = m |
|
40 | module = m | |
40 | fromlist = [] |
|
41 | fromlist = [] | |
|
42 | as_ = None | |||
|
43 | if '@' in module: | |||
|
44 | module, as_ = module.split('@') | |||
41 | mod = __import__(module, scope, scope, fromlist) |
|
45 | mod = __import__(module, scope, scope, fromlist) | |
42 | if fromlist == []: |
|
46 | if fromlist == []: | |
43 | # mod is only the top package, but we need all packages |
|
47 | # mod is only the top package, but we need all packages | |
@@ -46,7 +50,9 b' def demandload(scope, modules):' | |||||
46 | mn = comp[0] |
|
50 | mn = comp[0] | |
47 | while True: |
|
51 | while True: | |
48 | # mn and mod.__name__ might not be the same |
|
52 | # mn and mod.__name__ might not be the same | |
49 | scope[mn] = mod |
|
53 | if not as_: | |
|
54 | as_ = mn | |||
|
55 | scope[as_] = mod | |||
50 | requiredmodules[mod.__name__] = 1 |
|
56 | requiredmodules[mod.__name__] = 1 | |
51 | if len(comp) == i: break |
|
57 | if len(comp) == i: break | |
52 | mod = getattr(mod,comp[i]) |
|
58 | mod = getattr(mod,comp[i]) |
@@ -9,7 +9,8 b' from demandload import demandload' | |||||
9 | from i18n import gettext as _ |
|
9 | from i18n import gettext as _ | |
10 | from node import * |
|
10 | from node import * | |
11 | demandload(globals(), "cmdutil mdiff util") |
|
11 | demandload(globals(), "cmdutil mdiff util") | |
12 |
demandload(globals(), |
|
12 | demandload(globals(), '''cStringIO email.Parser errno os re shutil sys tempfile | |
|
13 | popen2''') | |||
13 |
|
14 | |||
14 | # helper functions |
|
15 | # helper functions | |
15 |
|
16 | |||
@@ -182,7 +183,7 b' def readgitpatch(patchname):' | |||||
182 |
|
183 | |||
183 | return (dopatch, gitpatches) |
|
184 | return (dopatch, gitpatches) | |
184 |
|
185 | |||
185 | def dogitpatch(patchname, gitpatches): |
|
186 | def dogitpatch(patchname, gitpatches, cwd=None): | |
186 | """Preprocess git patch so that vanilla patch can handle it""" |
|
187 | """Preprocess git patch so that vanilla patch can handle it""" | |
187 | pf = file(patchname) |
|
188 | pf = file(patchname) | |
188 | pfline = 1 |
|
189 | pfline = 1 | |
@@ -196,7 +197,7 b' def dogitpatch(patchname, gitpatches):' | |||||
196 | if not p.copymod: |
|
197 | if not p.copymod: | |
197 | continue |
|
198 | continue | |
198 |
|
199 | |||
199 | copyfile(p.oldpath, p.path) |
|
200 | copyfile(p.oldpath, p.path, basedir=cwd) | |
200 |
|
201 | |||
201 | # rewrite patch hunk |
|
202 | # rewrite patch hunk | |
202 | while pfline < p.lineno: |
|
203 | while pfline < p.lineno: | |
@@ -227,23 +228,20 b' def patch(patchname, ui, strip=1, cwd=No' | |||||
227 | """apply the patch <patchname> to the working directory. |
|
228 | """apply the patch <patchname> to the working directory. | |
228 | a list of patched files is returned""" |
|
229 | a list of patched files is returned""" | |
229 |
|
230 | |||
230 | (dopatch, gitpatches) = readgitpatch(patchname) |
|
231 | # helper function | |
|
232 | def __patch(patchname): | |||
|
233 | """patch and updates the files and fuzz variables""" | |||
|
234 | files = {} | |||
|
235 | fuzz = False | |||
231 |
|
236 | |||
232 | files = {} |
|
237 | patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), | |
233 | fuzz = False |
|
238 | 'patch') | |
234 | if dopatch: |
|
|||
235 | if dopatch == 'filter': |
|
|||
236 | patchname = dogitpatch(patchname, gitpatches) |
|
|||
237 | patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') |
|
|||
238 | args = [] |
|
239 | args = [] | |
239 | if cwd: |
|
240 | if cwd: | |
240 | args.append('-d %s' % util.shellquote(cwd)) |
|
241 | args.append('-d %s' % util.shellquote(cwd)) | |
241 | fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip, |
|
242 | fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip, | |
242 | util.shellquote(patchname))) |
|
243 | util.shellquote(patchname))) | |
243 |
|
244 | |||
244 | if dopatch == 'filter': |
|
|||
245 | False and os.unlink(patchname) |
|
|||
246 |
|
||||
247 | for line in fp: |
|
245 | for line in fp: | |
248 | line = line.rstrip() |
|
246 | line = line.rstrip() | |
249 | ui.note(line + '\n') |
|
247 | ui.note(line + '\n') | |
@@ -264,11 +262,24 b' def patch(patchname, ui, strip=1, cwd=No' | |||||
264 | ui.warn(pf + '\n') |
|
262 | ui.warn(pf + '\n') | |
265 | printed_file = True |
|
263 | printed_file = True | |
266 | ui.warn(line + '\n') |
|
264 | ui.warn(line + '\n') | |
267 |
|
||||
268 | code = fp.close() |
|
265 | code = fp.close() | |
269 | if code: |
|
266 | if code: | |
270 | raise util.Abort(_("patch command failed: %s") % |
|
267 | raise util.Abort(_("patch command failed: %s") % | |
271 | util.explain_exit(code)[0]) |
|
268 | util.explain_exit(code)[0]) | |
|
269 | return files, fuzz | |||
|
270 | ||||
|
271 | (dopatch, gitpatches) = readgitpatch(patchname) | |||
|
272 | ||||
|
273 | if dopatch: | |||
|
274 | if dopatch == 'filter': | |||
|
275 | patchname = dogitpatch(patchname, gitpatches, cwd=cwd) | |||
|
276 | try: | |||
|
277 | files, fuzz = __patch(patchname) | |||
|
278 | finally: | |||
|
279 | if dopatch == 'filter': | |||
|
280 | os.unlink(patchname) | |||
|
281 | else: | |||
|
282 | files, fuzz = {}, False | |||
272 |
|
283 | |||
273 | for gp in gitpatches: |
|
284 | for gp in gitpatches: | |
274 | files[gp.path] = (gp.op, gp) |
|
285 | files[gp.path] = (gp.op, gp) | |
@@ -492,7 +503,10 b' def diff(repo, node1=None, node2=None, f' | |||||
492 | header.append('deleted file mode %s\n' % mode) |
|
503 | header.append('deleted file mode %s\n' % mode) | |
493 | else: |
|
504 | else: | |
494 | omode = gitmode(mmap.execf(f)) |
|
505 | omode = gitmode(mmap.execf(f)) | |
495 | nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f))) |
|
506 | if node2: | |
|
507 | nmode = gitmode(mmap2.execf(f)) | |||
|
508 | else: | |||
|
509 | nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f))) | |||
496 | addmodehdr(header, omode, nmode) |
|
510 | addmodehdr(header, omode, nmode) | |
497 | r = None |
|
511 | r = None | |
498 | if dodiff: |
|
512 | if dodiff: | |
@@ -537,3 +551,24 b" def export(repo, revs, template='hg-%h.p" | |||||
537 |
|
551 | |||
538 | for seqno, cset in enumerate(revs): |
|
552 | for seqno, cset in enumerate(revs): | |
539 | single(cset, seqno, fp) |
|
553 | single(cset, seqno, fp) | |
|
554 | ||||
|
555 | def diffstat(patchlines): | |||
|
556 | fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt") | |||
|
557 | try: | |||
|
558 | p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) | |||
|
559 | try: | |||
|
560 | for line in patchlines: print >> p.tochild, line | |||
|
561 | p.tochild.close() | |||
|
562 | if p.wait(): return | |||
|
563 | fp = os.fdopen(fd, 'r') | |||
|
564 | stat = [] | |||
|
565 | for line in fp: stat.append(line.lstrip()) | |||
|
566 | last = stat.pop() | |||
|
567 | stat.insert(0, last) | |||
|
568 | stat = ''.join(stat) | |||
|
569 | if stat.startswith('0 files'): raise ValueError | |||
|
570 | return stat | |||
|
571 | except: raise | |||
|
572 | finally: | |||
|
573 | try: os.unlink(name) | |||
|
574 | except: pass |
@@ -139,6 +139,11 b' class lazyparser(object):' | |||||
139 | if self.all: return |
|
139 | if self.all: return | |
140 | if data is None: |
|
140 | if data is None: | |
141 | self.dataf.seek(blockstart) |
|
141 | self.dataf.seek(blockstart) | |
|
142 | if blockstart + blocksize > self.datasize: | |||
|
143 | # the revlog may have grown since we've started running, | |||
|
144 | # but we don't have space in self.index for more entries. | |||
|
145 | # limit blocksize so that we don't get too much data. | |||
|
146 | blocksize = max(self.datasize - blockstart, 0) | |||
142 | data = self.dataf.read(blocksize) |
|
147 | data = self.dataf.read(blocksize) | |
143 | lend = len(data) / self.s |
|
148 | lend = len(data) / self.s | |
144 | i = blockstart / self.s |
|
149 | i = blockstart / self.s |
@@ -32,12 +32,6 b' class sshrepository(remoterepository):' | |||||
32 | remotecmd = self.ui.config("ui", "remotecmd", "hg") |
|
32 | remotecmd = self.ui.config("ui", "remotecmd", "hg") | |
33 |
|
33 | |||
34 | if create: |
|
34 | if create: | |
35 | try: |
|
|||
36 | self.validate_repo(ui, sshcmd, args, remotecmd) |
|
|||
37 | return # the repo is good, nothing more to do |
|
|||
38 | except hg.RepoError: |
|
|||
39 | pass |
|
|||
40 |
|
||||
41 | cmd = '%s %s "%s init %s"' |
|
35 | cmd = '%s %s "%s init %s"' | |
42 | cmd = cmd % (sshcmd, args, remotecmd, self.path) |
|
36 | cmd = cmd % (sshcmd, args, remotecmd, self.path) | |
43 |
|
37 | |||
@@ -52,6 +46,9 b' class sshrepository(remoterepository):' | |||||
52 | return self._url |
|
46 | return self._url | |
53 |
|
47 | |||
54 | def validate_repo(self, ui, sshcmd, args, remotecmd): |
|
48 | def validate_repo(self, ui, sshcmd, args, remotecmd): | |
|
49 | # cleanup up previous run | |||
|
50 | self.cleanup() | |||
|
51 | ||||
55 | cmd = '%s %s "%s -R %s serve --stdio"' |
|
52 | cmd = '%s %s "%s -R %s serve --stdio"' | |
56 | cmd = cmd % (sshcmd, args, remotecmd, self.path) |
|
53 | cmd = cmd % (sshcmd, args, remotecmd, self.path) | |
57 |
|
54 | |||
@@ -90,7 +87,7 b' class sshrepository(remoterepository):' | |||||
90 | if not l: break |
|
87 | if not l: break | |
91 | self.ui.status(_("remote: "), l) |
|
88 | self.ui.status(_("remote: "), l) | |
92 |
|
89 | |||
93 |
def |
|
90 | def cleanup(self): | |
94 | try: |
|
91 | try: | |
95 | self.pipeo.close() |
|
92 | self.pipeo.close() | |
96 | self.pipei.close() |
|
93 | self.pipei.close() | |
@@ -101,6 +98,8 b' class sshrepository(remoterepository):' | |||||
101 | except: |
|
98 | except: | |
102 | pass |
|
99 | pass | |
103 |
|
100 | |||
|
101 | __del__ = cleanup | |||
|
102 | ||||
104 | def do_cmd(self, cmd, **args): |
|
103 | def do_cmd(self, cmd, **args): | |
105 | self.ui.debug(_("sending %s command\n") % cmd) |
|
104 | self.ui.debug(_("sending %s command\n") % cmd) | |
106 | self.pipeo.write("%s\n" % cmd) |
|
105 | self.pipeo.write("%s\n" % cmd) |
@@ -12,13 +12,14 b' demandload(globals(), "ConfigParser mdif' | |||||
12 |
|
12 | |||
13 | class ui(object): |
|
13 | class ui(object): | |
14 | def __init__(self, verbose=False, debug=False, quiet=False, |
|
14 | def __init__(self, verbose=False, debug=False, quiet=False, | |
15 |
interactive=True, traceback=False, parentui=None |
|
15 | interactive=True, traceback=False, parentui=None): | |
16 | readhooks=[]): |
|
|||
17 | self.overlay = {} |
|
16 | self.overlay = {} | |
18 | if parentui is None: |
|
17 | if parentui is None: | |
19 | # this is the parent of all ui children |
|
18 | # this is the parent of all ui children | |
20 | self.parentui = None |
|
19 | self.parentui = None | |
21 |
self.readhooks = |
|
20 | self.readhooks = [] | |
|
21 | self.trusted_users = {} | |||
|
22 | self.trusted_groups = {} | |||
22 | self.cdata = ConfigParser.SafeConfigParser() |
|
23 | self.cdata = ConfigParser.SafeConfigParser() | |
23 | self.readconfig(util.rcpath()) |
|
24 | self.readconfig(util.rcpath()) | |
24 |
|
25 | |||
@@ -36,7 +37,9 b' class ui(object):' | |||||
36 | else: |
|
37 | else: | |
37 | # parentui may point to an ui object which is already a child |
|
38 | # parentui may point to an ui object which is already a child | |
38 | self.parentui = parentui.parentui or parentui |
|
39 | self.parentui = parentui.parentui or parentui | |
39 |
self.readhooks = |
|
40 | self.readhooks = parentui.readhooks[:] | |
|
41 | self.trusted_users = parentui.trusted_users.copy() | |||
|
42 | self.trusted_groups = parentui.trusted_groups.copy() | |||
40 | parent_cdata = self.parentui.cdata |
|
43 | parent_cdata = self.parentui.cdata | |
41 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) |
|
44 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) | |
42 | # make interpolation work |
|
45 | # make interpolation work | |
@@ -51,7 +54,7 b' class ui(object):' | |||||
51 | def updateopts(self, verbose=False, debug=False, quiet=False, |
|
54 | def updateopts(self, verbose=False, debug=False, quiet=False, | |
52 | interactive=True, traceback=False, config=[]): |
|
55 | interactive=True, traceback=False, config=[]): | |
53 | self.quiet = (self.quiet or quiet) and not verbose and not debug |
|
56 | self.quiet = (self.quiet or quiet) and not verbose and not debug | |
54 | self.verbose = (self.verbose or verbose) or debug |
|
57 | self.verbose = ((self.verbose or verbose) or debug) and not self.quiet | |
55 | self.debugflag = (self.debugflag or debug) |
|
58 | self.debugflag = (self.debugflag or debug) | |
56 | self.interactive = (self.interactive and interactive) |
|
59 | self.interactive = (self.interactive and interactive) | |
57 | self.traceback = self.traceback or traceback |
|
60 | self.traceback = self.traceback or traceback | |
@@ -72,7 +75,22 b' class ui(object):' | |||||
72 | fn = [fn] |
|
75 | fn = [fn] | |
73 | for f in fn: |
|
76 | for f in fn: | |
74 | try: |
|
77 | try: | |
75 |
|
|
78 | fp = open(f) | |
|
79 | except IOError: | |||
|
80 | continue | |||
|
81 | if ((self.trusted_users or self.trusted_groups) and | |||
|
82 | '*' not in self.trusted_users and | |||
|
83 | '*' not in self.trusted_groups): | |||
|
84 | st = util.fstat(fp) | |||
|
85 | user = util.username(st.st_uid) | |||
|
86 | group = util.groupname(st.st_gid) | |||
|
87 | if (user not in self.trusted_users and | |||
|
88 | group not in self.trusted_groups): | |||
|
89 | self.warn(_('not reading file %s from untrusted ' | |||
|
90 | 'user %s, group %s\n') % (f, user, group)) | |||
|
91 | continue | |||
|
92 | try: | |||
|
93 | self.cdata.readfp(fp, f) | |||
76 | except ConfigParser.ParsingError, inst: |
|
94 | except ConfigParser.ParsingError, inst: | |
77 | raise util.Abort(_("Failed to parse %s\n%s") % (f, inst)) |
|
95 | raise util.Abort(_("Failed to parse %s\n%s") % (f, inst)) | |
78 | # translate paths relative to root (or home) into absolute paths |
|
96 | # translate paths relative to root (or home) into absolute paths | |
@@ -81,9 +99,19 b' class ui(object):' | |||||
81 | for name, path in self.configitems("paths"): |
|
99 | for name, path in self.configitems("paths"): | |
82 | if path and "://" not in path and not os.path.isabs(path): |
|
100 | if path and "://" not in path and not os.path.isabs(path): | |
83 | self.cdata.set("paths", name, os.path.join(root, path)) |
|
101 | self.cdata.set("paths", name, os.path.join(root, path)) | |
|
102 | user = util.username() | |||
|
103 | if user is not None: | |||
|
104 | self.trusted_users[user] = 1 | |||
|
105 | for user in self.configlist('trusted', 'users'): | |||
|
106 | self.trusted_users[user] = 1 | |||
|
107 | for group in self.configlist('trusted', 'groups'): | |||
|
108 | self.trusted_groups[group] = 1 | |||
84 | for hook in self.readhooks: |
|
109 | for hook in self.readhooks: | |
85 | hook(self) |
|
110 | hook(self) | |
86 |
|
111 | |||
|
112 | def addreadhook(self, hook): | |||
|
113 | self.readhooks.append(hook) | |||
|
114 | ||||
87 | def setconfig(self, section, name, val): |
|
115 | def setconfig(self, section, name, val): | |
88 | self.overlay[(section, name)] = val |
|
116 | self.overlay[(section, name)] = val | |
89 |
|
117 | |||
@@ -94,7 +122,9 b' class ui(object):' | |||||
94 | try: |
|
122 | try: | |
95 | return self.cdata.get(section, name) |
|
123 | return self.cdata.get(section, name) | |
96 | except ConfigParser.InterpolationError, inst: |
|
124 | except ConfigParser.InterpolationError, inst: | |
97 |
raise util.Abort(_("Error in configuration |
|
125 | raise util.Abort(_("Error in configuration section [%s] " | |
|
126 | "parameter '%s':\n%s") | |||
|
127 | % (section, name, inst)) | |||
98 | if self.parentui is None: |
|
128 | if self.parentui is None: | |
99 | return default |
|
129 | return default | |
100 | else: |
|
130 | else: | |
@@ -116,7 +146,9 b' class ui(object):' | |||||
116 | try: |
|
146 | try: | |
117 | return self.cdata.getboolean(section, name) |
|
147 | return self.cdata.getboolean(section, name) | |
118 | except ConfigParser.InterpolationError, inst: |
|
148 | except ConfigParser.InterpolationError, inst: | |
119 |
raise util.Abort(_("Error in configuration |
|
149 | raise util.Abort(_("Error in configuration section [%s] " | |
|
150 | "parameter '%s':\n%s") | |||
|
151 | % (section, name, inst)) | |||
120 | if self.parentui is None: |
|
152 | if self.parentui is None: | |
121 | return default |
|
153 | return default | |
122 | else: |
|
154 | else: | |
@@ -134,7 +166,8 b' class ui(object):' | |||||
134 | try: |
|
166 | try: | |
135 | items.update(dict(self.cdata.items(section))) |
|
167 | items.update(dict(self.cdata.items(section))) | |
136 | except ConfigParser.InterpolationError, inst: |
|
168 | except ConfigParser.InterpolationError, inst: | |
137 |
raise util.Abort(_("Error in configuration:\n%s") |
|
169 | raise util.Abort(_("Error in configuration section [%s]:\n%s") | |
|
170 | % (section, inst)) | |||
138 | x = items.items() |
|
171 | x = items.items() | |
139 | x.sort() |
|
172 | x.sort() | |
140 | return x |
|
173 | return x | |
@@ -146,10 +179,14 b' class ui(object):' | |||||
146 | yield section, name, value |
|
179 | yield section, name, value | |
147 | seen[section, name] = 1 |
|
180 | seen[section, name] = 1 | |
148 | for section in self.cdata.sections(): |
|
181 | for section in self.cdata.sections(): | |
149 | for name, value in self.cdata.items(section): |
|
182 | try: | |
150 | if (section, name) in seen: continue |
|
183 | for name, value in self.cdata.items(section): | |
151 | yield section, name, value.replace('\n', '\\n') |
|
184 | if (section, name) in seen: continue | |
152 |
|
|
185 | yield section, name, value.replace('\n', '\\n') | |
|
186 | seen[section, name] = 1 | |||
|
187 | except ConfigParser.InterpolationError, inst: | |||
|
188 | raise util.Abort(_("Error in configuration section [%s]:\n%s") | |||
|
189 | % (section, inst)) | |||
153 | if self.parentui is not None: |
|
190 | if self.parentui is not None: | |
154 | for parent in self.parentui.walkconfig(seen): |
|
191 | for parent in self.parentui.walkconfig(seen): | |
155 | yield parent |
|
192 | yield parent |
@@ -15,7 +15,7 b' platform-specific details from the core.' | |||||
15 | from i18n import gettext as _ |
|
15 | from i18n import gettext as _ | |
16 | from demandload import * |
|
16 | from demandload import * | |
17 | demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile") |
|
17 | demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile") | |
18 | demandload(globals(), "os threading time") |
|
18 | demandload(globals(), "os threading time pwd grp") | |
19 |
|
19 | |||
20 | # used by parsedate |
|
20 | # used by parsedate | |
21 | defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', |
|
21 | defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', | |
@@ -509,6 +509,38 b' def getuser():' | |||||
509 | raise Abort(_('user name not available - set USERNAME ' |
|
509 | raise Abort(_('user name not available - set USERNAME ' | |
510 | 'environment variable')) |
|
510 | 'environment variable')) | |
511 |
|
511 | |||
|
512 | def username(uid=None): | |||
|
513 | """Return the name of the user with the given uid. | |||
|
514 | ||||
|
515 | If uid is None, return the name of the current user.""" | |||
|
516 | try: | |||
|
517 | # force an ImportError if there's no module pwd | |||
|
518 | getpwuid = pwd.getpwuid | |||
|
519 | if uid is None: | |||
|
520 | uid = os.getuid() | |||
|
521 | try: | |||
|
522 | return getpwuid(uid)[0] | |||
|
523 | except KeyError: | |||
|
524 | return str(uid) | |||
|
525 | except ImportError: | |||
|
526 | return None | |||
|
527 | ||||
|
528 | def groupname(gid=None): | |||
|
529 | """Return the name of the group with the given gid. | |||
|
530 | ||||
|
531 | If gid is None, return the name of the current group.""" | |||
|
532 | try: | |||
|
533 | # force an ImportError if there's no module grp | |||
|
534 | getgrgid = grp.getgrgid | |||
|
535 | if gid is None: | |||
|
536 | gid = os.getgid() | |||
|
537 | try: | |||
|
538 | return getgrgid(gid)[0] | |||
|
539 | except KeyError: | |||
|
540 | return str(gid) | |||
|
541 | except ImportError: | |||
|
542 | return None | |||
|
543 | ||||
512 | # Platform specific variants |
|
544 | # Platform specific variants | |
513 | if os.name == 'nt': |
|
545 | if os.name == 'nt': | |
514 | demandload(globals(), "msvcrt") |
|
546 | demandload(globals(), "msvcrt") |
@@ -8,7 +8,7 b' error = error-gitweb.tmpl' | |||||
8 | naventry = '<a href="?cmd=changelog;rev=#rev#;style=gitweb">#label|escape#</a> ' |
|
8 | naventry = '<a href="?cmd=changelog;rev=#rev#;style=gitweb">#label|escape#</a> ' | |
9 | navshortentry = '<a href="?cmd=shortlog;rev=#rev#;style=gitweb">#label|escape#</a> ' |
|
9 | navshortentry = '<a href="?cmd=shortlog;rev=#rev#;style=gitweb">#label|escape#</a> ' | |
10 | filedifflink = '<a href="?cmd=filediff;node=#node#;file=#file|urlescape#;style=gitweb">#file|escape#</a> ' |
|
10 | filedifflink = '<a href="?cmd=filediff;node=#node#;file=#file|urlescape#;style=gitweb">#file|escape#</a> ' | |
11 | filenodelink = '<tr class="light"><td><a class="list" href="">#file|escape#</a></td><td></td><td class="link"><a href="?cmd=file;filenode=#filenode#;file=#file|urlescape#;style=gitweb">file</a> | <!-- FIXME: <a href="?fd=#filenode|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?cmd=filelog;filenode=#filenode|short#;file=#file|urlescape#;style=gitweb">revisions</a></td></tr>' |
|
11 | filenodelink = '<tr class="light"><td><a class="list" href="">#file|escape#</a></td><td></td><td class="link"><a href="?cmd=file;filenode=#filenode#;file=#file|urlescape#;style=gitweb">file</a> | <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a> | <!-- FIXME: <a href="?fd=#filenode|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?cmd=filelog;filenode=#filenode|short#;file=#file|urlescape#;style=gitweb">revisions</a></td></tr>' | |
12 | fileellipses = '...' |
|
12 | fileellipses = '...' | |
13 | changelogentry = changelogentry-gitweb.tmpl |
|
13 | changelogentry = changelogentry-gitweb.tmpl | |
14 | searchentry = changelogentry-gitweb.tmpl |
|
14 | searchentry = changelogentry-gitweb.tmpl | |
@@ -19,12 +19,12 b' manifestfileentry = \'<tr class="parity#p' | |||||
19 | filerevision = filerevision-gitweb.tmpl |
|
19 | filerevision = filerevision-gitweb.tmpl | |
20 | fileannotate = fileannotate-gitweb.tmpl |
|
20 | fileannotate = fileannotate-gitweb.tmpl | |
21 | filelog = filelog-gitweb.tmpl |
|
21 | filelog = filelog-gitweb.tmpl | |
22 |
fileline = '<div style="font-family:monospace |
|
22 | fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr"> #linenumber#</span> #line|escape#</pre></div>' | |
23 | annotateline = '<tr style="font-family:monospace; white-space: pre;" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="?cs=#node|short#;style=gitweb">#author|obfuscate#@#rev#</a></td><td>#line|escape#</td></tr>' |
|
23 | annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="?cs=#node|short#;style=gitweb">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>' | |
24 |
difflineplus = '<div |
|
24 | difflineplus = '<div style="color:#008800;">#line|escape#</div>' | |
25 |
difflineminus = '<div |
|
25 | difflineminus = '<div style="color:#cc0000;">#line|escape#</div>' | |
26 |
difflineat = '<div |
|
26 | difflineat = '<div style="color:#990099;">#line|escape#</div>' | |
27 |
diffline = '<div |
|
27 | diffline = '<div>#line|escape#</div>' | |
28 | changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>' |
|
28 | changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>' | |
29 | changesetparent = '<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb">#node|short#</a></td></tr>' |
|
29 | changesetparent = '<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb">#node|short#</a></td></tr>' | |
30 | filerevparent = '<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>' |
|
30 | filerevparent = '<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>' | |
@@ -37,7 +37,7 b' filerevchild = \'<tr><td class="metatag">' | |||||
37 | fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="?cmd=annotate;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>' |
|
37 | fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="?cmd=annotate;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>' | |
38 | tags = tags-gitweb.tmpl |
|
38 | tags = tags-gitweb.tmpl | |
39 | tagentry = '<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>#tag|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=changelog;rev=#node|short#;style=gitweb">changelog</a> | <a href="?mf=#tagmanifest|short#;path=/;style=gitweb">manifest</a></td></tr>' |
|
39 | tagentry = '<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>#tag|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=changelog;rev=#node|short#;style=gitweb">changelog</a> | <a href="?mf=#tagmanifest|short#;path=/;style=gitweb">manifest</a></td></tr>' | |
40 | diffblock = '#lines#' |
|
40 | diffblock = '<pre>#lines#</pre>' | |
41 | changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>' |
|
41 | changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>' | |
42 | changesettag = '<tr><td>tag</td><td>#tag|escape#</td></tr>' |
|
42 | changesettag = '<tr><td>tag</td><td>#tag|escape#</td></tr>' | |
43 | filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>' |
|
43 | filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>' | |
@@ -46,5 +46,5 b' filediffchild = \'<tr><th class="child">c' | |||||
46 | 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>' |
|
46 | 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>' | |
47 | shortlog = shortlog-gitweb.tmpl |
|
47 | shortlog = shortlog-gitweb.tmpl | |
48 | 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>' |
|
48 | 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>' | |
49 | 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>' |
|
49 | 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"><a href="?f=#node|short#;file=#file|urlescape#;style=gitweb">file</a> | <!-- 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>' | |
50 | archiveentry = ' | <a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> ' |
|
50 | archiveentry = ' | <a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> ' |
@@ -47,3 +47,4 b' a.rss_logo {' | |||||
47 | text-align:center; text-decoration:none; |
|
47 | text-align:center; text-decoration:none; | |
48 | } |
|
48 | } | |
49 | a.rss_logo:hover { background-color:#ee5500; } |
|
49 | a.rss_logo:hover { background-color:#ee5500; } | |
|
50 | pre { margin: 0; } |
@@ -31,3 +31,65 b' writing tests:' | |||||
31 | use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ |
|
31 | use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
32 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
|
32 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |
33 | to strip dates |
|
33 | to strip dates | |
|
34 | ||||
|
35 | - You can append your own hgrc settings to the file that the environment | |||
|
36 | variable HGRCPATH points to. This file is cleared before running a test. | |||
|
37 | ||||
|
38 | You also need to be careful that the tests are portable from one platform | |||
|
39 | to another. You're probably working on Linux, where the GNU toolchain has | |||
|
40 | more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc. | |||
|
41 | While testing on all platforms is the only sure-fire way to make sure that | |||
|
42 | you've written portable code, here's a list of problems that have been | |||
|
43 | found and fixed in the tests. Another, more comprehensive list may be | |||
|
44 | found in the GNU Autoconf manual, online here: | |||
|
45 | ||||
|
46 | http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html | |||
|
47 | ||||
|
48 | sh: | |||
|
49 | ||||
|
50 | The Bourne shell is a very basic shell. /bin/sh on Linux is typically | |||
|
51 | bash, which even in Bourne-shell mode has many features that Bourne shells | |||
|
52 | on other Unix systems don't have (and even on Linux /bin/sh isn't | |||
|
53 | guaranteed to be bash). You'll need to be careful about constructs that | |||
|
54 | seem ubiquitous, but are actually not available in the least common | |||
|
55 | denominator. While using another shell (ksh, bash explicitly, posix shell, | |||
|
56 | etc.) explicitly may seem like another option, these may not exist in a | |||
|
57 | portable location, and so are generally probably not a good idea. You may | |||
|
58 | find that rewriting the test in python will be easier. | |||
|
59 | ||||
|
60 | - don't use pushd/popd; save the output of "pwd" and use "cd" in place of | |||
|
61 | the pushd, and cd back to the saved pwd instead of popd. | |||
|
62 | ||||
|
63 | - don't use math expressions like let, (( ... )), or $(( ... )); use "expr" | |||
|
64 | instead. | |||
|
65 | ||||
|
66 | grep: | |||
|
67 | ||||
|
68 | - don't use the -q option; redirect stdout to /dev/null instead. | |||
|
69 | ||||
|
70 | - don't use extended regular expressions with grep; use egrep instead, and | |||
|
71 | don't escape any regex operators. | |||
|
72 | ||||
|
73 | sed: | |||
|
74 | ||||
|
75 | - make sure that the beginning-of-line matcher ("^") is at the very | |||
|
76 | beginning of the expression -- it may not be supported inside parens. | |||
|
77 | ||||
|
78 | echo: | |||
|
79 | ||||
|
80 | - echo may interpret "\n" and print a newline; use printf instead if you | |||
|
81 | want a literal "\n" (backslash + n). | |||
|
82 | ||||
|
83 | false: | |||
|
84 | ||||
|
85 | - false is guaranteed only to return a non-zero value; you cannot depend on | |||
|
86 | it being 1. On Solaris in particular, /bin/false returns 255. Rewrite | |||
|
87 | your test to not depend on a particular return value, or create a | |||
|
88 | temporary "false" executable, and call that instead. | |||
|
89 | ||||
|
90 | diff: | |||
|
91 | ||||
|
92 | - don't use the -N option. There's no particularly good workaround short | |||
|
93 | of writing a reasonably complicated replacement script, but substituting | |||
|
94 | gdiff for diff if you can't rewrite the test not to need -N will probably | |||
|
95 | do. |
@@ -211,6 +211,10 b' def run_one(test):' | |||||
211 | sys.stdout.write('.') |
|
211 | sys.stdout.write('.') | |
212 | sys.stdout.flush() |
|
212 | sys.stdout.flush() | |
213 |
|
213 | |||
|
214 | # create a fresh hgrc | |||
|
215 | hgrc = file(HGRCPATH, 'w+') | |||
|
216 | hgrc.close() | |||
|
217 | ||||
214 | err = os.path.join(TESTDIR, test+".err") |
|
218 | err = os.path.join(TESTDIR, test+".err") | |
215 | ref = os.path.join(TESTDIR, test+".out") |
|
219 | ref = os.path.join(TESTDIR, test+".out") | |
216 |
|
220 | |||
@@ -319,11 +323,11 b" os.environ['TZ'] = 'GMT'" | |||||
319 | os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"' |
|
323 | os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"' | |
320 | os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"' |
|
324 | os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"' | |
321 | os.environ["HGUSER"] = "test" |
|
325 | os.environ["HGUSER"] = "test" | |
322 | os.environ["HGRCPATH"] = "" |
|
|||
323 |
|
326 | |||
324 | TESTDIR = os.environ["TESTDIR"] = os.getcwd() |
|
327 | TESTDIR = os.environ["TESTDIR"] = os.getcwd() | |
325 | HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.") |
|
328 | HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.") | |
326 | DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids') |
|
329 | DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids') | |
|
330 | HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc') | |||
327 |
|
331 | |||
328 | vlog("# Using TESTDIR", TESTDIR) |
|
332 | vlog("# Using TESTDIR", TESTDIR) | |
329 | vlog("# Using HGTMP", HGTMP) |
|
333 | vlog("# Using HGTMP", HGTMP) |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "mq=" >> $HGRCPATH | |
5 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
6 | cat > $HGTMP/false <<EOF |
|
5 | cat > $HGTMP/false <<EOF | |
7 | #!/bin/sh |
|
6 | #!/bin/sh | |
8 | exit 1 |
|
7 | exit 1 |
@@ -2,9 +2,8 b'' | |||||
2 |
|
2 | |||
3 | set -e |
|
3 | set -e | |
4 |
|
4 | |||
5 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
5 | echo "[extensions]" >> $HGRCPATH | |
6 | echo "[extensions]" >> $HGTMP/.hgrc |
|
6 | echo "hbisect=" >> $HGRCPATH | |
7 | echo "hbisect=" >> $HGTMP/.hgrc |
|
|||
8 |
|
7 | |||
9 | echo % init |
|
8 | echo % init | |
10 | hg init |
|
9 | hg init |
@@ -59,9 +59,9 b' 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:4' | |||||
59 | line 1 |
|
59 | line 1 | |
60 |
|
60 | |||
61 | # error if style not readable |
|
61 | # error if style not readable | |
62 |
abort: Permission denied |
|
62 | abort: Permission denied: ./q | |
63 | # error if no style |
|
63 | # error if no style | |
64 |
abort: No such file or directory |
|
64 | abort: No such file or directory: notexist | |
65 | # error if style missing key |
|
65 | # error if style missing key | |
66 | abort: ./t: no key named 'changeset' |
|
66 | abort: ./t: no key named 'changeset' | |
67 | # error if include fails |
|
67 | # error if include fails |
@@ -13,7 +13,7 b' echo "%%% should show a removed and b ad' | |||||
13 | hg status |
|
13 | hg status | |
14 |
|
14 | |||
15 | echo "reverting..." |
|
15 | echo "reverting..." | |
16 | hg revert |
|
16 | hg revert --all | |
17 |
|
17 | |||
18 | echo "%%% should show b unknown and a back to normal" |
|
18 | echo "%%% should show b unknown and a back to normal" | |
19 | hg status |
|
19 | hg status | |
@@ -42,10 +42,10 b' echo "%%% should show a removed and b ad' | |||||
42 | hg status |
|
42 | hg status | |
43 |
|
43 | |||
44 | echo "%%% revert should fail" |
|
44 | echo "%%% revert should fail" | |
45 | hg revert |
|
45 | hg revert --all | |
46 |
|
46 | |||
47 | echo "%%% revert should be ok now" |
|
47 | echo "%%% revert should be ok now" | |
48 | hg revert -r2 |
|
48 | hg revert -r2 --all | |
49 |
|
49 | |||
50 | echo "%%% should show b unknown and a marked modified (merged)" |
|
50 | echo "%%% should show b unknown and a marked modified (merged)" | |
51 | hg status |
|
51 | hg status |
@@ -17,7 +17,7 b' foo-b' | |||||
17 | A b |
|
17 | A b | |
18 | R a |
|
18 | R a | |
19 | %%% revert should fail |
|
19 | %%% revert should fail | |
20 | abort: working dir has two parents; you must specify the revision to revert to |
|
20 | abort: uncommitted merge - please provide a specific revision | |
21 | %%% revert should be ok now |
|
21 | %%% revert should be ok now | |
22 | undeleting a |
|
22 | undeleting a | |
23 | forgetting b |
|
23 | forgetting b |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 |
echo " |
|
4 | echo "extdiff=" >> $HGRCPATH | |
5 | echo "extdiff=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | hg init a |
|
6 | hg init a | |
8 | cd a |
|
7 | cd a | |
@@ -14,9 +13,9 b' if [ $? -ne 0 ]; then' | |||||
14 | fi |
|
13 | fi | |
15 | hg extdiff -o -Nr $opt |
|
14 | hg extdiff -o -Nr $opt | |
16 |
|
15 | |||
17 |
echo "[extdiff]" >> $HG |
|
16 | echo "[extdiff]" >> $HGRCPATH | |
18 |
echo "cmd.falabala=echo" >> $HG |
|
17 | echo "cmd.falabala=echo" >> $HGRCPATH | |
19 |
echo "opts.falabala=diffing" >> $HG |
|
18 | echo "opts.falabala=diffing" >> $HGRCPATH | |
20 |
|
19 | |||
21 | hg falabala |
|
20 | hg falabala | |
22 |
|
21 |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "fetch=" >> $HGRCPATH | |
5 | echo "fetch=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | hg init a |
|
6 | hg init a | |
8 | echo a > a/a |
|
7 | echo a > a/a |
@@ -50,3 +50,7 b" hg ci -mrenamemod -d '0 0'" | |||||
50 | echo '% rename+mod+chmod' |
|
50 | echo '% rename+mod+chmod' | |
51 | hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ |
|
51 | hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
52 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
|
52 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |
|
53 | ||||
|
54 | echo '% nonexistent in tip+chmod' | |||
|
55 | hg diff --git -r 5:6 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
56 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
@@ -40,3 +40,7 b' rename to dst' | |||||
40 | 4 |
|
40 | 4 | |
41 | 5 |
|
41 | 5 | |
42 | +a |
|
42 | +a | |
|
43 | % nonexistent in tip+chmod | |||
|
44 | diff --git a/src b/src | |||
|
45 | old mode 100644 | |||
|
46 | new mode 100755 |
@@ -11,7 +11,7 b' cat hg1.pid hg2.pid >> $DAEMON_PIDS' | |||||
11 |
|
11 | |||
12 | echo % clone via stream |
|
12 | echo % clone via stream | |
13 | http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \ |
|
13 | http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \ | |
14 | sed -e 's/[0-9][0-9.]*/XXX/g' |
|
14 | sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/' | |
15 | hg verify -R copy |
|
15 | hg verify -R copy | |
16 |
|
16 | |||
17 | echo % try to clone via stream, should use pull instead |
|
17 | echo % try to clone via stream, should use pull instead |
@@ -15,7 +15,7 b' sleep 2' | |||||
15 |
|
15 | |||
16 | echo %% url for proxy, stream |
|
16 | echo %% url for proxy, stream | |
17 | http_proxy=http://localhost:20060/ hg --config http_proxy.always=True clone --uncompressed http://localhost:20059/ b | \ |
|
17 | http_proxy=http://localhost:20060/ hg --config http_proxy.always=True clone --uncompressed http://localhost:20059/ b | \ | |
18 | sed -e 's/[0-9][0-9.]*/XXX/g' |
|
18 | sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/' | |
19 | cd b |
|
19 | cd b | |
20 | hg verify |
|
20 | hg verify | |
21 | cd .. |
|
21 | cd .. |
@@ -2,7 +2,7 b' adding a' | |||||
2 | %% url for proxy, stream |
|
2 | %% url for proxy, stream | |
3 | streaming all changes |
|
3 | streaming all changes | |
4 | XXX files to transfer, XXX bytes of data |
|
4 | XXX files to transfer, XXX bytes of data | |
5 |
transferred XXX bytes in XXX seconds (XXX |
|
5 | transferred XXX bytes in XXX seconds (XXX XB/sec) | |
6 | XXX files updated, XXX files merged, XXX files removed, XXX files unresolved |
|
6 | XXX files updated, XXX files merged, XXX files removed, XXX files unresolved | |
7 | checking changesets |
|
7 | checking changesets | |
8 | checking manifests |
|
8 | checking manifests |
@@ -2,7 +2,7 b' adding foo' | |||||
2 | % clone via stream |
|
2 | % clone via stream | |
3 | streaming all changes |
|
3 | streaming all changes | |
4 | XXX files to transfer, XXX bytes of data |
|
4 | XXX files to transfer, XXX bytes of data | |
5 |
transferred XXX bytes in XXX seconds (XXX |
|
5 | transferred XXX bytes in XXX seconds (XXX XB/sec) | |
6 | XXX files updated, XXX files merged, XXX files removed, XXX files unresolved |
|
6 | XXX files updated, XXX files merged, XXX files removed, XXX files unresolved | |
7 | checking changesets |
|
7 | checking changesets | |
8 | checking manifests |
|
8 | checking manifests |
@@ -27,6 +27,9 b' hg init local' | |||||
27 | echo this > local/foo |
|
27 | echo this > local/foo | |
28 | hg ci --cwd local -A -m "init" -d "1000000 0" |
|
28 | hg ci --cwd local -A -m "init" -d "1000000 0" | |
29 |
|
29 | |||
|
30 | echo "#test failure" | |||
|
31 | hg init local | |||
|
32 | ||||
30 | echo "# init+push to remote2" |
|
33 | echo "# init+push to remote2" | |
31 | hg init -e ./dummyssh ssh://user@dummy/remote2 |
|
34 | hg init -e ./dummyssh ssh://user@dummy/remote2 | |
32 | hg incoming -R remote2 local |
|
35 | hg incoming -R remote2 local | |
@@ -35,6 +38,12 b' hg push -R local -e ./dummyssh ssh://use' | |||||
35 | echo "# clone to remote1" |
|
38 | echo "# clone to remote1" | |
36 | hg clone -e ./dummyssh local ssh://user@dummy/remote1 |
|
39 | hg clone -e ./dummyssh local ssh://user@dummy/remote1 | |
37 |
|
40 | |||
|
41 | echo "# init to existing repo" | |||
|
42 | hg init -e ./dummyssh ssh://user@dummy/remote1 | |||
|
43 | ||||
|
44 | echo "# clone to existing repo" | |||
|
45 | hg clone -e ./dummyssh local ssh://user@dummy/remote1 | |||
|
46 | ||||
38 | echo "# output of dummyssh" |
|
47 | echo "# output of dummyssh" | |
39 | cat dummylog |
|
48 | cat dummylog | |
40 |
|
49 |
@@ -1,5 +1,7 b'' | |||||
1 | # creating 'local' |
|
1 | # creating 'local' | |
2 | adding foo |
|
2 | adding foo | |
|
3 | #test failure | |||
|
4 | abort: repository local already exists! | |||
3 | # init+push to remote2 |
|
5 | # init+push to remote2 | |
4 | changeset: 0:c4e059d443be |
|
6 | changeset: 0:c4e059d443be | |
5 | tag: tip |
|
7 | tag: tip | |
@@ -15,20 +17,24 b' remote: adding file changes' | |||||
15 | remote: added 1 changesets with 1 changes to 1 files |
|
17 | remote: added 1 changesets with 1 changes to 1 files | |
16 | # clone to remote1 |
|
18 | # clone to remote1 | |
17 | searching for changes |
|
19 | searching for changes | |
18 | remote: abort: repository remote1 not found! |
|
|||
19 | remote: adding changesets |
|
20 | remote: adding changesets | |
20 | remote: adding manifests |
|
21 | remote: adding manifests | |
21 | remote: adding file changes |
|
22 | remote: adding file changes | |
22 | remote: added 1 changesets with 1 changes to 1 files |
|
23 | remote: added 1 changesets with 1 changes to 1 files | |
|
24 | # init to existing repo | |||
|
25 | abort: repository remote1 already exists! | |||
|
26 | abort: could not create remote repo! | |||
|
27 | # clone to existing repo | |||
|
28 | abort: repository remote1 already exists! | |||
|
29 | abort: could not create remote repo! | |||
23 | # output of dummyssh |
|
30 | # output of dummyssh | |
24 | Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: |
|
|||
25 | Got arguments 1:user@dummy 2:hg init remote2 3: 4: 5: |
|
31 | Got arguments 1:user@dummy 2:hg init remote2 3: 4: 5: | |
26 | Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: |
|
32 | Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: | |
27 | Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: |
|
33 | Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: | |
28 |
Got arguments 1:user@dummy 2:hg |
|
34 | Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: | |
29 | Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5: |
|
35 | Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5: | |
30 | Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: |
|
36 | Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: | |
31 |
Got arguments 1:user@dummy 2:hg |
|
37 | Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: | |
32 | # comparing repositories |
|
38 | # comparing repositories | |
33 | 0:c4e059d443be |
|
39 | 0:c4e059d443be | |
34 | 0:c4e059d443be |
|
40 | 0:c4e059d443be |
@@ -15,7 +15,7 b' hg update -C 0' | |||||
15 | hg id |
|
15 | hg id | |
16 | echo "changed file1" >> file1 |
|
16 | echo "changed file1" >> file1 | |
17 | hg id |
|
17 | hg id | |
18 | hg revert |
|
18 | hg revert --all | |
19 | hg diff |
|
19 | hg diff | |
20 | hg status |
|
20 | hg status | |
21 | hg id |
|
21 | hg id | |
@@ -29,11 +29,11 b' HGMERGE=merge hg update' | |||||
29 | hg diff |
|
29 | hg diff | |
30 | hg status |
|
30 | hg status | |
31 | hg id |
|
31 | hg id | |
32 | hg revert |
|
32 | hg revert --all | |
33 | hg diff |
|
33 | hg diff | |
34 | hg status |
|
34 | hg status | |
35 | hg id |
|
35 | hg id | |
36 | hg revert -r tip |
|
36 | hg revert -r tip --all | |
37 | hg diff |
|
37 | hg diff | |
38 | hg status |
|
38 | hg status | |
39 | hg id |
|
39 | hg id |
@@ -16,7 +16,7 b' hg update -C 0' | |||||
16 | hg id |
|
16 | hg id | |
17 | echo "changed file1" >> file1 |
|
17 | echo "changed file1" >> file1 | |
18 | hg id |
|
18 | hg id | |
19 | hg revert --no-backup |
|
19 | hg revert --no-backup --all | |
20 | hg diff |
|
20 | hg diff | |
21 | hg status |
|
21 | hg status | |
22 | hg id |
|
22 | hg id | |
@@ -31,11 +31,11 b' hg diff | sed -e "s/\\(+++ [a-zA-Z0-9_/.-' | |||||
31 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/" |
|
31 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/" | |
32 | hg status |
|
32 | hg status | |
33 | hg id |
|
33 | hg id | |
34 | hg revert --no-backup |
|
34 | hg revert --no-backup --all | |
35 | hg diff |
|
35 | hg diff | |
36 | hg status |
|
36 | hg status | |
37 | hg id |
|
37 | hg id | |
38 | hg revert -r tip --no-backup |
|
38 | hg revert -r tip --no-backup --all | |
39 | hg diff |
|
39 | hg diff | |
40 | hg status |
|
40 | hg status | |
41 | hg id |
|
41 | hg id |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "mq=" >> $HGRCPATH | |
5 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | echo % help |
|
6 | echo % help | |
8 | hg help mq |
|
7 | hg help mq | |
@@ -116,6 +115,19 b' hg push ../../k' | |||||
116 | echo % qunapplied |
|
115 | echo % qunapplied | |
117 | hg qunapplied |
|
116 | hg qunapplied | |
118 |
|
117 | |||
|
118 | echo % qpush/qpop with index | |||
|
119 | hg qnew test1b.patch | |||
|
120 | echo 1b > 1b | |||
|
121 | hg add 1b | |||
|
122 | hg qrefresh | |||
|
123 | hg qpush 2 | |||
|
124 | hg qpop 0 | |||
|
125 | hg qpush test.patch+1 | |||
|
126 | hg qpush test.patch+2 | |||
|
127 | hg qpop test2.patch-1 | |||
|
128 | hg qpop test2.patch-2 | |||
|
129 | hg qpush test1b.patch+1 | |||
|
130 | ||||
119 | echo % push should succeed |
|
131 | echo % push should succeed | |
120 | hg qpop -a |
|
132 | hg qpop -a | |
121 | hg push ../../k |
|
133 | hg push ../../k | |
@@ -127,7 +139,28 b' hg ci -Ama' | |||||
127 | hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/' |
|
139 | hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/' | |
128 | hg unbundle .hg/strip-backup/* |
|
140 | hg unbundle .hg/strip-backup/* | |
129 |
|
141 | |||
130 | cat >>$HGTMP/.hgrc <<EOF |
|
142 | echo '% cd b; hg qrefresh' | |
|
143 | hg init refresh | |||
|
144 | cd refresh | |||
|
145 | echo a > a | |||
|
146 | hg ci -Ama -d'0 0' | |||
|
147 | hg qnew -mfoo foo | |||
|
148 | echo a >> a | |||
|
149 | hg qrefresh | |||
|
150 | mkdir b | |||
|
151 | cd b | |||
|
152 | echo f > f | |||
|
153 | hg add f | |||
|
154 | hg qrefresh | |||
|
155 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
156 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo | |||
|
157 | echo % hg qrefresh . | |||
|
158 | hg qrefresh . | |||
|
159 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
160 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo | |||
|
161 | hg status | |||
|
162 | ||||
|
163 | cat >>$HGRCPATH <<EOF | |||
131 | [diff] |
|
164 | [diff] | |
132 | git = True |
|
165 | git = True | |
133 | EOF |
|
166 | EOF |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "mq=" >> $HGRCPATH | |
5 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | hg init |
|
6 | hg init | |
8 | hg qinit |
|
7 | hg qinit |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "mq=" >> $HGRCPATH | |
5 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | echo % init |
|
6 | echo % init | |
8 | hg init a |
|
7 | hg init a |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "mq=" >> $HGRCPATH | |
5 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | hg init a |
|
6 | hg init a | |
8 | cd a |
|
7 | cd a |
@@ -1,9 +1,8 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | # Environement setup for MQ |
|
3 | # Environement setup for MQ | |
4 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
4 | echo "[extensions]" >> $HGRCPATH | |
5 | echo "[extensions]" >> $HGTMP/.hgrc |
|
5 | echo "mq=" >> $HGRCPATH | |
6 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
7 |
|
6 | |||
8 | #Repo init |
|
7 | #Repo init | |
9 | hg init |
|
8 | hg init |
@@ -1,8 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH |
|
3 | echo "[extensions]" >> $HGRCPATH | |
4 | echo "[extensions]" >> $HGTMP/.hgrc |
|
4 | echo "mq=" >> $HGRCPATH | |
5 | echo "mq=" >> $HGTMP/.hgrc |
|
|||
6 |
|
5 | |||
7 | hg init a |
|
6 | hg init a | |
8 | cd a |
|
7 | cd a |
@@ -110,6 +110,19 b' pushing to ../../k' | |||||
110 | abort: source has mq patches applied |
|
110 | abort: source has mq patches applied | |
111 | % qunapplied |
|
111 | % qunapplied | |
112 | test2.patch |
|
112 | test2.patch | |
|
113 | % qpush/qpop with index | |||
|
114 | applying test2.patch | |||
|
115 | Now at: test2.patch | |||
|
116 | Now at: test.patch | |||
|
117 | applying test1b.patch | |||
|
118 | Now at: test1b.patch | |||
|
119 | applying test2.patch | |||
|
120 | Now at: test2.patch | |||
|
121 | Now at: test1b.patch | |||
|
122 | Now at: test.patch | |||
|
123 | applying test1b.patch | |||
|
124 | applying test2.patch | |||
|
125 | Now at: test2.patch | |||
113 | % push should succeed |
|
126 | % push should succeed | |
114 | Patch queue now empty |
|
127 | Patch queue now empty | |
115 | pushing to ../../k |
|
128 | pushing to ../../k | |
@@ -127,6 +140,30 b' adding manifests' | |||||
127 | adding file changes |
|
140 | adding file changes | |
128 | added 1 changesets with 1 changes to 1 files |
|
141 | added 1 changesets with 1 changes to 1 files | |
129 | (run 'hg update' to get a working copy) |
|
142 | (run 'hg update' to get a working copy) | |
|
143 | % cd b; hg qrefresh | |||
|
144 | adding a | |||
|
145 | foo | |||
|
146 | ||||
|
147 | diff -r cb9a9f314b8b a | |||
|
148 | --- a/a | |||
|
149 | +++ b/a | |||
|
150 | @@ -1,1 +1,2 @@ a | |||
|
151 | a | |||
|
152 | +a | |||
|
153 | diff -r cb9a9f314b8b b/f | |||
|
154 | --- /dev/null | |||
|
155 | +++ b/b/f | |||
|
156 | @@ -0,0 +1,1 @@ | |||
|
157 | +f | |||
|
158 | % hg qrefresh . | |||
|
159 | foo | |||
|
160 | ||||
|
161 | diff -r cb9a9f314b8b b/f | |||
|
162 | --- /dev/null | |||
|
163 | +++ b/b/f | |||
|
164 | @@ -0,0 +1,1 @@ | |||
|
165 | +f | |||
|
166 | M a | |||
130 | new file |
|
167 | new file | |
131 |
|
168 | |||
132 | diff --git a/new b/new |
|
169 | diff --git a/new b/new |
@@ -14,6 +14,6 b' hg add b/x' | |||||
14 | echo '# should print A b/x' |
|
14 | echo '# should print A b/x' | |
15 | hg st |
|
15 | hg st | |
16 | echo '# should forget b/x' |
|
16 | echo '# should forget b/x' | |
17 | hg revert |
|
17 | hg revert --all | |
18 | echo '# should print nothing' |
|
18 | echo '# should print nothing' | |
19 | hg st b |
|
19 | hg st b |
@@ -9,7 +9,7 b' hg commit -m 1 -d "1000000 0"' | |||||
9 | hg remove |
|
9 | hg remove | |
10 | rm foo |
|
10 | rm foo | |
11 | hg remove foo |
|
11 | hg remove foo | |
12 | hg revert |
|
12 | hg revert --all | |
13 | rm foo |
|
13 | rm foo | |
14 | hg remove --after |
|
14 | hg remove --after | |
15 | hg commit -m 2 -d "1000000 0" |
|
15 | hg commit -m 2 -d "1000000 0" |
@@ -31,7 +31,7 b' echo %% should show a b c e' | |||||
31 | ls |
|
31 | ls | |
32 | echo %% should verbosely save backup to e.orig |
|
32 | echo %% should verbosely save backup to e.orig | |
33 | echo z > e |
|
33 | echo z > e | |
34 | hg revert -v |
|
34 | hg revert --all -v | |
35 | echo %% should say no changes needed |
|
35 | echo %% should say no changes needed | |
36 | hg revert a |
|
36 | hg revert a | |
37 | echo %% should say file not managed |
|
37 | echo %% should say file not managed | |
@@ -46,9 +46,9 b' echo z > z' | |||||
46 | hg add z |
|
46 | hg add z | |
47 | hg st |
|
47 | hg st | |
48 | echo %% should add a, forget z |
|
48 | echo %% should add a, forget z | |
49 | hg revert -r0 |
|
49 | hg revert --all -r0 | |
50 | echo %% should forget a |
|
50 | echo %% should forget a | |
51 | hg revert -rtip |
|
51 | hg revert --all -rtip | |
52 | rm -f a *.orig |
|
52 | rm -f a *.orig | |
53 | echo %% should silently add a |
|
53 | echo %% should silently add a | |
54 | hg revert -r0 a |
|
54 | hg revert -r0 a | |
@@ -56,7 +56,7 b' hg st a' | |||||
56 |
|
56 | |||
57 | hg update -C |
|
57 | hg update -C | |
58 | chmod +x c |
|
58 | chmod +x c | |
59 | hg revert |
|
59 | hg revert --all | |
60 | echo %% should print non-executable |
|
60 | echo %% should print non-executable | |
61 | test -x c || echo non-executable |
|
61 | test -x c || echo non-executable | |
62 |
|
62 | |||
@@ -64,7 +64,7 b' chmod +x c' | |||||
64 | hg commit -d '1000001 0' -m exe |
|
64 | hg commit -d '1000001 0' -m exe | |
65 |
|
65 | |||
66 | chmod -x c |
|
66 | chmod -x c | |
67 | hg revert |
|
67 | hg revert --all | |
68 | echo %% should print executable |
|
68 | echo %% should print executable | |
69 | test -x c && echo executable |
|
69 | test -x c && echo executable | |
70 |
|
70 | |||
@@ -78,6 +78,15 b" hg commit -d '2 0' -m a" | |||||
78 | hg update 0 |
|
78 | hg update 0 | |
79 | mkdir b |
|
79 | mkdir b | |
80 | echo b > b/b |
|
80 | echo b > b/b | |
|
81 | ||||
|
82 | echo % should fail - no arguments | |||
81 | hg revert -rtip |
|
83 | hg revert -rtip | |
82 |
|
84 | |||
|
85 | echo % should succeed | |||
|
86 | hg revert --all -rtip | |||
|
87 | ||||
|
88 | echo %% issue332 | |||
|
89 | hg ci -A -m b -d '1000001 0' | |||
|
90 | echo foobar > b/b | |||
|
91 | hg revert b | |||
83 | true |
|
92 | true |
@@ -13,7 +13,7 b' hg ci -m "2" -d "1000000 0"' | |||||
13 |
|
13 | |||
14 | echo %% Should show unknown |
|
14 | echo %% Should show unknown | |
15 | hg status |
|
15 | hg status | |
16 | hg revert -r 0 |
|
16 | hg revert -r 0 --all | |
17 | echo %% Should show unknown and b removed |
|
17 | echo %% Should show unknown and b removed | |
18 | hg status |
|
18 | hg status | |
19 | echo %% Should show a and unknown |
|
19 | echo %% Should show a and unknown |
@@ -54,4 +54,10 b' executable' | |||||
54 | %% issue 241 |
|
54 | %% issue 241 | |
55 | adding a |
|
55 | adding a | |
56 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
56 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
57 | % should fail - no arguments | |||
|
58 | abort: no files or directories specified; use --all to revert the whole repo | |||
|
59 | % should succeed | |||
57 | reverting a |
|
60 | reverting a | |
|
61 | %% issue332 | |||
|
62 | adding b/b | |||
|
63 | reverting b/b |
@@ -1,3 +1,3 b'' | |||||
1 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
2 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
2 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
3 |
abort: Permission denied |
|
3 | abort: Permission denied: test-ro-message/b/vehicle |
@@ -38,7 +38,7 b' cd ..' | |||||
38 |
|
38 | |||
39 | echo "# clone remote via stream" |
|
39 | echo "# clone remote via stream" | |
40 | hg clone -e ./dummyssh --uncompressed ssh://user@dummy/remote local-stream 2>&1 | \ |
|
40 | hg clone -e ./dummyssh --uncompressed ssh://user@dummy/remote local-stream 2>&1 | \ | |
41 | sed -e 's/[0-9][0-9.]*/XXX/g' |
|
41 | sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/' | |
42 | cd local-stream |
|
42 | cd local-stream | |
43 | hg verify |
|
43 | hg verify | |
44 | cd .. |
|
44 | cd .. | |
@@ -80,7 +80,7 b' cd ../remote' | |||||
80 | echo "# check remote tip" |
|
80 | echo "# check remote tip" | |
81 | hg tip |
|
81 | hg tip | |
82 | hg verify |
|
82 | hg verify | |
83 | hg cat foo |
|
83 | hg cat -r tip foo | |
84 |
|
84 | |||
85 | echo z > z |
|
85 | echo z > z | |
86 | hg ci -A -m z -d '1000001 0' z |
|
86 | hg ci -A -m z -d '1000001 0' z |
@@ -2,7 +2,7 b'' | |||||
2 | # clone remote via stream |
|
2 | # clone remote via stream | |
3 | streaming all changes |
|
3 | streaming all changes | |
4 | XXX files to transfer, XXX bytes of data |
|
4 | XXX files to transfer, XXX bytes of data | |
5 |
transferred XXX bytes in XXX seconds (XXX |
|
5 | transferred XXX bytes in XXX seconds (XXX XB/sec) | |
6 | XXX files updated, XXX files merged, XXX files removed, XXX files unresolved |
|
6 | XXX files updated, XXX files merged, XXX files removed, XXX files unresolved | |
7 | checking changesets |
|
7 | checking changesets | |
8 | checking manifests |
|
8 | checking manifests |
@@ -1,6 +1,6 b'' | |||||
1 | #!/usr/bin/env python |
|
1 | #!/usr/bin/env python | |
2 |
|
2 | |||
3 | from mercurial import ui |
|
3 | from mercurial import ui, util | |
4 |
|
4 | |||
5 | testui = ui.ui() |
|
5 | testui = ui.ui() | |
6 | testui.updateopts(config=[ |
|
6 | testui.updateopts(config=[ | |
@@ -11,10 +11,19 b' testui.updateopts(config=[' | |||||
11 | 'lists.list2=foo bar baz', |
|
11 | 'lists.list2=foo bar baz', | |
12 | 'lists.list3=alice, bob', |
|
12 | 'lists.list3=alice, bob', | |
13 | 'lists.list4=foo bar baz alice, bob', |
|
13 | 'lists.list4=foo bar baz alice, bob', | |
|
14 | 'interpolation.value1=hallo', | |||
|
15 | 'interpolation.value2=%(value1)s world', | |||
|
16 | 'interpolation.value3=%(novalue)s', | |||
|
17 | 'interpolation.value4=%(bad)1', | |||
|
18 | 'interpolation.value5=%bad2', | |||
14 | ]) |
|
19 | ]) | |
15 |
|
20 | |||
16 | print repr(testui.configitems('values')) |
|
21 | print repr(testui.configitems('values')) | |
17 | print repr(testui.configitems('lists')) |
|
22 | print repr(testui.configitems('lists')) | |
|
23 | try: | |||
|
24 | print repr(testui.configitems('interpolation')) | |||
|
25 | except util.Abort, inst: | |||
|
26 | print inst | |||
18 | print "---" |
|
27 | print "---" | |
19 | print repr(testui.config('values', 'string')) |
|
28 | print repr(testui.config('values', 'string')) | |
20 | print repr(testui.config('values', 'bool1')) |
|
29 | print repr(testui.config('values', 'bool1')) | |
@@ -45,3 +54,18 b" print repr(testui.configlist('lists', 'u" | |||||
45 | print repr(testui.configlist('lists', 'unknown', ['foo bar'])) |
|
54 | print repr(testui.configlist('lists', 'unknown', ['foo bar'])) | |
46 | print repr(testui.configlist('lists', 'unknown', ['foo', 'bar'])) |
|
55 | print repr(testui.configlist('lists', 'unknown', ['foo', 'bar'])) | |
47 | print "---" |
|
56 | print "---" | |
|
57 | print repr(testui.config('interpolation', 'value1')) | |||
|
58 | print repr(testui.config('interpolation', 'value2')) | |||
|
59 | try: | |||
|
60 | print repr(testui.config('interpolation', 'value3')) | |||
|
61 | except util.Abort, inst: | |||
|
62 | print inst | |||
|
63 | try: | |||
|
64 | print repr(testui.config('interpolation', 'value4')) | |||
|
65 | except util.Abort, inst: | |||
|
66 | print inst | |||
|
67 | try: | |||
|
68 | print repr(testui.config('interpolation', 'value5')) | |||
|
69 | except util.Abort, inst: | |||
|
70 | print inst | |||
|
71 | print "---" |
@@ -1,5 +1,7 b'' | |||||
1 | [('bool1', 'true'), ('bool2', 'false'), ('string', 'string value')] |
|
1 | [('bool1', 'true'), ('bool2', 'false'), ('string', 'string value')] | |
2 | [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')] |
|
2 | [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')] | |
|
3 | Error in configuration section [interpolation]: | |||
|
4 | '%' must be followed by '%' or '(', found: '%bad2' | |||
3 | --- |
|
5 | --- | |
4 | 'string value' |
|
6 | 'string value' | |
5 | 'true' |
|
7 | 'true' | |
@@ -27,3 +29,17 b' True' | |||||
27 | ['foo bar'] |
|
29 | ['foo bar'] | |
28 | ['foo', 'bar'] |
|
30 | ['foo', 'bar'] | |
29 | --- |
|
31 | --- | |
|
32 | 'hallo' | |||
|
33 | 'hallo world' | |||
|
34 | Error in configuration section [interpolation] parameter 'value3': | |||
|
35 | Bad value substitution: | |||
|
36 | section: [interpolation] | |||
|
37 | option : value3 | |||
|
38 | key : novalue | |||
|
39 | rawval : | |||
|
40 | ||||
|
41 | Error in configuration section [interpolation] parameter 'value4': | |||
|
42 | bad interpolation variable reference '%(bad)1' | |||
|
43 | Error in configuration section [interpolation] parameter 'value5': | |||
|
44 | '%' must be followed by '%' or '(', found: '%bad2' | |||
|
45 | --- |
General Comments 0
You need to be logged in to leave comments.
Login now