Liking cljdoc? Tell your friends :D

patcho.cli

CLI tool functions for querying Patcho topic versions.

Setup - add to deps.edn: {:aliases {:patcho {:extra-deps {dev.gersak/patcho {:mvn/version "0.4.2"}} :exec-ns patcho.cli}}}

Usage: clj -X:patcho version :topic :myapp/database :require myapp.patches clj -X:patcho versions :require myapp.patches clj -X:patcho topics :require myapp.patches

The version command returns a plain string for easy shell capture:

VERSION=$(clj -X:patcho version :topic :myapp/database :require myapp.patches)

The versions and topics commands return EDN for programmatic use:

(def versions (let [{:keys [out]} (b/process {:command-args ["clj" "-X:patcho" "versions" ":require" "myapp.patches"] :out :capture})] (edn/read-string out)))

CLI tool functions for querying Patcho topic versions.

Setup - add to deps.edn:
  {:aliases
   {:patcho {:extra-deps {dev.gersak/patcho {:mvn/version "0.4.2"}}
             :exec-ns patcho.cli}}}

Usage:
  clj -X:patcho version :topic :myapp/database :require myapp.patches
  clj -X:patcho versions :require myapp.patches
  clj -X:patcho topics :require myapp.patches

The `version` command returns a plain string for easy shell capture:

  VERSION=$(clj -X:patcho version :topic :myapp/database :require myapp.patches)

The `versions` and `topics` commands return EDN for programmatic use:

  (def versions
    (let [{:keys [out]} (b/process
                          {:command-args ["clj" "-X:patcho" "versions"
                                          ":require" "myapp.patches"]
                           :out :capture})]
      (edn/read-string out)))
raw docstring

patcho.lifecycle

Module lifecycle management with dependency resolution.

Provides runtime lifecycle management for modules with explicit dependency declaration and automatic startup ordering.

Design Philosophy

This namespace provides a lightweight registry for managing module lifecycle:

  • Modules register themselves at namespace load time
  • Dependencies are declared explicitly
  • Operations are RECURSIVE - automatically handle dependencies
  • Cleanup uses reference counting (claimed-by semantics)
  • State tracking prevents double-start/stop
  • Setup phase is separate from start/stop (one-time vs runtime)

Usage

Registration (at namespace load time)

(ns my.module
  (:require [patcho.lifecycle :as lifecycle]))

(lifecycle/register-module! :my/module
  {:depends-on [:other/module]
   :setup (fn []
            (create-tables!))
   :cleanup (fn []
              (drop-tables!))
   :start (fn []
            (start-connections!)
            (subscribe-to-events!))
   :stop (fn []
           (unsubscribe!)
           (close-connections!))})

Application Startup

(ns my.app
  (:require
    my.database      ; Registers :my/database
    my.cache         ; Registers :my/cache (depends on :my/database)
    my.api           ; Registers :my/api (depends on :my/cache)
    [patcho.lifecycle :as lifecycle]))

;; Set default store once (typically in main or init)
(lifecycle/set-store! (lifecycle/->FileLifecycleStore ".lifecycle"))

;; Simple approach: Just start! (auto-runs setup if needed)
(lifecycle/start! :my/api)
;; → Setups (if needed) and starts: :my/database → :my/cache → :my/api
;; Setup is idempotent - only runs once, tracked via lifecycle store

;; OR explicit control: Run setup separately (optional)
(lifecycle/setup! :my/api)  ; One-time: setup all dependencies
(lifecycle/start! :my/api)  ; Runtime: start all dependencies

;; Visualize dependencies
(lifecycle/print-dependency-tree :my/api)
;; :my/api
;; └── :my/cache
;;     └── :my/database

;; Later: stop (RECURSIVE - stops dependents first)
(lifecycle/stop! :my/database)
;; → Stops: :my/api → :my/cache → :my/database

;; Surgical stop (only this module)
(lifecycle/stop-only! :my/api)

;; Cleanup (RECURSIVE with reference checking)
(lifecycle/cleanup! :my/api)
;; → Cleans :my/api
;; → Cleans :my/cache (if no other modules depend on it)
;; → Cleans :my/database (if no other modules depend on it)

Relationship to patcho.patch

Lifecycle management is complementary to version management:

  • patcho.patch: Version migrations (data/schema state transitions)
  • patcho.lifecycle: Runtime management (start/stop with dependencies)

They work together:

  1. Apply patches to reach target version (patch/level!)
  2. Start runtime services (lifecycle/start!) - auto-runs setup if needed

Note: start! automatically runs setup for modules that have a setup function, making the system easy to use while maintaining explicit control when needed.

Design Decisions

  • Registry pattern: Modules stored in atom (like Patcho's patches)
  • Keyword topics: Same style as Patcho (:my/module)
  • Explicit dependencies: Clear, validated at runtime
  • RECURSIVE operations: start/setup/cleanup handle deps automatically
  • Auto-setup: start! runs setup if needed (idempotent via lifecycle store)
  • Reference counting: cleanup only removes if not claimed by others
  • State tracking: Prevents double-start bugs
  • Functions not protocols: Simple, direct
  • Minimal dependencies: Just clojure.core
Module lifecycle management with dependency resolution.

Provides runtime lifecycle management for modules with explicit dependency
declaration and automatic startup ordering.

## Design Philosophy

This namespace provides a lightweight registry for managing module lifecycle:
- Modules register themselves at namespace load time
- Dependencies are declared explicitly
- Operations are RECURSIVE - automatically handle dependencies
- Cleanup uses reference counting (claimed-by semantics)
- State tracking prevents double-start/stop
- Setup phase is separate from start/stop (one-time vs runtime)

## Usage

### Registration (at namespace load time)

    (ns my.module
      (:require [patcho.lifecycle :as lifecycle]))

    (lifecycle/register-module! :my/module
      {:depends-on [:other/module]
       :setup (fn []
                (create-tables!))
       :cleanup (fn []
                  (drop-tables!))
       :start (fn []
                (start-connections!)
                (subscribe-to-events!))
       :stop (fn []
               (unsubscribe!)
               (close-connections!))})

### Application Startup

    (ns my.app
      (:require
        my.database      ; Registers :my/database
        my.cache         ; Registers :my/cache (depends on :my/database)
        my.api           ; Registers :my/api (depends on :my/cache)
        [patcho.lifecycle :as lifecycle]))

    ;; Set default store once (typically in main or init)
    (lifecycle/set-store! (lifecycle/->FileLifecycleStore ".lifecycle"))

    ;; Simple approach: Just start! (auto-runs setup if needed)
    (lifecycle/start! :my/api)
    ;; → Setups (if needed) and starts: :my/database → :my/cache → :my/api
    ;; Setup is idempotent - only runs once, tracked via lifecycle store

    ;; OR explicit control: Run setup separately (optional)
    (lifecycle/setup! :my/api)  ; One-time: setup all dependencies
    (lifecycle/start! :my/api)  ; Runtime: start all dependencies

    ;; Visualize dependencies
    (lifecycle/print-dependency-tree :my/api)
    ;; :my/api
    ;; └── :my/cache
    ;;     └── :my/database

    ;; Later: stop (RECURSIVE - stops dependents first)
    (lifecycle/stop! :my/database)
    ;; → Stops: :my/api → :my/cache → :my/database

    ;; Surgical stop (only this module)
    (lifecycle/stop-only! :my/api)

    ;; Cleanup (RECURSIVE with reference checking)
    (lifecycle/cleanup! :my/api)
    ;; → Cleans :my/api
    ;; → Cleans :my/cache (if no other modules depend on it)
    ;; → Cleans :my/database (if no other modules depend on it)

## Relationship to patcho.patch

Lifecycle management is complementary to version management:
- patcho.patch: Version migrations (data/schema state transitions)
- patcho.lifecycle: Runtime management (start/stop with dependencies)

They work together:
1. Apply patches to reach target version (patch/level!)
2. Start runtime services (lifecycle/start!) - auto-runs setup if needed

Note: start! automatically runs setup for modules that have a setup function,
making the system easy to use while maintaining explicit control when needed.

## Design Decisions

- Registry pattern: Modules stored in atom (like Patcho's patches)
- Keyword topics: Same style as Patcho (:my/module)
- Explicit dependencies: Clear, validated at runtime
- RECURSIVE operations: start/setup/cleanup handle deps automatically
- Auto-setup: start! runs setup if needed (idempotent via lifecycle store)
- Reference counting: cleanup only removes if not claimed by others
- State tracking: Prevents double-start bugs
- Functions not protocols: Simple, direct
- Minimal dependencies: Just clojure.core
raw docstring

patcho.patch

A simple version migration system for Clojure applications.

Patcho provides a declarative way to define version-based patches that can be applied to migrate between different versions of your application or modules.

Key features:

  • Automatic patch sequencing based on semantic versioning
  • Support for both upgrades and downgrades
  • Topic-based organization for modular systems
  • Simple macro-based API

Basic usage: (require '[patcho.patch :as patch])

; Define current version (patch/current-version ::my-app "2.0.0")

; Define upgrade patches (patch/upgrade ::my-app "1.0.0" (println "Initial setup"))

(patch/upgrade ::my-app "2.0.0" (println "Major upgrade"))

; Apply patches (patch/apply ::my-app "1.0.0") ; Runs 2.0.0 upgrade (patch/apply ::my-app nil) ; Runs all upgrades

A simple version migration system for Clojure applications.

Patcho provides a declarative way to define version-based patches that can be
applied to migrate between different versions of your application or modules.

Key features:
- Automatic patch sequencing based on semantic versioning
- Support for both upgrades and downgrades
- Topic-based organization for modular systems
- Simple macro-based API

Basic usage:
  (require '[patcho.patch :as patch])
  
  ; Define current version
  (patch/current-version ::my-app "2.0.0")
  
  ; Define upgrade patches
  (patch/upgrade ::my-app "1.0.0"
    (println "Initial setup"))
  
  (patch/upgrade ::my-app "2.0.0"
    (println "Major upgrade"))
  
  ; Apply patches
  (patch/apply ::my-app "1.0.0")  ; Runs 2.0.0 upgrade
  (patch/apply ::my-app nil)        ; Runs all upgrades
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close