Fosi Fossil Service
Small teams. Open source. Built on Fossil.

CaaS / Lamina

Unified Management for Fossil Repositories

Public | Owner: CaaS | Default branch: trunk | Last update: 2026-10-25 00:41

Artifact 220195d810f680c0f9ac90cf9885d4607946e3309db5d75f7e0f995cffdab50b:


;; 路径段(slug)与保留字校验(设计文档 §4.3)
(defmodule lamina_validate
  (export all))

(defun reserved ()
  (list "login" "logout" "setup" "admin" "explore" "organizations"
        "about" "static" "priv" "favicon.ico" "robots.txt" "assets"))

;; 合法 slug:字母(含大写)、数字、中划线,最长 64,且不是保留字。
;; 保留字按小写比较,Admin 与 admin 一样不能占用系统路径。
(defun slug-pattern () "^[A-Za-z0-9][A-Za-z0-9-]{0,63}$")

(defun reserved? (s)
  (lists:member (string:lowercase s) (reserved)))

(defun valid-slug? (s)
  (and
   (is_list s)
   (case (re:run s (slug-pattern))
     (`#(match ,_) 'true)
     (_ 'false))
   (not (reserved? s))))

(defun check-slug (slug)
  (cond
    ((not (is_list slug)) `#(error "名称无效"))
    ((reserved? slug) `#(error "该名称是系统保留字"))
    ((case (re:run slug (slug-pattern))
       (`#(match ,_) 'false)
       (_ 'true))
     `#(error "名称只能包含字母、数字和中划线,且以字母或数字开头"))
    ('true 'ok)))

;; 组织名/仓库名组合在 DB 中唯一;org-name 为 'none 表示未归类仓库
;; 返回 'ok | {error, Msg}
(defun check-availability (org-name slug)
  (case (check-slug slug)
    ('ok
     (let ((n (repo-count org-name slug)))
       (if (> n 0)
           `#(error "该路径已被占用")
           'ok)))
    (other other)))

(defun repo-count (org-name slug)
  (let ((result
         (case org-name
           ('none
            (catch (lamina_db:q "SELECT COUNT(*) FROM repositories WHERE name=? AND organization_id IS NULL;"
                                  (list slug))))
           (_
            (catch (lamina_db:q "SELECT COUNT(*) FROM repositories r JOIN organizations o ON r.organization_id=o.id WHERE r.name=? AND o.name=?;"
                                  (list slug org-name)))))))
    (case result
      (`((,n)) (to-int n))
      (_ 1)))) ; 查询失败按已占用处理,保守拒绝

(defun to-int (v)
  (cond
    ((is_integer v) v)
    ((is_binary v) (binary_to_integer v))
    ('true (list_to_integer v))))

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/CaaS/Lamina

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.