scripts/stack-volumes.jq
Rama main · réplica de lectura del repositorio original.
# One snapshot drives both dry-run output and execution. Last-use records are
# scoped to a Docker daemon by stack.sh and to a volume incarnation here.
def project: .Config.Labels["com.docker.compose.project"] // "";
def stopped: .State.Status as $s | ["exited", "dead", "created"] | index($s) != null;
def epoch: try (sub("\\.[0-9]+"; "") | sub("\\+00:00$"; "Z") | fromdateiso8601) catch $now;
def activity: [.State.FinishedAt, .State.StartedAt, .Created] | map(epoch) | max;
($classifications | split("\n") | map(select(length > 0) | split("\t") |
{key: .[0], value: {kind: .[1], scope: (.[2] == "true")}}) | from_entries) as $classes |
($containers[0]) as $cs |
($volumes[0]) as $vs |
($classes | with_entries(
.key as $p | .value += {
members: [$cs[] | select(project == $p)],
owned: (["mike", "orphan", "supabase"] | index($classes[$p].kind) != null)
} |
.value.removable = (.value.scope and .value.owned and (.value.members | length > 0) and
(.value.members | all(stopped)))
)) as $projects |
[$projects[] | select(.removable) | .members[].Id] as $removed |
($allowed | split(",") | map(select(length > 0))) as $allowed_supa |
reduce $vs[] as $v (
{containers: $removed,
removed_projects: [$projects | to_entries[] | select(.value.removable) | .key],
protected: [$projects | to_entries[] | select(.value.scope and .value.owned and
(.value.members | any(stopped | not))) | .key],
state: {version: 1, volumes: {}}, remove: [], kept: []};
($v.Labels // {}) as $labels |
($labels["com.docker.compose.project"] // $labels["com.supabase.cli.project"] // "") as $p |
($labels["com.supabase.cli.project"] // "") as $supa |
($labels | has("com.docker.volume.anonymous")) as $anon |
($projects[$p] // {kind: "unknown", members: [], owned: false, scope: false}) as $pr |
($previous[0].volumes[$v.Name] | if .created == $v.CreatedAt and .project == $p and .supabase == $supa
then . else null end) as $old |
(if $p != "" then $pr.scope else ($anon and $only == "") end) as $scope |
# A known foreign project always vetoes a saved ownership record or name.
# Unknown named volumes need a previous verified record; a mike* prefix
# alone is insufficient when no containers establish provenance.
(if $pr.kind == "other" then false
elif $supa != "" then ($allowed_supa | index($supa) != null)
elif $anon and $p == "" then true
elif $pr.owned then true
else ($pr.kind == "unknown" and $old != null) end) as $mine |
if $scope | not then
if $old != null then .state.volumes[$v.Name] = $old else . end
elif $mine | not then .
else
[$cs[] | select(any(.Mounts[]?; .Type == "volume" and .Name == $v.Name))] as $refs |
(any($refs[]; .Id as $id | $removed | index($id) == null) or
any($pr.members[]; stopped | not)) as $busy |
(if ($old.idle_since | type) == "number" then $old.idle_since else 0 end) as $prior |
# While referenced outside the teardown plan, invalidate the idle
# bound: a later manual down must start a new grace period. Otherwise
# use actual activity or retain the prior bound for an orphan. Never use
# the volume's creation age.
(if $busy then null
elif $pr.removable then ([$prior, ($pr.members | map(activity) | max)] | max)
elif ($refs | length) > 0 then ([$prior, ($refs | map(activity) | max)] | max)
elif $old != null and $prior > 0 then $prior
else $now end) as $idle |
.state.volumes[$v.Name] = {created: $v.CreatedAt, project: $p, supabase: $supa, idle_since: $idle} |
if ($busy | not) and ($now - $idle >= $age) then .remove += [$v.Name]
else .kept += [$v.Name] end
end
)