aboutsummaryrefslogtreecommitdiffstats
path: root/rpm-spec-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'rpm-spec-mode.el')
-rw-r--r--rpm-spec-mode.el1358
1 files changed, 1358 insertions, 0 deletions
diff --git a/rpm-spec-mode.el b/rpm-spec-mode.el
new file mode 100644
index 0000000..82af626
--- /dev/null
+++ b/rpm-spec-mode.el
@@ -0,0 +1,1358 @@
+;;; rpm-spec-mode.el --- RPM spec file editing commands for Emacs/XEmacs
+
+;; $Id$
+
+;; Copyright (C) 1997-2002 Stig Bjørlykke, <stigb@tihlde.org>
+
+;; Author: Stig Bjørlykke, <stigb@tihlde.org>
+;; Keywords: unix, languages
+;; Version: 0.12
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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 2, or (at your option)
+;; any later version.
+
+;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Synched up with: not in GNU Emacs.
+
+;;; Thanx to:
+
+;; Tore Olsen <toreo@tihlde.org> for some general fixes.
+;; Steve Sanbeg <sanbeg@dset.com> for navigation functions and
+;; some Emacs fixes.
+;; Tim Powers <timp@redhat.com> and Trond Eivind Glomsrød
+;; <teg@redhat.com> for Red Hat adaptions and some fixes.
+;; Chmouel Boudjnah <chmouel@mandrakesoft.com> for Mandrake fixes.
+
+;;; ToDo:
+
+;; - rewrite function names.
+;; - autofill changelog entries.
+;; - customize rpm-tags-list and rpm-group-tags-list.
+;; - get values from `rpm --showrc'.
+;; - ssh/rsh for compile.
+;; - finish integrating the new navigation functions in with existing stuff.
+;; - use a single prefix consistently (internal)
+
+;;; Commentary:
+
+;; This mode is used for editing spec files used for building RPM packages.
+;;
+;; Most recent version is available from:
+;; <URL:http://www.tihlde.org/~stigb/rpm-spec-mode.el>
+;;
+;; Put this in your .emacs file to enable autoloading of rpm-spec-mode,
+;; and auto-recognition of ".spec" files:
+;;
+;; (autoload 'rpm-spec-mode "rpm-spec-mode.el" "RPM spec mode." t)
+;; (setq auto-mode-alist (append '(("\\.spec" . rpm-spec-mode))
+;; auto-mode-alist))
+;;------------------------------------------------------------
+;;
+
+;;; Code:
+(require 'cl)
+
+(defconst rpm-spec-mode-version "0.12" "Version of `rpm-spec-mode'.")
+
+;Fix for GNU/Emacs
+(if (not(featurep 'xemacs))
+ (fset 'define-obsolete-variable-alias 'make-obsolete))
+
+(defgroup rpm-spec nil
+ "RPM spec mode with Emacs/XEmacs enhancements."
+ :prefix "rpm-spec-"
+ :group 'languages)
+
+(defcustom rpm-spec-build-command "rpmbuild"
+ "Command for building a RPM package."
+ :type 'string
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-add-attr nil
+ "Add \"%attr\" entry for file listings or not."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-short-circuit nil
+ "Skip straight to specified stage.
+(ie, skip all stages leading up to the specified stage). Only valid
+in \"%build\" and \"%install\" stage."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-no-deps nil
+ "Do not verify the dependencies."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-timecheck "0"
+ "Set the \"timecheck\" age (0 to disable).
+The timecheck value expresses, in seconds, the maximum age of a file
+being packaged. Warnings will be printed for all files beyond the
+timecheck age."
+ :type 'integer
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-buildroot ""
+ "Override the BuildRoot tag with directory <dir>."
+ :type 'string
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-target ""
+ "Interpret given string as `arch-vendor-os'.
+Set the macros _target, _target_arch and _target_os accordingly"
+ :type 'string
+ :group 'rpm-spec)
+
+(define-obsolete-variable-alias
+ 'rpm-completion-ignore-case 'rpm-spec-completion-ignore-case)
+
+(defcustom rpm-spec-completion-ignore-case t
+ "*Non-nil means that case differences are ignored during completion.
+A value of nil means that case is significant.
+This is used during Tempo template completion."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-clean nil
+ "Remove the build tree after the packages are made."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-rmsource nil
+ "Remove the source and spec file after the packages are made."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-nobuild nil
+ "Do not execute any build stages. Useful for testing out spec files."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-sign-gpg nil
+ "Embed a GPG signature in the package.
+This signature can be used to verify the integrity and the origin of
+the package."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-nodeps nil
+ "Do not verify build dependencies."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-old-rpm nil
+ "Set if using `rpm' as command for building packages."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(define-obsolete-variable-alias
+ 'rpm-initialize-sections 'rpm-spec-initialize-sections)
+
+(defcustom rpm-spec-initialize-sections t
+ "Automatically add empty section headings to new spec files."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-use-tabs nil
+ "Use tabs instead of a space to indent tags."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(define-obsolete-variable-alias
+ 'rpm-insert-version 'rpm-spec-insert-changelog-version)
+
+(defcustom rpm-spec-insert-changelog-version t
+ "Automatically add version in a new change log entry."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-insert-changelog-version-with-shell t
+ "Automatically add version with shell in a new change log entry."
+ :type 'boolean
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-user-full-name nil
+ "*Full name of the user.
+This is used in the change log and the Packager tag. It defaults to the
+value returned by function `user-full-name'."
+ :type '(choice (const :tag "Use `user-full-name'" nil)
+ string)
+ :group 'rpm-spec)
+
+(defcustom rpm-spec-user-mail-address nil
+ "*Email address of the user.
+This is used in the change log and the Packager tag. It defaults to the
+value returned by function `user-mail-address'."
+ :type '(choice (const :tag "Use `user-mail-address'" nil)
+ string)
+ :group 'rpm-spec)
+
+(defgroup rpm-spec-faces nil
+ "Font lock faces for `rpm-spec-mode'."
+ :group 'rpm-spec
+ :group 'faces)
+
+;;------------------------------------------------------------
+;; variables used by navigation functions.
+
+(defconst rpm-sections
+ '("preamble" "description" "prep" "setup" "build" "install" "clean"
+ "changelog" "files")
+ "Partial list of section names.")
+(defvar rpm-section-list
+ '(("preamble") ("description") ("prep") ("setup") ("build") ("install")
+ ("clean") ("changelog") ("files"))
+ "Partial list of section names.")
+(defconst rpm-scripts
+ '("pre" "post" "preun" "postun"
+ "trigger" "triggerin" "triggerun" "triggerpostun")
+ "List of rpm scripts.")
+(defconst rpm-section-seperate "^%\\(\\w+\\)\\s-")
+(defconst rpm-section-regexp
+ (eval-when-compile
+ (concat "^%"
+ (regexp-opt
+ ;; From RPM 4.1 sources, file build/parseSpec.c: partList[].
+ '("build" "changelog" "clean" "description" "files" "install"
+ "package" "post" "postun" "pre" "prep" "preun" "trigger"
+ "triggerin" "triggerpostun" "triggerun" "verifyscript") t)
+ "\\b"))
+ "Regular expression to match beginning of a section.")
+
+;;------------------------------------------------------------
+
+(defface rpm-spec-tag-face
+ '(( ((class color) (background light)) (:foreground "blue") )
+ ( ((class color) (background dark)) (:foreground "blue") ))
+ "*The face used for tags."
+ :group 'rpm-spec-faces)
+
+(defface rpm-spec-macro-face
+ '(( ((class color) (background light)) (:foreground "purple") )
+ ( ((class color) (background dark)) (:foreground "yellow") ))
+ "*The face used for macros."
+ :group 'rpm-spec-faces)
+
+(defface rpm-spec-var-face
+ '(( ((class color) (background light)) (:foreground "maroon") )
+ ( ((class color) (background dark)) (:foreground "maroon") ))
+ "*The face used for environment variables."
+ :group 'rpm-spec-faces)
+
+(defface rpm-spec-doc-face
+ '(( ((class color) (background light)) (:foreground "magenta") )
+ ( ((class color) (background dark)) (:foreground "magenta") ))
+ "*The face used for document files."
+ :group 'rpm-spec-faces)
+
+(defface rpm-spec-dir-face
+ '(( ((class color) (background light)) (:foreground "green") )
+ ( ((class color) (background dark)) (:foreground "green") ))
+ "*The face used for directories."
+ :group 'rpm-spec-faces)
+
+(defface rpm-spec-package-face
+ '(( ((class color) (background light)) (:foreground "red") )
+ ( ((class color) (background dark)) (:foreground "red") ))
+ "*The face used for files."
+ :group 'rpm-spec-faces)
+
+(defface rpm-spec-ghost-face
+ '(( ((class color) (background light)) (:foreground "red") )
+ ( ((class color) (background dark)) (:foreground "red") ))
+ "*The face used for ghost tags."
+ :group 'rpm-spec-faces)
+
+;;; GNU emacs font-lock needs these...
+(defvar rpm-spec-macro-face
+ 'rpm-spec-macro-face "*Face for macros.")
+(defvar rpm-spec-var-face
+ 'rpm-spec-var-face "*Face for environment variables.")
+(defvar rpm-spec-tag-face
+ 'rpm-spec-tag-face "*Face for tags.")
+(defvar rpm-spec-package-face
+ 'rpm-spec-package-face "*Face for package tag.")
+(defvar rpm-spec-dir-face
+ 'rpm-spec-dir-face "*Face for directory entries.")
+(defvar rpm-spec-doc-face
+ 'rpm-spec-doc-face "*Face for documentation entries.")
+(defvar rpm-spec-ghost-face
+ 'rpm-spec-ghost-face "*Face for \"%ghost\" files.")
+
+(defvar rpm-default-umask "-"
+ "*Default umask for files, specified with \"%attr\".")
+(defvar rpm-default-owner "root"
+ "*Default owner for files, specified with \"%attr\".")
+(defvar rpm-default-group "root"
+ "*Default group for files, specified with \"%attr\".")
+
+;;------------------------------------------------------------
+
+(defvar rpm-no-gpg nil "Tell rpm not to sign package.")
+
+(defvar rpm-tags-list
+ ;; From RPM 4.1 sources, file build/parsePreamble.c: preambleList[].")
+ '(("AutoProv")
+ ("AutoReq")
+ ("AutoReqProv")
+ ("BuildArch")
+ ("BuildArchitectures")
+ ("BuildConflicts")
+ ("BuildPreReq")
+ ("BuildRequires")
+ ("BuildRoot")
+ ("Conflicts")
+ ("License")
+ ("%description")
+ ("Distribution")
+ ("DistURL")
+ ("DocDir")
+ ("Epoch")
+ ("ExcludeArch")
+ ("ExcludeOS")
+ ("ExclusiveArch")
+ ("ExclusiveOS")
+ ("%files")
+ ("Group")
+ ("Icon")
+ ("%ifarch")
+ ("License")
+ ("Name")
+ ("NoPatch")
+ ("NoSource")
+ ("Obsoletes")
+ ("%package")
+ ("Packager")
+ ("Patch")
+ ("Prefix")
+ ("Prefixes")
+ ("PreReq")
+ ("Provides")
+ ("Release")
+ ("Requires")
+ ("RHNPlatform")
+ ("Serial")
+ ("Source")
+ ("Summary")
+ ("URL")
+ ("Vendor")
+ ("Version"))
+ "List of elements that are valid tags.")
+
+;; echo "(defvar rpm-group-tags-list"
+;; echo " ;; Auto generated from Mandrake linux GROUPS file"
+;; printf "\t%s\n" "'("
+;; cat /usr/share/doc/*/GROUPS | while read i; do
+;; printf "\t %s%s%s\n" '("' "$i" '")'
+;; done
+;; printf "\t%s\n\t%s" ")" '"List of elements that are valid group tags.")'
+
+(defvar rpm-group-tags-list
+ ;; Auto generated from Mandrake Linux GROUPS file
+ '(
+ ("Accessibility")
+ ("Archiving/Backup")
+ ("Archiving/Cd burning")
+ ("Archiving/Compression")
+ ("Archiving/Other")
+ ("Books/Computer books")
+ ("Books/Faqs")
+ ("Books/Howtos")
+ ("Books/Literature")
+ ("Books/Other")
+ ("Communications")
+ ("Databases")
+ ("Development/C")
+ ("Development/C++")
+ ("Development/Databases")
+ ("Development/GNOME and GTK+")
+ ("Development/Java")
+ ("Development/KDE and QT")
+ ("Development/Kernel")
+ ("Development/Other")
+ ("Development/Perl")
+ ("Development/Python")
+ ("Editors")
+ ("Emulators")
+ ("File tools")
+ ("Games/Adventure")
+ ("Games/Arcade")
+ ("Games/Boards")
+ ("Games/Cards")
+ ("Games/Other")
+ ("Games/Puzzles")
+ ("Games/Sports")
+ ("Games/Strategy")
+ ("Graphical desktop/Enlightenment")
+ ("Graphical desktop/FVWM based")
+ ("Graphical desktop/GNOME")
+ ("Graphical desktop/Icewm")
+ ("Graphical desktop/KDE")
+ ("Graphical desktop/Other")
+ ("Graphical desktop/Sawfish")
+ ("Graphical desktop/Window Maker")
+ ("Graphics")
+ ("Monitoring")
+ ("Networking/Chat")
+ ("Networking/File transfer")
+ ("Networking/IRC")
+ ("Networking/Instant messaging")
+ ("Networking/Mail")
+ ("Networking/News")
+ ("Networking/Other")
+ ("Networking/Remote access")
+ ("Networking/WWW")
+ ("Office")
+ ("Publishing")
+ ("Sciences/Astronomy")
+ ("Sciences/Biology")
+ ("Sciences/Chemistry")
+ ("Sciences/Computer science")
+ ("Sciences/Geosciences")
+ ("Sciences/Mathematics")
+ ("Sciences/Other")
+ ("Sciences/Physics")
+ ("Shells")
+ ("Sound")
+ ("System/Base")
+ ("System/Configuration/Boot and Init")
+ ("System/Configuration/Hardware")
+ ("System/Configuration/Networking")
+ ("System/Configuration/Other")
+ ("System/Configuration/Packaging")
+ ("System/Configuration/Printing")
+ ("System/Fonts/Console")
+ ("System/Fonts/True type")
+ ("System/Fonts/Type1")
+ ("System/Fonts/X11 bitmap")
+ ("System/Internationalization")
+ ("System/Kernel and hardware")
+ ("System/Libraries")
+ ("System/Servers")
+ ("System/XFree86")
+ ("Terminals")
+ ("Text tools")
+ ("Toys")
+ ("Video")
+ )
+ "List of elements that are valid group tags.")
+
+(defvar rpm-spec-mode-syntax-table nil
+ "Syntax table in use in `rpm-spec-mode' buffers.")
+(unless rpm-spec-mode-syntax-table
+ (setq rpm-spec-mode-syntax-table (make-syntax-table))
+ (modify-syntax-entry ?\\ "\\" rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?\n "> " rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?\f "> " rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?\# "< " rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?/ "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?* "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?+ "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?- "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?= "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?% "_" rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?< "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?> "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?& "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?| "." rpm-spec-mode-syntax-table)
+ (modify-syntax-entry ?\' "." rpm-spec-mode-syntax-table))
+
+(defvar rpm-spec-mode-map nil
+ "Keymap used in `rpm-spec-mode'.")
+(unless rpm-spec-mode-map
+ (setq rpm-spec-mode-map (make-sparse-keymap))
+ (and (functionp 'set-keymap-name)
+ (set-keymap-name rpm-spec-mode-map 'rpm-spec-mode-map))
+ (define-key rpm-spec-mode-map "\C-c\C-c" 'rpm-change-tag)
+ (define-key rpm-spec-mode-map "\C-c\C-e" 'rpm-add-change-log-entry)
+ (define-key rpm-spec-mode-map "\C-c\C-i" 'rpm-insert-tag)
+ (define-key rpm-spec-mode-map "\C-c\C-n" 'rpm-forward-section)
+ (define-key rpm-spec-mode-map "\C-c\C-o" 'rpm-goto-section)
+ (define-key rpm-spec-mode-map "\C-c\C-p" 'rpm-backward-section)
+ (define-key rpm-spec-mode-map "\C-c\C-r" 'rpm-increase-release-tag)
+ (define-key rpm-spec-mode-map "\C-c\C-u" 'rpm-insert-true-prefix)
+ (define-key rpm-spec-mode-map "\C-c\C-ba" 'rpm-build-all)
+ (define-key rpm-spec-mode-map "\C-c\C-bb" 'rpm-build-binary)
+ (define-key rpm-spec-mode-map "\C-c\C-bc" 'rpm-build-compile)
+ (define-key rpm-spec-mode-map "\C-c\C-bi" 'rpm-build-install)
+ (define-key rpm-spec-mode-map "\C-c\C-bl" 'rpm-list-check)
+ (define-key rpm-spec-mode-map "\C-c\C-bp" 'rpm-build-prepare)
+ (define-key rpm-spec-mode-map "\C-c\C-bs" 'rpm-build-source)
+ (define-key rpm-spec-mode-map "\C-c\C-dd" 'rpm-insert-dir)
+ (define-key rpm-spec-mode-map "\C-c\C-do" 'rpm-insert-docdir)
+ (define-key rpm-spec-mode-map "\C-c\C-fc" 'rpm-insert-config)
+ (define-key rpm-spec-mode-map "\C-c\C-fd" 'rpm-insert-doc)
+ (define-key rpm-spec-mode-map "\C-c\C-ff" 'rpm-insert-file)
+ (define-key rpm-spec-mode-map "\C-c\C-fg" 'rpm-insert-ghost)
+ (define-key rpm-spec-mode-map "\C-c\C-xa" 'rpm-toggle-add-attr)
+ (define-key rpm-spec-mode-map "\C-c\C-xb" 'rpm-change-buildroot-option)
+ (define-key rpm-spec-mode-map "\C-c\C-xc" 'rpm-toggle-clean)
+ (define-key rpm-spec-mode-map "\C-c\C-xd" 'rpm-toggle-nodeps)
+ (define-key rpm-spec-mode-map "\C-c\C-xf" 'rpm-files-group)
+ (define-key rpm-spec-mode-map "\C-c\C-xg" 'rpm-toggle-sign-gpg)
+ (define-key rpm-spec-mode-map "\C-c\C-xi" 'rpm-change-timecheck-option)
+ (define-key rpm-spec-mode-map "\C-c\C-xn" 'rpm-toggle-nobuild)
+ (define-key rpm-spec-mode-map "\C-c\C-xo" 'rpm-files-owner)
+ (define-key rpm-spec-mode-map "\C-c\C-xp" 'rpm-change-target-option)
+ (define-key rpm-spec-mode-map "\C-c\C-xr" 'rpm-toggle-rmsource)
+ (define-key rpm-spec-mode-map "\C-cxd" 'rpm-toggle-no-deps)
+ (define-key rpm-spec-mode-map "\C-c\C-xs" 'rpm-toggle-short-circuit)
+ (define-key rpm-spec-mode-map "\C-c\C-xu" 'rpm-files-umask)
+ ;;(define-key rpm-spec-mode-map "\C-q" 'indent-spec-exp)
+ ;;(define-key rpm-spec-mode-map "\t" 'sh-indent-line)
+ )
+
+(defconst rpm-spec-mode-menu
+ (purecopy '("RPM spec"
+ ["Insert Tag..." rpm-insert-tag t]
+ ["Change Tag..." rpm-change-tag t]
+ "---"
+ ["Go to section..." rpm-mouse-goto-section :keys "C-c C-o"]
+ ["Forward section" rpm-forward-section t]
+ ["Backward section" rpm-backward-section t]
+ "---"
+ ["Add change log entry..." rpm-add-change-log-entry t]
+ ["Increase release tag" rpm-increase-release-tag t]
+ "---"
+ ("Add file entry"
+ ["Regular file..." rpm-insert-file t]
+ ["Config file..." rpm-insert-config t]
+ ["Document file..." rpm-insert-doc t]
+ ["Ghost file..." rpm-insert-ghost t]
+ "---"
+ ["Directory..." rpm-insert-dir t]
+ ["Document directory..." rpm-insert-docdir t]
+ "---"
+ ["Insert %{prefix}" rpm-insert-true-prefix t]
+ "---"
+ ["Default add \"%attr\" entry" rpm-toggle-add-attr
+ :style toggle :selected rpm-spec-add-attr]
+ ["Change default umask for files..." rpm-files-umask t]
+ ["Change default owner for files..." rpm-files-owner t]
+ ["Change default group for files..." rpm-files-group t])
+ ("Build Options"
+ ["Short circuit" rpm-toggle-short-circuit
+ :style toggle :selected rpm-spec-short-circuit]
+ ["No deps" rpm-toggle-no-deps
+ :style toggle :selected rpm-spec-no-deps]
+ ["Remove source" rpm-toggle-rmsource
+ :style toggle :selected rpm-spec-rmsource]
+ ["Clean" rpm-toggle-clean
+ :style toggle :selected rpm-spec-clean]
+ ["No build" rpm-toggle-nobuild
+ :style toggle :selected rpm-spec-nobuild]
+ ["GPG sign" rpm-toggle-sign-gpg
+ :style toggle :selected rpm-spec-sign-gpg]
+ ["Ignore dependencies" rpm-toggle-nodeps
+ :style toggle :selected rpm-spec-nodeps]
+ "---"
+ ["Change timecheck value..." rpm-change-timecheck-option t]
+ ["Change buildroot value..." rpm-change-buildroot-option t]
+ ["Change target value..." rpm-change-target-option t])
+ ("RPM Build"
+ ["Execute \"%prep\" stage" rpm-build-prepare t]
+ ["Do a \"list check\"" rpm-list-check t]
+ ["Do the \"%build\" stage" rpm-build-compile t]
+ ["Do the \"%install\" stage" rpm-build-install t]
+ "---"
+ ["Build binary package" rpm-build-binary t]
+ ["Build source package" rpm-build-source t]
+ ["Build binary and source" rpm-build-all t])
+ "---"
+ ["About rpm-spec-mode" rpm-about-rpm-spec-mode t]
+ )))
+
+(defvar rpm-spec-font-lock-keywords
+ '(
+ ("%[a-zA-Z0-9-_]+" 0 rpm-spec-macro-face)
+ ("^\\([a-zA-Z0-9]+\\)\\(\([a-zA-Z0-9,]+\)\\):"
+ (1 rpm-spec-tag-face)
+ (2 rpm-spec-ghost-face))
+ ("^\\([a-zA-Z0-9]+\\):" 1 rpm-spec-tag-face)
+ ("%\\(de\\(fine\\|scription\\)\\|files\\|package\\)[ \t]+\\([^-][^ \t\n]*\\)"
+ (3 rpm-spec-package-face))
+ ("%p\\(ost\\|re\\)\\(un\\)?[ \t]+\\([^-][^ \t\n]*\\)"
+ (3 rpm-spec-package-face))
+ ("%configure " 0 rpm-spec-macro-face)
+ ("%dir[ \t]+\\([^ \t\n]+\\)[ \t]*" 1 rpm-spec-dir-face)
+ ("%doc\\(dir\\)?[ \t]+\\(.*\\)\n" 2 rpm-spec-doc-face)
+ ("%\\(ghost\\|config\\)[ \t]+\\(.*\\)\n" 2 rpm-spec-ghost-face)
+ ("^%.+-[a-zA-Z][ \t]+\\([a-zA-Z0-9\.-]+\\)" 1 rpm-spec-doc-face)
+ ("^\\(.+\\)(\\([a-zA-Z]\\{2,2\\}\\)):"
+ (1 rpm-spec-tag-face)
+ (2 rpm-spec-doc-face))
+ ("^\\*\\(.*[0-9] \\)\\(.*\\)\\(<.*>\\)\\(.*\\)\n"
+ (1 rpm-spec-dir-face)
+ (2 rpm-spec-package-face)
+ (3 rpm-spec-tag-face)
+ (4 font-lock-warning-face))
+ ("%{[^{}]*}" 0 rpm-spec-macro-face)
+ ("$[a-zA-Z0-9_]+" 0 rpm-spec-var-face)
+ ("${[a-zA-Z0-9_]+}" 0 rpm-spec-var-face)
+ )
+ "Additional expressions to highlight in `rpm-spec-mode'.")
+
+;;Initialize font lock for xemacs
+(put 'rpm-spec-mode 'font-lock-defaults '(rpm-spec-font-lock-keywords))
+
+(defvar rpm-spec-mode-abbrev-table nil
+ "Abbrev table in use in `rpm-spec-mode' buffers.")
+(define-abbrev-table 'rpm-spec-mode-abbrev-table ())
+
+;;------------------------------------------------------------
+
+;;;###autoload
+(defun rpm-spec-mode ()
+ "Major mode for editing RPM spec files.
+This is much like C mode except for the syntax of comments. It uses
+the same keymap as C mode and has the same variables for customizing
+indentation. It has its own abbrev table and its own syntax table.
+
+Turning on RPM spec mode calls the value of the variable `rpm-spec-mode-hook'
+with no args, if that value is non-nil."
+ (interactive)
+ (kill-all-local-variables)
+ (condition-case nil
+ (require 'shindent)
+ (error
+ (require 'sh-script)))
+ (require 'cc-mode)
+ (use-local-map rpm-spec-mode-map)
+ (setq major-mode 'rpm-spec-mode)
+ (rpm-update-mode-name)
+ (setq local-abbrev-table rpm-spec-mode-abbrev-table)
+ (set-syntax-table rpm-spec-mode-syntax-table)
+
+ (require 'easymenu)
+ (easy-menu-define rpm-spec-call-menu rpm-spec-mode-map
+ "Post menu for `rpm-spec-mode'." rpm-spec-mode-menu)
+ (easy-menu-add rpm-spec-mode-menu)
+
+ (if (= (buffer-size) 0)
+ (rpm-spec-initialize))
+
+ (if (executable-find "rpmbuild")
+ (setq rpm-spec-build-command "rpmbuild")
+ (setq rpm-spec-old-rpm t)
+ (setq rpm-spec-build-command "rpm"))
+
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start (concat "$\\|" page-delimiter))
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-separate paragraph-start)
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (setq paragraph-ignore-fill-prefix t)
+; (make-local-variable 'indent-line-function)
+; (setq indent-line-function 'c-indent-line)
+ (make-local-variable 'require-final-newline)
+ (setq require-final-newline t)
+ (make-local-variable 'comment-start)
+ (setq comment-start "# ")
+ (make-local-variable 'comment-end)
+ (setq comment-end "")
+ (make-local-variable 'comment-column)
+ (setq comment-column 32)
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip "#+ *")
+; (make-local-variable 'comment-indent-function)
+; (setq comment-indent-function 'c-comment-indent)
+ ;;Initialize font lock for GNU emacs.
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(rpm-spec-font-lock-keywords nil t))
+ (run-hooks 'rpm-spec-mode-hook))
+
+(defun rpm-command-filter (process string)
+ "Filter to process normal output."
+ (save-excursion
+ (set-buffer (process-buffer process))
+ (save-excursion
+ (goto-char (process-mark process))
+ (insert-before-markers string)
+ (set-marker (process-mark process) (point)))))
+
+; insert one space, or the number of tabs if rpm-spec-use-tabs is true
+(defun rpm-insert-space-or-tabs (tabs)
+ (if rpm-spec-use-tabs
+ (if (> tabs 0)
+ (concat "\t" (rpm-insert-space-or-tabs (1- tabs)))
+ "")
+ " "))
+
+;;------------------------------------------------------------
+
+(defun rpm-add-change-log-entry (&optional change-log-entry)
+ "Find change log and add an entry for today."
+ (interactive "P")
+ (goto-char (point-min))
+ (if (search-forward-regexp "^%changelog[ \t]*$" nil t)
+ (let* ((address (or rpm-spec-user-mail-address user-mail-address))
+ (fullname (or rpm-spec-user-full-name user-full-name))
+ (string (concat "* " (substring (current-time-string) 0 11)
+ (substring (current-time-string) -4) " "
+ fullname " <" address "> "
+ (or
+ (and rpm-spec-insert-changelog-version
+ (or (and rpm-spec-insert-changelog-version-with-shell
+ (rpm-find-spec-version-with-shell))
+ (rpm-find-spec-version))))
+ "")))
+ (if (not (search-forward string nil t))
+ (insert "\n" string "\n")
+ (progn (next-line 1)
+ (beginning-of-line)))
+ (unless (eq (point) (1- (point-max)))
+ (insert "\n")
+ (previous-line 1))
+ (insert "- ")
+ (if change-log-entry
+ (insert (concat (format "%s." change-log-entry)))))
+ (message "No \"%%changelog\" entry found...")))
+
+;;------------------------------------------------------------
+
+(defun rpm-insert-f (&optional filetype filename)
+ "Insert new \"%files\" entry."
+ (save-excursion
+ (and (rpm-goto-section "files") (rpm-end-of-section))
+ (if (or (eq filename 1) (not filename))
+ (insert (read-file-name
+ (concat filetype "filename: ") "" "" nil) "\n")
+ (insert filename "\n"))
+ (forward-line -1)
+ (if rpm-spec-add-attr
+ (let ((rpm-default-mode rpm-default-umask))
+ (insert "%attr(" rpm-default-mode ", " rpm-default-owner ", "
+ rpm-default-group ") ")))
+ (insert filetype)))
+
+(defun rpm-insert-file (&optional filename)
+ "Insert regular file."
+ (interactive "p")
+ (rpm-insert-f "" filename))
+
+(defun rpm-insert-config (&optional filename)
+ "Insert config file."
+ (interactive "p")
+ (rpm-insert-f "%config " filename))
+
+(defun rpm-insert-doc (&optional filename)
+ "Insert doc file."
+ (interactive "p")
+ (rpm-insert-f "%doc " filename))
+
+(defun rpm-insert-ghost (&optional filename)
+ "Insert ghost file."
+ (interactive "p")
+ (rpm-insert-f "%ghost " filename))
+
+(defun rpm-insert-dir (&optional dirname)
+ "Insert directory."
+ (interactive "p")
+ (rpm-insert-f "%dir " dirname))
+
+(defun rpm-insert-docdir (&optional dirname)
+ "Insert doc directory."
+ (interactive "p")
+ (rpm-insert-f "%docdir " dirname))
+
+;;------------------------------------------------------------
+(defun rpm-completing-read (prompt table &optional pred require init hist)
+ "Read from the minibuffer, with completion.
+Like `completing-read', but the variable `rpm-spec-completion-ignore-case'
+controls whether case is significant."
+ (let ((completion-ignore-case rpm-spec-completion-ignore-case))
+ (completing-read prompt table pred require init hist)))
+
+(defun rpm-insert (&optional what file-completion)
+ "Insert given tag. Use file-completion if argument is t."
+ (beginning-of-line)
+ (if (not what)
+ (setq what (rpm-completing-read "Tag: " rpm-tags-list)))
+ (if (string-match "^%" what)
+ (setq read-text (concat "Packagename for " what ": ")
+ insert-text (concat what " "))
+ (setq read-text (concat what ": ")
+ insert-text (concat what ": ")))
+ (cond
+ ((string-equal what "Group")
+ (rpm-insert-group))
+ ((string-equal what "Source")
+ (rpm-insert-n "Source"))
+ ((string-equal what "Patch")
+ (rpm-insert-n "Patch"))
+ (t
+ (if file-completion
+ (insert insert-text (read-file-name (concat read-text) "" "" nil) "\n")
+ (insert insert-text (read-from-minibuffer (concat read-text)) "\n")))))
+
+(defun rpm-topdir ()
+ (or
+ (getenv "RPM")
+ (getenv "rpm")
+ (if (file-directory-p "~/rpm") "~/rpm/")
+ (if (file-directory-p "~/RPM") "~/RPM/")
+ (if (file-directory-p "/usr/src/redhat/") "/usr/src/redhat/")
+ "/usr/src/RPM"))
+
+(defun rpm-insert-n (what &optional arg)
+ "Insert given tag with possible number."
+ (save-excursion
+ (goto-char (point-max))
+ (if (search-backward-regexp (concat "^" what "\\([0-9]*\\):") nil t)
+ (let ((release (1+ (string-to-int (match-string 1)))))
+ (forward-line 1)
+ (let ((default-directory (concat (rpm-topdir) "/SOURCES/")))
+ (insert what (int-to-string release) ": "
+ (read-file-name (concat what "file: ") "" "" nil) "\n")))
+ (goto-char (point-min))
+ (rpm-end-of-section)
+ (insert what ": " (read-from-minibuffer (concat what "file: ")) "\n"))))
+
+(defun rpm-change (&optional what arg)
+ "Update given tag."
+ (save-excursion
+ (if (not what)
+ (setq what (rpm-completing-read "Tag: " rpm-tags-list)))
+ (cond
+ ((string-equal what "Group")
+ (rpm-change-group))
+ ((string-equal what "Source")
+ (rpm-change-n "Source"))
+ ((string-equal what "Patch")
+ (rpm-change-n "Patch"))
+ (t
+ (goto-char (point-min))
+ (if (search-forward-regexp (concat "^" what ":\\s-*\\(.*\\)$") nil t)
+ (replace-match
+ (concat what ": " (read-from-minibuffer
+ (concat "New " what ": ") (match-string 1))))
+ (message (concat what " tag not found...")))))))
+
+(defun rpm-change-n (what &optional arg)
+ "Change given tag with possible number."
+ (save-excursion
+ (goto-char (point-min))
+ (let ((number (read-from-minibuffer (concat what " number: "))))
+ (if (search-forward-regexp
+ (concat "^" what number ":\\s-*\\(.*\\)") nil t)
+ (let ((default-directory (concat (rpm-topdir) "/SOURCES/")))
+ (replace-match
+ (concat what number ": "
+ (read-file-name (concat "New " what number " file: ")
+ "" "" nil (match-string 1)))))
+ (message (concat what " number \"" number "\" not found..."))))))
+
+(defun rpm-insert-group (group)
+ "Insert Group tag."
+ (interactive (list (rpm-completing-read "Group: " rpm-group-tags-list)))
+ (beginning-of-line)
+ (insert "Group:" (rpm-insert-space-or-tabs 2) group "\n"))
+
+(defun rpm-change-group (&optional arg)
+ "Update Group tag."
+ (interactive "p")
+ (save-excursion
+ (goto-char (point-min))
+ (if (search-forward-regexp "^Group:[ \t]*\\(.*\\)$" nil t)
+ (replace-match
+ (concat "Group:"
+ (rpm-insert-space-or-tabs 2)
+ (rpm-completing-read "Group: " rpm-group-tags-list
+ nil nil (match-string 1))))
+ (message "Group tag not found..."))))
+
+(defun rpm-insert-tag (&optional arg)
+ "Insert or change a tag."
+ (interactive "p")
+ (if current-prefix-arg
+ (rpm-change)
+ (rpm-insert)))
+
+(defun rpm-change-tag (&optional arg)
+ "Change a tag."
+ (interactive "p")
+ (rpm-change))
+
+(defun rpm-insert-packager (&optional arg)
+ "Insert Packager tag."
+ (interactive "p")
+ (beginning-of-line)
+ (insert "Packager:"
+ (rpm-insert-space-or-tabs 1)
+ (or rpm-spec-user-full-name (user-full-name))
+ " <" (or rpm-spec-user-mail-address (user-mail-address)) ">\n"))
+
+(defun rpm-change-packager (&optional arg)
+ "Update Packager tag."
+ (interactive "p")
+ (rpm-change "Packager"))
+
+;;------------------------------------------------------------
+
+(defun rpm-current-section nil
+ (interactive)
+ (save-excursion
+ (rpm-forward-section)
+ (rpm-backward-section)
+ (if (bobp) "preamble"
+ (buffer-substring (match-beginning 1) (match-end 1)))))
+
+(defun rpm-backward-section nil
+ "Move backward to the beginning of the previous section.
+Go to beginning of previous section."
+ (interactive)
+ (or (re-search-backward rpm-section-regexp nil t)
+ (goto-char (point-min))))
+
+(defun rpm-beginning-of-section nil
+ "Move backward to the beginning of the current section.
+Go to beginning of current section."
+ (interactive)
+ (or (and (looking-at rpm-section-regexp) (point))
+ (re-search-backward rpm-section-regexp nil t)
+ (goto-char (point-min))))
+
+(defun rpm-forward-section nil
+ "Move forward to the beginning of the next section."
+ (interactive)
+ (forward-char)
+ (if (re-search-forward rpm-section-regexp nil t)
+ (progn (forward-line 0) (point))
+ (goto-char (point-max))))
+
+(defun rpm-end-of-section nil
+ "Move forward to the end of this section."
+ (interactive)
+ (forward-char)
+ (if (re-search-forward rpm-section-regexp nil t)
+ (forward-line -1)
+ (goto-char (point-max)))
+;; (while (or (looking-at paragraph-separate) (looking-at "^\\s-*#"))
+ (while (looking-at "^\\s-*\\($\\|#\\)")
+ (forward-line -1))
+ (forward-line 1)
+ (point))
+
+(defun rpm-goto-section (section)
+ "Move point to the beginning of the specified section;
+leave point at previous location."
+ (interactive (list (rpm-completing-read "Section: " rpm-section-list)))
+ (push-mark)
+ (goto-char (point-min))
+ (or
+ (equal section "preamble")
+ (re-search-forward (concat "^%" section "\\b") nil t)
+ (let ((s (cdr rpm-sections)))
+ (while (not (equal section (car s)))
+ (re-search-forward (concat "^%" (car s) "\\b") nil t)
+ (setq s (cdr s)))
+ (if (re-search-forward rpm-section-regexp nil t)
+ (forward-line -1) (goto-char (point-max)))
+ (insert "\n%" section "\n"))))
+
+(defun rpm-mouse-goto-section (&optional section)
+ (interactive
+ (x-popup-menu
+ nil
+ (list "sections"
+ (cons "Sections" (mapcar (lambda (e) (list e e)) rpm-sections))
+ (cons "Scripts" (mapcar (lambda (e) (list e e)) rpm-scripts))
+ )))
+ ;; If user doesn't pick a section, exit quietly.
+ (and section
+ (if (member section rpm-sections)
+ (rpm-goto-section section)
+ (goto-char (point-min))
+ (or (re-search-forward (concat "^%" section "\\b") nil t)
+ (and (re-search-forward "^%files\\b" nil t) (forward-line -1))
+ (goto-char (point-max))))))
+
+(defun rpm-insert-true-prefix ()
+ (interactive)
+ (insert "%{prefix}"))
+
+;;------------------------------------------------------------
+
+(defun rpm-build (buildoptions)
+ "Build this RPM package."
+ (setq rpm-buffer-name
+ (concat "*" rpm-spec-build-command " "
+ (file-name-nondirectory buffer-file-name) "*"))
+ (rpm-process-check rpm-buffer-name)
+ (if (get-buffer rpm-buffer-name)
+ (kill-buffer rpm-buffer-name))
+ (create-file-buffer rpm-buffer-name)
+ (display-buffer rpm-buffer-name)
+ (setq buildoptions (list buildoptions buffer-file-name))
+ (if (or rpm-spec-short-circuit rpm-spec-nobuild)
+ (setq rpm-no-gpg t))
+ (if rpm-spec-rmsource
+ (setq buildoptions (cons "--rmsource" buildoptions)))
+ (if rpm-spec-clean
+ (setq buildoptions (cons "--clean" buildoptions)))
+ (if rpm-spec-short-circuit
+ (setq buildoptions (cons "--short-circuit" buildoptions)))
+ (if rpm-spec-no-deps
+ (setq buildoptions (cons "--nodeps" buildoptions)))
+ (if (and (not (equal rpm-spec-timecheck "0"))
+ (not (equal rpm-spec-timecheck "")))
+ (setq buildoptions (cons "--timecheck" (cons rpm-spec-timecheck
+ buildoptions))))
+ (if (not (equal rpm-spec-buildroot ""))
+ (setq buildoptions (cons "--buildroot" (cons rpm-spec-buildroot
+ buildoptions))))
+ (if (not (equal rpm-spec-target ""))
+ (setq buildoptions (cons "--target" (cons rpm-spec-target
+ buildoptions))))
+ (if rpm-spec-nobuild
+ (setq buildoptions (cons (if rpm-spec-old-rpm "--test" "--nobuild")
+ buildoptions)))
+ (if rpm-spec-nodeps
+ (setq buildoptions (cons "--nodeps" buildoptions)))
+ (if (and rpm-spec-sign-gpg (not rpm-no-gpg))
+ (setq buildoptions (cons "--sign" buildoptions)))
+ (save-excursion
+ (set-buffer (get-buffer rpm-buffer-name))
+ (goto-char (point-max)))
+ (let ((process
+ (apply 'start-process rpm-spec-build-command rpm-buffer-name
+ rpm-spec-build-command buildoptions)))
+ (if (and rpm-spec-sign-gpg (not rpm-no-gpg))
+ (let ((rpm-passwd-cache (read-passwd "GPG passphrase: ")))
+ (process-send-string process (concat rpm-passwd-cache "\n"))))
+ (set-process-filter process 'rpm-command-filter)))
+
+(defun rpm-build-prepare (&optional arg)
+ "Run a `rpmbuild -bp'."
+ (interactive "p")
+ (setq rpm-no-gpg t)
+ (rpm-build "-bp"))
+
+(defun rpm-list-check (&optional arg)
+ "Run a `rpmbuild -bl'."
+ (interactive "p")
+ (setq rpm-no-gpg t)
+ (rpm-build "-bl"))
+
+(defun rpm-build-compile (&optional arg)
+ "Run a `rpmbuild -bc'."
+ (interactive "p")
+ (setq rpm-no-gpg t)
+ (rpm-build "-bc"))
+
+(defun rpm-build-install (&optional arg)
+ "Run a `rpmbuild -bi'."
+ (interactive "p")
+ (setq rpm-no-gpg t)
+ (rpm-build "-bi"))
+
+(defun rpm-build-binary (&optional arg)
+ "Run a `rpmbuild -bb'."
+ (interactive "p")
+ (setq rpm-no-gpg nil)
+ (rpm-build "-bb"))
+
+(defun rpm-build-source (&optional arg)
+ "Run a `rpmbuild -bs'."
+ (interactive "p")
+ (setq rpm-no-gpg nil)
+ (rpm-build "-bs"))
+
+(defun rpm-build-all (&optional arg)
+ "Run a `rpmbuild -ba'."
+ (interactive "p")
+ (setq rpm-no-gpg nil)
+ (rpm-build "-ba"))
+
+(defun rpm-process-check (buffer)
+ "Check if BUFFER has a running process.
+If so, give the user the choice of aborting the process or the current
+command."
+ (let ((process (get-buffer-process (get-buffer buffer))))
+ (if (and process (eq (process-status process) 'run))
+ (if (yes-or-no-p (concat "Process `" (process-name process)
+ "' running. Kill it? "))
+ (delete-process process)
+ (error "Cannot run two simultaneous processes ...")))))
+
+;;------------------------------------------------------------
+
+(defun rpm-toggle-short-circuit (&optional arg)
+ "Toggle `rpm-spec-short-circuit'."
+ (interactive "p")
+ (setq rpm-spec-short-circuit (not rpm-spec-short-circuit))
+ (rpm-update-mode-name)
+ (message (concat "Turned `--short-circuit' "
+ (if rpm-spec-short-circuit "on" "off") ".")))
+
+(defun rpm-toggle-no-deps (&optional arg)
+ "Toggle rpm-spec-no-deps."
+ (interactive "p")
+ (setq rpm-spec-no-deps (not rpm-spec-no-deps))
+ (rpm-update-mode-name)
+ (message (concat "Turned `--nodeps' "
+ (if rpm-spec-no-deps "on" "off") ".")))
+
+(defun rpm-toggle-rmsource (&optional arg)
+ "Toggle `rpm-spec-rmsource'."
+ (interactive "p")
+ (setq rpm-spec-rmsource (not rpm-spec-rmsource))
+ (rpm-update-mode-name)
+ (message (concat "Turned `--rmsource' "
+ (if rpm-spec-rmsource "on" "off") ".")))
+
+(defun rpm-toggle-clean (&optional arg)
+ "Toggle `rpm-spec-clean'."
+ (interactive "p")
+ (setq rpm-spec-clean (not rpm-spec-clean))
+ (rpm-update-mode-name)
+ (message (concat "Turned `--clean' "
+ (if rpm-spec-clean "on" "off") ".")))
+
+(defun rpm-toggle-nobuild (&optional arg)
+ "Toggle `rpm-spec-nobuild'."
+ (interactive "p")
+ (setq rpm-spec-nobuild (not rpm-spec-nobuild))
+ (rpm-update-mode-name)
+ (message (concat "Turned `" (if rpm-spec-old-rpm "--test" "--nobuild") "' "
+ (if rpm-spec-nobuild "on" "off") ".")))
+
+(defun rpm-toggle-sign-gpg (&optional arg)
+ "Toggle `rpm-spec-sign-gpg'."
+ (interactive "p")
+ (setq rpm-spec-sign-gpg (not rpm-spec-sign-gpg))
+ (rpm-update-mode-name)
+ (message (concat "Turned `--sign' "
+ (if rpm-spec-sign-gpg "on" "off") ".")))
+
+(defun rpm-toggle-add-attr (&optional arg)
+ "Toggle `rpm-spec-add-attr'."
+ (interactive "p")
+ (setq rpm-spec-add-attr (not rpm-spec-add-attr))
+ (rpm-update-mode-name)
+ (message (concat "Default add \"attr\" entry turned "
+ (if rpm-spec-add-attr "on" "off") ".")))
+
+(defun rpm-toggle-nodeps (&optional arg)
+ "Toggle `rpm-spec-nodeps'."
+ (interactive "p")
+ (setq rpm-spec-nodeps (not rpm-spec-nodeps))
+ (rpm-update-mode-name)
+ (message (concat "Turned `--nodeps' "
+ (if rpm-spec-nodeps "on" "off") ".")))
+
+(defun rpm-update-mode-name ()
+ "Update `mode-name' according to values set."
+ (setq mode-name "RPM-SPEC")
+ (setq modes (concat (if rpm-spec-add-attr "A")
+ (if rpm-spec-clean "C")
+ (if rpm-spec-nodeps "D")
+ (if rpm-spec-sign-gpg "G")
+ (if rpm-spec-nobuild "N")
+ (if rpm-spec-rmsource "R")
+ (if rpm-spec-short-circuit "S")
+ (if rpm-spec-no-deps "D")
+ ))
+ (if (not (equal modes ""))
+ (setq mode-name (concat mode-name ":" modes))))
+
+;;------------------------------------------------------------
+
+(defun rpm-change-timecheck-option (&optional arg)
+ "Change the value for timecheck."
+ (interactive "p")
+ (setq rpm-spec-timecheck
+ (read-from-minibuffer "New timecheck: " rpm-spec-timecheck)))
+
+(defun rpm-change-buildroot-option (&optional arg)
+ "Change the value for buildroot."
+ (interactive "p")
+ (setq rpm-spec-buildroot
+ (read-from-minibuffer "New buildroot: " rpm-spec-buildroot)))
+
+(defun rpm-change-target-option (&optional arg)
+ "Change the value for target."
+ (interactive "p")
+ (setq rpm-spec-target
+ (read-from-minibuffer "New target: " rpm-spec-target)))
+
+(defun rpm-files-umask (&optional arg)
+ "Change the default umask for files."
+ (interactive "p")
+ (setq rpm-default-umask
+ (read-from-minibuffer "Default file umask: " rpm-default-umask)))
+
+(defun rpm-files-owner (&optional arg)
+ "Change the default owner for files."
+ (interactive "p")
+ (setq rpm-default-owner
+ (read-from-minibuffer "Default file owner: " rpm-default-owner)))
+
+(defun rpm-files-group (&optional arg)
+ "Change the source directory."
+ (interactive "p")
+ (setq rpm-default-group
+ (read-from-minibuffer "Default file group: " rpm-default-group)))
+
+(defun rpm-increase-release-tag (&optional arg)
+ "Increase the release tag by 1."
+ (interactive "p")
+ (save-excursion
+ (goto-char (point-min))
+ (if (search-forward-regexp "^Release:\\([ \t]*\\)\\(\\([^.\n]+\\.\\)*\\)\\([0-9]+\\)\\(.*\\)" nil t)
+ (let ((release (1+ (string-to-int (match-string 4)))))
+ (setq release (concat (match-string 1) (match-string 2) (int-to-string release) (match-string 5)))
+ (replace-match (concat "Release:" release))
+ (message (concat "Release tag changed to " release ".")))
+ (if (search-forward-regexp "^Release:[ \t]*%{?\\([^}]*\\)}?$" nil t)
+ (rpm-increase-release-with-macros)
+ (message "No Release tag found...")))))
+
+;;------------------------------------------------------------
+
+(defun rpm-spec-field-value (field max)
+ "Get the value of FIELD, searching up to buffer position MAX.
+See `search-forward-regexp'."
+ (save-excursion
+ (ignore-errors
+ (let ((str
+ (progn
+ (goto-char (point-min))
+ (search-forward-regexp (concat
+ field ":[ \t]*\\(.*?\\)[ \t]*$") max)
+ (match-string 1))))
+ (if (string-match "%{?\\([^}]*\\)}?$" str)
+ (progn
+ (goto-char (point-min))
+ (search-forward-regexp
+ (concat "%define[ \t]+" (substring str (match-beginning 1)
+ (match-end 1))
+ "[ \t]+\\(.*\\)"))
+ (match-string 1))
+ str)))))
+
+(defun rpm-find-spec-version (&optional with-epoch)
+ "Get the version string.
+If WITH-EPOCH is non-nil, the string contains the Epoch/Serial value,
+if one is present in the file."
+ (save-excursion
+ (goto-char (point-min))
+ (let* ((max (search-forward-regexp rpm-section-regexp))
+ (version (rpm-spec-field-value "Version" max))
+ (release (rpm-spec-field-value "Release" max))
+ (epoch (rpm-spec-field-value "Epoch" max)) )
+ (when (and version (< 0 (length version)))
+ (unless epoch (setq epoch (rpm-spec-field-value "Serial" max)))
+ (concat (and with-epoch epoch (concat epoch ":"))
+ version
+ (and release (concat "-" release)))))))
+
+(defun rpm--with-temp-file (prefix f)
+ (let ((file (make-temp-file prefix)))
+ (unwind-protect
+ (funcall f file)
+ (delete-file file))))
+
+(defun rpm-find-spec-version-with-shell ()
+ "Find the version and release with the rpm command
+ more robust but slower than the lisp version"
+ (rpm--with-temp-file "spec" (lambda (tmpfile)
+ (write-region (point-min) (point-max) tmpfile nil 1)
+ (let ((relver))
+ (with-temp-buffer
+ (apply 'call-process "rpm" nil t nil
+ (list "-q" "--qf" "'%{VERSION}-%{RELEASE}\\n'" "--specfile" tmpfile))
+ (goto-char (point-min))
+ (if (re-search-forward "\\([0-9]+.+\\)" nil t)
+ (setq relver (match-string 1)))
+ )
+ relver)
+ )))
+
+(defun rpm-increase-release-with-macros ()
+ (save-excursion
+ (let ((str
+ (progn
+ (goto-char (point-min))
+ (search-forward-regexp (concat "Release:[ \t]*\\(.+\\).*$") nil)
+ (match-string 1)))
+ (increase-macro (lambda (macros)
+ (goto-char (point-min))
+ (if (search-forward-regexp
+ (concat "%define[ \t]+" macros
+ "\\([ \t]+\\)\\(\\([^.\n]+\\.\\)*\\)\\([0-9]+\\)\\(.*\\)") nil t)
+ (let ((dinrel (concat macros (match-string 1) (match-string 2)
+ (int-to-string (1+ (string-to-int
+ (match-string 4))))
+ (match-string 5))))
+ (replace-match (concat "%define " dinrel))
+ (message (concat "Release tag changed to " dinrel "."))
+ t)))))
+
+ (if (string-match "%{?\\([^}]*\\)}?$" str)
+ (or (funcall increase-macro (substring str (match-beginning 1) (match-end 1)))
+ (and (search-forward-regexp
+ (concat "%define[ \t]+" macros "[ \t]+%mkrel[ \t]+%{rel}") nil t)
+ (funcall increase-macro "rel")))))))
+
+;;------------------------------------------------------------
+
+(defun rpm-spec-initialize ()
+ "Create a default spec file if one does not exist or is empty."
+ (let (file name version (release "1"))
+ (setq file (if (buffer-file-name)
+ (file-name-nondirectory (buffer-file-name))
+ (buffer-name)))
+ (string-match "\\(.*\\).spec" file)
+ (setq name (match-string 1 file))
+
+ (insert
+ "%define name " (or name "")
+ "\n%define version " (or version "")
+ "\n%define release " (or release "") "mdk"
+ "\n\nSummary:" (rpm-insert-space-or-tabs 1)
+ "\nName:" (rpm-insert-space-or-tabs 2) "%{name}"
+ "\nVersion:" (rpm-insert-space-or-tabs 1) "%{version}"
+ "\nRelease:" (rpm-insert-space-or-tabs 1) "%{release}"
+ "\nSource0:" (rpm-insert-space-or-tabs 1) "%{name}-%{version}.tar.bz2"
+ "\nLicense:" (rpm-insert-space-or-tabs 1)
+ "\nGroup:" (rpm-insert-space-or-tabs 2)
+ "\nUrl:" (rpm-insert-space-or-tabs 2)
+ "\nBuildRoot:" (rpm-insert-space-or-tabs 1) "%{_tmppath}/%{name}-%{version}-%{release}-buildroot\n"
+ "\n\n%description\n"
+ "\n%prep\n%setup -q\n\n%build\n\n%install\nrm -rf $RPM_BUILD_ROOT"
+ "\n\n\n%clean\nrm -rf $RPM_BUILD_ROOT"
+ "\n\n%files\n%defattr(-,root,root)\n"
+ "\n\n%changelog\n"))
+ (goto-char (point-min)))
+
+;;------------------------------------------------------------
+
+(defun rpm-about-rpm-spec-mode (&optional arg)
+ "About `rpm-spec-mode'."
+ (interactive "p")
+ (message
+ (concat "rpm-spec-mode version "
+ rpm-spec-mode-version
+ " by Stig Bjørlykke, <stigb@tihlde.org>")))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.spec$" . rpm-spec-mode))
+
+(provide 'rpm-spec-mode)
+
+;;; rpm-spec-mode.el ends here