修訂 | 324 (tree) |
---|---|
時間 | 2015-11-10 19:25:02 |
作者 | mhayashi1120 |
improve svn executable switcher
@@ -1,5 +1,6 @@ | ||
1 | 1 | 2015-11-10 Masahiro Hayashi (林 雅博) <mhayashi1120@gmail.com> |
2 | 2 | |
3 | + * Improve: detect more information when register new svn command. | |
3 | 4 | * Fix: select higher version of svn if registered multiple versions. |
4 | 5 | * Improve: Fix testing environment |
5 | 6 |
@@ -516,11 +516,11 @@ | ||
516 | 516 | |
517 | 517 | |
518 | 518 | |
519 | -(defvar fsvn-initialize-function nil) | |
519 | +(defvar fsvn--initialize-hook nil) | |
520 | +(defvar fsvn--after-initialize-hook nil) | |
520 | 521 | |
521 | 522 | (defun fsvn-initialize-loading () |
522 | 523 | (interactive) |
523 | - (fsvn-set-command-information) | |
524 | 524 | (unless (file-directory-p fsvn-home-directory) |
525 | 525 | (make-directory fsvn-home-directory t)) |
526 | 526 | (mapc |
@@ -530,10 +530,11 @@ | ||
530 | 530 | (make-directory dirname)))) |
531 | 531 | fsvn-temp-directory-dirs) |
532 | 532 | (fsvn-cleanup-temp-directory) |
533 | + (run-hooks 'fsvn--initialize-hook) | |
534 | + (fsvn-set-command-information) | |
533 | 535 | (fsvn-build-subcommand) |
534 | - (when fsvn-initialize-function | |
535 | - (funcall fsvn-initialize-function)) | |
536 | - (fsvn-toggle-feature t 'no-msg)) | |
536 | + (fsvn-toggle-feature t 'no-msg) | |
537 | + (run-hooks 'fsvn--after-initialize-hook)) | |
537 | 538 | |
538 | 539 | (defun fsvn-toggle-command-boolean (optional-arg current-value) |
539 | 540 | (cond |
@@ -22,6 +22,7 @@ | ||
22 | 22 | |
23 | 23 | (defvar fsvn-process-environment-lang nil) |
24 | 24 | (defmacro fsvn-process-environment (&rest form) |
25 | + (declare (debug t)) | |
25 | 26 | `(let ((process-environment (copy-sequence process-environment))) |
26 | 27 | (setenv "LC_MESSAGES" (or fsvn-process-environment-lang "C")) |
27 | 28 | ,@form)) |
@@ -325,6 +326,7 @@ | ||
325 | 326 | " "))) |
326 | 327 | |
327 | 328 | (defun fsvn-guess-file-contents-coding-system (flatten-args) |
329 | + "Guess output coding-system file in FLATTEN-ARGS." | |
328 | 330 | (let (ignore) |
329 | 331 | (catch 'guessed |
330 | 332 | (mapc |
@@ -684,11 +684,6 @@ | ||
684 | 684 | (terminal-coding-system) |
685 | 685 | (fsvn-prop-file-coding-system propname)))) |
686 | 686 | |
687 | -(defvar fsvn-targets-file-converter nil | |
688 | - "File name converter for function `--targets' argument. | |
689 | -Default value is `identity' | |
690 | -Usefull for cygwin version `svn'") | |
691 | - | |
692 | 687 | (defun fsvn-make-targets-file (files) |
693 | 688 | "Create --targts argument file. |
694 | 689 | Argument FILES ." |
@@ -698,7 +693,7 @@ | ||
698 | 693 | (mapc |
699 | 694 | (lambda (f) |
700 | 695 | (let ((file (fsvn-url-escape-revision-mark f))) |
701 | - (insert (funcall (or fsvn-targets-file-converter 'identity) file) "\n"))) | |
696 | + (insert file "\n"))) | |
702 | 697 | files) |
703 | 698 | (write-region (point-min) (point-max) tmpfile nil 'no-msg))) |
704 | 699 | (propertize tmpfile 'fsvn-target-files files))) |
@@ -426,25 +426,37 @@ | ||
426 | 426 | ;; default |
427 | 427 | fsvn-svn-command-internal)) |
428 | 428 | |
429 | -(defun fsvn-get-version (command) | |
429 | +(defun fsvn-deps--command-information (command) | |
430 | + "Get command information by `svn --version` command." | |
430 | 431 | (with-temp-buffer |
431 | 432 | (fsvn-deps-process-environment |
432 | - ;;TODO 1.6.9 stderr "svn: warning: cannot set LC_CTYPE locale" | |
433 | - ;; not depend on fsvn-call-process | |
434 | - (process-file command nil (list (current-buffer) nil) nil "--version" "--quiet")) | |
435 | - (let ((raw-version (car (fsvn-text-buffer-line-as-list))) | |
436 | - version) | |
437 | - ;; trim "1.8.6-dev" like version | |
438 | - (unless (string-match "\\`\\([0-9]+\\.[0-9]+\\.[0-9]+\\)" raw-version) | |
439 | - (error "Unsupported version")) | |
440 | - (match-string 1 raw-version)))) | |
433 | + (process-file command nil (list (current-buffer) nil) nil "--version")) | |
434 | + (goto-char (point-min)) | |
435 | + (let (raw-version version functional-version | |
436 | + type cygwinp) | |
437 | + (unless (looking-at ".*version \\(\\([0-9.]+\\)\\(?:-dev\\)?\\)") | |
438 | + (error "Version not found")) | |
439 | + (setq raw-version (match-string 1)) | |
440 | + (setq version (match-string 2)) | |
441 | + (unless (string-match "\\`[0-9]+\\.[0-9]+" raw-version) | |
442 | + (error "Invalid version string")) | |
443 | + (setq functional-version (match-string 0 raw-version)) | |
444 | + (forward-line 1) | |
445 | + (if (looking-at "^ +compiled.*on \\([^\s\n]+\\)") | |
446 | + ;; ignore if not found not so important. | |
447 | + (setq type (match-string 1)) | |
448 | + (setq type "unknown")) | |
449 | + (setq cygwinp (and (string-match "cygwin" type) t)) | |
450 | + (list version functional-version raw-version | |
451 | + type cygwinp)))) | |
441 | 452 | |
442 | -(defun fsvn-get-ensure-version (command) | |
443 | - (let ((ver (fsvn-get-version command))) | |
453 | +(defun fsvn-deps--get-ensure-version (command) | |
454 | + (let* ((info (fsvn-deps--command-information command)) | |
455 | + (ver (nth 0 info))) | |
444 | 456 | (when (fboundp 'version<=) |
445 | 457 | (when (version<= ver "1.4") |
446 | 458 | (error "Svn command must be 1.5.x or later"))) |
447 | - ver)) | |
459 | + info)) | |
448 | 460 | |
449 | 461 | (defun fsvn-set-command-information () |
450 | 462 | ;; FIXME modified this variables value by `start-process' on windows NTEmacs 24.5 |
@@ -459,37 +471,49 @@ | ||
459 | 471 | (error "No executable \"%s\"" fsvn-svnadmin-command)) |
460 | 472 | (fsvn-add-command-location fsvn-svn-command-internal |
461 | 473 | fsvn-svnadmin-command-internal) |
462 | - (let ((ver (fsvn-get-ensure-version fsvn-svn-command-internal))) | |
463 | - (setq fsvn-svn-version ver))) | |
474 | + (let ((info (fsvn-deps--get-ensure-version fsvn-svn-command-internal))) | |
475 | + (setq fsvn-svn-version (nth 0 info)))) | |
464 | 476 | |
465 | 477 | (defun fsvn-add-command-location (svn-command &optional admin-command) |
466 | - (let ((bin (executable-find svn-command))) | |
467 | - (unless bin | |
478 | + (let ((svn-bin (executable-find svn-command)) | |
479 | + admin-bin) | |
480 | + (unless svn-bin | |
468 | 481 | (error "Not a svn executable")) |
469 | 482 | (unless admin-command |
470 | 483 | (let ((regexp (concat "\\`\\(.+?\\)" (regexp-opt exec-suffixes t) "?\\'"))) |
471 | - (unless (string-match regexp bin) | |
484 | + (unless (string-match regexp svn-bin) | |
472 | 485 | (error "Filename not matched (assert)")) |
473 | - (let ((base (match-string 1 bin)) | |
474 | - (suffix (match-string 2 bin))) | |
486 | + (let ((base (match-string 1 svn-bin)) | |
487 | + (suffix (match-string 2 svn-bin))) | |
475 | 488 | (setq admin-command (concat base "admin" suffix))))) |
476 | - (unless (executable-find admin-command) | |
489 | + (setq admin-bin (executable-find admin-command)) | |
490 | + (unless admin-bin | |
477 | 491 | (error "Not found a svnadmin executable")) |
478 | 492 | ;; detect command behavior |
479 | - (let* ((ver (fsvn-get-ensure-version svn-command)) | |
480 | - ;; key is Major.Minor version | |
481 | - (key (and (string-match "\\`[0-9]+\\.[0-9]+" ver) | |
482 | - (match-string 0 ver))) | |
483 | - (converter (fsvn-deps--guess-physical-path-converter | |
484 | - svn-command admin-command)) | |
485 | - (alist fsvn-svn-command-alist) | |
486 | - target) | |
487 | - (unless (setq target (assoc key alist)) | |
488 | - (setq target (cons key nil)) | |
489 | - (setq alist (cons target alist))) | |
490 | - (setcdr target (list bin converter)) | |
491 | - (setq fsvn-svn-command-alist alist) | |
492 | - ver))) | |
493 | + (let* ((svn-info (fsvn-deps--get-ensure-version svn-bin)) | |
494 | + (admin-info (fsvn-deps--get-ensure-version admin-bin)) | |
495 | + (svn-ver (nth 0 svn-info)) | |
496 | + (admin-ver (nth 0 admin-info))) | |
497 | + (unless (equal svn-ver admin-ver) | |
498 | + (error "Command version is differ svn:%s but svnadmin:%s" | |
499 | + svn-ver admin-ver)) | |
500 | + (let* ( | |
501 | + ;; key is Major.Minor version | |
502 | + (key (nth 1 svn-info)) | |
503 | + (path-converter (fsvn-deps--guess-physical-path-converter svn-bin admin-bin)) | |
504 | + (target-converter (if (nth 4 svn-info) ; cygwin | |
505 | + 'fsvn-cygwin-convert-target-file | |
506 | + nil)) | |
507 | + (alist fsvn-svn-command-alist) | |
508 | + target) | |
509 | + (unless (setq target (assoc key alist)) | |
510 | + (setq target (cons key nil)) | |
511 | + (setq alist (cons target alist))) | |
512 | + (setcdr target | |
513 | + (list svn-bin admin-bin | |
514 | + path-converter target-converter)) | |
515 | + (setq fsvn-svn-command-alist alist) | |
516 | + svn-ver)))) | |
493 | 517 | |
494 | 518 | (defun fsvn-build-subcommand (&optional force) |
495 | 519 | (mapc |
@@ -1226,7 +1250,7 @@ | ||
1226 | 1250 | |
1227 | 1251 | |
1228 | 1252 | |
1229 | -(defun fsvn-svn-fetch-physical-path-function (command) | |
1253 | +(defun fsvn-deps--fetch-command-behavior (command) | |
1230 | 1254 | ;; canonicalize |
1231 | 1255 | (setq command (expand-file-name command)) |
1232 | 1256 | (catch 'found |
@@ -1233,8 +1257,8 @@ | ||
1233 | 1257 | (let ((lis fsvn-svn-command-alist)) |
1234 | 1258 | (while lis |
1235 | 1259 | (let ((pair (car lis))) |
1236 | - (when (string= (nth 1 pair) command) | |
1237 | - (throw 'found (nth 2 pair))) | |
1260 | + (when (string= (expand-file-name (nth 1 pair)) command) | |
1261 | + (throw 'found pair)) | |
1238 | 1262 | (setq lis (cdr lis))))))) |
1239 | 1263 | |
1240 | 1264 | ;; cygwin version svn accept only "/" started filename not emacs path |
@@ -1241,24 +1265,39 @@ | ||
1241 | 1265 | ;; e.g. |
1242 | 1266 | ;; x c:/hoge/windows |
1243 | 1267 | ;; o /cygdrive/c/hoge/windows |
1244 | -(defun fsvn-command-args-to-physical-args (command args) | |
1245 | - (let ((ensurer (fsvn-svn-fetch-physical-path-function command))) | |
1246 | - (if (null ensurer) | |
1268 | +(defun fsvn-command-args-to-physical-args (svn-command args) | |
1269 | + (let* ((behavior (fsvn-deps--fetch-command-behavior svn-command)) | |
1270 | + (ensurer (nth 3 behavior)) | |
1271 | + (targets-converter (nth 4 behavior))) | |
1272 | + (if (and (null ensurer) | |
1273 | + (null targets-converter)) | |
1247 | 1274 | args |
1248 | - (mapcar | |
1249 | - (lambda (x) | |
1250 | - (cond | |
1251 | - ((fsvn-url-local-p x) | |
1252 | - (funcall ensurer x)) | |
1253 | - ((string-match "\\`\\(--[^=]+\\)=\\(.*\\)" x) | |
1254 | - (let ((option (match-string 1 x)) | |
1255 | - (path (match-string 2 x))) | |
1256 | - (if (fsvn-url-local-p path) | |
1257 | - (format "%s=%s" option (funcall ensurer path)) | |
1258 | - x))) | |
1259 | - (t | |
1260 | - x))) | |
1261 | - args)))) | |
1275 | + (let ((targetp nil)) | |
1276 | + (mapcar | |
1277 | + (lambda (x) | |
1278 | + (cond | |
1279 | + ((fsvn-url-local-p x) | |
1280 | + (when (and targetp targets-converter) | |
1281 | + (funcall targets-converter x)) | |
1282 | + (setq targetp nil) | |
1283 | + (cond | |
1284 | + (ensurer | |
1285 | + (funcall ensurer x)) | |
1286 | + (t x))) | |
1287 | + ((string-match "\\`\\(--[^=]+\\)=\\(.*\\)" x) | |
1288 | + (setq targetp nil) | |
1289 | + (let ((option (match-string 1 x)) | |
1290 | + (path (match-string 2 x))) | |
1291 | + (if (fsvn-url-local-p path) | |
1292 | + (format "%s=%s" option (funcall ensurer path)) | |
1293 | + x))) | |
1294 | + ((string= "--targets" x) | |
1295 | + (setq targetp t) | |
1296 | + x) | |
1297 | + (t | |
1298 | + (setq targetp nil) | |
1299 | + x))) | |
1300 | + args))))) | |
1262 | 1301 | |
1263 | 1302 | |
1264 | 1303 |
@@ -24,8 +24,6 @@ | ||
24 | 24 | (defvar diff-switches) |
25 | 25 | (defvar current-prefix-arg) |
26 | 26 | |
27 | -(defvar fsvn-targets-file-converter) | |
28 | - | |
29 | 27 | |
30 | 28 | |
31 | 29 | (defun fsvn-win-x64-p () |
@@ -206,13 +204,13 @@ | ||
206 | 204 | (defun fsvn-cygwin-guessed-installed () |
207 | 205 | (fsvn-cygwin-installed-folder)) |
208 | 206 | |
209 | -(defvar fsvn-cygwin-svn-p nil) | |
210 | -(defun fsvn-cygwin-svn-p () | |
211 | - (let ((command (executable-find fsvn-svn-command-internal)) | |
212 | - (cygdir (fsvn-cygwin-installed-dir))) | |
213 | - (and command | |
214 | - cygdir | |
215 | - (string-match (concat "\\`" (regexp-quote cygdir)) command)))) | |
207 | +(defun fsvn-cygwin-svn-p (&optional command) | |
208 | + (fsvn-let* | |
209 | + ((filename (or command fsvn-svn-command-internal)) | |
210 | + (command-path (executable-find filename)) | |
211 | + (cygdir (fsvn-cygwin-installed-dir)) | |
212 | + ((string-match (concat "\\`" (regexp-quote cygdir)) command-path))) | |
213 | + t)) | |
216 | 214 | |
217 | 215 | (defun fsvn-cygwin-expand-path (name &optional default) |
218 | 216 | (let ((inst-dir fsvn-cygwin-installed-dir) |
@@ -261,32 +259,43 @@ | ||
261 | 259 | (setq fsvn-url-filename-expand-function 'fsvn-win-expand-file) |
262 | 260 | |
263 | 261 | ;; cygwin svn `--targets' arg accept only cygpath |
264 | -(defun fsvn-win-targets-file-converter (x) | |
265 | - (fsvn-cygwin-expand-path x)) | |
262 | +;; It is not so high cost re-generate target file, I think.. | |
263 | +(defun fsvn-cygwin-convert-target-file (file) | |
264 | + (with-temp-buffer | |
265 | + (let ((coding-system-for-read (fsvn-file-name-coding-system))) | |
266 | + (insert-file-contents file)) | |
267 | + (goto-char (point-min)) | |
268 | + (while (not (eobp)) | |
269 | + (let ((file (buffer-substring (point-at-bol) (point-at-eol)))) | |
270 | + (delete-region (point-at-bol) (point-at-eol)) | |
271 | + (insert (fsvn-cygwin-ensure-physical-path file)) | |
272 | + (forward-line 1))) | |
273 | + (let ((coding-system-for-write (fsvn-file-name-coding-system))) | |
274 | + (write-region (point-min) (point-max) file nil 'no-msg)))) | |
266 | 275 | |
267 | 276 | (defun fsvn-win-initialize-loading () |
268 | - (setq fsvn-cygwin-svn-p (fsvn-cygwin-svn-p)) | |
269 | 277 | ;; Update cygwin settings |
270 | 278 | ;; FIXME: about after install/reinstall/uninstall cygwin |
271 | 279 | (setq fsvn-cygwin-installed-folder (fsvn-cygwin-installed-folder) |
272 | 280 | fsvn-cygwin-guessed-installed (fsvn-cygwin-guessed-installed) |
273 | 281 | fsvn-cygwin-installed-dir (fsvn-cygwin-installed-dir) |
274 | - fsvn-cygwin-drive-prefix-dir (fsvn-cygwin-drive-prefix-dir)) | |
275 | - (cond | |
276 | - (fsvn-cygwin-svn-p | |
277 | - (setq fsvn-targets-file-converter 'fsvn-win-targets-file-converter | |
278 | - fsvn-password-prompt-accessible-p t)) | |
282 | + fsvn-cygwin-drive-prefix-dir (fsvn-cygwin-drive-prefix-dir))) | |
283 | + | |
284 | +(defun fsvn-win-after-initialize-loading () | |
285 | + (cond | |
286 | + ;; FIXME this is only works default svn-command | |
287 | + ;; Currently `fsvn-authenticate-repository' is a function | |
288 | + ;; only use this variable (`fsvn-password-prompt-accessible-p') | |
289 | + ((fsvn-cygwin-svn-p) | |
290 | + (setq fsvn-password-prompt-accessible-p t)) | |
279 | 291 | (t |
280 | - (setq fsvn-targets-file-converter nil | |
281 | - fsvn-password-prompt-accessible-p nil)))) | |
292 | + (setq fsvn-password-prompt-accessible-p nil)))) | |
282 | 293 | |
283 | -(setq fsvn-initialize-function 'fsvn-win-initialize-loading) | |
294 | +(add-hook 'fsvn--initialize-hook 'fsvn-win-initialize-loading) | |
295 | +(add-hook 'fsvn--after-initialize-hook 'fsvn-win-after-initialize-loading) | |
284 | 296 | |
285 | 297 | |
286 | 298 | |
287 | -(defun fsvn-win-enable-password-prompt () | |
288 | - fsvn-cygwin-svn-p) | |
289 | - | |
290 | 299 | (defun fsvn-win-authenticate-repository (repository) |
291 | 300 | (fsvn-win-start-external-terminal fsvn-svn-command-internal "info" repository)) |
292 | 301 |