You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
;;; dockerfile-mode.el --- Major mode for editing Docker's Dockerfiles -*- lexical-binding: t -*-
;; Copyright (c) 2013 Spotify AB;; Package-Requires: ((emacs "24") (s "1.12"));; Package-Version: 1.3;; Package-Commit: d31f7685ebc5832d957e25070a930aa42984327d;; Homepage: https://github.com/spotify/dockerfile-mode;;;; Licensed under the Apache License, Version 2.0 (the "License"); you may not;; use this file except in compliance with the License. You may obtain a copy of;; the License at;;;; http://www.apache.org/licenses/LICENSE-2.0;;;; Unless required by applicable law or agreed to in writing, software;; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT;; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the;; License for the specific language governing permissions and limitations under;; the License.
;;; Commentary:
;; Provides a major mode `dockerfile-mode' for use with the standard;; `Dockerfile' file format. Additional convenience functions allow;; images to be built easily.
;;; Code:
(require 'sh-script)(require 'rx)(require 's)
(declare-function cygwin-convert-file-name-to-windows "cygw32.c" (file &optional absolute-p))
(defgroup dockerfile nil "dockerfile code editing commands for Emacs." :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) :prefix "dockerfile-" :group 'languages)
(defcustom dockerfile-mode-hook nil "*Hook called by `dockerfile-mode'." :type 'hook :group 'dockerfile)
(defcustom dockerfile-mode-command "docker" "Which binary to use to build images" :group 'dockerfile :type 'string)
(defcustom dockerfile-use-sudo nil "Runs docker builder command with sudo." :type 'boolean :group 'dockerfile)
(defcustom dockerfile-build-args nil "List of --build-arg to pass to docker build.
Each element of the list will be passed as a separate --build-arg to the docker build command."
:type '(repeat string) :group 'dockerfile)
(defface dockerfile-image-name '((t (:inherit (font-lock-type-face bold)))) "Face to highlight the base image name after FROM instruction.")
(defface dockerfile-image-alias '((t (:inherit (font-lock-constant-face bold)))) "Face to highlight the base image alias inf FROM ... AS <alias> construct.")
(defconst dockerfile--from-regex (rx "from " (group (+? nonl)) (or " " eol) (? "as " (group (1+ nonl)))))
(defvar dockerfile-font-lock-keywords `(,(cons (rx (or line-start "onbuild ") (group (or "from" "maintainer" "run" "cmd" "expose" "env" "arg" "add" "copy" "entrypoint" "volume" "user" "workdir" "onbuild" "label" "stopsignal" "shell" "healthcheck")) word-boundary) font-lock-keyword-face) (,dockerfile--from-regex (1 'dockerfile-image-name) (2 'dockerfile-image-alias nil t)) ,@(sh-font-lock-keywords) ,@(sh-font-lock-keywords-2) ,@(sh-font-lock-keywords-1)) "Default `font-lock-keywords' for `dockerfile mode'.")
(defvar dockerfile-mode-map (let ((map (make-sparse-keymap)) (menu-map (make-sparse-keymap))) (define-key map "\C-c\C-b" #'dockerfile-build-buffer) (define-key map "\C-c\M-b" #'dockerfile-build-no-cache-buffer) (define-key map "\C-c\C-c" #'comment-region) (define-key map [menu-bar dockerfile-mode] (cons "Dockerfile" menu-map)) (define-key menu-map [dfc] '(menu-item "Comment Region" comment-region :help "Comment Region")) (define-key menu-map [dfb] '(menu-item "Build" dockerfile-build-buffer :help "Send the Dockerfile to docker build")) (define-key menu-map [dfb] '(menu-item "Build without cache" dockerfile-build-no-cache-buffer :help "Send the Dockerfile to docker build without cache")) map))
(defvar dockerfile-mode-syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?# "<" table) (modify-syntax-entry ?\n ">" table) (modify-syntax-entry ?' "\"" table) (modify-syntax-entry ?= "." table) table) "Syntax table for `dockerfile-mode'.")
(define-abbrev-table 'dockerfile-mode-abbrev-table nil "Abbrev table used while in `dockerfile-mode'.")
(unless dockerfile-mode-abbrev-table (define-abbrev-table 'dockerfile-mode-abbrev-table ()))
(defun dockerfile-indent-line-function () "Indent lines in a Dockerfile.
Lines beginning with a keyword are ignored, and any others areindented by one `tab-width'."
(unless (member (get-text-property (point-at-bol) 'face) '(font-lock-comment-delimiter-face font-lock-keyword-face)) (save-excursion (beginning-of-line) (skip-chars-forward "[ \t]" (point-at-eol)) (unless (equal (point) (point-at-eol)) ; Ignore empty lines. ;; Delete existing whitespace. (delete-char (- (point-at-bol) (point))) (indent-to tab-width)))))
(defun dockerfile-build-arg-string () "Create a --build-arg string for each element in `dockerfile-build-args'." (mapconcat (lambda (arg) (concat "--build-arg " (shell-quote-argument arg))) dockerfile-build-args " "))
(defun dockerfile-standard-filename (file) "Convert the FILE name to OS standard.
If in Cygwin environment, uses Cygwin specific function to convert thefile name. Otherwise, uses Emacs' standard conversion function."
(if (fboundp 'cygwin-convert-file-name-to-windows) (s-replace "\\" "\\\\" (cygwin-convert-file-name-to-windows file)) (convert-standard-filename file)))
(defun dockerfile-tag-string (image-name) "Return a --tag shell-quoted IMAGE-NAME string or an empty string if image-name is blank." (if (string= image-name "") "" (format "--tag %s " (shell-quote-argument image-name))))
(defvar dockerfile-image-name nil "Name of the dockerfile currently being used.
This can be set in file or directory-local variables.")
(define-obsolete-variable-alias 'docker-image-name 'dockerfile-image-name)
(defvar dockerfile-image-name-history nil "History of image names read by `dockerfile-read-image-name'.")
(defun dockerfile-read-image-name () "Read a docker image name." (read-string "Image name: " dockerfile-image-name 'dockerfile-image-name-history))
;;;###autoload(defun dockerfile-build-buffer (image-name &optional no-cache) "Build an image called IMAGE-NAME based upon the buffer.
If prefix arg NO-CACHE is set, don't cache the image.The build string will be of the format:`sudo docker build --no-cache --tag IMAGE-NAME --build-args arg1.. -f filename directory`"
(interactive (list (dockerfile-read-image-name) prefix-arg)) (save-buffer) (compilation-start (format "%s%s build %s %s %s -f %s %s" (if dockerfile-use-sudo "sudo " "") dockerfile-mode-command (if no-cache "--no-cache" "") (dockerfile-tag-string image-name) (dockerfile-build-arg-string) (shell-quote-argument (dockerfile-standard-filename (buffer-file-name))) (shell-quote-argument (dockerfile-standard-filename default-directory))) nil (lambda (_) (format "*docker-build-output: %s *" image-name))))
;;;###autoload(defun dockerfile-build-no-cache-buffer (image-name) "Build an image called IMAGE-NAME based upon the buffer without cache." (interactive (list (dockerfile-read-image-name))) (dockerfile-build-buffer image-name t))
(defun dockerfile--imenu-function () "Find the previous headline from point.
Search for a FROM instruction. If an alias is used this isreturned, otherwise the base image name is used."
(when (re-search-backward dockerfile--from-regex nil t) (let ((data (match-data))) (when (match-string 2) ;; we drop the first match group because ;; imenu-generic-expression can only use one offset, so we ;; normalize to `1'. (set-match-data (list (nth 0 data) (nth 1 data) (nth 4 data) (nth 5 data)))) t)))
;;;###autoload(define-derived-mode dockerfile-mode prog-mode "Dockerfile" "A major mode to edit Dockerfiles.
\\{dockerfile-mode-map}"
(set-syntax-table dockerfile-mode-syntax-table) (set (make-local-variable 'imenu-generic-expression) `(("Stage" dockerfile--imenu-function 1))) (set (make-local-variable 'require-final-newline) mode-require-final-newline) (set (make-local-variable 'comment-start) "#") (set (make-local-variable 'comment-end) "") (set (make-local-variable 'comment-start-skip) "#+ *") (set (make-local-variable 'parse-sexp-ignore-comments) t) (set (make-local-variable 'font-lock-defaults) '(dockerfile-font-lock-keywords nil t)) (setq local-abbrev-table dockerfile-mode-abbrev-table) (set (make-local-variable 'indent-line-function) #'dockerfile-indent-line-function))
;;;###autoload(add-to-list 'auto-mode-alist '("Dockerfile\\(?:\\..*\\)?\\'" . dockerfile-mode))
(provide 'dockerfile-mode)
;;; dockerfile-mode.el ends here
|