# HG changeset patch # User Jordi GutiƩrrez Hermoso # Date 1495121638 14400 # Node ID 2260eaac02ae3e73c391eaf1bcc4cfa58b856cbf # Parent c745e2cc79eef916dda9341a2c609efa1ee8a981 add puppet mode diff --git a/elpa/epl-0.8/epl-autoloads.el b/elpa/epl-0.8/epl-autoloads.el new file mode 100644 --- /dev/null +++ b/elpa/epl-0.8/epl-autoloads.el @@ -0,0 +1,15 @@ +;;; epl-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil nil ("epl.el") (22782 38539 334113 509000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; epl-autoloads.el ends here diff --git a/elpa/epl-0.8/epl-pkg.el b/elpa/epl-0.8/epl-pkg.el new file mode 100644 --- /dev/null +++ b/elpa/epl-0.8/epl-pkg.el @@ -0,0 +1,1 @@ +(define-package "epl" "0.8" "Emacs Package Library" '((cl-lib "0.3")) :url "http://github.com/cask/epl" :keywords '("convenience")) diff --git a/elpa/epl-0.8/epl.el b/elpa/epl-0.8/epl.el new file mode 100644 --- /dev/null +++ b/elpa/epl-0.8/epl.el @@ -0,0 +1,695 @@ +;;; epl.el --- Emacs Package Library -*- lexical-binding: t; -*- + +;; Copyright (C) 2013-2015 Sebastian Wiesner +;; Copyright (C) 1985-1986, 1992, 1994-1995, 1999-2015 Free Software + +;; Author: Sebastian Wiesner +;; Maintainer: Johan Andersson +;; Sebastian Wiesner +;; Version: 0.8 +;; Package-Version: 0.8 +;; Package-Requires: ((cl-lib "0.3")) +;; Keywords: convenience +;; URL: http://github.com/cask/epl + +;; This file is NOT part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; A package management library for Emacs, based on package.el. + +;; The purpose of this library is to wrap all the quirks and hassle of +;; package.el into a sane API. + +;; The following functions comprise the public interface of this library: + +;;; Package directory selection + +;; `epl-package-dir' gets the directory of packages. + +;; `epl-default-package-dir' gets the default package directory. + +;; `epl-change-package-dir' changes the directory of packages. + +;;; Package system management + +;; `epl-initialize' initializes the package system and activates all +;; packages. + +;; `epl-reset' resets the package system. + +;; `epl-refresh' refreshes all package archives. + +;; `epl-add-archive' adds a new package archive. + +;;; Package objects + +;; Struct `epl-requirement' describes a requirement of a package with `name' and +;; `version' slots. + +;; `epl-requirement-version-string' gets a requirement version as string. + +;; Struct `epl-package' describes an installed or installable package with a +;; `name' and some internal `description'. + +;; `epl-package-version' gets the version of a package. + +;; `epl-package-version-string' gets the version of a package as string. + +;; `epl-package-summary' gets the summary of a package. + +;; `epl-package-requirements' gets the requirements of a package. + +;; `epl-package-directory' gets the installation directory of a package. + +;; `epl-package-from-buffer' creates a package object for the package contained +;; in the current buffer. + +;; `epl-package-from-file' creates a package object for a package file, either +;; plain lisp or tarball. + +;; `epl-package-from-descriptor-file' creates a package object for a package +;; description (i.e. *-pkg.el) file. + +;;; Package database access + +;; `epl-package-installed-p' determines whether a package is installed, either +;; built-in or explicitly installed. + +;; `epl-package-outdated-p' determines whether a package is outdated, that is, +;; whether a package with a higher version number is available. + +;; `epl-built-in-packages', `epl-installed-packages', `epl-outdated-packages' +;; and `epl-available-packages' get all packages built-in, installed, outdated, +;; or available for installation respectively. + +;; `epl-find-built-in-package', `epl-find-installed-packages' and +;; `epl-find-available-packages' find built-in, installed and available packages +;; by name. + +;; `epl-find-upgrades' finds all upgradable packages. + +;; `epl-built-in-p' return true if package is built-in to Emacs. + +;;; Package operations + +;; `epl-install-file' installs a package file. + +;; `epl-package-install' installs a package. + +;; `epl-package-delete' deletes a package. + +;; `epl-upgrade' upgrades packages. + +;;; Code: + +(require 'cl-lib) +(require 'package) + + +(unless (fboundp #'define-error) + ;; `define-error' for 24.3 and earlier, copied from subr.el + (defun define-error (name message &optional parent) + "Define NAME as a new error signal. +MESSAGE is a string that will be output to the echo area if such an error +is signaled without being caught by a `condition-case'. +PARENT is either a signal or a list of signals from which it inherits. +Defaults to `error'." + (unless parent (setq parent 'error)) + (let ((conditions + (if (consp parent) + (apply #'append + (mapcar (lambda (parent) + (cons parent + (or (get parent 'error-conditions) + (error "Unknown signal `%s'" parent)))) + parent)) + (cons parent (get parent 'error-conditions))))) + (put name 'error-conditions + (delete-dups (copy-sequence (cons name conditions)))) + (when message (put name 'error-message message))))) + +(defsubst epl--package-desc-p (package) + "Whether PACKAGE is a `package-desc' object. + +Like `package-desc-p', but return nil, if `package-desc-p' is not +defined as function." + (and (fboundp 'package-desc-p) (package-desc-p package))) + + +;;; EPL errors +(define-error 'epl-error "EPL error") + +(define-error 'epl-invalid-package "Invalid EPL package" 'epl-error) + +(define-error 'epl-invalid-package-file "Invalid EPL package file" + 'epl-invalid-package) + + +;;; Package directory +(defun epl-package-dir () + "Get the directory of packages." + package-user-dir) + +(defun epl-default-package-dir () + "Get the default directory of packages." + (eval (car (get 'package-user-dir 'standard-value)))) + +(defun epl-change-package-dir (directory) + "Change the directory of packages to DIRECTORY." + (setq package-user-dir directory) + (epl-initialize)) + + +;;; Package system management +(defvar epl--load-path-before-initialize nil + "Remember the load path for `epl-reset'.") + +(defun epl-initialize (&optional no-activate) + "Load Emacs Lisp packages and activate them. + +With NO-ACTIVATE non-nil, do not activate packages." + (setq epl--load-path-before-initialize load-path) + (package-initialize no-activate)) + +(defalias 'epl-refresh 'package-refresh-contents) + +(defun epl-add-archive (name url) + "Add a package archive with NAME and URL." + (add-to-list 'package-archives (cons name url))) + +(defun epl-reset () + "Reset the package system. + +Clear the list of installed and available packages, the list of +package archives and reset the package directory." + (setq package-alist nil + package-archives nil + package-archive-contents nil + load-path epl--load-path-before-initialize) + (when (boundp 'package-obsolete-alist) ; Legacy package.el + (setq package-obsolete-alist nil)) + (epl-change-package-dir (epl-default-package-dir))) + + +;;; Package structures +(cl-defstruct (epl-requirement + (:constructor epl-requirement-create)) + "Structure describing a requirement. + +Slots: + +`name' The name of the required package, as symbol. + +`version' The version of the required package, as version list." + name + version) + +(defun epl-requirement-version-string (requirement) + "The version of a REQUIREMENT, as string." + (package-version-join (epl-requirement-version requirement))) + +(cl-defstruct (epl-package (:constructor epl-package-create)) + "Structure representing a package. + +Slots: + +`name' The package name, as symbol. + +`description' The package description. + +The format package description varies between package.el +variants. For `package-desc' variants, it is simply the +corresponding `package-desc' object. For legacy variants, it is +a vector `[VERSION REQS DOCSTRING]'. + +Do not access `description' directly, but instead use the +`epl-package' accessors." + name + description) + +(defmacro epl-package-as-description (var &rest body) + "Cast VAR to a package description in BODY. + +VAR is a symbol, bound to an `epl-package' object. This macro +casts this object to the `description' object, and binds the +description to VAR in BODY." + (declare (indent 1)) + (unless (symbolp var) + (signal 'wrong-type-argument (list #'symbolp var))) + `(if (epl-package-p ,var) + (let ((,var (epl-package-description ,var))) + ,@body) + (signal 'wrong-type-argument (list #'epl-package-p ,var)))) + +(defsubst epl-package--package-desc-p (package) + "Whether the description of PACKAGE is a `package-desc'." + (epl--package-desc-p (epl-package-description package))) + +(defun epl-package-version (package) + "Get the version of PACKAGE, as version list." + (epl-package-as-description package + (cond + ((fboundp 'package-desc-version) (package-desc-version package)) + ;; Legacy + ((fboundp 'package-desc-vers) + (let ((version (package-desc-vers package))) + (if (listp version) version (version-to-list version)))) + (:else (error "Cannot get version from %S" package))))) + +(defun epl-package-version-string (package) + "Get the version from a PACKAGE, as string." + (package-version-join (epl-package-version package))) + +(defun epl-package-summary (package) + "Get the summary of PACKAGE, as string." + (epl-package-as-description package + (cond + ((fboundp 'package-desc-summary) (package-desc-summary package)) + ((fboundp 'package-desc-doc) (package-desc-doc package)) ; Legacy + (:else (error "Cannot get summary from %S" package))))) + +(defsubst epl-requirement--from-req (req) + "Create a `epl-requirement' from a `package-desc' REQ." + (let ((version (cadr req))) + (epl-requirement-create :name (car req) + :version (if (listp version) version + (version-to-list version))))) + +(defun epl-package-requirements (package) + "Get the requirements of PACKAGE. + +The requirements are a list of `epl-requirement' objects." + (epl-package-as-description package + (mapcar #'epl-requirement--from-req (package-desc-reqs package)))) + +(defun epl-package-directory (package) + "Get the directory PACKAGE is installed to. + +Return the absolute path of the installation directory of +PACKAGE, or nil, if PACKAGE is not installed." + (cond + ((fboundp 'package-desc-dir) + (package-desc-dir (epl-package-description package))) + ((fboundp 'package--dir) + (package--dir (symbol-name (epl-package-name package)) + (epl-package-version-string package))) + (:else (error "Cannot get package directory from %S" package)))) + +(defun epl-package-->= (pkg1 pkg2) + "Determine whether PKG1 is before PKG2 by version." + (not (version-list-< (epl-package-version pkg1) + (epl-package-version pkg2)))) + +(defun epl-package--from-package-desc (package-desc) + "Create an `epl-package' from a PACKAGE-DESC. + +PACKAGE-DESC is a `package-desc' object, from recent package.el +variants." + (if (and (fboundp 'package-desc-name) + (epl--package-desc-p package-desc)) + (epl-package-create :name (package-desc-name package-desc) + :description package-desc) + (signal 'wrong-type-argument (list 'epl--package-desc-p package-desc)))) + +(defun epl-package--parse-info (info) + "Parse a package.el INFO." + (if (epl--package-desc-p info) + (epl-package--from-package-desc info) + ;; For legacy package.el, info is a vector [NAME REQUIRES DESCRIPTION + ;; VERSION COMMENTARY]. We need to re-shape this vector into the + ;; `package-alist' format [VERSION REQUIRES DESCRIPTION] to attach it to the + ;; new `epl-package'. + (let ((name (intern (aref info 0))) + (info (vector (aref info 3) (aref info 1) (aref info 2)))) + (epl-package-create :name name :description info)))) + +(defun epl-package-from-buffer (&optional buffer) + "Create an `epl-package' object from BUFFER. + +BUFFER defaults to the current buffer. + +Signal `epl-invalid-package' if the buffer does not contain a +valid package file." + (let ((info (with-current-buffer (or buffer (current-buffer)) + (condition-case err + (package-buffer-info) + (error (signal 'epl-invalid-package (cdr err))))))) + (epl-package--parse-info info))) + +(defun epl-package-from-lisp-file (file-name) + "Parse the package headers the file at FILE-NAME. + +Return an `epl-package' object with the header metadata." + (with-temp-buffer + (insert-file-contents file-name) + (condition-case err + (epl-package-from-buffer (current-buffer)) + ;; Attach file names to invalid package errors + (epl-invalid-package + (signal 'epl-invalid-package-file (cons file-name (cdr err)))) + ;; Forward other errors + (error (signal (car err) (cdr err)))))) + +(defun epl-package-from-tar-file (file-name) + "Parse the package tarball at FILE-NAME. + +Return a `epl-package' object with the meta data of the tarball +package in FILE-NAME." + (condition-case nil + ;; In legacy package.el, `package-tar-file-info' takes the name of the tar + ;; file to parse as argument. In modern package.el, it has no arguments + ;; and works on the current buffer. Hence, we just try to call the legacy + ;; version, and if that fails because of a mismatch between formal and + ;; actual arguments, we use the modern approach. To avoid spurious + ;; signature warnings by the byte compiler, we suppress warnings when + ;; calling the function. + (epl-package--parse-info (with-no-warnings + (package-tar-file-info file-name))) + (wrong-number-of-arguments + (with-temp-buffer + (insert-file-contents-literally file-name) + ;; Switch to `tar-mode' to enable extraction of the file. Modern + ;; `package-tar-file-info' relies on `tar-mode', and signals an error if + ;; called in a buffer with a different mode. + (tar-mode) + (epl-package--parse-info (with-no-warnings + (package-tar-file-info))))))) + +(defun epl-package-from-file (file-name) + "Parse the package at FILE-NAME. + +Return an `epl-package' object with the meta data of the package +at FILE-NAME." + (if (string-match-p (rx ".tar" string-end) file-name) + (epl-package-from-tar-file file-name) + (epl-package-from-lisp-file file-name))) + +(defun epl-package--parse-descriptor-requirement (requirement) + "Parse a REQUIREMENT in a package descriptor." + ;; This function is only called on legacy package.el. On package-desc + ;; package.el, we just let package.el do the work. + (cl-destructuring-bind (name version-string) requirement + (list name (version-to-list version-string)))) + +(defun epl-package-from-descriptor-file (descriptor-file) + "Load a `epl-package' from a package DESCRIPTOR-FILE. + +A package descriptor is a file defining a new package. Its name +typically ends with -pkg.el." + (with-temp-buffer + (insert-file-contents descriptor-file) + (goto-char (point-min)) + (let ((sexp (read (current-buffer)))) + (unless (eq (car sexp) 'define-package) + (error "%S is no valid package descriptor" descriptor-file)) + (if (and (fboundp 'package-desc-from-define) + (fboundp 'package-desc-name)) + ;; In Emacs snapshot, we can conveniently call a function to parse the + ;; descriptor + (let ((desc (apply #'package-desc-from-define (cdr sexp)))) + (epl-package-create :name (package-desc-name desc) + :description desc)) + ;; In legacy package.el, we must manually deconstruct the descriptor, + ;; because the load function has eval's the descriptor and has a lot of + ;; global side-effects. + (cl-destructuring-bind + (name version-string summary requirements) (cdr sexp) + (epl-package-create + :name (intern name) + :description + (vector (version-to-list version-string) + (mapcar #'epl-package--parse-descriptor-requirement + ;; Strip the leading `quote' from the package list + (cadr requirements)) + summary))))))) + + +;;; Package database access +(defun epl-package-installed-p (package) + "Determine whether a PACKAGE is installed. + +PACKAGE is either a package name as symbol, or a package object." + (let ((name (if (epl-package-p package) + (epl-package-name package) + package)) + (version (when (epl-package-p package) + (epl-package-version package)))) + (package-installed-p name version))) + +(defun epl--parse-built-in-entry (entry) + "Parse an ENTRY from the list of built-in packages. + +Return the corresponding `epl-package' object." + (if (fboundp 'package--from-builtin) + ;; In package-desc package.el, convert the built-in package to a + ;; `package-desc' and convert that to an `epl-package' + (epl-package--from-package-desc (package--from-builtin entry)) + (epl-package-create :name (car entry) :description (cdr entry)))) + +(defun epl-built-in-packages () + "Get all built-in packages. + +Return a list of `epl-package' objects." + ;; This looks mighty strange, but it's the only way to force package.el to + ;; build the list of built-in packages. Without this, `package--builtins' + ;; might be empty. + (package-built-in-p 'foo) + (mapcar #'epl--parse-built-in-entry package--builtins)) + +(defun epl-find-built-in-package (name) + "Find a built-in package with NAME. + +NAME is a package name, as symbol. + +Return the built-in package as `epl-package' object, or nil if +there is no built-in package with NAME." + (when (package-built-in-p name) + ;; We must call `package-built-in-p' *before* inspecting + ;; `package--builtins', because otherwise `package--builtins' might be + ;; empty. + (epl--parse-built-in-entry (assq name package--builtins)))) + +(defun epl-package-outdated-p (package) + "Determine whether a PACKAGE is outdated. + +A package is outdated, if there is an available package with a +higher version. + +PACKAGE is either a package name as symbol, or a package object. +In the former case, test the installed or built-in package with +the highest version number, in the later case, test the package +object itself. + +Return t, if the package is outdated, or nil otherwise." + (let* ((package (if (epl-package-p package) + package + (or (car (epl-find-installed-packages package)) + (epl-find-built-in-package package)))) + (available (car (epl-find-available-packages + (epl-package-name package))))) + (and package available (version-list-< (epl-package-version package) + (epl-package-version available))))) + +(defun epl--parse-package-list-entry (entry) + "Parse a list of packages from ENTRY. + +ENTRY is a single entry in a package list, e.g. `package-alist', +`package-archive-contents', etc. Typically it is a cons cell, +but the exact format varies between package.el versions. This +function tries to parse all known variants. + +Return a list of `epl-package' objects parsed from ENTRY." + (let ((descriptions (cdr entry))) + (cond + ((listp descriptions) + (sort (mapcar #'epl-package--from-package-desc descriptions) + #'epl-package-->=)) + ;; Legacy package.el has just a single package in an entry, which is a + ;; standard description vector + ((vectorp descriptions) + (list (epl-package-create :name (car entry) + :description descriptions))) + (:else (error "Cannot parse entry %S" entry))))) + +(defun epl-installed-packages () + "Get all installed packages. + +Return a list of package objects." + (apply #'append (mapcar #'epl--parse-package-list-entry package-alist))) + +(defsubst epl--filter-outdated-packages (packages) + "Filter outdated packages from PACKAGES." + (let (res) + (dolist (package packages) + (when (epl-package-outdated-p package) + (push package res))) + (nreverse res))) + +(defun epl-outdated-packages () + "Get all outdated packages, as in `epl-package-outdated-p'. + +Return a list of package objects." + (epl--filter-outdated-packages (epl-installed-packages))) + +(defsubst epl--find-package-in-list (name list) + "Find a package by NAME in a package LIST. + +Return a list of corresponding `epl-package' objects." + (let ((entry (assq name list))) + (when entry + (epl--parse-package-list-entry entry)))) + +(defun epl-find-installed-package (name) + "Find the latest installed package by NAME. + +NAME is a package name, as symbol. + +Return the installed package with the highest version number as +`epl-package' object, or nil, if no package with NAME is +installed." + (car (epl-find-installed-packages name))) +(make-obsolete 'epl-find-installed-package 'epl-find-installed-packages "0.7") + +(defun epl-find-installed-packages (name) + "Find all installed packages by NAME. + +NAME is a package name, as symbol. + +Return a list of all installed packages with NAME, sorted by +version number in descending order. Return nil, if there are no +packages with NAME." + (epl--find-package-in-list name package-alist)) + +(defun epl-available-packages () + "Get all packages available for installation. + +Return a list of package objects." + (apply #'append (mapcar #'epl--parse-package-list-entry + package-archive-contents))) + +(defun epl-find-available-packages (name) + "Find available packages for NAME. + +NAME is a package name, as symbol. + +Return a list of available packages for NAME, sorted by version +number in descending order. Return nil, if there are no packages +for NAME." + (epl--find-package-in-list name package-archive-contents)) + +(cl-defstruct (epl-upgrade + (:constructor epl-upgrade-create)) + "Structure describing an upgradable package. +Slots: + +`installed' The installed package + +`available' The package available for installation." + installed + available) + +(defun epl-find-upgrades (&optional packages) + "Find all upgradable PACKAGES. + +PACKAGES is a list of package objects to upgrade, defaulting to +all installed packages. + +Return a list of `epl-upgrade' objects describing all upgradable +packages." + (let ((packages (or packages (epl-installed-packages))) + upgrades) + (dolist (pkg packages) + (let* ((version (epl-package-version pkg)) + (name (epl-package-name pkg)) + ;; Find the latest available package for NAME + (available-pkg (car (epl-find-available-packages name))) + (available-version (when available-pkg + (epl-package-version available-pkg)))) + (when (and available-version (version-list-< version available-version)) + (push (epl-upgrade-create :installed pkg + :available available-pkg) + upgrades)))) + (nreverse upgrades))) + +(defalias 'epl-built-in-p 'package-built-in-p) + + +;;; Package operations + +(defalias 'epl-install-file 'package-install-file) + +(defun epl-package-install (package &optional force) + "Install a PACKAGE. + +PACKAGE is a `epl-package' object. If FORCE is given and +non-nil, install PACKAGE, even if it is already installed." + (when (or force (not (epl-package-installed-p package))) + (if (epl-package--package-desc-p package) + (package-install (epl-package-description package)) + ;; The legacy API installs by name. We have no control over versioning, + ;; etc. + (package-install (epl-package-name package))))) + +(defun epl-package-delete (package) + "Delete a PACKAGE. + +PACKAGE is a `epl-package' object to delete." + ;; package-delete allows for packages being trashed instead of fully deleted. + ;; Let's prevent his silly behavior + (let ((delete-by-moving-to-trash nil)) + ;; The byte compiler will warn us that we are calling `package-delete' with + ;; the wrong number of arguments, since it can't infer that we guarantee to + ;; always call the correct version. Thus we suppress all warnings when + ;; calling `package-delete'. I wish there was a more granular way to + ;; disable just that specific warning, but it is what it is. + (if (epl-package--package-desc-p package) + (with-no-warnings + (package-delete (epl-package-description package))) + ;; The legacy API deletes by name (as string!) and version instead by + ;; descriptor. Hence `package-delete' takes two arguments. For some + ;; insane reason, the arguments are strings here! + (let ((name (symbol-name (epl-package-name package))) + (version (epl-package-version-string package))) + (with-no-warnings + (package-delete name version)) + ;; Legacy package.el does not remove the deleted package + ;; from the `package-alist', so we do it manually here. + (let ((pkg (assq (epl-package-name package) package-alist))) + (when pkg + (setq package-alist (delq pkg package-alist)))))))) + +(defun epl-upgrade (&optional packages preserve-obsolete) + "Upgrade PACKAGES. + +PACKAGES is a list of package objects to upgrade, defaulting to +all installed packages. + +The old versions of the updated packages are deleted, unless +PRESERVE-OBSOLETE is non-nil. + +Return a list of all performed upgrades, as a list of +`epl-upgrade' objects." + (let ((upgrades (epl-find-upgrades packages))) + (dolist (upgrade upgrades) + (epl-package-install (epl-upgrade-available upgrade) 'force) + (unless preserve-obsolete + (epl-package-delete (epl-upgrade-installed upgrade)))) + upgrades)) + +(provide 'epl) + +;;; epl.el ends here diff --git a/elpa/pkg-info-0.6/pkg-info-autoloads.el b/elpa/pkg-info-0.6/pkg-info-autoloads.el new file mode 100644 --- /dev/null +++ b/elpa/pkg-info-0.6/pkg-info-autoloads.el @@ -0,0 +1,122 @@ +;;; pkg-info-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "pkg-info" "pkg-info.el" (22782 38550 605214 +;;;;;; 495000)) +;;; Generated autoloads from pkg-info.el + +(autoload 'pkg-info-library-original-version "pkg-info" "\ +Get the original version in the header of LIBRARY. + +The original version is stored in the X-Original-Version header. +This header is added by the MELPA package archive to preserve +upstream version numbers. + +LIBRARY is either a symbol denoting a named feature, or a library +name as string. + +If SHOW is non-nil, show the version in the minibuffer. + +Return the version from the header of LIBRARY as list. Signal an +error if the LIBRARY was not found or had no X-Original-Version +header. + +See Info node `(elisp)Library Headers' for more information +about library headers. + +\(fn LIBRARY &optional SHOW)" t nil) + +(autoload 'pkg-info-library-version "pkg-info" "\ +Get the version in the header of LIBRARY. + +LIBRARY is either a symbol denoting a named feature, or a library +name as string. + +If SHOW is non-nil, show the version in the minibuffer. + +Return the version from the header of LIBRARY as list. Signal an +error if the LIBRARY was not found or had no proper header. + +See Info node `(elisp)Library Headers' for more information +about library headers. + +\(fn LIBRARY &optional SHOW)" t nil) + +(autoload 'pkg-info-defining-library-original-version "pkg-info" "\ +Get the original version of the library defining FUNCTION. + +The original version is stored in the X-Original-Version header. +This header is added by the MELPA package archive to preserve +upstream version numbers. + +If SHOW is non-nil, show the version in mini-buffer. + +This function is mainly intended to find the version of a major +or minor mode, i.e. + + (pkg-info-defining-library-version 'flycheck-mode) + +Return the version of the library defining FUNCTION. Signal an +error if FUNCTION is not a valid function, if its defining +library was not found, or if the library had no proper version +header. + +\(fn FUNCTION &optional SHOW)" t nil) + +(autoload 'pkg-info-defining-library-version "pkg-info" "\ +Get the version of the library defining FUNCTION. + +If SHOW is non-nil, show the version in mini-buffer. + +This function is mainly intended to find the version of a major +or minor mode, i.e. + + (pkg-info-defining-library-version 'flycheck-mode) + +Return the version of the library defining FUNCTION. Signal an +error if FUNCTION is not a valid function, if its defining +library was not found, or if the library had no proper version +header. + +\(fn FUNCTION &optional SHOW)" t nil) + +(autoload 'pkg-info-package-version "pkg-info" "\ +Get the version of an installed PACKAGE. + +If SHOW is non-nil, show the version in the minibuffer. + +Return the version as list, or nil if PACKAGE is not installed. + +\(fn PACKAGE &optional SHOW)" t nil) + +(autoload 'pkg-info-version-info "pkg-info" "\ +Obtain complete version info for LIBRARY and PACKAGE. + +LIBRARY is a symbol denoting a named feature, or a library name +as string. PACKAGE is a symbol denoting an ELPA package. If +omitted or nil, default to LIBRARY. + +If SHOW is non-nil, show the version in the minibuffer. + +When called interactively, prompt for LIBRARY. When called +interactively with prefix argument, prompt for PACKAGE as well. + +Return a string with complete version information for LIBRARY. +This version information contains the version from the headers of +LIBRARY, and the version of the installed PACKAGE, the LIBRARY is +part of. If PACKAGE is not installed, or if the PACKAGE version +is the same as the LIBRARY version, do not include a package +version. + +\(fn LIBRARY &optional PACKAGE SHOW)" t nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; pkg-info-autoloads.el ends here diff --git a/elpa/pkg-info-0.6/pkg-info-pkg.el b/elpa/pkg-info-0.6/pkg-info-pkg.el new file mode 100644 --- /dev/null +++ b/elpa/pkg-info-0.6/pkg-info-pkg.el @@ -0,0 +1,1 @@ +(define-package "pkg-info" "0.6" "Information about packages" '((epl "0.8")) :url "https://github.com/lunaryorn/pkg-info.el" :keywords '("convenience")) diff --git a/elpa/pkg-info-0.6/pkg-info.el b/elpa/pkg-info-0.6/pkg-info.el new file mode 100644 --- /dev/null +++ b/elpa/pkg-info-0.6/pkg-info.el @@ -0,0 +1,331 @@ +;;; pkg-info.el --- Information about packages -*- lexical-binding: t; -*- + +;; Copyright (C) 2013-2015 Sebastian Wiesner + +;; Author: Sebastian Wiesner +;; URL: https://github.com/lunaryorn/pkg-info.el +;; Package-Version: 0.6 +;; Keywords: convenience +;; Version: 0.6 +;; Package-Requires: ((epl "0.8")) + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This library extracts information from installed packages. + +;;;; Functions: + +;; `pkg-info-library-version' extracts the version from the header of a library. +;; +;; `pkg-info-defining-library-version' extracts the version from the header of a +;; library defining a function. +;; +;; `pkg-info-package-version' gets the version of an installed package. +;; +;; `pkg-info-format-version' formats a version list as human readable string. +;; +;; `pkg-info-version-info' returns complete version information for a specific +;; package. +;; +;; `pkg-info-get-melpa-recipe' gets the MELPA recipe for a package. +;; +;; `pkg-info-get-melpa-fetcher' gets the fetcher used to build a package on +;; MELPA. +;; +;; `pkg-info-wiki-package-p' determines whether a package was build from +;; EmacsWiki on MELPA. + +;;; Code: + +(require 'epl) + +(require 'lisp-mnt) +(require 'find-func) +(require 'json) ; `json-read' +(require 'url-http) ; `url-http-parse-response' + +(defvar url-http-end-of-headers) + + +;;; Version information +(defun pkg-info-format-version (version) + "Format VERSION as human-readable string. + +Return a human-readable string representing VERSION." + ;; XXX: Find a better, more flexible way of formatting? + (package-version-join version)) + +(defsubst pkg-info--show-version-and-return (version show) + "Show and return VERSION. + +When SHOW is non-nil, show VERSION in minibuffer. + +Return VERSION." + (when show + (message (if (listp version) (pkg-info-format-version version) version))) + version) + +(defun pkg-info--read-library () + "Read a library from minibuffer." + (completing-read "Load library: " + (apply-partially 'locate-file-completion-table + load-path + (get-load-suffixes)))) + +(defun pkg-info--read-function () + "Read a function name from minibuffer." + (let ((input (completing-read "Function: " obarray #'boundp :require-match))) + (if (string= input "") nil (intern input)))) + +(defun pkg-info--read-package () + "Read a package name from minibuffer." + (let* ((installed (epl-installed-packages)) + (names (sort (mapcar (lambda (pkg) + (symbol-name (epl-package-name pkg))) + installed) + #'string<)) + (default (car names))) + (completing-read "Installed package: " names nil 'require-match + nil nil default))) + +(defun pkg-info-library-source (library) + "Get the source file of LIBRARY. + +LIBRARY is either a symbol denoting a named feature, or a library +name as string. + +Return the source file of LIBRARY as string." + (find-library-name (if (symbolp library) (symbol-name library) library))) + +(defun pkg-info-defining-library (function) + "Get the source file of the library defining FUNCTION. + +FUNCTION is a function symbol. + +Return the file name of the library as string. Signal an error +if the library does not exist, or if the definition of FUNCTION +was not found." + (unless (functionp function) + (signal 'wrong-type-argument (list 'functionp function))) + (let ((library (symbol-file function 'defun))) + (unless library + (error "Can't find definition of %s" function)) + library)) + +(defun pkg-info-x-original-version (file) + "Read the X-Original-Version header from FILE. + +Return the value as version list, or return nil if FILE lacks +this header. Signal an error, if the value of the header is not +a valid version." + (let ((version-str (with-temp-buffer + (insert-file-contents file) + (lm-header "X-Original-Version")))) + (when version-str + (version-to-list version-str)))) + +;;;###autoload +(defun pkg-info-library-original-version (library &optional show) + "Get the original version in the header of LIBRARY. + +The original version is stored in the X-Original-Version header. +This header is added by the MELPA package archive to preserve +upstream version numbers. + +LIBRARY is either a symbol denoting a named feature, or a library +name as string. + +If SHOW is non-nil, show the version in the minibuffer. + +Return the version from the header of LIBRARY as list. Signal an +error if the LIBRARY was not found or had no X-Original-Version +header. + +See Info node `(elisp)Library Headers' for more information +about library headers." + (interactive (list (pkg-info--read-library) t)) + (let ((version (pkg-info-x-original-version + (pkg-info-library-source library)))) + (if version + (pkg-info--show-version-and-return version show) + (error "Library %s has no original version" library)))) + +;;;###autoload +(defun pkg-info-library-version (library &optional show) + "Get the version in the header of LIBRARY. + +LIBRARY is either a symbol denoting a named feature, or a library +name as string. + +If SHOW is non-nil, show the version in the minibuffer. + +Return the version from the header of LIBRARY as list. Signal an +error if the LIBRARY was not found or had no proper header. + +See Info node `(elisp)Library Headers' for more information +about library headers." + (interactive (list (pkg-info--read-library) t)) + (let* ((source (pkg-info-library-source library)) + (version (epl-package-version (epl-package-from-file source)))) + (pkg-info--show-version-and-return version show))) + +;;;###autoload +(defun pkg-info-defining-library-original-version (function &optional show) + "Get the original version of the library defining FUNCTION. + +The original version is stored in the X-Original-Version header. +This header is added by the MELPA package archive to preserve +upstream version numbers. + +If SHOW is non-nil, show the version in mini-buffer. + +This function is mainly intended to find the version of a major +or minor mode, i.e. + + (pkg-info-defining-library-version 'flycheck-mode) + +Return the version of the library defining FUNCTION. Signal an +error if FUNCTION is not a valid function, if its defining +library was not found, or if the library had no proper version +header." + (interactive (list (pkg-info--read-function) t)) + (pkg-info-library-original-version (pkg-info-defining-library function) show)) + +;;;###autoload +(defun pkg-info-defining-library-version (function &optional show) + "Get the version of the library defining FUNCTION. + +If SHOW is non-nil, show the version in mini-buffer. + +This function is mainly intended to find the version of a major +or minor mode, i.e. + + (pkg-info-defining-library-version 'flycheck-mode) + +Return the version of the library defining FUNCTION. Signal an +error if FUNCTION is not a valid function, if its defining +library was not found, or if the library had no proper version +header." + (interactive (list (pkg-info--read-function) t)) + (pkg-info-library-version (pkg-info-defining-library function) show)) + +;;;###autoload +(defun pkg-info-package-version (package &optional show) + "Get the version of an installed PACKAGE. + +If SHOW is non-nil, show the version in the minibuffer. + +Return the version as list, or nil if PACKAGE is not installed." + (interactive (list (pkg-info--read-package) t)) + (let* ((name (if (stringp package) (intern package) package)) + (package (car (epl-find-installed-packages name)))) + (unless package + (error "Can't find installed package %s" name)) + (pkg-info--show-version-and-return (epl-package-version package) show))) + +;;;###autoload +(defun pkg-info-version-info (library &optional package show) + "Obtain complete version info for LIBRARY and PACKAGE. + +LIBRARY is a symbol denoting a named feature, or a library name +as string. PACKAGE is a symbol denoting an ELPA package. If +omitted or nil, default to LIBRARY. + +If SHOW is non-nil, show the version in the minibuffer. + +When called interactively, prompt for LIBRARY. When called +interactively with prefix argument, prompt for PACKAGE as well. + +Return a string with complete version information for LIBRARY. +This version information contains the version from the headers of +LIBRARY, and the version of the installed PACKAGE, the LIBRARY is +part of. If PACKAGE is not installed, or if the PACKAGE version +is the same as the LIBRARY version, do not include a package +version." + (interactive (list (pkg-info--read-library) + (when current-prefix-arg + (pkg-info--read-package)) + t)) + (let* ((package (or package (if (stringp library) (intern library) library))) + (orig-version (condition-case nil + (pkg-info-library-original-version library) + (error nil))) + ;; If we have X-Original-Version, we assume that MELPA replaced the + ;; library version with its generated version, so we use the + ;; X-Original-Version header instead, and ignore the library version + ;; header + (lib-version (or orig-version (pkg-info-library-version library))) + (pkg-version (condition-case nil + (pkg-info-package-version package) + (error nil))) + (version (if (and pkg-version + (not (version-list-= lib-version pkg-version))) + (format "%s (package: %s)" + (pkg-info-format-version lib-version) + (pkg-info-format-version pkg-version)) + (pkg-info-format-version lib-version)))) + (pkg-info--show-version-and-return version show))) + +(defconst pkg-info-melpa-recipe-url "http://melpa.org/recipes.json" + "The URL from which to fetch MELPA recipes.") + +(defvar pkg-info-melpa-recipes nil + "An alist of MELPA recipes.") + +(defun pkg-info-retrieve-melpa-recipes () + "Retrieve MELPA recipes from MELPA archive." + (let ((buffer (url-retrieve-synchronously pkg-info-melpa-recipe-url))) + (with-current-buffer buffer + (unwind-protect + (let ((response-code (url-http-parse-response))) + (unless (equal response-code 200) + (error "Failed to retrieve MELPA recipes from %s (code %s)" + pkg-info-melpa-recipe-url response-code)) + (goto-char url-http-end-of-headers) + (json-read)) + (when (and buffer (buffer-live-p buffer)) + (kill-buffer buffer)))))) + +(defun pkg-info-get-melpa-recipes () + "Get MELPA recipes." + (setq pkg-info-melpa-recipes + (or pkg-info-melpa-recipes + (pkg-info-retrieve-melpa-recipes)))) + +(defun pkg-info-get-melpa-recipe (package) + "Get the MELPA recipe for PACKAGE. + +Return nil if PACKAGE is not on MELPA." + (cdr (assq package (pkg-info-get-melpa-recipes)))) + +(defun pkg-info-get-melpa-fetcher (package) + "Get the MELPA fetcher for PACKAGE." + (cdr (assq 'fetcher (pkg-info-get-melpa-recipe package)))) + +(defun pkg-info-wiki-package-p (package) + "Determine whether PACKAGE is build from the EmacsWiki." + (equal (pkg-info-get-melpa-fetcher package) "wiki")) + +(provide 'pkg-info) + +;; Local Variables: +;; indent-tabs-mode: nil +;; coding: utf-8 +;; End: + +;;; pkg-info.el ends here diff --git a/elpa/puppet-mode-0.3/puppet-mode-autoloads.el b/elpa/puppet-mode-0.3/puppet-mode-autoloads.el new file mode 100644 --- /dev/null +++ b/elpa/puppet-mode-0.3/puppet-mode-autoloads.el @@ -0,0 +1,24 @@ +;;; puppet-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "puppet-mode" "puppet-mode.el" (22782 38552 +;;;;;; 233246 702000)) +;;; Generated autoloads from puppet-mode.el + +(autoload 'puppet-mode "puppet-mode" "\ + + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("\\.pp\\'" . puppet-mode)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; puppet-mode-autoloads.el ends here diff --git a/elpa/puppet-mode-0.3/puppet-mode-pkg.el b/elpa/puppet-mode-0.3/puppet-mode-pkg.el new file mode 100644 --- /dev/null +++ b/elpa/puppet-mode-0.3/puppet-mode-pkg.el @@ -0,0 +1,1 @@ +(define-package "puppet-mode" "0.3" "Major mode for Puppet manifests" '((emacs "24.1") (cl-lib "0.5") (pkg-info "0.4")) :url "https://github.com/lunaryorn/puppet-mode" :keywords '("languages")) diff --git a/elpa/puppet-mode-0.3/puppet-mode.el b/elpa/puppet-mode-0.3/puppet-mode.el new file mode 100644 --- /dev/null +++ b/elpa/puppet-mode-0.3/puppet-mode.el @@ -0,0 +1,896 @@ +;;; puppet-mode.el --- Major mode for Puppet manifests -*- lexical-binding: t; -*- + +;; Copyright (C) 2013, 2014 Sebastian Wiesner +;; Copyright (C) 2013, 2014 Bozhidar Batsov +;; Copyright (C) 2011 Puppet Labs Inc + +;; Author: Bozhidar Batsov +;; Sebastian Wiesner +;; Russ Allbery +;; Maintainer: Bozhidar Batsov +;; Sebastian Wiesner +;; URL: https://github.com/lunaryorn/puppet-mode +;; Package-Version: 0.3 +;; Keywords: languages +;; Version: 0.3 +;; Package-Requires: ((emacs "24.1") (cl-lib "0.5") (pkg-info "0.4")) + +;; This file is not part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;; This file incorporates work covered by the following copyright and +;; permission notice: + +;; 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: + +;; Major mode for Puppet manifests + +;;; Code: + + +;;;; Compatibility +(eval-and-compile + ;; `defvar-local' for Emacs 24.2 and below + (unless (fboundp 'defvar-local) + (defmacro defvar-local (var val &optional docstring) + "Define VAR as a buffer-local variable with default value VAL. +Like `defvar' but additionally marks the variable as being automatically +buffer-local wherever it is set." + (declare (debug defvar) (doc-string 3)) + `(progn + (defvar ,var ,val ,docstring) + (make-variable-buffer-local ',var)))) + + ;; `setq-local' for Emacs 24.2 and below + (unless (fboundp 'setq-local) + (defmacro setq-local (var val) + "Set variable VAR to value VAL in current buffer." + `(set (make-local-variable ',var) ,val)))) + + +;;;; Requirements +(require 'pkg-info) + +(require 'cl-lib) +(require 'rx) +(require 'align) + + +;;;; Customization +(defgroup puppet nil + "Puppet mastering in Emacs" + :prefix "puppet-" + :group 'languages + :link '(url-link :tag "Github" "https://github.com/lunaryorn/puppet-mode") + :link '(emacs-commentary-link :tag "Commentary" "puppet-mode")) + +(defcustom puppet-indent-level 2 + "Indentation of Puppet statements." + :type 'integer + :group 'puppet + :safe 'integerp) + +(defcustom puppet-include-indent 2 + "Indentation of continued Puppet include statements." + :type 'integer + :group 'puppet + :safe 'integerp) + +(defcustom puppet-indent-tabs-mode nil + "Indentation can insert tabs in puppet mode if this is non-nil." + :type 'boolean + :group 'puppet + :safe 'booleanp) + +(defcustom puppet-comment-column 32 + "Indentation column of comments." + :type 'integer + :group 'puppet + :safe 'integerp) + +(defcustom puppet-fontify-variables-in-comments nil + "When non-nil, fontify variable references in comments." + :type 'boolean + :group 'puppet + :safe 'booleanp + :package-version '(puppet-mode . "0.3")) + +(defcustom puppet-validate-command "puppet parser validate --color=false" + "Command to validate the syntax of a Puppet manifest." + :type 'string + :group 'puppet) + +(defcustom puppet-lint-command + (concat + "puppet-lint --with-context " + "--log-format \"%{path}:%{linenumber}: %{kind}: %{message} (%{check})\"") + "Command to lint a Puppet manifest." + :type 'string + :group 'puppet + :package-version '(puppet-mode . "0.3")) + +(defcustom puppet-apply-command "puppet apply --verbose --noop" + "Command to apply a Puppet manifest." + :type 'string + :group 'puppet + :package-version '(puppet-mode . "0.3")) + +(defface puppet-regular-expression-literal + '((t :inherit font-lock-constant-face)) + "Face for regular expression literals in Puppet." + :group 'puppet + :package-version '(puppet-mode . "0.3")) + +(defface puppet-escape-sequence + '((t :inherit font-lock-constant-face)) + "Face for escape sequences in double-quoted strings-consed literals in Puppet." + :group 'puppet + :package-version '(puppet-mode . "0.3")) + + +;;;; Version information +(defun puppet-version (&optional show-version) + "Get the Puppet Mode version as string. + +If called interactively or if SHOW-VERSION is non-nil, show the +version in the echo area and the messages buffer. + +The returned string includes both, the version from package.el +and the library version, if both a present and different. + +If the version number could not be determined, signal an error, +if called interactively, or if SHOW-VERSION is non-nil, otherwise +just return nil." + (interactive (list t)) + (let ((version (pkg-info-version-info 'puppet-mode))) + (when show-version + (message "Puppet Mode version: %s" version)) + version)) + + +;;;; Utilities + +(defun puppet-syntax-context (&optional pos) + "Determine the syntax context at POS, defaulting to point. + +Return nil, if there is no special context at POS, or one of + +`comment' + POS is inside a comment + +`single-quoted' + POS is inside a single-quoted string + +`double-quoted' + POS is inside a double-quoted string" + (let ((state (save-excursion (syntax-ppss pos)))) + (if (nth 4 state) + 'comment + (cl-case (nth 3 state) + (?\' 'single-quoted) + (?\" 'double-quoted))))) + +(defun puppet-in-string-or-comment-p (&optional pos) + "Determine whether POS is inside a string or comment." + (not (null (puppet-syntax-context pos)))) + + +;;;; Specialized rx + +(eval-when-compile + (defconst puppet-rx-constituents + `( + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_reserved.html#reserved-words + (keyword . ,(rx symbol-start + (or "and" "case" "class" "default" "define" "else" "elsif" + "false" "if" "in" "import" "inherits" "node" "or" + "true" "undef" "unless") + symbol-end)) + ;; http://docs.puppetlabs.com/references/latest/function.html + (builtin-function . ,(rx symbol-start + (or "alert" "collect" "contain" + "create_resources" "crit" "debug" "defined" + "each" "emerg" "err" "extlookup" "fail" + "file" "filter" "fqdn_rand" "generate" + "hiera" "hiera_array" "hiera_hash" + "hiera_include" "include" "info" + "inline_template" "lookup" "map" "md5" + "notice" "realize" "reduce" "regsubst" + "require" "search" "select" "sha1" + "shellquote" "slice" "split" "sprintf" "tag" + "tagged" "template" "versioncmp" "warning") + symbol-end)) + ;; http://docs.puppetlabs.com/references/latest/type.html + (builtin-type . ,(rx symbol-start + (or "augeas" "computer" "cron" "exec" "file" + "filebucket" "group" "host" "interface" "k5login" + "macauthorization" "mailalias" "maillist" "mcx" + "mount" "nagios_command" "nagios_contact" + "nagios_contactgroup" "nagios_host" + "nagios_hostdependency" "nagios_hostescalation" + "nagios_hostextinfo" "nagios_hostgroup" + "nagios_service" "nagios_servicedependency" + "nagios_serviceescalation" "nagios_serviceextinfo" + "nagios_servicegroup" "nagios_timeperiod" "notify" + "package" "resources" "router" "schedule" + "scheduled_task" "selboolean" "selmodule" + "service" "ssh_authorized_key" "sshkey" "stage" + "tidy" "user" "vlan" "yumrepo" "zfs" "zone" + "zpool") + symbol-end)) + ;; http://docs.puppetlabs.com/references/stable/metaparameter.html. + ;; Strictly speaking, this is no meta parameter, but it's so common that + ;; it got a mention in the docs, see + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_resources.html#ensure, + ;; so we'll consider it as metaparameter anyway + (builtin-metaparam . ,(rx symbol-start + (or "alias" "audit" "before" "loglevel" "noop" + "notify" "require" "schedule" "stage" + "subscribe" "tag" + ;; Because it's so common and important + "ensure") + symbol-end)) + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_reserved.html#classes-and-types + (resource-name . ,(rx symbol-start + ;; Optional top-level scope + (optional (any "a-z") + (zero-or-more (any "a-z" "0-9" "_"))) + ;; Nested sub-scopes + (zero-or-more "::" + (any "a-z") + (zero-or-more (any "a-z" "0-9" "_"))) + symbol-end)) + (cap-resource-name . ,(rx symbol-start + ;; Optional top-level scope + (optional (any "A-Z") + (zero-or-more (any "a-z" "0-9" "_"))) + ;; Nested sub-scopes + (zero-or-more "::" + (any "A-Z") + (zero-or-more (any "a-z" "0-9" "_"))) + symbol-end)) + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_reserved.html#variables + (simple-variable-name . ,(rx symbol-start + (one-or-more (any "A-Z" "a-z" "0-9" "_")) + symbol-end)) + (variable-name . ,(rx symbol-start + ;; The optional scope designation + (optional + (optional (any "a-z") + (zero-or-more (any "A-Z" "a-z" "0-9" "_"))) + (zero-or-more "::" + (any "a-z") + (zero-or-more (any "A-Z" "a-z" "0-9" "_"))) + "::") + ;; The final variable name + (one-or-more (any "A-Z" "a-z" "0-9" "_")) + symbol-end)) + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#double-quoted-strings + (dq-escape . ,(rx (or line-start (not (any "\\"))) + (zero-or-more "\\\\") + ;; We do not include \n and \', because these are + ;; available in single-quoted strings as well + (group "\\" (any ?\" ?$ ?n ?r ?t ?s))))) + "Additional special sexps for `puppet-rx'") + + (defmacro puppet-rx (&rest sexps) + "Specialized `rx' variant for Puppet Mode. + +In addition to the standard forms of `rx', the following forms +are available: + +`keyword' + Any valid Puppet keyword + +`builtin-function' + Any built-in Puppet function + +`builtin-type' + Any built-in Puppet type + +`builtin-metaparam' + Any built-in meta-parameter, and `ensure' + +`resource-name' + Any valid resource name, including scopes + +`cap-resource-name' + Any capitalized resource name, including capitalized scopes + +`simple-variable-name' + Any variable name without scopes, without leading dollar sign + +`variable-name' + Any variable name including scopes, without a leading dollar sign + +`dq-escape' + Special escape sequences for double-quoted strings" + (let ((rx-constituents (append puppet-rx-constituents rx-constituents))) + (cond ((null sexps) + (error "No regexp")) + ((cdr sexps) + (rx-to-string `(and ,@sexps) t)) + (t + (rx-to-string (car sexps) t)))))) + + +;;;; Checking + +(defvar-local puppet-last-validate-command nil + "The last command used for validation.") + +(defvar-local puppet-last-lint-command nil + "The last command used for linting.") + +;; This variable is intentionally not buffer-local, since you typically only +;; apply top-level manifests, but not class or type definitions. +(defvar puppet-last-apply-command nil + "The last command used to apply a manifest.") + +(defun puppet-run-check-command (command buffer-name-template) + "Run COMMAND to check the current buffer." + (save-some-buffers (not compilation-ask-about-save) nil) + (compilation-start command nil (lambda (_) + (format buffer-name-template command)))) + +(defun puppet-read-command (prompt previous-command default-command) + "Read a command from minibuffer with PROMPT." + (let ((filename (or (buffer-file-name) ""))) + (read-string prompt (or previous-command + (concat default-command " " + (shell-quote-argument filename)))))) + +(defun puppet-validate (command) + "Validate the syntax of the current buffer with COMMAND. + +When called interactively, prompt for COMMAND." + (interactive (list (puppet-read-command "Validate command: " + puppet-last-validate-command + puppet-validate-command))) + (setq puppet-last-validate-command command) + (puppet-run-check-command command "*Puppet Validate: %s*")) + +(defun puppet-lint (command) + "Lint the current buffer with COMMAND. + +When called interactively, prompt for COMMAND." + (interactive (list (puppet-read-command "Lint command: " + puppet-last-lint-command + puppet-lint-command))) + (setq puppet-last-lint-command command) + (puppet-run-check-command command "*Puppet Lint: %s*")) + +(defun puppet-apply (command) + "Apply the current manifest with COMMAND. + +When called interactively, prompt for COMMAND." + (interactive (list (puppet-read-command "Apply command: " + puppet-last-apply-command + puppet-apply-command))) + (setq puppet-last-apply-command command) + (puppet-run-check-command command "*Puppet Apply: %s*")) + + +;;;; Navigation +;; TODO: Check which of these are still needed for SMIE + +(defun puppet-beginning-of-defun-function (&optional arg) + "Move to the ARG'th beginning of a block." + (let* ((arg (or arg 1)) + (search (if (< arg 0) #'search-forward #'search-backward)) + (steps (abs arg))) + (while (> steps 0) + (let ((pos (funcall search "{" nil 'no-error))) + ;; Skip over strings and comments + (while (and pos (puppet-in-string-or-comment-p pos)) + (setq pos (funcall search "{" nil 'no-error))) + (if pos + (cl-decf steps) + ;; Drop out of outer loop + (setq steps 0)))) + (when (< arg 0) + (backward-char)))) + + +;;;; Indentation code +(defun puppet-block-indent () + "If point is in a block, return the indentation of the first line of that +block (the line containing the opening brace). Used to set the indentation +of the closing brace of a block." + (save-excursion + (beginning-of-defun) + (current-indentation))) + +(defun puppet-in-array () + "If point is in an array, return the position of the opening '[' of +that array, else return nil." + (save-excursion + (save-match-data + (let ((opoint (point)) + (apoint (search-backward "[" nil t))) + (when apoint + ;; This is a bit of a hack and doesn't allow for strings. We really + ;; want to parse by sexps at some point. + (let ((close-brackets (count-matches "]" apoint opoint)) + (open-brackets 0)) + (while (and apoint (> close-brackets open-brackets)) + (setq apoint (search-backward "[" nil t)) + (when apoint + (setq close-brackets (count-matches "]" apoint opoint)) + (setq open-brackets (1+ open-brackets))))) + apoint))))) + +(defun puppet-in-include () + "If point is in a continued list of include statements, return the position +of the initial include plus puppet-include-indent." + (save-excursion + (save-match-data + (let ((include-column nil) + (not-found t)) + (while not-found + (forward-line -1) + (cond + ((bobp) + (setq not-found nil)) + ((looking-at "^\\s-*include\\s-+.*,\\s-*$") + (setq include-column + (+ (current-indentation) puppet-include-indent)) + (setq not-found nil)) + ((not (looking-at ".*,\\s-*$")) + (setq not-found nil)))) + include-column)))) + +(defun puppet-indent-line () + "Indent current line as puppet code." + (interactive) + (beginning-of-line) + (if (bobp) + (indent-line-to 0) ; First line is always non-indented + (let ((not-indented t) + (array-start (puppet-in-array)) + (include-start (puppet-in-include)) + (block-indent (puppet-block-indent)) + cur-indent) + (cond + (array-start + ;; This line probably starts with an element from an array. + ;; Indent the line to the same indentation as the first + ;; element in that array. That is, this... + ;; + ;; exec { + ;; "add_puppetmaster_mongrel_startup_links": + ;; command => "string1", + ;; creates => [ "string2", "string3", + ;; "string4", "string5", + ;; "string6", "string7", + ;; "string3" ], + ;; refreshonly => true, + ;; } + ;; + ;; ...should instead look like this: + ;; + ;; exec { + ;; "add_puppetmaster_mongrel_startup_links": + ;; command => "string1", + ;; creates => [ "string2", "string3", + ;; "string4", "string5", + ;; "string6", "string7", + ;; "string8" ], + ;; refreshonly => true, + ;; } + (save-excursion + (goto-char array-start) + (forward-char 1) + (re-search-forward "\\S-") + (forward-char -1) + (setq cur-indent (current-column)))) + (include-start + (setq cur-indent include-start)) + ((and (looking-at "^\\s-*},?\\s-*$") block-indent) + ;; This line contains a closing brace or a closing brace followed by a + ;; comma and we're at the inner block, so we should indent it matching + ;; the indentation of the opening brace of the block. + (setq cur-indent block-indent)) + (t + ;; Otherwise, we did not start on a block-ending-only line. + (save-excursion + ;; Iterate backwards until we find an indentation hint + (while not-indented + (forward-line -1) + (cond + ;; Comment lines are ignored unless we're at the start of the + ;; buffer. + ((eq (puppet-syntax-context) 'comment) + (if (bobp) + (setq not-indented nil))) + + ;; Brace or paren on a line by itself will already be indented to + ;; the right level, so we can cheat and stop there. + ((looking-at "^\\s-*[\)}]\\s-*") + (setq cur-indent (current-indentation)) + (setq not-indented nil)) + + ;; Brace (possibly followed by a comma) or paren not on a line by + ;; itself will be indented one level too much, but don't catch + ;; cases where the block is started and closed on the same line. + ((looking-at "^[^\n\({]*[\)}],?\\s-*$") + (setq cur-indent (- (current-indentation) puppet-indent-level)) + (setq not-indented nil)) + + ;; Indent by one level more than the start of our block. We lose + ;; if there is more than one block opened and closed on the same + ;; line but it's still unbalanced; hopefully people don't do that. + ((looking-at "^.*{[^\n}]*$") + (setq cur-indent (+ (current-indentation) puppet-indent-level)) + (setq not-indented nil)) + + ;; Indent by one level if the line ends with an open paren. + ((looking-at "^.*\(\\s-*$") + (setq cur-indent (+ (current-indentation) puppet-indent-level)) + (setq not-indented nil)) + + ;; Semicolon ends a block for a resource when multiple resources + ;; are defined in the same block, but try not to get the case of + ;; a complete resource on a single line wrong. + ((looking-at "^\\([^'\":\n]\\|\"[^\n\"]*\"\\|'[^\n']*'\\)*;\\s-*$") + (setq cur-indent (- (current-indentation) puppet-indent-level)) + (setq not-indented nil)) + + ;; Indent an extra level after : since it introduces a resource. + ((looking-at "^.*:\\s-*$") + (setq cur-indent (+ (current-indentation) puppet-indent-level)) + (setq not-indented nil)) + + ;; Start of buffer. + ((bobp) + (setq not-indented nil))))) + + ;; If this line contains only a closing paren, we should lose one + ;; level of indentation. + (if (looking-at "^\\s-*\)\\s-*$") + (setq cur-indent (- cur-indent puppet-indent-level))))) + + ;; We've figured out the indentation, so do it. + (if (and cur-indent (> cur-indent 0)) + (indent-line-to cur-indent) + (indent-line-to 0))))) + + +;;;; Font locking + +(defvar puppet-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?\' "\"'" table) + (modify-syntax-entry ?\" "\"\"" table) + ;; C-style comments. Yes, Puppet has these! + (modify-syntax-entry ?/ ". 14b" table) + (modify-syntax-entry ?* ". 23b" table) + (modify-syntax-entry ?# "<" table) + (modify-syntax-entry ?\n ">" table) + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?$ "'" table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?\( "()" table) + (modify-syntax-entry ?\) ")(" table) + (modify-syntax-entry ?\{ "(}" table) + (modify-syntax-entry ?\} "){" table) + (modify-syntax-entry ?\[ "(]" table) + (modify-syntax-entry ?\] ")[" table) + table) + "Syntax table in use in `puppet-mode' buffers.") + +(defvar puppet-font-lock-keywords + `( + ;; Regular expression literals + (, (rx (group "/" + (zero-or-more + (or (not (any "/" "\\" "\n")) ; Not the end of a regexp + (and "\\" not-newline))) ; Any escaped character + "/")) 1 'puppet-regular-expression-literal) + ;; Keywords + (,(puppet-rx keyword) 0 font-lock-keyword-face) + ;; Variables + (,(puppet-rx "$" variable-name) 0 font-lock-variable-name-face) + ;; Type declarations + (,(puppet-rx symbol-start (or "class" "define" "node") symbol-end + (one-or-more space) + (group resource-name)) + 1 font-lock-type-face) + ;; Resource usage, see + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_resources.html + (,(puppet-rx symbol-start + (group (repeat 0 2 "@") ; Virtual and exported resources + resource-name) + (zero-or-more space) "{") + 1 font-lock-type-face) + ;; Resource defaults, see + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_defaults.html + (,(puppet-rx (group cap-resource-name) (zero-or-more space) "{") + 1 font-lock-type-face) + ;; Resource references, see + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#resource-references + (,(puppet-rx (group cap-resource-name) (zero-or-more space) "[") + 1 font-lock-type-face) + ;; Resource collectors, see + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_collectors.html + (,(puppet-rx (group cap-resource-name) (zero-or-more space) + (optional "<") ; Exported collector + "<|") + 1 font-lock-type-face) + ;; Negation + ("!" 0 font-lock-negation-char-face) + ;; Builtin meta parameters + (,(puppet-rx (group builtin-metaparam) (zero-or-more space) "=>") + 1 font-lock-builtin-face) + ;; Built-in functions + (,(puppet-rx builtin-function) 0 font-lock-builtin-face) + ;; Variable expansions in strings and comments + (puppet-match-valid-expansion 1 font-lock-variable-name-face t) + (puppet-match-invalid-expansion 1 font-lock-warning-face t) + ;; Escape sequences in strings + (puppet-match-valid-escape 1 'puppet-escape-sequence t) + ) + "Font lock keywords for Puppet Mode.") + +(defun puppet-match-property (property context limit) + "Match a PROPERTY in CONTEXT before LIMIT. + +PROPERTY is the text property to look for. CONTEXT is one of +`single-quoted', `double-quoted' or `comment', or a list with any +of these symbols. The expansion will only match if it is in any +given CONTEXT." + (when (symbolp context) + (setq context (list context))) + (let* ((pos (next-single-char-property-change (point) property nil limit))) + (when (and pos (> pos (point))) + (goto-char pos) + (let* ((value (get-text-property pos property))) + (if (memq (car value) context) + (progn (set-match-data (cdr value)) t) + (puppet-match-property property context limit)))))) + +(defun puppet-match-valid-expansion (limit) + "Match a valid expansion before LIMIT. + +A valid expansion is a variable expansion in a double-quoted +string." + (let ((valid-contexts '(double-quoted))) + (when puppet-fontify-variables-in-comments + (push 'comment valid-contexts)) + (puppet-match-property 'puppet-expansion valid-contexts limit))) + +(defun puppet-match-invalid-expansion (limit) + "Match an invalid expansion before LIMIT. + +An invalid expansion is a variable expansion in a single-quoted +string." + (puppet-match-property 'puppet-expansion 'single-quoted limit)) + +(defun puppet-match-valid-escape (limit) + "Match a valid escape sequence before LIMIT." + (puppet-match-property 'puppet-escape 'double-quoted limit)) + +(defun puppet-syntax-propertize-match (property) + "Propertize a match with PROPERTY. + +When in a special syntax context, add PROPERTY to the first +character of the first group of the current `match-data'. The +value of PROPERTY is `(CONTEXT . MATCH-DATA)', where CONTEXT is +one of nil, `single-quoted', `double-quoted' or `comment' and +denotes the surrounding context, and MATCH-DATA is the original +match data from propertization." + (let* ((beg (match-beginning 1)) + (context (puppet-syntax-context))) + (when context + (put-text-property beg (1+ beg) property + (cons context (match-data)))))) + +(defun puppet-syntax-propertize-function (start end) + "Propertize text between START and END. + +Used as `syntax-propertize-function' in Puppet Mode." + (let ((case-fold-search nil)) + (goto-char start) + (remove-text-properties start end '(puppet-expansion puppet-escape)) + (funcall + (syntax-propertize-rules + ;; Find escape sequences and variable expansions + ((puppet-rx dq-escape) + (1 (ignore (puppet-syntax-propertize-match 'puppet-escape)))) + ((puppet-rx (or line-start (not (any "\\"))) + (zero-or-more "\\\\") + (group "$" (or (and "{" variable-name "}") variable-name))) + (1 (ignore (puppet-syntax-propertize-match 'puppet-expansion))))) + start end))) + + +;;;; Alignment + +;; Configure alignment +(add-to-list 'align-sq-string-modes 'puppet-mode) +(add-to-list 'align-dq-string-modes 'puppet-mode) +(add-to-list 'align-open-comment-modes 'puppet-mode) + +(defconst puppet-mode-align-rules + '((puppet-resource-arrow + (regexp . "\\(\\s-*\\)=>\\(\\s-*\\)") + (group . (1 2)) + (modes . '(puppet-mode)))) + "Align rules for Puppet Mode.") + +(defun puppet-align-block () + "Align the current block." + (interactive) + (save-excursion + (beginning-of-defun) + (let ((beg (point))) + (end-of-defun) + (align beg (point))))) + + +;;;; Imenu + +(defun puppet-imenu-collect-entries (pattern) + "Collect all index entries matching PATTERN. + +The first matching group of PATTERN is used as title and position +for each entry." + (goto-char (point-min)) + (let ((case-fold-search nil) + entries) + (while (re-search-forward pattern nil 'no-error) + (let ((context (save-excursion (syntax-ppss (match-beginning 0))))) + ;; Skip this match if it's inside a string or comment + (unless (or (nth 3 context) (nth 4 context)) + (push (cons (match-string 1) (match-beginning 1)) entries)))) + (nreverse entries))) + +(defun puppet-imenu-create-index () + "Create an IMenu index for the current buffer." + (let ((case-fold-search nil) + ;; Variable assignments + (variables (puppet-imenu-collect-entries + (puppet-rx (group "$" simple-variable-name) + (zero-or-more space) "="))) + ;; Resource defaults + (defaults (puppet-imenu-collect-entries + (puppet-rx cap-resource-name (zero-or-more space) "{"))) + ;; Nodes, classes and defines + (nodes (puppet-imenu-collect-entries + (puppet-rx symbol-start "node" symbol-end + (one-or-more space) resource-name))) + (classes (puppet-imenu-collect-entries + (puppet-rx symbol-start "class" symbol-end + (one-or-more space) resource-name))) + (defines (puppet-imenu-collect-entries + (puppet-rx symbol-start "define" symbol-end + (one-or-more space) resource-name))) + resources) + ;; Resources are a little more complicated since we need to extract the type + ;; and the name + (goto-char (point-min)) + (while (re-search-forward + (puppet-rx symbol-start + (group (repeat 0 2 "@") ; Virtual and exported resources + resource-name) + (zero-or-more space) "{" + ;; FIXME: Support condensed forms + (zero-or-more space) + (group (one-or-more not-newline)) ":") + nil 'no-error) + ;; FIXME: Doesn't work for any condensed forms, see + ;; http://docs.puppetlabs.com/puppet/latest/reference/lang_resources.html#condensed-forms + ;; We probably need to be more clever here + (push (cons (concat (match-string 1) " " (match-string 2)) + (match-beginning 1)) + resources)) + (let (index + ;; Keep this in reversed order, for `push' + (parts (list (cons "Variables" (nreverse variables)) + (cons "Defaults" (nreverse defaults)) + (cons "Definitions" (nreverse defines)) + (cons "Classes" (nreverse classes)) + (cons "Nodes" (nreverse nodes))))) + (dolist (part parts) + (when (cdr part) + (push part index))) + (append index (nreverse resources))))) + + +;;;; Major mode definition + +(defvar puppet-mode-map + (let ((map (make-sparse-keymap))) + ;; Editing + (define-key map (kbd "C-c C-a") #'puppet-align-block) + ;; Navigation + (define-key map (kbd "C-c C-j") #'imenu) + ;; Apply manifests + (define-key map (kbd "C-c C-c") #'puppet-apply) + ;; Linting and validation + (define-key map (kbd "C-c C-v") #'puppet-validate) + (define-key map (kbd "C-c C-l") #'puppet-lint) + ;; The menu bar + (easy-menu-define puppet-menu map "Puppet Mode menu" + `("Puppet" + :help "Puppet-specific Features" + ["Align the current block" puppet-align-block + :help "Align parameters in the current block"] + "-" + ["Jump to resource/variable" imenu + :help "Jump to a resource or variable"] + "-" + ["Apply manifest" puppet-apply :help "Apply a Puppet manifest"] + "-" + ["Validate file syntax" puppet-validate + :help "Validate the syntax of this file"] + ["Lint file" puppet-lint + :help "Check the file for semantic issues"])) + map) + "Key map for Puppet Mode buffers.") + +;;;###autoload +(define-derived-mode puppet-mode prog-mode "Puppet" () + "Major mode for editing Puppet manifests. + +\\{puppet-mode-map}" + ;; Misc variables + (setq-local require-final-newline t) + ;; Comment setup + (setq-local comment-start "# ") + (setq-local comment-start-skip "#+ *") + (setq-local comment-use-syntax t) + (setq-local comment-end "") + (setq-local comment-auto-fill-only-comments t) + (setq comment-column puppet-comment-column) + ;; Navigation (TODO: Will we still need this with SMIE?) + (setq-local beginning-of-defun-function #'puppet-beginning-of-defun-function) + ;; Indentation + (setq-local indent-line-function 'puppet-indent-line) + (setq indent-tabs-mode puppet-indent-tabs-mode) + ;; Paragaphs + (setq-local paragraph-ignore-fill-prefix t) + (setq-local paragraph-start "\f\\|[ \t]*$\\|#$") + (setq-local paragraph-separate "\\([ \t\f]*\\|#\\)$") + ;; Font locking + (setq font-lock-defaults '((puppet-font-lock-keywords) nil nil)) + (setq-local syntax-propertize-function #'puppet-syntax-propertize-function) + ;; Alignment + (setq align-mode-rules-list puppet-mode-align-rules) + ;; IMenu + (setq imenu-create-index-function #'puppet-imenu-create-index)) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.pp\\'" . puppet-mode)) + +(provide 'puppet-mode) + +;; Local Variables: +;; indent-tabs-mode: nil +;; End: + +;;; puppet-mode.el ends here diff --git a/elpa/puppet-mode-readme.txt b/elpa/puppet-mode-readme.txt new file mode 100644 --- /dev/null +++ b/elpa/puppet-mode-readme.txt @@ -0,0 +1,1 @@ +Major mode for Puppet manifests