From c3004ea93a0130f3f5d397f7659b675b57e02ea7 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 9 Jun 2023 11:51:32 +0100 Subject: [PATCH] Mainly making the code more elegant. Actual problems not solved. --- .gitignore | 2 ++ project.clj | 15 +++++--- src/cc/journeyman/real_name/core.clj | 52 +++++++++++++++++++--------- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 31f0c11..8d23c0a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ pom.xml.asc .hg/ .clj-kondo/ .lsp/ + +docs/ diff --git a/project.clj b/project.clj index 5195eb5..60d4f8e 100644 --- a/project.clj +++ b/project.clj @@ -1,7 +1,12 @@ -(defproject real-name "0.1.0-SNAPSHOT" - :description "FIXME: write description" - :url "http://example.com/FIXME" +(defproject org.clojars.simon_brooke/real-name "0.1.0-SNAPSHOT" + :codox {:metadata {:doc "**TODO**: write docs" + :doc/format :markdown} + :output-path "docs" + :source-uri "https://github.com/simon-brooke/real-name/blob/master/{filepath}#L{line}"} + :dependencies [[org.clojure/clojure "1.10.3"]] + :description "Resolve real names from user names in a platform independent fashion." :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} - :dependencies [[org.clojure/clojure "1.10.3"]] - :repl-options {:init-ns cc.journeyman.real-name.core}) + :plugins [[lein-codox "0.10.7"]] + :repl-options {:init-ns cc.journeyman.real-name.core} + :url "https://github.com/simon-brooke/real-name/") diff --git a/src/cc/journeyman/real_name/core.clj b/src/cc/journeyman/real_name/core.clj index e2a6cc2..f5b5924 100644 --- a/src/cc/journeyman/real_name/core.clj +++ b/src/cc/journeyman/real_name/core.clj @@ -2,7 +2,7 @@ "Resolve real names from user names in a platform independent fashion." (:require [clojure.java.io :refer [reader]] [clojure.java.shell :refer [sh]] - [clojure.string :refer [split trim]]) + [clojure.string :refer [split starts-with? trim]]) (:gen-class)) (defn- mac-os-x @@ -20,24 +20,44 @@ :os-name (System/getProperty "os.name") :os-version (System/getProperty "os.version")}))))) +(defn delimited-record->map + "Split this `record` into fields delimited by this `delimiter-pattern` and + return it as a map with these `keys`." + [^String record ^java.util.regex.Pattern delimiter-pattern keys] + (apply assoc + (cons {} (interleave keys (split record delimiter-pattern))))) + +(defn process-gecos + "Process this `gecos` field into a map of its sub-fields. See + https://en.wikipedia.org/wiki/Gecos_field" + [gecos] + (delimited-record->map gecos #"," [:real-name :address :work-phone :home-phone :other])) + +(defn process-passwd-line + "Process this `line` from a passwd file" + [line] + (let [record (delimited-record->map line #":" [:uname :pass :uid :gid :gecos :sh])] + (when record (assoc record :gecos (process-gecos (:gecos record)))))) + +(defn process-passwd + "Process the password file into a map whose keys are user names and whose + values are maps of associated records from lines in the file." + [] + (reduce #(assoc %1 (:uname %2) %2) + {} + (map process-passwd-line + (remove #(starts-with? % "#")(line-seq (reader "/etc/passwd")))))) + (defn- unix "Generic unix, parse the GECOS field of the passwd record matching `username`." ([username] - (unix username 4)) - ([username gecos-field] - (let [passwd (map #(split % #":") (line-seq (reader "/etc/passwd"))) - userrecord (first (filter #(= (first %) username) passwd)) - gecos (when userrecord (split (nth userrecord gecos-field) #","))] - (if gecos (trim (first gecos)) - (throw (ex-info (format "Real name for `%s` not found" username) - {:username username - :known-users (map - first - (filter - #(> (read-string (nth % 2)) 999) - (filter #(= (count %) 7) passwd))) - :os-name (System/getProperty "os.name") - :os-version (System/getProperty "os.version")})))))) + (let [real-name (-> ((process-passwd) username) :gecos :real-name)] + (if real-name + real-name + (throw (ex-info (format "Real name for `%s` not found." username) + {:username username + :os-name (System/getProperty "os.name") + :os-version (System/getProperty "os.version")})))))) (defn- windows7+ "Very experimental, probably wrong."