Here are some "real world" (some day to day one-time tasks from my work) using Rebellion(pkg, github) an infrastructure library for Racket.
Last active
November 5, 2019 00:30
-
-
Save samdphillips/abfd8b477d5963e929ec4449815b0a38 to your computer and use it in GitHub Desktop.
Using Rebellion in Anger
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket/base | |
#| | |
Given a directory containing a bunch of files with data, | |
... | |
#s(db-info "myhostname1" "/var/lib/db/mydatabase" 588969) | |
... | |
#s(db-info "myhostname110" "/var/lib/db/mydatabase" 234457) | |
find the aggregate size per database. We also skip some internal databases. | |
|# | |
(require racket/function | |
racket/match | |
racket/path | |
racket/sequence | |
unstable/match | |
rebellion/collection/entry | |
rebellion/collection/hash | |
rebellion/streaming/reducer | |
rebellion/streaming/transducer) | |
(define (combining-into-hash combiner) | |
(define (update-hash h e) | |
(define k (entry-key e)) | |
(define v (entry-value e)) | |
(hash-update h k (λ (old) (combiner old v)) (λ () v))) | |
(make-fold-reducer update-hash empty-hash #:name 'combining-into-hash)) | |
(struct db-info (hostname path size) #:prefab) | |
(define (db-info-name a-db-info) | |
(match (db-info-path a-db-info) | |
[(pregexp #px"/([^/]+)$" (list _ name)) name])) | |
(define DATA-DIR (build-path (current-directory) "size-data")) | |
(define (rktd-file? filename) | |
(bytes=? (path-get-extension filename) #".rktd")) | |
(define (internal-file? filename) | |
(match? filename | |
(regexp #rx"^_") | |
"kvstore" | |
"scratch")) | |
(define (file->records filename) | |
(with-input-from-file filename | |
(lambda () | |
(sequence->list (in-port read))))) | |
(transduce (directory-list DATA-DIR #:build? #t) | |
(filtering rktd-file?) | |
(append-mapping file->records) | |
(bisecting db-info-name values) | |
(filtering-keys (negate internal-file?)) | |
(mapping-values db-info-size) | |
#:into (combining-into-hash +)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket/base | |
#| | |
Simply parsing an INI-style file into a hash. | |
|# | |
(require (for-syntax racket/base | |
syntax/parse) | |
racket/function | |
racket/match | |
(rename-in rebellion/base/variant | |
[variant orig:variant]) | |
rebellion/collection/entry | |
rebellion/collection/hash | |
rebellion/streaming/reducer | |
rebellion/streaming/transducer) | |
(define-match-expander variant | |
(syntax-parser | |
[(_ tag:keyword pat) | |
#'(? variant? | |
(? (lambda (v) (variant-tagged-as? v 'tag)) | |
(app variant-value pat)))]) | |
(make-rename-transformer #'orig:variant)) | |
(define generate-conf | |
(make-transducer #:starter | |
(lambda () (variant #:consume #f)) | |
#:consumer | |
(match-lambda** | |
[(#f (variant #:entry _)) | |
(variant #:consume #f)] | |
[(#f (variant #:section name)) | |
(variant #:consume (list name))] | |
[(vs (variant #:entry e)) | |
(variant #:consume (cons e vs))] | |
[(vs (variant #:section name)) | |
(let ([vs (reverse vs)]) | |
(variant #:emit | |
(cons (entry (car vs) (cdr vs)) | |
name)))]) | |
#:emitter | |
(match-lambda | |
[(cons emit name) | |
(emission (variant #:consume (list name)) emit)]) | |
#:half-closed-emitter | |
(lambda (state) | |
(let ([vs (reverse state)]) | |
(half-closed-emission (variant #:finish #f) | |
(entry (car vs) (cdr vs))))) | |
#:half-closer | |
(lambda (state) | |
(variant #:half-closed-emit state)) | |
#:finisher void)) | |
(define strip-comments | |
(match-lambda | |
[(regexp #rx"^([^#]*)#.*$" (list _ data)) data] | |
[data data])) | |
(define (empty-string? s) | |
(regexp-match? #rx"^\\s*$" s)) | |
(define classify-line | |
(match-lambda | |
[(regexp #rx"\\[([^]]+)]" (list _ name)) | |
(variant #:section name)] | |
[(pregexp #px"^(.*?)\\s*=\\s*(\\d+)$" (list _ key value)) | |
(variant #:entry (entry key (string->number value)))] | |
[(pregexp #px"^(.*?)\\s*=\\s*(.*)$" (list _ key value)) | |
(variant #:entry (entry key value))])) | |
(define variable-pattern #px"\\$([A-Z_]+)") | |
(define (expand-variables lookup-hash) | |
(lambda (input-string) | |
(regexp-replace variable-pattern | |
input-string | |
(lambda (s name) | |
(hash-ref lookup-hash name (lambda () s)))))) | |
(call-with-input-file "database.conf" | |
(lambda (inp) | |
(transduce (in-lines inp) | |
(mapping strip-comments) | |
(filtering (negate empty-string?)) | |
(mapping (expand-variables | |
(hash "DB_PATH" "/var/lib/db"))) | |
(mapping classify-line) | |
generate-conf | |
(mapping-values | |
(lambda (vs) | |
(reduce-all into-hash vs))) | |
#:into | |
into-hash))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment