mirror of
https://github.com/dimitri/el-get.git
synced 2024-09-29 04:58:53 +08:00
659 lines
22 KiB
EmacsLisp
659 lines
22 KiB
EmacsLisp
;;; el-get.el
|
||
;;
|
||
;; Manage the external elisp bits and pieces you depend upon
|
||
;;
|
||
;; Copyright (C) 2010 Dimitri Fontaine
|
||
;;
|
||
;; Author: Dimitri Fontaine <dim@tapoueh.org>
|
||
;; URL: http://www.emacswiki.org/emacs/el-get.el
|
||
;; Version: 0.3
|
||
;; Created: 2010-06-17
|
||
;; Keywords: emacs package elisp install elpa git apt-get fink debian macosx
|
||
;; Licence: WTFPL, grab your copy here: http://sam.zoy.org/wtfpl/
|
||
;;
|
||
;; This file is NOT part of GNU Emacs.
|
||
;;
|
||
;; Install:
|
||
;; 1. Install ELPA, see http://tromey.com/elpa/install.html
|
||
;; 2. (require 'el-get)
|
||
;; 3. then define your el-get-sources
|
||
;; 4. Use (el-get) from your .emacs or M-x el-get-install etc.
|
||
;;
|
||
|
||
(require 'dired)
|
||
(require 'package nil t) ; that's ELPA, but you can use el-get to install it
|
||
|
||
(defgroup el-get nil "el-get customization group"
|
||
:group 'convenience)
|
||
|
||
(defvar el-get-git-clone-hook nil "Hook run after git clone.")
|
||
(defvar el-get-git-svn-clone-hook nil "Hook run after git svn clone.")
|
||
(defvar el-get-apt-get-install-hook nil "Hook run after apt-get install.")
|
||
(defvar el-get-fink-install-hook nil "Hook run after fink install.")
|
||
(defvar el-get-elpa-install-hook nil "Hook run after ELPA package install.")
|
||
(defvar el-get-http-install-hook nil "Hook run after http retrieve.")
|
||
|
||
(defcustom el-get-methods
|
||
'(:git (:install el-get-git-clone
|
||
:install-hook el-get-git-clone-hook
|
||
:update el-get-git-pull
|
||
:remove el-get-rmdir)
|
||
:git-svn (:install el-get-git-svn-clone
|
||
:install-hook el-get-git-svn-clone-hook
|
||
:update el-get-git-svn-update
|
||
:remove el-get-rmdir)
|
||
:apt-get (:install el-get-apt-get-install
|
||
:install-hook el-get-apt-get-install-hook
|
||
:update el-get-apt-get-install
|
||
:remove el-get-apt-get-remove)
|
||
:fink (:install el-get-fink-install
|
||
:install-hook el-get-fink-install-hook
|
||
:update el-get-fink-install
|
||
:remove el-get-fink-remove)
|
||
:elpa (:install el-get-elpa-install
|
||
:install-hook el-get-elpa-install-hook
|
||
:update el-get-elpa-update
|
||
:remove el-get-rmdir)
|
||
:http (:install el-get-http-install
|
||
:install-hook el-get-http-install-hook
|
||
:update el-get-http-install
|
||
:remove el-get-rmdir))
|
||
"Register methods that el-get can use to fetch and update a given package.
|
||
|
||
The methods list is a PLIST, each entry has a method name
|
||
property which value is another PLIST, which must contain values
|
||
for :install, :install-hook, :update and :remove
|
||
properties. Those should be the elisp functions to call for doing
|
||
the named package action in the given method."
|
||
:type '(repeat (cons symbol function))
|
||
:group 'el-get)
|
||
|
||
(defvar el-get-dir "~/.emacs.d/el-get/"
|
||
"Define where to fetch the packages.")
|
||
|
||
(defvar el-get-apt-get (executable-find "apt-get")
|
||
"The apt-get executable.")
|
||
|
||
(defvar el-get-apt-get-base "/usr/share/emacs/site-lisp"
|
||
"Where to link the el-get symlink to, /<package> will get appended.")
|
||
|
||
(defvar el-get-fink (executable-find "fink")
|
||
"The fink executable.")
|
||
|
||
(defvar el-get-fink-base "/sw/share/doc"
|
||
"Where to link the el-get symlink to, /<package> will get appended.")
|
||
|
||
;; debian uses ginstall-info and it's compatible to fink's install-info on
|
||
;; MacOSX, so:
|
||
(defvar el-get-install-info (or (executable-find "ginstall-info")
|
||
(executable-find "install-info")))
|
||
|
||
(defvar el-get-sources nil
|
||
"List of sources for packages.
|
||
|
||
Each source entry is a PLIST where the following properties are supported:
|
||
|
||
name
|
||
|
||
The name of the package. It can be different from the name of
|
||
the directory where the package is stored (after a `git
|
||
clone' for example, in which case a symlink will be created.
|
||
|
||
type
|
||
|
||
The type of the package, currently el-get offers support for
|
||
`apt-get', `elpa', `git' and `http'. You can easily support
|
||
your own types here, see the variable `el-get-methods'.
|
||
|
||
url
|
||
|
||
Where to fetch the package, only meaningful for `git' and `http' types.
|
||
|
||
build
|
||
|
||
Your build recipe gets there, often it looks like (\"./configure\" \"make\")
|
||
|
||
load-path
|
||
|
||
This should be a list of directories you want `el-get' to add
|
||
to your `load-path'.
|
||
|
||
info
|
||
|
||
This string allows you to setup a directory where to find a
|
||
'package.info' file, or a path/to/whatever.info file. It will
|
||
even run `ginstall-info' for you to create the `dir' entry so
|
||
that C-h i will be able to list the newly installed
|
||
documentation. Note that you might need to kill (C-x k) your
|
||
info buffer then C-h i again to be able to see the new menu
|
||
entry.
|
||
|
||
load
|
||
|
||
List of files to load, or a single file to load after having
|
||
installed the source but before `require'ing its features.
|
||
|
||
features
|
||
|
||
List of features el-get will `require' for you.
|
||
")
|
||
|
||
|
||
(defun el-get-method (method-name action)
|
||
"return the function to call for doing action (e.g. install) in given method"
|
||
(let* ((method (intern-soft (concat ":" (format "%s" method-name))))
|
||
(actions (plist-get el-get-methods method)))
|
||
(plist-get actions action)))
|
||
|
||
(defun el-get-check-init ()
|
||
"Check that we can run el-get"
|
||
(unless (file-directory-p el-get-dir)
|
||
(make-directory el-get-dir)))
|
||
|
||
(defun el-get-package-directory (package)
|
||
"Returns the package installation directory absolute name"
|
||
(concat (file-name-as-directory el-get-dir) package))
|
||
|
||
(defun el-get-add-path-to-list (package list path)
|
||
"(add-to-list list path) checking for path existence within
|
||
given package directory."
|
||
(let* ((pdir (el-get-package-directory package))
|
||
(fullpath (expand-file-name (concat (file-name-as-directory pdir) path))))
|
||
(unless (file-directory-p fullpath)
|
||
(error "el-get could not find directory `%s' for package %s" path package))
|
||
(add-to-list list fullpath)))
|
||
|
||
(defun el-get-package-exists-p (package)
|
||
"true only when the given package name is either a directory or a symlink in el-get-dir"
|
||
(let ((pdir (el-get-package-directory package)))
|
||
;; seems overkill as file-directory-p will always be true
|
||
(or (file-directory-p pdir)
|
||
(file-symlink-p pdir))))
|
||
|
||
|
||
;;
|
||
;; call-process-list utility, to do same as bash && feature
|
||
;;
|
||
(defun el-get-call-process-list-sentinel (proc change)
|
||
"When proc has exited and was successful, chain next command"
|
||
(when (eq (process-status proc) 'exit)
|
||
(let ((status (process-exit-status proc))
|
||
(cname (process-get proc :command-name))
|
||
(cbuf (process-get proc :buffer-name))
|
||
(message (process-get proc :message))
|
||
(errorm (process-get proc :error))
|
||
(package (process-get proc :el-get-package))
|
||
(final-f (process-get proc :el-get-final-func))
|
||
(next (process-get proc :el-get-call-process-list)))
|
||
(if (not (eq 0 status))
|
||
(progn
|
||
(set-window-buffer (selected-window) cbuf)
|
||
(error "el-get: %s" cname errorm))
|
||
(message "el-get: %s" message))
|
||
|
||
(when cbuf (kill-buffer cbuf))
|
||
(if next
|
||
(el-get-call-process-list package next final-f)
|
||
(funcall final-f package)))))
|
||
|
||
(defun el-get-call-process-list (package commands final-func)
|
||
"run each command one after the other, in order, stopping at
|
||
first error.
|
||
|
||
commands should be a list of plists with at least the following
|
||
properties:
|
||
|
||
:default-directory
|
||
|
||
default-directory from where to start the command
|
||
|
||
:command-name
|
||
|
||
Name of the command to start, gives the name of the Emacs subprocess.
|
||
|
||
:buffer-name
|
||
|
||
Name of the buffer associated with the command.
|
||
|
||
:program
|
||
|
||
The program to start
|
||
|
||
:args
|
||
|
||
The list of arguments for the program to start
|
||
|
||
:message
|
||
|
||
The message to send upon success
|
||
|
||
:error
|
||
|
||
The error to send upon failure
|
||
|
||
Any other property will get put into the process object.
|
||
"
|
||
(let* ((c (car commands))
|
||
(cdir (plist-get c :default-directory))
|
||
(cname (plist-get c :command-name))
|
||
(cbuf (plist-get c :buffer-name))
|
||
(killed (when (get-buffer cbuf) (kill-buffer cbuf)))
|
||
(program (plist-get c :program))
|
||
(args (plist-get c :args))
|
||
(default-directory (if cdir (file-name-as-directory cdir)
|
||
default-directory))
|
||
(proc (apply 'start-process cname cbuf program args)))
|
||
|
||
;; add the properties to the process, then set the sentinel
|
||
(mapc (lambda (x) (process-put proc x (plist-get c x))) c)
|
||
(process-put proc :el-get-package package)
|
||
(process-put proc :el-get-final-func final-func)
|
||
(process-put proc :el-get-call-process-list (cdr commands))
|
||
(set-process-sentinel proc 'el-get-call-process-list-sentinel)))
|
||
|
||
|
||
;;
|
||
;; git support
|
||
;;
|
||
(defun el-get-git-executable ()
|
||
"return git executable to use, or signal an error when not found"
|
||
(let ((git-executable (if (file-executable-p magit-git-executable)
|
||
magit-git-executable
|
||
(executable-find "git"))))
|
||
(unless (file-executable-p git-executable)
|
||
(error
|
||
(concat "el-get-git-clone requires `magit-git-executable' to be set, "
|
||
"or the binary `git' to be found in your PATH")))
|
||
git-executable))
|
||
|
||
(defun el-get-git-clone (package url)
|
||
"clone the given package following the url"
|
||
(let* ((git-executable (el-get-git-executable))
|
||
(ret
|
||
(shell-command-to-string
|
||
(format "cd %s && %s --no-pager clone %s %s"
|
||
el-get-dir git-executable url package))))
|
||
(run-hooks 'el-get-git-clone-hook)
|
||
ret))
|
||
|
||
(defun el-get-git-pull (package url)
|
||
"git pull the package"
|
||
(let ((pdir (el-get-package-directory package)))
|
||
(when (file-directory-p pdir)
|
||
(shell-command-to-string
|
||
(concat "cd " pdir
|
||
" && " magit-git-executable " --no-pager pull " url)))))
|
||
|
||
|
||
;;
|
||
;; git-svn support
|
||
;;
|
||
(defun el-get-git-svn-clone (package url post-install-fun)
|
||
"Clone the given svn PACKAGE following the URL using git."
|
||
(let ((git-executable (el-get-git-executable))
|
||
(name (format "*git svn clone %s*" package))
|
||
(ok (format "Package %s installed." package))
|
||
(ko (format "Could not install package %s." package)))
|
||
|
||
(el-get-call-process-list
|
||
package
|
||
`((:command-name ,name
|
||
:buffer-name ,name
|
||
:default-directory ,el-get-dir
|
||
:program ,git-executable
|
||
:args ( "--no-pager" "svn" "clone" ,url ,package)
|
||
:message ,ok
|
||
:error ,ko))
|
||
post-install-fun)))
|
||
|
||
(defun el-get-git-svn-update (package url post-update-fun)
|
||
"Update PACKAGE using git-svn. URL is given for compatibility reasons."
|
||
(let ((git-executable (el-get-git-executable))
|
||
(pdir (el-get-package-directory package))
|
||
(f-name (format "*git svn fetch %s*" package))
|
||
(f-ok (format "Fetched package %s." package))
|
||
(f-ko (format "Could not fetch package %s." package))
|
||
(r-name (format "*git svn rebase %s*" package))
|
||
(r-ok (format "Rebased package %s." package))
|
||
(r-ko (format "Could not rebase package %s." package)))
|
||
|
||
(el-get-call-process-list
|
||
package
|
||
`((:command-name ,f-name
|
||
:buffer-name ,f-name
|
||
:default-directory ,pdir
|
||
:program ,git-executable
|
||
:args ("--no-pager" "svn" "fetch")
|
||
:message ,f-ok
|
||
:error ,f-ko)
|
||
|
||
(:command-name ,r-name
|
||
:buffer-name ,r-name
|
||
:default-directory ,pdir
|
||
:program ,git-executable
|
||
:args ("--no-pager" "svn" "rebase")
|
||
:message ,r-ok
|
||
:error ,r-ko))
|
||
post-update-fun)))
|
||
|
||
|
||
;;
|
||
;; apt-get support
|
||
;;
|
||
(defun el-get-sudo-shell-command-to-string (command)
|
||
"Ask a password then use sudo, when required"
|
||
(let* ((sudo-test (shell-command-to-string "sudo echo el-get"))
|
||
(sudo-pass (if (string= sudo-test "el-get\n")
|
||
nil
|
||
(read-passwd "sudo password: "))))
|
||
(shell-command-to-string
|
||
(concat (when sudo-pass (concat "echo " sudo-pass " | "))
|
||
"sudo -S " command))))
|
||
|
||
(defun el-get-apt-get-symlink (basedir package)
|
||
"ln -s /usr/share/emacs/site-lisp/package ~/.emacs.d/el-get/package"
|
||
(let ((debdir (concat (file-name-as-directory basedir) package)))
|
||
(shell-command
|
||
(concat "cd " el-get-dir " && ln -s " debdir " " package))))
|
||
|
||
(defun el-get-apt-get-package-status (package)
|
||
"returns the package status from dpkg --get-selections"
|
||
(substring
|
||
(shell-command-to-string
|
||
(format
|
||
"dpkg -l %s| awk '/^ii/ && $2 = \"%s\" {print \"ok\"}'" package package)) 0 -1))
|
||
|
||
(defun el-get-apt-get-install (package &optional url)
|
||
"apt-get install package, url is there for API compliance"
|
||
;; this can be somewhat chatty but I guess you want to know about it
|
||
(message "%S" (el-get-sudo-shell-command-to-string
|
||
(concat el-get-apt-get " install " package)))
|
||
(unless (string= (el-get-apt-get-package-status package) "install")
|
||
(error "Error: apt-get reports package %s status is not \"install\"" package))
|
||
(el-get-apt-get-symlink el-get-apt-get-base package)
|
||
(run-hooks 'el-get-apt-get-install-hook)
|
||
nil)
|
||
|
||
(defun el-get-apt-get-remove (package &optional url)
|
||
"apt-get remove package, url is there for API compliance"
|
||
;; this can be somewhat chatty but I guess you want to know about it
|
||
(message "%S" (el-get-sudo-shell-command-to-string
|
||
(concat el-get-apt-get " remove -y " package))))
|
||
|
||
|
||
;;
|
||
;; fink support
|
||
;;
|
||
(defun el-get-fink-install (package &optional url)
|
||
"fink install package, url is there for API compliance"
|
||
;; this can be somewhat chatty but I guess you want to know about it
|
||
(message "%S" (el-get-sudo-shell-command-to-string
|
||
(concat el-get-fink " install " package)))
|
||
(unless (string= (el-get-apt-get-package-status package) "ok")
|
||
(error "Error: fink reports package %s status is not \"ok\"" package))
|
||
(el-get-apt-get-symlink el-get-fink-base package)
|
||
(run-hooks 'el-get-fink-install-hook)
|
||
nil)
|
||
|
||
(defun el-get-fink-remove (package &optional url)
|
||
"fink remove package, url is there for API compliance"
|
||
;; this can be somewhat chatty but I guess you want to know about it
|
||
(message "%S" (el-get-sudo-shell-command-to-string
|
||
(concat el-get-fink " remove -r " package))))
|
||
|
||
|
||
;;
|
||
;; ELPA support
|
||
;;
|
||
(defun el-get-elpa-package-directory (package)
|
||
"return the directory where ELPA stores a 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 "
|
||
(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-symlink-package (package)
|
||
"ln -s ~/.emacs.d/elpa/<package> ~/.emacs.d/el-get/<package>"
|
||
(let ((elpa-dir (el-get-elpa-package-directory package)))
|
||
(unless (el-get-package-exists-p package)
|
||
(shell-command
|
||
(concat "cd " el-get-dir
|
||
" && ln -s \"" elpa-dir "\" \"" package "\"")))))
|
||
|
||
(defun el-get-elpa-install (package &optional url)
|
||
"ask elpa to install given package"
|
||
(let ((elpa-dir (el-get-elpa-package-directory package)))
|
||
(unless (and elpa-dir (file-directory-p elpa-dir))
|
||
(package-install (intern-soft 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)))
|
||
|
||
(defun el-get-elpa-update (package &optional url)
|
||
"ask elpa to update given package"
|
||
(el-get-rmdir (concat (file-name-as-directory package-user-dir) package))
|
||
(package-install (intern-soft package)))
|
||
|
||
|
||
;;
|
||
;; http support
|
||
;;
|
||
(defun el-get-http-retrieve (package url)
|
||
"Get an elisp file using `url-retrieve-synchronously'.
|
||
|
||
Returns the feature provided if any"
|
||
(let* ((pdir (el-get-package-directory package))
|
||
(dest (concat (file-name-as-directory pdir) package ".el")))
|
||
(with-current-buffer (url-retrieve-synchronously url)
|
||
;; prune HTTP headers before save
|
||
(beginning-of-buffer)
|
||
(re-search-forward "^$" nil 'move)
|
||
(forward-char)
|
||
(delete-region (point-min) (point))
|
||
(write-file dest))))
|
||
|
||
(defun el-get-http-install (package url)
|
||
"Dowload a single-file package over HTTP "
|
||
(let ((pdir (el-get-package-directory package)))
|
||
(unless (file-directory-p pdir)
|
||
(make-directory pdir))
|
||
(el-get-http-retrieve package url)))
|
||
|
||
;;
|
||
;; Common support bits
|
||
;;
|
||
(defun el-get-rmdir (package url)
|
||
"Just rm -rf the package directory. Follow symlinks."
|
||
(dired-delete-file (el-get-package-directory package) 'always))
|
||
|
||
(defun el-get-build (package commands &optional subdir)
|
||
"run each command from the package directory"
|
||
(let* ((pdir (el-get-package-directory package))
|
||
(wdir (if subdir (concat (file-name-as-directory pdir) subdir) pdir)))
|
||
(dolist (c commands)
|
||
(message "el-get %s: cd %s && %s" package wdir c)
|
||
(message "%S" (shell-command-to-string
|
||
(concat "cd " wdir " && " c))))))
|
||
|
||
(defun el-get-package-def (package)
|
||
"Return a single `el-get-sources' entry for given package"
|
||
(dolist (s el-get-sources source)
|
||
(when (string= package (format "%s" (plist-get s :name)))
|
||
(setq source s))))
|
||
|
||
|
||
;;
|
||
;; User Interface, Interactive part
|
||
;;
|
||
(defun el-get-read-package-name (action &optional package)
|
||
"Ask user for a package name in minibuffer, with completion.
|
||
|
||
When given a package name, check for its existence"
|
||
(let ((plist
|
||
(mapcar (lambda (x) (format "%s" (plist-get x :name))) el-get-sources)))
|
||
(if package
|
||
(unless (member package plist)
|
||
(error "el-get: can not find package name `%s' in `el-get-sources'" package))
|
||
(completing-read (format "%s package: " action) plist))))
|
||
|
||
(defun el-get-init (&optional package)
|
||
"Care about load-path, Info-directory-list, and (require 'features)"
|
||
(interactive)
|
||
(let* ((package (or package (el-get-read-package-name "Init" package)))
|
||
(source (el-get-package-def package))
|
||
(method (plist-get source :type))
|
||
(loads (plist-get source :load))
|
||
(feats (plist-get source :features))
|
||
(el-path (or (plist-get source :load-path) '(".")))
|
||
(infodir (plist-get source :info))
|
||
(pdir (el-get-package-directory package)))
|
||
|
||
;; apt-get and ELPA will take care of load-path, Info-directory-list
|
||
(unless (member method '(elpa apt-get))
|
||
;; append entries to load-path and Info-directory-list
|
||
(mapc (lambda (path)
|
||
(el-get-add-path-to-list package 'load-path path))
|
||
(if (stringp el-path) (list el-path) el-path))
|
||
|
||
(let* ((infodir-abs-conf (concat (file-name-as-directory pdir) infodir))
|
||
(infodir-abs (if (file-directory-p infodir-abs-conf)
|
||
infodir-abs-conf
|
||
(file-name-directory infodir-abs-conf)))
|
||
(infodir-rel (if (file-directory-p infodir-abs-conf)
|
||
infodir
|
||
(file-name-directory infodir)))
|
||
(infofile (if (and (file-exists-p infodir-abs-conf)
|
||
(not (file-directory-p infodir-abs-conf)))
|
||
infodir-abs-conf
|
||
(concat (file-name-as-directory infodir-abs) package))))
|
||
|
||
(when (and infodir (file-directory-p infodir-abs))
|
||
(require 'info)
|
||
(info-initialize)
|
||
;; add to Info-directory-list
|
||
(el-get-add-path-to-list package 'Info-directory-list infodir-rel)
|
||
;; build the infodir entry, too
|
||
(el-get-build
|
||
package
|
||
`(,(format "%s %s.info dir" el-get-install-info infofile)) infodir-rel))))
|
||
|
||
;; loads
|
||
(when loads
|
||
(mapc (lambda (file)
|
||
(let ((pfile (concat (file-name-as-directory pdir) file)))
|
||
(unless (file-exists-p pfile)
|
||
(error "el-get could not find file '%s'" pfile))
|
||
(message "load '%s'" pfile)
|
||
(load pfile)))
|
||
(if (stringp loads) (list loads) loads)))
|
||
|
||
;; features, only ELPA will handle them on its own
|
||
(unless (eq method 'elpa)
|
||
;; if a feature is provided, require it now
|
||
(when feats
|
||
(mapc (lambda (feature) (message "require '%s" (require feature)))
|
||
(if (symbolp feats) (list feats) feats))))
|
||
|
||
;; return the package
|
||
package))
|
||
|
||
(defun el-get-post-install (package)
|
||
"Post install a package. This will get run by a sentinel."
|
||
(let* ((source (el-get-package-def package))
|
||
(hooks (el-get-method (plist-get source :type) :install-hook))
|
||
(commands (plist-get source :build)))
|
||
;; post-install is the right place to run install-hook
|
||
(run-hooks hooks)
|
||
;; consider building when sources are thus setup
|
||
(el-get-build package commands)
|
||
;; and init
|
||
(el-get-init package)))
|
||
|
||
(defun el-get-install (&optional package)
|
||
"Install given package. Read the package name with completion when not given."
|
||
(interactive)
|
||
(let* ((package (or package (el-get-read-package-name "Install" package)))
|
||
(source (el-get-package-def package))
|
||
(method (plist-get source :type))
|
||
(install (el-get-method method :install))
|
||
(url (plist-get source :url)))
|
||
|
||
;; check we can install the package
|
||
(el-get-check-init)
|
||
|
||
;; and install the package now
|
||
(message "el-get install %s" package)
|
||
(funcall install package url 'el-get-post-install)))
|
||
|
||
(defun el-get-post-update (package)
|
||
"Post update a package. This will get run by a sentinel."
|
||
(let* ((source (el-get-package-def package))
|
||
(commands (plist-get (plist-get source :type) :build)))
|
||
(el-get-build package commands)))
|
||
|
||
(defun el-get-update (&optional package)
|
||
"Update given package. Read the package name with completion when not given."
|
||
(interactive)
|
||
(let* ((package (or package (el-get-read-package-name "Install" package)))
|
||
(source (el-get-package-def package))
|
||
(method (plist-get source :type))
|
||
(update (el-get-method method :update))
|
||
(url (plist-get source :url))
|
||
(commands (plist-get source :build)))
|
||
;; update the package now
|
||
(message "el-get update %s" package)
|
||
(funcall update package url 'el-get-post-update)))
|
||
|
||
(defun el-get-remove (&optional package)
|
||
"Remove given package. Read the package name with completion when not given."
|
||
(interactive)
|
||
(let* ((package (or package (el-get-read-package-name "Install" package)))
|
||
(source (el-get-package-def package))
|
||
(method (plist-get source :type))
|
||
(remove (el-get-method method :remove))
|
||
(url (plist-get source :url)))
|
||
;; remove the package now
|
||
(message "el-get remove %s" package)
|
||
(funcall remove package url)))
|
||
|
||
|
||
;;
|
||
;; User Interface, Non Interactive part
|
||
;;
|
||
(defun el-get ()
|
||
"Check that all sources have been downloaded once, and init them as needed.
|
||
|
||
This will not update the sources by using `apt-get install' or
|
||
`git pull', but it will ensure the sources have been installed
|
||
and will set the load-path and Info-directory-list depending on
|
||
the el-get-sources setup.
|
||
|
||
el-get is also responsible for doing (require 'feature) for each
|
||
and every feature declared in `el-get-sources', so that it's
|
||
suitable for use in your emacs init script.
|
||
"
|
||
(mapcar
|
||
(lambda (source)
|
||
(let* ((package (format "%s" (plist-get source :name))))
|
||
;; check if the package needs to be fetched (and built)
|
||
(if (el-get-package-exists-p package)
|
||
(el-get-init package)
|
||
(el-get-install package))))
|
||
el-get-sources))
|
||
|
||
(provide 'el-get)
|