version.lisp 5.94 KB
Newer Older
1 2 3 4
(in-package :asdf-tools)

;;; Extracting version information

5
(defparameter *version-tag-glob* "[0-9][.][0-9]*") ;; NB: it's a glob, not regex
6 7

(defun version-from-tag (&optional commit)
8
  ;; run-program issue: :output :line closes the fd, which causes the program to die in error.
9
  (first (nth-value 2 (git `(describe --tags --match ,*version-tag-glob* ,commit) :output :lines))))
10 11 12

(defun version-from-file (&optional commit)
  (if commit
13
      (nth-value 2 (git `(show (,commit":version.lisp-expr")) :output :form))
14 15 16
      (safe-read-file-form (pn "version.lisp-expr"))))

(defun debian-version-from-file (&optional commit)
17
  (match (if commit
18
             ;; run-program issue: :output :line closes the fd, which causes the program to die in error.
19 20
             (first (nth-value 2 (git `(show (,commit":debian/changelog"))
                                      :output :lines :error-output nil)))
21 22
             (read-file-line (pn "debian/changelog")))
    ((ppcre "^[^(]*\\(([-0-9.:-]+)\\)" ver) ver)))
23

24 25 26 27 28 29 30 31
(defun parse-debian-version (&optional (debian-version (debian-version-from-file)))
  (cl-ppcre:register-groups-bind (epoch ver rel)
      ("^(?:([0-9]+):)?([0-9.]+)(?:-([0-9]+))$" debian-version)
    ;; NB: (A) we return version first, not epoch, because it's the primary result!
    ;; (B) epoch = nil is semantically same as epoch = 0
    ;; (C) rel = nil is for debian-native packages, e.g. base-passwd or cowbuilder
    (values ver epoch rel)))

32 33 34 35 36 37 38 39
(defun debian-version-string (ver epoch rel)
  (format nil "~@[~D:~]~A~@[-~A~]" epoch ver rel))

(defun debian-version-without-epoch (version-string)
  (multiple-value-bind (ver epoch rel) (parse-debian-version version-string)
    (declare (ignore epoch))
    (debian-version-string ver nil rel)))

40 41 42 43
;;; Bumping the version of ASDF

(defparameter *versioned-files*
  '(("version.lisp-expr" "\"" "\"")
44
    ("uiop/version.lisp" "(defparameter *uiop-version* \"" "\")")
45 46
    ("asdf.asd" "  :version \"" "\" ;; to be automatically updated by make bump-version")
    ("header.lisp" "This is ASDF " ": Another System Definition Facility.")
47
    ("upgrade.lisp" "   (asdf-version \"" "\")")
48
    ("doc/asdf.texinfo" "Manual for Version " ""))) ;; NB: two occurrences with this pattern.
49

50 51 52 53

(defparameter *old-version* :default)
(defparameter *new-version* :default)

54
(defun compute-next-version (v)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
  (let ((pv (parse-version v 'error)))
    (assert (first pv))
    (assert (second pv))
    (unless (third pv) (appendf pv (list 0)))
    (unless (fourth pv) (appendf pv (list 0)))
    (incf (car (last pv)))
    (unparse-version pv)))

(defun versions-from-args (&optional v1 v2)
  (labels ((check (old new)
             (parse-version old 'error)
             (parse-version new 'error)
             (values old new)))
    (cond
      ((and v1 v2) (check v1 v2))
      (v1 (check (version-from-file) v1))
71
      ((not (eq *new-version* :default)) *new-version*) ;; Ugly passing of argument from Makefile.
72
      (t (let ((old (version-from-file)))
73
           (check old (compute-next-version old)))))))
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

(deftype byte-vector () '(array (unsigned-byte 8) (*)))

(defun maybe-replace-file (file transformer
                           &key (reader 'read-file-string)
                             (writer nil) (comparator 'equalp)
                             (external-format *utf-8-external-format*))
  (format t "Transforming file ~A... " (file-namestring file))
  (let* ((old-contents (funcall reader file))
         (new-contents (funcall transformer old-contents)))
    (if (funcall comparator old-contents new-contents)
        (format t "no changes needed!~%")
        (let ((written-contents
                (if writer
                    (with-output (s ())
                      (funcall writer s new-contents))
                    new-contents)))
          (check-type written-contents (or string (byte-vector)))
          (clobber-file-with-vector file written-contents :external-format external-format)
93 94
          (format t "done.~%"))))
  (success))
95 96 97 98 99 100 101 102 103 104

(defun version-transformer (new-version file prefix suffix &optional dont-warn)
  (let* ((qprefix (cl-ppcre:quote-meta-chars prefix))
         (versionrx "([0-9]+(\\.[0-9]+)+)")
         (qsuffix (cl-ppcre:quote-meta-chars suffix))
         (regex (strcat "(" qprefix ")(" versionrx ")(" qsuffix ")"))
         (replacement
           (constantly (strcat prefix new-version suffix))))
    (lambda (text)
      (multiple-value-bind (new-text foundp)
105
          (cl-ppcre:regex-replace-all regex text replacement)
106 107 108 109 110 111 112 113
        (unless (or foundp dont-warn)
          (warn "Missing version in ~A" (file-namestring file)))
        (values new-text foundp)))))

(defun transform-file (new-version file prefix suffix)
  (maybe-replace-file (pn file) (version-transformer new-version file prefix suffix)))

(defun transform-files (new-version)
114 115
  (loop :for f :in *versioned-files* :do (apply 'transform-file new-version f))
  (success))
116 117 118 119 120 121 122 123 124

(defun test-transform-file (new-version file prefix suffix)
  (let ((lines (read-file-lines (pn file))))
    (dolist (l lines (progn (warn "Couldn't find a match in ~A" file) nil))
      (multiple-value-bind (new-text foundp)
          (funcall (version-transformer new-version file prefix suffix t) l)
        (when foundp
          (format t "Found a match:~%  ==> ~A~%Replacing with~%  ==> ~A~%~%"
                  l new-text)
125
          (return (success)))))))
126 127 128 129

(defun test-transform (new-version)
  (apply 'test-transform-file new-version (first *versioned-files*)))

130
(defun bump-version (&optional v1 v2)
131
  "bump asdf version, do not commit"
132 133
  (with-asdf-dir ()
    (multiple-value-bind (old-version new-version)
134
        (versions-from-args v1 v2)
135 136 137 138 139 140
      (format t "Bumping ASDF version from ~A to ~A~%" old-version new-version)
      (transform-files new-version)
      (println "Rebuilding ASDF with bumped version")
      (build-asdf)
      new-version)))

141
(defun bump (&optional v1 v2)
142
  "bump asdf version, then commit and tag"
143
  (let ((v (bump-version v1 v2)))
144 145 146
    (git `(commit -a -m ("Bump version to ",v)))
    (git `(tag ,v))
    v))
147