diff options
| author | Eric S. Raymond | 2014-12-01 14:51:03 -0500 |
|---|---|---|
| committer | Eric S. Raymond | 2014-12-01 14:51:26 -0500 |
| commit | 808699f13673a881949ab94d3c0e87f5ba9cd4cf (patch) | |
| tree | 9cd17372e8eb75cdeb40372548042aeee521abf2 /lisp | |
| parent | 6d80f26a9ae8e43973dbc946a9c070192fd5c431 (diff) | |
| download | emacs-808699f13673a881949ab94d3c0e87f5ba9cd4cf.tar.gz emacs-808699f13673a881949ab94d3c0e87f5ba9cd4cf.zip | |
bzr-state randomly/unpredictably fails on non-bzr files.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/vc/vc-bzr.el | 109 |
1 files changed, 108 insertions, 1 deletions
diff --git a/lisp/vc/vc-bzr.el b/lisp/vc/vc-bzr.el index 34a7c7be786..7f30378227f 100644 --- a/lisp/vc/vc-bzr.el +++ b/lisp/vc/vc-bzr.el | |||
| @@ -178,6 +178,113 @@ in the repository root directory of FILE." | |||
| 178 | (insert-file-contents-literally file) | 178 | (insert-file-contents-literally file) |
| 179 | (sha1 (current-buffer)))) | 179 | (sha1 (current-buffer)))) |
| 180 | 180 | ||
| 181 | (defun vc-bzr-state-heuristic (file) | ||
| 182 | "Like `vc-bzr-state' but hopefully without running Bzr." | ||
| 183 | ;; `bzr status' could be slow with large histories and pending merges, | ||
| 184 | ;; so this tries to avoid calling it if possible. bzr status is | ||
| 185 | ;; faster now, so this is not as important as it was. | ||
| 186 | ;; | ||
| 187 | ;; This function tries first to parse Bzr internal file | ||
| 188 | ;; `checkout/dirstate', but it may fail if Bzr internal file format | ||
| 189 | ;; has changed. As a safeguard, the `checkout/dirstate' file is | ||
| 190 | ;; only parsed if it contains the string `#bazaar dirstate flat | ||
| 191 | ;; format 3' in the first line. | ||
| 192 | ;; If the `checkout/dirstate' file cannot be parsed, fall back to | ||
| 193 | ;; running `vc-bzr-state'." | ||
| 194 | ;; | ||
| 195 | ;; The format of the dirstate file is explained in bzrlib/dirstate.py | ||
| 196 | ;; in the bzr distribution. Basically: | ||
| 197 | ;; header-line giving the version of the file format in use. | ||
| 198 | ;; a few lines of stuff | ||
| 199 | ;; entries, one per line, with null-separated fields. Each line: | ||
| 200 | ;; entry_key = dirname (may be empty), basename, file-id | ||
| 201 | ;; current = common ( = kind, fingerprint, size, executable ) | ||
| 202 | ;; + working ( = packed_stat ) | ||
| 203 | ;; parent = common ( as above ) + history ( = rev_id ) | ||
| 204 | ;; kinds = (r)elocated, (a)bsent, (d)irectory, (f)ile, (l)ink | ||
| 205 | (let* ((root (vc-bzr-root file)) | ||
| 206 | (dirstate (expand-file-name vc-bzr-admin-dirstate root))) | ||
| 207 | (when root ; Short cut. | ||
| 208 | (condition-case err | ||
| 209 | (with-temp-buffer | ||
| 210 | (insert-file-contents dirstate) | ||
| 211 | (goto-char (point-min)) | ||
| 212 | (if (not (looking-at "#bazaar dirstate flat format 3")) | ||
| 213 | (vc-bzr-state file) ; Some other unknown format? | ||
| 214 | (let* ((relfile (file-relative-name file root)) | ||
| 215 | (reldir (file-name-directory relfile))) | ||
| 216 | (cond | ||
| 217 | ((not | ||
| 218 | (re-search-forward | ||
| 219 | (concat "^\0" | ||
| 220 | (if reldir (regexp-quote | ||
| 221 | (directory-file-name reldir))) | ||
| 222 | "\0" | ||
| 223 | (regexp-quote (file-name-nondirectory relfile)) | ||
| 224 | "\0" | ||
| 225 | "[^\0]*\0" ;id? | ||
| 226 | "\\([^\0]*\\)\0" ;"a/f/d", a=removed? | ||
| 227 | "\\([^\0]*\\)\0" ;sha1 (empty if conflicted)? | ||
| 228 | "\\([^\0]*\\)\0" ;size?p | ||
| 229 | ;; y/n. Whether or not the current copy | ||
| 230 | ;; was executable the last time bzr checked? | ||
| 231 | "[^\0]*\0" | ||
| 232 | "[^\0]*\0" ;? | ||
| 233 | ;; Parent information. Absent in a new repo. | ||
| 234 | "\\(?:\\([^\0]*\\)\0" ;"a/f/d" a=added? | ||
| 235 | "\\([^\0]*\\)\0" ;sha1 again? | ||
| 236 | "\\([^\0]*\\)\0" ;size again? | ||
| 237 | ;; y/n. Whether or not the repo thinks | ||
| 238 | ;; the file should be executable? | ||
| 239 | "\\([^\0]*\\)\0" | ||
| 240 | "[^\0]*\0\\)?" ;last revid? | ||
| 241 | ;; There are more fields when merges are pending. | ||
| 242 | ) | ||
| 243 | nil t)) | ||
| 244 | 'unregistered) | ||
| 245 | ;; Apparently the second sha1 is the one we want: when | ||
| 246 | ;; there's a conflict, the first sha1 is absent (and the | ||
| 247 | ;; first size seems to correspond to the file with | ||
| 248 | ;; conflict markers). | ||
| 249 | ((eq (char-after (match-beginning 1)) ?a) 'removed) | ||
| 250 | ;; If there is no parent, this must be a new repo. | ||
| 251 | ;; If file is in dirstate, can only be added (b#8025). | ||
| 252 | ((or (not (match-beginning 4)) | ||
| 253 | (eq (char-after (match-beginning 4)) ?a)) 'added) | ||
| 254 | ((or (and (eq (string-to-number (match-string 3)) | ||
| 255 | (nth 7 (file-attributes file))) | ||
| 256 | (equal (match-string 5) | ||
| 257 | (save-match-data (vc-bzr-sha1 file))) | ||
| 258 | ;; For a file, does the executable state match? | ||
| 259 | ;; (Bug#7544) | ||
| 260 | (or (not | ||
| 261 | (eq (char-after (match-beginning 1)) ?f)) | ||
| 262 | (let ((exe | ||
| 263 | (memq | ||
| 264 | ?x | ||
| 265 | (mapcar | ||
| 266 | 'identity | ||
| 267 | (nth 8 (file-attributes file)))))) | ||
| 268 | (if (eq (char-after (match-beginning 7)) | ||
| 269 | ?y) | ||
| 270 | exe | ||
| 271 | (not exe))))) | ||
| 272 | (and | ||
| 273 | ;; It looks like for lightweight | ||
| 274 | ;; checkouts \2 is empty and we need to | ||
| 275 | ;; look for size in \6. | ||
| 276 | (eq (match-beginning 2) (match-end 2)) | ||
| 277 | (eq (string-to-number (match-string 6)) | ||
| 278 | (nth 7 (file-attributes file))) | ||
| 279 | (equal (match-string 5) | ||
| 280 | (vc-bzr-sha1 file)))) | ||
| 281 | 'up-to-date) | ||
| 282 | (t 'edited))))) | ||
| 283 | ;; The dirstate file can't be read, or some other problem. | ||
| 284 | (error | ||
| 285 | (message "Falling back on \"slow\" status detection (%S)" err) | ||
| 286 | (vc-bzr-state file)))))) | ||
| 287 | |||
| 181 | ;; This is a cheap approximation that is autoloaded. If it finds a | 288 | ;; This is a cheap approximation that is autoloaded. If it finds a |
| 182 | ;; possible match it loads this file and runs the real function. | 289 | ;; possible match it loads this file and runs the real function. |
| 183 | ;; It requires vc-bzr-admin-checkout-format-file to be autoloaded too. | 290 | ;; It requires vc-bzr-admin-checkout-format-file to be autoloaded too. |
| @@ -189,7 +296,7 @@ in the repository root directory of FILE." | |||
| 189 | 296 | ||
| 190 | (defun vc-bzr-registered (file) | 297 | (defun vc-bzr-registered (file) |
| 191 | "Return non-nil if FILE is registered with bzr." | 298 | "Return non-nil if FILE is registered with bzr." |
| 192 | (let ((state (vc-bzr-state file))) | 299 | (let ((state (vc-bzr-state-heuristic file))) |
| 193 | (not (memq state '(nil unregistered ignored))))) | 300 | (not (memq state '(nil unregistered ignored))))) |
| 194 | 301 | ||
| 195 | (defconst vc-bzr-state-words | 302 | (defconst vc-bzr-state-words |