about summary refs log blame commit diff
path: root/tools/emacs-pkgs/defzone/defzone.el
blob: b67501cbd860b56e409e504faf480e5ccaa621c3 (plain) (tree)















































                                                                                    
;;; defzone.el --- Generate zone files from Elisp  -*- lexical-binding: t; -*-

(require 'dash)
(require 'dash-functional)
(require 's)

(defun record-to-record (zone record &optional subdomain)
  "Evaluate a record definition and turn it into a zone file
  record in ZONE, optionally prefixed with SUBDOMAIN."

  (declare (indent defun))             ; TODO(tazjin): remove
  (let ((name (if subdomain (s-join "." (list subdomain zone)) zone)))
    (pcase record
      (`(SOA . (,ttl . (,mname ,rname ,serial ,refresh ,retry ,expire ,min)))
       (format "%s %s IN SOA %s %s %s %s %s %s %s"
               name ttl mname rname serial refresh retry expire min))

      (`(NS . (,ttl . ,targets))
       (->> targets
            (-map (lambda (target) (format "%s %s IN NS %s" name ttl target)))
            (s-join "\n")))

      (`(MX . (,ttl . ,pairs))
       (->> pairs
            (-map (-lambda ((preference . exchange))
                    (format "%s %s IN MX %s %s" name ttl preference exchange)))
            (s-join "\n")))

      (`(TXT ,ttl ,text) (format "%s %s IN TXT %s" name ttl (prin1-to-string text)))

      (`(A . (,ttl . ,ips))
       (->> ips
            (-map (lambda (ip) (format "%s %s IN A %s" name ttl ip)))
            (s-join "\n")))

      (`(CNAME ,ttl ,target) (format "%s %s IN CNAME %s" name ttl target))

      ((and `(,sub . ,records)
            (guard (stringp sub)))
       (s-join "\n" (-map (lambda (r) (record-to-record zone r sub)) records)))

      (_ (error "Invalid record definition: %s" record)))))

(defmacro defzone (fqdn &rest records)
  "Generate zone file for the zone at FQDN from a simple DSL."
  (declare (indent defun))

  `(s-join "\n" (-map (lambda (r) (record-to-record ,fqdn r)) (quote ,records))))