Skip to content

Commit

Permalink
Introduce task display option.
Browse files Browse the repository at this point in the history
  • Loading branch information
takagi committed Sep 2, 2015
1 parent 2b58dca commit 230bc31
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 74 deletions.
10 changes: 6 additions & 4 deletions Lakefile
Expand Up @@ -10,20 +10,21 @@

(task "default" ("hello" "hello.o" "dir" "name:foo"))

;; A task that print hello.
(task "hello" ()
"A task that print hello."
(echo "do task hello!"))

;; Call a task from another.
(task "call-hello" ()
;; Call a task from another.
(execute "hello"))

(defparameter cc "gcc")

(file "hello.o" ("hello.c")
"A file task that compiles a C source file."
(sh #?"${cc} -c hello.c"))

(directory "dir")
(directory "dir" "Create a directory.")

(directory "foo") ; superseded by the next task.

Expand All @@ -37,6 +38,7 @@
(namespace "name"

(task "foo" ("bar")
"A task in \"name\" namespace."
(echo "name.foo"))

(task "bar" ()
Expand All @@ -48,6 +50,6 @@
(task "call-foo" ()
(execute "foo")))

;; Use environment variable via roswell.
(task "home" ()
;; Use environment variable via roswell.
(echo (ros:getenv "HOME")))
23 changes: 17 additions & 6 deletions README.md
Expand Up @@ -73,9 +73,9 @@ Lake provides the following forms to define tasks and namespaces in `Lakefile`:

### Task

TASK task-name dependency-list form*
TASK task-name dependency-list [description] form*

`task` represents a sequence of operations to accomplish some task. `task-name` is a string that specifies the target task by its name. `dependency-list` is a list of tasks names on which the target task depends. The dependency task names are given in both relative and absolute manner, which begins with a colon `:`. `form`s can be any Common Lisp forms.
`task` represents a sequence of operations to accomplish some task. `task-name` is a string that specifies the target task by its name. `dependency-list` is a list of task names on which the target task depends. The dependency task names are given in both relative and absolute manner, which begins with a colon `:`. `description` is a doc string. `form`s can be any Common Lisp forms.

$ cat Lakefile
...
Expand All @@ -97,13 +97,14 @@ Lake provides the following forms to define tasks and namespaces in `Lakefile`:

### File

FILE file-name dependency-list form*
FILE file-name dependency-list [description] form*

`file` task represents a sequence of operations as well as `task` except that it is executed only when the target file is out of date. `file-name` is a string that specifies the target file's name. `dependency-list` is a list of tasks or file names on which the target file depends. The dependency task/file names are given in both relative and absolute manner, which begins with a colon `:`. `form`s can be any Common Lisp forms.
`file` task represents a sequence of operations as well as `task` except that it is executed only when the target file is out of date. `file-name` is a string that specifies the target file's name. `dependency-list` is a list of tasks or file names on which the target file depends. The dependency task/file names are given in both relative and absolute manner, which begins with a colon `:`. `description` is a doc string. `form`s can be any Common Lisp forms.

$ cat Lakefile
...
(file "hello" ("hello.c")
"Compile hello from C source code."
(sh "gcc -o hello hello.c"))

$ lake hello
Expand All @@ -112,9 +113,9 @@ Lake provides the following forms to define tasks and namespaces in `Lakefile`:

### Directory

DIRECTORY directory-name
DIRECTORY directory-name [description]

`directory` task represents a task that ensures a directory with name of `directory-name` exists. `directory` task does not depend on other tasks.
`directory` task represents a task that ensures a directory with name of `directory-name` exists. `description` is a doc string. `directory` task does not depend on other tasks.

$ cat Lakefile
...
Expand Down Expand Up @@ -184,6 +185,14 @@ Executes a task specified with `target` as a string within another. The name of
(task "ls" ()
(sh "ls -l"))

### [Function] display-tasks

DISPLAY-TASKS &key pathname verbose

Displays the tasks with descriptions in a Lakefile specified with `pathname`. Not nil `verbose` provides verbose mode. If `pathname` is not given, a file of name `Lakefile` in the current direcotry is searched for. You should be aware that where the Common Lisp process' current directory is.

(display-tasks)

## Command Line Interface

### lake
Expand All @@ -200,6 +209,8 @@ Lake provides its command line interface as a roswell script.
Use FILE as a Lakefile.
-h
Print usage.
-T
Display the tasks with descriptions, then exit.
-v
Verbose mode.

Expand Down
8 changes: 8 additions & 0 deletions roswell/lake.ros
Expand Up @@ -11,8 +11,14 @@ exec ros -Q -- $0 "$@"
(write-line "Options:")
(write-line " -f FILE Use FILE as a lakefile.")
(write-line " -h Print this message and exit.")
(write-line " -T Display the tasks with descriptions, then exit.")
(write-line " -v Verbose mode."))

(defun print-tasks (pathname)
(if pathname
(lake:display-tasks :pathname pathname)
(lake:display-tasks)))

(defun main (&rest argv)
(declare (ignorable argv))
(handler-case
Expand All @@ -24,6 +30,8 @@ exec ros -Q -- $0 "$@"
((string= "-f" arg) (setf f-mode t))
((string= "-h" arg) (print-help)
(ros:quit 1))
((string= "-T" arg) (print-tasks pathname)
(ros:quit 1))
((string= "-v" arg) (setf v-mode t))
(t (push arg targets))))
(let ((params `(:verbose ,v-mode
Expand Down
87 changes: 67 additions & 20 deletions src/lake.lisp
Expand Up @@ -2,6 +2,7 @@
(defpackage lake
(:use :cl)
(:export :lake
:display-tasks
:namespace
:task
:file
Expand Down Expand Up @@ -108,7 +109,8 @@
;;;

(defclass base-task ()
((name :initarg :name :reader task-name)))
((name :initarg :name :reader task-name)
(description :initarg :description :reader task-description)))

(defun task-namespace (task)
(task-name-namespace (task-name task)))
Expand Down Expand Up @@ -136,13 +138,17 @@
((dependency :initarg :dependency :reader task-dependency)
(action :initarg :action :reader task-action)))

(defun make-task (name namespace dependency action)
(defun make-task (name namespace dependency desc action)
(check-type action function)
(check-type desc (or string null))
(let ((name1 (resolve-task-name name namespace))
(dependency1 (loop for task-name in dependency
collect
(resolve-dependency-task-name task-name namespace))))
(make-instance 'task :name name1 :dependency dependency1 :action action)))
(make-instance 'task :name name1
:dependency dependency1
:description desc
:action action)))

(defun dependency-file-name (task-name)
(task-name-name task-name))
Expand Down Expand Up @@ -181,11 +187,23 @@
(verbose "done." t)
(values))

(defmacro task (name dependency &body action)
(defun parse-body (forms)
(flet ((desc-p (form rest)
(and (stringp form)
rest)))
(if forms
(destructuring-bind (form1 . rest) forms
(if (desc-p form1 rest)
(values rest form1)
(values forms nil)))
(values nil nil))))

(defmacro task (name dependency &body body)
(check-type name string)
`(register-task (make-task ,name *namespace* ',dependency
#'(lambda ()
,@action))))
(multiple-value-bind (forms desc) (parse-body body)
`(register-task (make-task ,name *namespace* ',dependency ,desc
#'(lambda ()
,@forms)))))


;;;
Expand All @@ -194,16 +212,17 @@

(defclass file-task (task) ())

(defun make-file-task (name namespace dependency action)
(defun make-file-task (name namespace dependency desc action)
(check-type action function)
(check-type desc (or string null))
(let ((name1 (resolve-task-name name namespace))
(dependency1 (loop for task-name in dependency
collect
(resolve-dependency-task-name task-name namespace))))
(make-instance 'file-task
:name name1
:dependency dependency1
:action action)))
(make-instance 'file-task :name name1
:dependency dependency1
:description desc
:action action)))

(defun file-task-file-name (file-task)
(task-name-name (task-name file-task)))
Expand Down Expand Up @@ -236,11 +255,12 @@
(verbose "skipped." t))
(values))

(defmacro file (name dependency &body action)
(defmacro file (name dependency &body body)
(check-type name string)
`(register-task (make-file-task ,name *namespace* ',dependency
#'(lambda ()
,@action))))
(multiple-value-bind (forms desc) (parse-body body)
`(register-task (make-file-task ,name *namespace* ',dependency ,desc
#'(lambda ()
,@forms)))))


;;;
Expand All @@ -249,11 +269,12 @@

(defclass directory-task (base-task) ())

(defun make-directory-task (name namespace)
(defun make-directory-task (name namespace desc)
(check-type desc (or string null))
(unless (valid-task-name-p name)
(error "The value ~S is an invalid task name." name))
(let ((name1 (resolve-task-name name namespace)))
(make-instance 'directory-task :name name1)))
(make-instance 'directory-task :name name1 :description desc)))

(defun directory-task-directory-name (directory-task)
(task-name-name (task-name directory-task)))
Expand All @@ -274,9 +295,10 @@
(verbose "done." t)
(values))

(defmacro directory (name)
(defmacro directory (name &optional desc)
(check-type name string)
`(register-task (make-directory-task ,name *namespace*)))
(check-type desc (or string null))
`(register-task (make-directory-task ,name *namespace* ,desc)))


;;;
Expand Down Expand Up @@ -344,3 +366,28 @@
(let ((*tasks* nil))
(load-lakefile pathname)
(%execute-task (get-task target)))))

(defun tasks-max-width (tasks)
(loop for task in tasks
when (task-description task)
maximize (length (task-name task))))

(defun %display-tasks (tasks)
(let ((width (tasks-max-width tasks)))
(loop for task in tasks
when (task-description task)
do (let ((padlen (- width (length (task-name task)))))
(format t "lake ~A~v@{ ~} # ~A~%"
(task-name task)
padlen
(task-description task))))))

(defun display-tasks (&key (pathname (get-lakefile-pathname))
(verbose nil))
(let ((*verbose* verbose))
;; Show message if verbose.
(verbose (format nil "Current directory: ~A~%" (getcwd)))
;; Load Lakefile to display tasks.
(let ((*tasks*))
(load-lakefile pathname)
(%display-tasks (reverse *tasks*)))))

0 comments on commit 230bc31

Please sign in to comment.