2011-09-20 21:15:52 +08:00
;;; 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 )
2011-09-23 03:48:11 +08:00
( require 'el-get-byte-compile )
;; 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 " ) ) )
2011-09-20 21:15:52 +08:00
( 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 ) ) )
2011-10-07 05:17:30 +08:00
( raw-build-commands
2011-09-20 21:15:52 +08:00
( or ( plist-get source build-type )
2011-10-07 05:17:30 +08:00
( plist-get source :build ) ) )
( build-commands
2011-10-08 07:31:25 +08:00
( if ( listp raw-build-commands )
2011-10-07 05:17:30 +08:00
;; If the :build property's car is a symbol, assume that it is an
;; expression that evaluates to a command list, rather than a
;; literal command list.
( if ( symbolp ( car raw-build-commands ) )
( eval raw-build-commands )
raw-build-commands )
( error " build commands for package %s are not a list " package ) ) )
( flat-build-commands
;; Flatten lists, but not strings
( mapcar ( lambda ( x ) ( if ( stringp x ) x ( el-get-flatten x ) ) )
build-commands ) ) )
2011-09-20 21:15:52 +08:00
2011-10-07 05:17:30 +08:00
;; Verify that each build command is a string or a list of strings
( let ( ( invalid-cmds
( remove-if ( lambda ( cmd )
( or ( stringp cmd )
( el-get-list-of-strings-p cmd ) ) )
flat-build-commands ) ) )
( when invalid-cmds
( error " Package %s has invalid build commands: %S " package invalid-cmds ) ) )
flat-build-commands ) )
2011-09-20 21:15:52 +08:00
( 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 ) )
2012-03-12 23:12:37 +08:00
( shell-file-name ( or ( and ( eq system-type 'windows-nt )
( executable-find " cmdproxy.exe " ) )
shell-file-name ) )
2011-09-20 21:15:52 +08:00
( process-list
( mapcar ( lambda ( c )
Warn for build commands that rely on whitespace-splitting
El-get-build allows a command to be specified as a single string. It
will split that string on whitespace into a list of strings, and each
element of that list will eventually be shell-quoted (by
`el-get-start-process-list`). This is wrong behavior that can easily
cause an innocent command to be over-escaped or split into too many
arguments, or both. For example, consider a build process that
involves running the following command:
make SOME_OPTION="this is the option value"
Written as a string in Elisp, that would be:
"make SOME_OPTION=\"this is the option value\""
After splitting on whitespace and then shell-quoting and then passing
the result to the shell, the above command is equivalent to running
the following at the shell:
"make" "SOME_OPTION=\"this" "is" "the" "option" "value\""
See the problem? What was once a single argument is now five, and the
quotation marks have been inappropriately quoted. For this reason, I
think auto-whitespace splitting should probably be deprecated. The
command should either be a single string, which would be interpreted
as a command to be run with no arguments, or a list of strings, like
this:
'("make" "SOME_OPTION=\"this is the option value\"")
2011-10-06 17:31:36 +08:00
( let* ( ( split ( cond ( ( stringp c )
2011-10-08 06:13:43 +08:00
;; `("sh" "-c" ,c) or equivalent
( prog1 ( list shell-file-name
shell-command-switch
c )
( when ( not ( string= c ( shell-quote-argument c ) ) )
( warn " Build command %S in package \" %s \" will be shell-interpolated. To bypass shell interpolation, the recipe for \" %s \" should specify build commands as lists of strings instead. " c package package ) ) ) )
2011-10-04 08:48:29 +08:00
( ( sequencep c ) c )
( t ( error " Invalid command: %S " c ) ) ) )
2011-09-20 21:15:52 +08:00
( 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
2012-02-12 05:25:09 +08:00
:sync , sync
2011-09-20 21:15:52 +08:00
: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 ) )
2012-03-07 05:25:09 +08:00
;; This ensures that post-build-fun is always a lambda, not a
;; symbol, which simplifies the following code.
( post-build-fun
( cond ( ( null post-build-fun ) ( lambda ( &rest args ) nil ) )
( ( symbolp post-build-fun )
` ( lambda ( &rest args )
( apply , ( symbol-function post-build-fun ) args ) ) )
( t ( assert ( functionp post-build-fun ) 'show-args )
post-build-fun ) ) )
2012-02-27 06:19:50 +08:00
;; Do byte-compilation after building, if needed
( byte-compile-then-post-build-fun
` ( lambda ( package )
( let ( ( bytecomp-files
( when el-get-byte-compile
( el-get-assemble-files-for-byte-compilation package ) ) ) )
2012-02-27 06:33:32 +08:00
;; The byte-compilation command needs to run even if
;; `bytecomp-files' is empty, because it also cleans up
;; stale compiled files if it finds any.
( el-get-start-process-list
package
( list ( el-get-byte-compile-process package , buf , wdir , sync bytecomp-files ) )
, post-build-fun ) ) ) )
2011-09-20 21:15:52 +08:00
;; unless installing-info, post-build-fun should take care of
;; building info too
2012-02-27 06:19:50 +08:00
( build-info-then-post-build-fun
2012-02-27 06:33:47 +08:00
( if installing-info byte-compile-then-post-build-fun
2011-09-20 21:15:52 +08:00
` ( lambda ( package )
( el-get-install-or-init-info package 'build )
2012-02-27 06:33:47 +08:00
( funcall , byte-compile-then-post-build-fun package ) ) ) ) )
2011-09-20 21:15:52 +08:00
( el-get-start-process-list
2012-02-27 06:19:50 +08:00
package process-list build-info-then-post-build-fun ) ) )
2011-09-20 21:15:52 +08:00
( 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 ) )
2011-09-23 03:48:11 +08:00
( pname ( el-get-as-string package ) )
2011-09-20 21:15:52 +08:00
( 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
2011-09-23 03:48:11 +08:00
( concat infodir-abs pname ) ) ) )
2011-09-20 21:15:52 +08:00
( 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
2011-10-06 17:06:29 +08:00
( list ( list el-get-install-info
( if ( string= ( substring infofile -5 ) " .info " )
2011-09-30 21:25:42 +08:00
infofile
2011-10-06 17:06:29 +08:00
( concat infofile " .info " ) )
" dir " ) )
infodir-rel t nil t ) ) )
2011-09-20 21:15:52 +08:00
( t
( error
" el-get-install-or-init-info: %s not supported " build-or-init ) ) ) ) ) ) )
( provide 'el-get-build )