Commit 0433ca0c authored by Dimitri Fontaine's avatar Dimitri Fontaine

Refactoring it all: a beginning. No time for testing yet, just showing ideas.

parent c9a772db
;;; el-get.el --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; 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 'autoload)
(defvar el-get-outdated-autoloads nil
"List of package names whose autoloads are outdated")
(defun el-get-save-and-kill (file)
"Save and kill all buffers visiting the named FILE"
(let (buf)
(while (setq buf (find-buffer-visiting file))
(with-current-buffer buf
(save-buffer)
(kill-buffer)))))
(defun el-get-ensure-byte-compilable-autoload-file (file)
"If FILE doesn't already exist, create it as a byte-compilable
autoload file (the default created by autoload.el has a local
no-byte-compile variable that suppresses byte compilation)."
;; If we don't explicitly strip out the no-byte-compile variable,
;; autoload.el will create it on demand
(unless (file-exists-p file)
(write-region
(replace-regexp-in-string ";; no-byte-compile: t\n" ""
(autoload-rubric file)) nil file)))
(defun el-get-load-fast (file)
"Load the compiled version of FILE if it exists; else load FILE verbatim"
(load (file-name-sans-extension file) nil (not el-get-verbose)))
(defun el-get-eval-autoloads ()
"Evaluate the autoloads from the autoload file."
(when (and el-get-generate-autoloads
(file-exists-p el-get-autoload-file))
(el-get-verbose-message "el-get: evaluating autoload file")
(el-get-load-fast el-get-autoload-file)))
(defun el-get-update-autoloads ()
"Regenerate, compile, and load any outdated packages' autoloads.
This function will run from a timer, and usually
shouldn't be invoked directly."
(message "el-get: updating outdated autoloads")
(setq el-get-autoload-timer nil) ;; Allow a new update to be primed
(let ((outdated el-get-outdated-autoloads)
;; Generating autoloads runs theses hooks; disable then
fundamental-mode-hook
prog-mode-hook
emacs-lisp-mode-hook
;; use dynamic scoping to set up our loaddefs file for
;; update-directory-autoloads
(generated-autoload-file el-get-autoload-file))
;; make sure we can actually byte-compile it
(el-get-ensure-byte-compilable-autoload-file generated-autoload-file)
;; clear the list early in case of errors
(setq el-get-outdated-autoloads nil)
(dolist (p outdated)
(if (string= (el-get-package-status p) "installed")
(apply 'update-directory-autoloads (el-get-load-path p))))
(el-get-save-and-kill el-get-autoload-file)
(when (file-exists-p el-get-autoload-file)
(message "el-get: byte-compiling autoload file")
(when el-get-byte-compile
(el-get-byte-compile-file el-get-autoload-file))
(el-get-eval-autoloads))))
(defconst el-get-load-suffix-regexp
(concat (mapconcat 'regexp-quote (get-load-suffixes) "\\|") "\\'"))
(defun el-get-remove-autoloads (package)
"Remove from `el-get-autoload-file' any autoloads associated
with the named PACKAGE"
;; Remove any compiled loaddefs file and schedule it for recompilation
(el-get-schedule-autoload-update)
(when (file-exists-p el-get-autoload-file)
(with-temp-buffer ;; empty buffer to trick `autoload-find-destination'
(let ((generated-autoload-file el-get-autoload-file)
;; Generating autoloads runs emacs-lisp-mode-hook; disable it
emacs-lisp-mode-hook
(autoload-modified-buffers (list (current-buffer))))
(dolist (dir (el-get-load-path package))
(when (file-directory-p dir)
(dolist (f (directory-files dir t el-get-load-suffix-regexp))
;; this will clear out any autoloads associated with the file
;; `autoload-find-destination' signature has changed in emacs24.
(if (> emacs-major-version 23)
(autoload-find-destination f (autoload-file-load-name f))
(autoload-find-destination f)))))))
(el-get-save-and-kill el-get-autoload-file)))
(defvar el-get-autoload-timer nil
"Where the currently primed autoload timer (if any) is stored")
(defun el-get-want-autoloads-p (package)
"Return t iff the given PACKAGE should have its autoloads
automatically generated by el-get"
(let ((source (el-get-package-def package)))
(or (not (plist-member source :autoloads))
(eq (plist-get source :autoloads) t))))
(defun el-get-schedule-autoload-update ()
"Autoloads need to be updated; delete any (now outdated)
compiled autoloads file and schedule the task to run later."
(let ((elc (concat (file-name-sans-extension el-get-autoload-file) ".elc")))
(when (file-exists-p elc)
(delete-file elc)))
(unless (or el-get-autoload-timer
(not el-get-generate-autoloads))
(setq el-get-autoload-timer
(run-with-idle-timer 0 nil 'el-get-update-autoloads))))
(defun el-get-invalidate-autoloads ( &optional package )
"Mark the named PACKAGE as needing new autoloads. If PACKAGE
is nil, marks all installed packages as needing new autoloads."
;; Trigger autoload recomputation unless it's already been done
(unless (or el-get-autoload-timer
(not el-get-generate-autoloads))
(setq el-get-autoload-timer
(run-with-idle-timer 0 nil 'el-get-update-autoloads)))
;; Save the package names for later
(mapc (lambda (p)
(when (el-get-want-autoloads-p p)
(add-to-list 'el-get-outdated-autoloads p)))
(if package (list package)
(el-get-list-package-names-with-status "installed")))
;; If we're invalidating everything, try to start from a clean slate
(unless package
(ignore-errors
(delete-file el-get-autoload-file)
(delete-file
(concat (file-name-sans-extension el-get-autoload-file) ".elc")))))
(provide 'el-get-autoloads)
;;; el-get --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; 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)
(defun el-get-build-commands (package)
"Return a list of build commands for the named PACKAGE.
The result will either be nil; a list of strings, each one to be
interpreted as a shell command; or a list of lists of
strings, each string representing a single shell argument."
(let* ((source (el-get-package-def package))
(build-type (intern (format ":build/%s" system-type)))
(build-commands
(or (plist-get source build-type)
(plist-get source :build))))
(unless (listp build-commands)
(error "build commands for package %s are not a list" package))
(unless (stringp (car build-commands))
(setq build-commands (eval build-commands)))
(mapcar (lambda (x) (if (stringp x) x (el-get-flatten x)))
build-commands)))
(defun el-get-build-command-program (name)
"Given the user command name, get the command program to execute.
That will find the program in current $PATH for you, unless given
command name is a relative filename beginning with \"./\", or its
absolute filename obtained with expand-file-name is executable."
(let ((fullname (expand-file-name name))
(exe (executable-find name)))
(cond ((string-match "^\./" name) name)
((file-executable-p fullname) fullname)
(t (or exe name)))))
(defun el-get-build
(package commands &optional subdir sync post-build-fun installing-info)
"Run each command from the package directory.
COMMANDS is a list of commands to run in order to build the
package.
The commands are run either synchronously or asynchronously
depending on the SYNC parameter, and can be run from SUBDIR
directory when given. By default COMMANDS are run from the
package directory as obtained by `el-get-package-directory'.
The function POST-BUILD-FUN will get called after the commands
are all successfully run. In case of asynchronous building, the
only way to have code running after the build is using this
parameter.
INSTALLING-INFO is t when called from
`el-get-install-or-init-info', as to avoid a nasty infinite
recursion.
"
(el-get-verbose-message "el-get-build %s" package)
(let* ((pdir (el-get-package-directory package))
(wdir (if subdir (concat (file-name-as-directory pdir) subdir) pdir))
(buf (format "*el-get-build: %s*" package))
(default-directory (file-name-as-directory wdir))
(process-list
(mapcar (lambda (c)
(let* ((split (if (stringp c)
(split-string c)
(mapcar 'shell-quote-argument c)))
(c (mapconcat 'identity split " "))
(name (car split))
(program (el-get-build-command-program name))
(args (cdr split)))
`(:command-name ,name
:buffer-name ,buf
:default-directory ,wdir
:shell t
:sync sync
:program ,program
:args (,@args)
:message ,(format "el-get-build %s: %s ok." package c)
:error ,(format
"el-get could not build %s [%s]" package c))))
commands))
(bytecomp-files (when el-get-byte-compile
(el-get-assemble-files-for-byte-compilation package)))
(full-process-list ;; includes byte compiling
(append
(when bytecomp-files
(list
(el-get-byte-compile-process package buf wdir sync bytecomp-files)))
process-list))
;; unless installing-info, post-build-fun should take care of
;; building info too
(build-info-then-post-build-fun
(if installing-info post-build-fun
`(lambda (package)
(el-get-install-or-init-info package 'build)
(funcall ,(if (symbolp post-build-fun)
(symbol-function post-build-fun)
;; it must be a lambda, just inline its value
post-build-fun)
package)))))
(el-get-start-process-list
package full-process-list build-info-then-post-build-fun)))
(defun el-get-set-info-path (package infodir-rel)
(require 'info)
(info-initialize)
(el-get-add-path-to-list package 'Info-directory-list infodir-rel))
(defun el-get-install-or-init-info (package build-or-init)
"Call `el-get-install-info' to create the necessary \"dir\"
file when build-or-init is 'build, or `el-get-set-info-path'
when build-or-init is 'init "
(let* ((source (el-get-package-def package))
(method (el-get-package-method source))
(infodir (plist-get source :info))
(pdir (el-get-package-directory package)))
;; apt-get, pacman and ELPA will set up Info-directory-list
(unless (member method '(elpa apt-get fink pacman))
(let* ((infodir-abs-conf (concat pdir infodir))
(infodir-abs (file-name-as-directory
(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)))
(info-dir (concat infodir-abs "dir"))
(infofile (if (and (file-exists-p infodir-abs-conf)
(not (file-directory-p infodir-abs-conf)))
infodir-abs-conf
(concat infodir-abs package))))
(cond
((eq build-or-init 'init)
(when (file-exists-p info-dir)
(el-get-set-info-path package infodir-rel)))
((eq build-or-init 'build)
;; rebuild each time asked --- e.g. on update
(when (and infodir
(file-directory-p infodir-abs)
(not (file-exists-p info-dir)))
(el-get-set-info-path package infodir-rel)
(el-get-build
package
`(,(format "%s %s dir"
el-get-install-info
(if (string= (substring infofile -5) ".info")
infofile
(concat infofile ".info")))) infodir-rel t nil t)))
(t
(error
"el-get-install-or-init-info: %s not supported" build-or-init)))))))
(provide 'el-get-build)
;;; el-get --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; 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 'bytecomp)
;; Emacs < 24
(eval-and-compile
(if (fboundp 'byte-recompile-file)
(defsubst el-get-byte-compile-file (el)
;; Byte-compile runs emacs-lisp-mode-hook; disable it
(let (emacs-lisp-mode-hook)
(byte-recompile-file el)))
(defun el-get-byte-compile-file (el)
"Same as `byte-compile-file', but skips unnecessary compilation.
Specifically, if the compiled elc file already exists and is
newer, then compilation will be skipped."
(let ((elc (concat (file-name-sans-extension el) ".elc"))
;; Byte-compile runs emacs-lisp-mode-hook; disable it
emacs-lisp-mode-hook)
(when (or (not (file-exists-p elc))
(file-newer-than-file-p el elc))
(condition-case err
(byte-compile-file el)
((debug error) ;; catch-all, allow for debugging
(message "%S" (error-message-string err)))))))))
(defun el-get-byte-compile-file-or-directory (file)
"Byte-compile FILE or all files within it if it is a directory."
(let ((byte-compile-warnings nil)
;; Byte-compile runs emacs-lisp-mode-hook; disable it
emacs-lisp-mode-hook)
(if (file-directory-p file)
(byte-recompile-directory file 0)
(el-get-byte-compile-file file))))
(defun el-get-assemble-files-for-byte-compilation (package)
"Assemble a list of *absolute* paths to byte-compile for PACKAGE."
(when el-get-byte-compile
(let* ((source (el-get-package-def package))
(comp-prop (plist-get source :compile))
(compile (el-get-as-list comp-prop))
;; nocomp is true only if :compile is explicitly set to nil.
(explicit-nocomp (and (plist-member source :compile)
(not comp-prop)))
(method (el-get-package-method source))
(pdir (el-get-package-directory package))
(el-path (el-get-load-path package))
(files '()))
(cond
(compile
;; only byte-compile what's in the :compile property of the recipe
(dolist (path compile)
(let ((fullpath (expand-file-name path pdir)))
(if (file-exists-p fullpath)
;; path is a file/dir, so add it literally
(add-to-list 'files fullpath)
;; path is a regexp, so add matching file names in package dir
(mapc (apply-partially 'add-to-list 'files)
(directory-files pdir nil fullpath))))))
;; If package has (:compile nil), or package has its own build
;; instructions, or package is already pre-compiled by the
;; installation method, then don't compile anything.
((or explicit-nocomp
(el-get-build-commands package)
(member method '(apt-get fink pacman)))
nil)
;; Default: compile the package's entire load-path
(t
(mapc (apply-partially 'add-to-list 'files) el-path)))
files)))
(defun el-get-byte-compile-from-stdin ()
"byte compile files read on STDIN
This is run as a subprocess with an `emacs -Q -batch -f
el-get-byte-compile` command and with the file list as stdin,
written by `prin1-to-string' so that `read' is able to process
it."
(let ((files (read)))
(loop for f in files
do (progn
(message "el-get-byte-compile-from-stdin: %s" f)
(el-get-byte-compile-file-or-directory f)))))
(defun el-get-byte-compile-process (package buffer working-dir sync files)
"return the 'el-get-start-process-list' entry to byte compile PACKAGE"
(let ((bytecomp-command
(list el-get-emacs
"-Q" "-batch" "-f" "toggle-debug-on-error"
"-l" (shell-quote-argument
(file-name-sans-extension
(symbol-file 'el-get-byte-compile-from-stdin 'defun)))
"-f" "el-get-byte-compile-from-stdin")))
`(:command-name "byte-compile"
:buffer-name ,buffer
:default-directory ,working-dir
:shell t
:sync ,sync
:stdin ,files
:program ,(car bytecomp-command)
:args ,(cdr bytecomp-command)
:message ,(format "el-get-build %s: byte-compile ok." package)
:error ,(format
"el-get could not byte-compile %s" package))))
(defun el-get-byte-compile (package)
"byte compile files for given package"
(let ((pdir (el-get-package-directory package))
(buf "*el-get-byte-compile*")
(files (el-get-assemble-files-for-byte-compilation package)))
(when files
(el-get-start-process-list
package
(list (el-get-byte-compile-process package buf pdir t files))
nil))))
(provide 'el-get-byte-compile)
This diff is collapsed.
This diff is collapsed.
;;; el-get --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; 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)
;;
;; Support for tracking package states
;;
(defvar el-get-pkg-state
(make-hash-table)
"A hash mapping el-get package name symbols to their installation states")
(defun el-get-package-state (package)
"Return the installation state of PACKAGE.
- nil indicates that installation of the package has not been requested
- 'installing indicates that the package's installation is in progress
- 'init indicates that the package has been initialized
- ('error . <data>) indicates that there was an installation error"
(gethash (el-get-as-symbol package) el-get-pkg-state))
(defun el-get-currently-installing-p (package)
(eq (el-get-package-state package) 'installing))
(defun el-get-currently-installing-packages ()
"Return the packages that are currently installing"
(loop
for pkg being the hash-keys of el-get-pkg-state
if (el-get-currently-installing-p pkg)
collect pkg))
(defun el-get-set-package-state (package state)
"Set the installation state of PACKAGE to STATE"
(puthash (el-get-as-symbol package) state el-get-pkg-state))
(defun el-get-mark-initialized (package)
"Record the fact that the given PACKAGE has been initialized."
(el-get-set-package-state package 'init))
(add-hook 'el-get-post-init-hooks 'el-get-mark-initialized)
(defun el-get-mark-removed (package)
"Record the fact that the given PACKAGE has been initialized."
(el-get-set-package-state package nil))
(add-hook 'el-get-post-remove-hooks 'el-get-mark-removed)
(defun el-get-mark-failed (package info)
"Record the fact that the given PACKAGE has failed to install
for reasons described in INFO."
(el-get-verbose-message "el-get-mark-failed: %s %s" package info)
(el-get-set-package-state package `(error ,info)))
(add-hook 'el-get-post-error-hooks 'el-get-mark-failed)
;;
;; generic one-shot event support
;;
(defvar el-get-generic-event-tasks (make-hash-table :test 'equal)
"A hash mapping event triggers to lists of functions to be called")
(defun el-get-generic-event-occurred (event &optional data)
"Fire all tasks added for the given EVENT (a hash key), passing DATA."
(let (tasks)
(while (setq tasks (gethash event el-get-generic-event-tasks))
(puthash event (cdr tasks) el-get-generic-event-tasks)
(ignore-errors (funcall (car tasks) data)))))
(defun el-get-add-generic-event-task (event task)
"Set up TASK to be called when EVENT (a hash key) occurs."
(puthash event (cons task (gethash event el-get-generic-event-tasks))
el-get-generic-event-tasks))
(defun el-get-clear-generic-event-tasks (event)
"Clear all tasks waiting on EVENT (a hash key)"
(remhash event el-get-generic-event-tasks))
;;
;; fire events for completion of el-get's init, install, and update
;; phases (and for errors).
;;
(defun el-get-event-id (package action)
(list (el-get-as-symbol package) (intern (format "el-get-%s" action))))
(defun el-get-event-occurred (package action &optional data)
"Handle the completion of ACTION on PACKAGE (both symbols),
passing DATA"
;; If this action finalizes the package state, first cancel other
;; final actions
(let* ((final-actions '(init error))
(found (position action final-actions)))
(when found
(el-get-clear-generic-event-tasks
(el-get-event-id package (elt final-actions (- 1 found))))))
;; Now fire off the generic event
(el-get-generic-event-occurred (el-get-event-id package action) data))
;; Install hooks that generate events
(dolist (action '(init install update error))
(add-hook (intern (format "el-get-post-%s-hooks" action))
`(lambda (p &optional data) (el-get-event-occurred p ',action data))))
(defun el-get-dependencies (package)
"Return the list of packages (as symbols) on which PACKAGE (a
symbol) depends"
(let* ((source (el-get-package-def (symbol-name package)))
(method (el-get-package-method source))
(deps (el-get-as-list (plist-get source :depends))))
;; Make sure all elpa packages depend on the package `package'.
;; The package `package' is an elpa package, though, so exclude
;; it to avoid a circular dependency.
(if (and (not (eq package 'package)) (eq method 'elpa))
(cons 'package deps)
deps)))
(defun el-get-package-initialized-p (package)
(eq (el-get-package-state package) 'init))
(defun el-get-demand1 (package)
"Install, if necessary, and init the el-get package given by
PACKAGE, a symbol"
(let ((p (symbol-name package)))
(if (string= (el-get-package-status p) "installed")
(el-get-init p)
(el-get-do-install p))))
(defun el-get-dependency-installed (package dependency)
"Install the given PACKAGE (a symbol) iff all its dependencies
are now installed"
(when (every 'el-get-package-initialized-p
(el-get-dependencies package))
(el-get-demand1 package)))
(defun el-get-dependency-error (package dependency data)
"Mark PACKAGE as having failed installation due to a failure to
install DEPENDENCY, with error information DATA"
(el-get-mark-failed package (list dependency data)))
(provide 'el-get-depends)
This diff is collapsed.
;;; el-get --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; 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)
;;
;; NOTE: this will probably benefit from some autoloading magic, later.
;;
(require 'el-get-apt-get)
(require 'el-get-bzr)
(require 'el-get-cvs)
(require 'el-get-darcs)
(require 'el-get-elpa)
(require 'el-get-emacsmirror)
(require 'el-get-emacswiki)
(require 'el-get-fink)
(require 'el-get-git)
(require 'el-get-git-svn)
(require 'el-get-hg)
(require 'el-get-http)
(require 'el-get-http-tar)
(require 'el-get-pacman)
(require 'el-get-svn)
(provide 'el-get-methods)
;;; el-get --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; 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 'help-mode) ; byte-compiling needs to know about xref-type buttons
;; we support notifications on darwin too, thanks to growlnotify
(defcustom el-get-growl-notify "/usr/local/bin/growlnotify"
"Absolute path of the growlnotify tool"
:group 'el-get
:type 'file)
;; notify user with emacs notifications API (new in 24)
;;
(when (and (eq system-type 'darwin)
(file-executable-p el-get-growl-notify))
(defun el-get-growl (title message)
"Send a message to growl, that implements notifications for darwin"
(let* ((name "*growl*")
(proc
(start-process name name el-get-growl-notify title "-a" "Emacs")))
(process-send-string proc (concat message "\n"))
(process-send-eof proc))))
;;
;; Notification support is either the internal one provided by Emacs 24, or
;; the external growl one as defined above, or the one provided by the
;; add-on found on http://www.emacswiki.org/emacs/notify.el (there's a
;; recipe) for older Emacs versions users
;;
(defun el-get-notify (title message)
"Notify the user using either the dbus based API or the `growl' one"
(if (fboundp 'dbus-register-signal)
;; avoid a bug in Emacs 24.0 under darwin
(require 'notifications nil t)
;; else try notify.el, there's a recipe for it
(unless (fboundp 'notify)
(when (featurep 'notify)
(require 'notify))))
(cond ((fboundp 'notifications-notify) (notifications-notify :title title
:body message))
((fboundp 'notify) (notify title message))
((fboundp 'el-get-growl) (el-get-growl title message))
(t (message "%s: %s" title message))))
(defun el-get-post-install-notification (package)
"Notify the PACKAGE has been installed."
(el-get-notify (format "%s installed" package)
"This package has been installed successfully by el-get."))
(add-hook 'el-get-post-install-hooks 'el-get-post-install-notification)
(defun el-get-post-update-notification (package)
"Notify the PACKAGE has been updated."
(el-get-notify (format "%s updated" package)
"This package has been updated successfully by el-get."))