Hei rakkaat! Ihan sellaisella asialla lähdin influenssaamaan, että tiedättekö sen tunteen, kun ajattelee, että tämmönen pikkujuttu hoituisi bash-skriptillä ihan jeespox ja sitten kuitenkin tulee jossain vaiheessa fiilis, että hitto kun clojurella tämäkin juttu tästä menis niin paljon helpommin? Eikä sitten kuitenkaan jaksaisi yhtään kammeta jotain koko appisboilerplatea sitä yhtä ajoa varten tai sitten jotain replia hinkutella? Noh, siis omg, hyviä uutisia: tähän on ratkaisu.

Tl:dr; asenna babashka, kirjoita skriptisi .clj -filuseen, ja aja bb skripti.clj.

Asennus onnistuu mäkkylässä brewlla ja Archillekin löytyy asennuspaketti AUR:sta. Muilla curlailet installerskriptin ja silleesti.

brew install borkdude/brew/babashka

Käyttö on niinkin helppoa, kuin bb ja hipsujen sisään se clojurekomento:

$ bb '(+ 1 2)'
3

Skriptejä kutsutaan taasen yksinkertaisesti bb skirpti.clj:


#!/usr/bin/env bb

(def oma-array [1 2 3])
(println (map #(inc %) oma-array))
$ bb anskun_skripti.clj                                                                                                                                                
(2 3 4)

Babashkassa on valmiiksi requirattuna namespaceja (esim. clojure.string, clojure.set ja vaikkapa clojure.data.csv). Nämä voi siis requirata skriptiinsä ihan perinteisellä :as tai :refer -notaatiolla:

#!/usr/bin/env bb

(ns anskun-skripti
  (:require [clojure.string :as str]))

(def oma-array [1 2 3])
(println (str "Sama array stringinä, olkaa hyvät: " oma-array))
$ bb anskun_skripti.clj
Sama array stringinä, olkaa hyvät: [1 2 3]

Lisäksi clojure.core -funkkarit ovat käytössä ihan ilman namespace aliastakin.

Ulkopuolisia kirjastoja ei saa helposti mukaan (voisi kai käyttää sitä load-file:a ladatakseen skriptin), mikä on vähän bummer. Toivotaan, että tähän tulee tulevaisuudessa helpotusta.

Jos tarvitsee jotain bashin ominaisuuksia käyttää, niin voi requirata vaan kätevästi [clojure.java.shell :refer [sh]] ja sitten kutsua bash-komentoja (sh "komento"), esim. (sh "touch" "testfile.txt"). Eli koska external kirjastoja ei saa kätevästi requirattua, en voinut käyttää software.amazon.awssdk/sqs:ää, joten käytän sitten muutenkin jo asennettua aws-cli:tä bashin kautta.

Tarve tähän tuli, kun piti csv-filussa olevia kamoja pöräyttää ensin jsoniksi, jotka siten aws:n sqs-jonoon tuutata. Semmonen kerran tehtävä ajo, johon olin logeista kaivanut tapahtumat, jotka menivät mönkään yhden taustajärjestelmän ollessa kiikussa. Siellä CloudWatchissahan saa sileen kätevästi yhden searchin tulokset tallennettua csv:nä, niin siksi tämä csv-hässäkkä tässä:

Jotta meidän lambda osaa syödä niitä viestejä tehdä temppunsa, niiden piti olla tietyssä json-muodossa ja sitten lähettää yksitellen yksi jsonobjekti matkaan.

Niin ja ton saa kyllä myös toki bashilla tehtyä, vaikka vähän jq:lla avustettuna. Tietty. Mut mukavampi se tälleen clojurella on. Niin tämmönen siitä sitten tuli.

#!/usr/bin/env bb
(ns anskun-skripti
  (:require [clojure.string :as str]
	    [clojure.java.shell :refer [sh]]
	    [clojure.data.csv :as csv]
	    [clojure.java.io :as io]
            [cheshire.core :as json]))

(def queue-url "") ;; tähän sun sqs-jonon urli
(def csv-file "") ;; tähän sun filunen

;; muutetaan csv ensin mapiksi (pöllitty clojure.data.csv-dkoumentaatiosta)

(defn csv-data->maps [csv-data]
  (map zipmap
       (->> (first csv-data)
            (map keyword)
            repeat)
	  (rest csv-data)))

(def data-map (csv-data->maps (csv/read-csv (io/reader csv-file))))

;; funkkari, joka lähettää aina yhden viestin, mutta muuttaa sen ensin jsoniksi

(defn send-one-message [item]
  (let [message (json/generate-string item)]
      (sh "aws" "sqs" "send-message" "--queue-url" queue-url "--message-body" message)))

;; ja sitten vaan lähetetään maailmaan yksitellen objekti kerrallaan:
(map send-one-message data-map)

Detaljina semmonen pointsukka, että ensiksi pitää olla toki se aws sqs silleen konffailtu, ettei kysy sitä pirun mfa tokenia joka välissä eli aws:n configissa kyseisen profilen blokin lopussa (tässä profilena maijameikalainen ja mulla aws-vault käytössä) credential_process = aws-vault exec maijameikalainen --json --prompt=osascript ja sit viel sanoa, että aws-vault exec maijameikalainen --no-session, niin saa kredentiaalit sessioon.

Mut joo, tällaselle huonolla lähimuistilla varustetulle keski-ikäiselle toi on ihan kiva, ettei tarvitse ihan hirveesti muistella kesken päivää, mitens se bashin syntaksi menikään 😀