;;; el-get --- Manage the external elisp bits and pieces you depend upon ;; ;; Copyright (C) 2010-2011 Dimitri Fontaine ;; ;; Author: Dimitri Fontaine ;; URL: http://www.emacswiki.org/emacs/el-get ;; GIT: https://github.com/dimitri/el-get ;; Licence: WTFPL, grab your copy here: http://sam.zoy.org/wtfpl/ ;; ;; This file is NOT part of GNU Emacs. ;; ;; Install ;; Please see the README.asciidoc file from the same distribution (require 'el-get-core) (require 'package nil t) (defcustom el-get-elpa-install-hook nil "Hook run after ELPA package install." :group 'el-get :type 'hook) (defcustom el-get-elpa-remove-hook nil "Hook run after ELPA package remove." :group 'el-get :type 'hook) (defun el-get-elpa-package-directory (package) "Return the directory where ELPA stores PACKAGE, or nil if PACKAGE isn't currently installed by ELPA." (let* ((pname (format "%s" package)) ; easy way to cope with symbols etc. (l ;; we use try-completion to find the realname of the directory ;; ELPA used, and this wants an alist, we trick ls -i -1 into ;; that. (mapcar 'split-string (split-string (shell-command-to-string (concat "ls -i1 " (expand-file-name (file-name-as-directory package-user-dir))))))) (realname (try-completion pname l))) (if realname (concat (file-name-as-directory package-user-dir) realname) realname))) (defun el-get-elpa-package-repo (package) "Get the ELPA repository cons cell for PACKAGE. The cons cell has the form (NAME . URL). See `package-archives'. If the package source only specifies a URL, the URL will be used for NAME as well. If PACKAGE's `:type' is not \"elpa\", or no repo is specified in the recipe, then return nil." (let* ((source (el-get-package-def package)) (type (el-get-package-type source)) (elpa-repo (plist-get source :repo))) (when (and (eq type 'elpa) elpa-repo) (cond ((stringp elpa-repo) (cons elpa-repo elpa-repo)) ((consp elpa-repo) (if (and (stringp (car elpa-repo)) (stringp (cdr elpa-repo))) elpa-repo (error "Invalid elpa repo spec: %s" elpa-repo))) (t (error "Invalid elpa repo spec: %s" elpa-repo)))))) (defun el-get-elpa-symlink-package (package) "ln -s ../elpa/ ~/.emacs.d/el-get/" (let ((elpa-dir (file-relative-name (el-get-elpa-package-directory package) el-get-dir))) (unless (el-get-package-exists-p package) ;; better style would be to check for (fboundp 'make-symbolic-link) but ;; that would be true on Vista, where by default only administrator is ;; granted to use the feature --- so hardcode those systems out (if (memq system-type '(ms-dos windows-nt)) ;; the symlink is a docs/debug feature, mkdir is ok enough (make-directory (el-get-package-directory package)) (message "%s" (shell-command (concat "cd " el-get-dir " && ln -s \"" elpa-dir "\" \"" package "\""))))))) (defun el-get-elpa-install (package url post-install-fun) "Ask elpa to install given PACKAGE." (let* ((elpa-dir (el-get-elpa-package-directory package)) (elpa-repo (el-get-elpa-package-repo package)) ;; Set `package-archive-base' to elpa-repo for old package.el (package-archive-base (or (cdr-safe elpa-repo) (bound-and-true-p package-archive-base))) ;; Prepend elpa-repo to `package-archives' for new package.el (package-archives (append (when elpa-repo (list elpa-repo)) (when (boundp 'package-archives) package-archives)))) (unless (and elpa-dir (file-directory-p elpa-dir)) ;; Make sure we have got *some* kind of record of the package archive. ;; TODO: should we refresh and retry once if package-install fails? (let ((p (if (fboundp 'package-read-all-archive-contents) (package-read-all-archive-contents) ; version from emacs24 (package-read-archive-contents))) ; old version ;; package-install generates autoloads, byte compiles emacs-lisp-mode-hook fundamental-mode-hook prog-mode-hook) (unless p (package-refresh-contents))) (package-install (intern package))) ;; we symlink even when the package already is installed because it's ;; not an error to have installed ELPA packages before using el-get, and ;; that will register them (el-get-elpa-symlink-package package)) (funcall post-install-fun package)) (defun el-get-elpa-update (package url post-update-fun) "Ask elpa to update given PACKAGE." (el-get-elpa-remove package url nil) (package-refresh-contents) (package-install (intern package)) (funcall post-update-fun package)) (defun el-get-elpa-remove (package url post-remove-fun) "Remove the right directory where ELPA did install the package." (el-get-rmdir package url post-remove-fun)) (defun el-get-elpa-post-remove (package) "Do remove the ELPA bits for package, now" (let ((p-elpa-dir (el-get-elpa-package-directory package))) (if p-elpa-dir (dired-delete-file p-elpa-dir 'always) (message "el-get: could not find ELPA dir for %s." package)))) (add-hook 'el-get-elpa-remove-hook 'el-get-elpa-post-remove) (el-get-register-method :elpa #'el-get-elpa-install #'el-get-elpa-update #'el-get-elpa-remove #'el-get-elpa-install-hook #'el-get-elpa-remove-hook) (provide 'el-get-elpa)