Compare commits
3
Commits
d3fec24bc6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7b169b87e | ||
|
|
a5093c1efc | ||
|
|
045924ec36 |
+144
-95
@@ -7,21 +7,6 @@ by saying so.*
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2026-09-07 — what this tool is `osprey`
|
|
||||||
|
|
||||||
**Decided:** *`loom-cli` is a fetcher and a comparator.* **It fetches a document
|
|
||||||
you depend on and tells you whether the publisher's copy has moved.** *It reports
|
|
||||||
and never repairs.*
|
|
||||||
|
|
||||||
**Believed to advance:** *every act in the loom model is a file in somebody's
|
|
||||||
repository — publishing is writing one, adopting is fetching a URL, homing a gap
|
|
||||||
is an `mv`.* **Almost nothing needs a program**, so the program should be the
|
|
||||||
part that cannot be done by hand: an HTTP request, repeated.
|
|
||||||
|
|
||||||
**Belief that could be shown wrong:** *that reporting is enough.* **If every
|
|
||||||
report is followed by the same manual act, we have moved the work rather than
|
|
||||||
removed it**, and the missing command will be obvious.
|
|
||||||
|
|
||||||
## 2026-09-07 — the design lives here and not in a spec `osprey`
|
## 2026-09-07 — the design lives here and not in a spec `osprey`
|
||||||
|
|
||||||
**Decided:** *this log is the artifact of `osprey`.* **No specification document
|
**Decided:** *this log is the artifact of `osprey`.* **No specification document
|
||||||
@@ -72,40 +57,6 @@ somebody's published surface or from a file they may rename at will.
|
|||||||
location.* **If anybody writes code that parses it back into a URL, the path
|
location.* **If anybody writes code that parses it back into a URL, the path
|
||||||
should stop looking like one.**
|
should stop looking like one.**
|
||||||
|
|
||||||
## 2026-09-07 — the lock, and what it holds `osprey`
|
|
||||||
|
|
||||||
**Decided:** *one record per adopted document in `.loom/externals/.locks`: the
|
|
||||||
**resolved** origin URL, and the `ETag` it came with.*
|
|
||||||
|
|
||||||
**Believed to advance:** *the specimen said there would be no lock file, on the
|
|
||||||
strength of the `ETag`-as-blob-hash claim.* **That claim failed twice**, so the
|
|
||||||
file exists and is named for what it is. *It was briefly called `.etags`, from
|
|
||||||
when we believed there would be one field.*
|
|
||||||
|
|
||||||
**Resolved, and not the short form.** *Measured: gitea `303`s
|
|
||||||
`/loom/externals/raw/externals.md` to `/raw/branch/main/…`* — **so a lock holding a
|
|
||||||
short URL is locked to whatever the default branch is at the time you ask**, and a
|
|
||||||
branch rename reports as a change in the document.
|
|
||||||
|
|
||||||
**Belief that could be shown wrong:** *that one file is cheap.* **Two fetches in
|
|
||||||
one round conflict inside it, and the conflict is in a file no human can resolve
|
|
||||||
by reading.** *If that bites, it becomes one record per document and the tree is
|
|
||||||
mirrored twice.*
|
|
||||||
|
|
||||||
## 2026-09-07 — unlocked is a state `osprey`
|
|
||||||
|
|
||||||
**Decided:** *a document with no lock is reported as unlocked.* **`check` never
|
|
||||||
adopts whatever the remote is currently serving as the lock.**
|
|
||||||
|
|
||||||
**Believed to advance:** *adopting it would assert the local copy is the one being
|
|
||||||
served, which is the thing you were about to check.* **It is the hash assumption
|
|
||||||
in a different coat, and it fails silently in the one case that matters — a copy
|
|
||||||
somebody edited.**
|
|
||||||
|
|
||||||
**Belief that could be shown wrong:** *that anybody will run `pull` again to fix
|
|
||||||
it.* **If unlocked documents simply accumulate, the report is noise and something
|
|
||||||
has to lock them.**
|
|
||||||
|
|
||||||
## 2026-09-07 — `404` is unresolved, and that is no longer provisional `osprey`
|
## 2026-09-07 — `404` is unresolved, and that is no longer provisional `osprey`
|
||||||
|
|
||||||
**Decided:** *`check` reports a `404` as unresolvable — the document was withdrawn
|
**Decided:** *`check` reports a `404` as unresolvable — the document was withdrawn
|
||||||
@@ -450,16 +401,6 @@ unknown.**
|
|||||||
next token*, **and because if a read scope is not enough, that is the only argument
|
next token*, **and because if a read scope is not enough, that is the only argument
|
||||||
for keeping ssh.**
|
for keeping ssh.**
|
||||||
|
|
||||||
## 2026-09-07 — `--help` is the documentation surface `marmalade`
|
|
||||||
|
|
||||||
**Decided:** *`--help` is what a person or an agent actually runs when handed an
|
|
||||||
unfamiliar CLI, so it is the surface that has to be good* — **say what a command
|
|
||||||
does and what it will not do.**
|
|
||||||
|
|
||||||
**A `.loom/published/` for `loomctl` is deferred, not declined.** *The distinction
|
|
||||||
matters because `init` was declined.* **It earns publication when somebody depends
|
|
||||||
on this tool's behaviour rather than reading its help.**
|
|
||||||
|
|
||||||
## 2026-09-07 — decided by fallback: where the credential lives `marmalade`
|
## 2026-09-07 — decided by fallback: where the credential lives `marmalade`
|
||||||
|
|
||||||
**Nobody chose this; the fallback became the decision and that is recorded so it
|
**Nobody chose this; the fallback became the decision and that is recorded so it
|
||||||
@@ -789,21 +730,6 @@ designed to be ephemeral is the first step in it not being ephemeral.**
|
|||||||
unit.* **If two presences ever work from different machines, the cart has nowhere
|
unit.* **If two presences ever work from different machines, the cart has nowhere
|
||||||
to live**, *and everything above stops being true at once.*
|
to live**, *and everything above stops being true at once.*
|
||||||
|
|
||||||
## 2026-09-07 — conversion now destroys, so the log is the only record `quince`
|
|
||||||
|
|
||||||
**Under `cart/v1` the cart is untracked, so converting a round deletes its dailies
|
|
||||||
outright.** *Every previous conversion left them in git.*
|
|
||||||
|
|
||||||
**So an entry that was not written before the `rm` is gone**, *and the write-ahead
|
|
||||||
log is the mechanism* — **stage as you go, because at conversion the cart is the
|
|
||||||
only copy and you are about to delete it.**
|
|
||||||
|
|
||||||
**And it sharpens a conflict recorded in `cart.usages.md`:** *the annotation
|
|
||||||
protocol here says commit before dissolving because git is the only archive.*
|
|
||||||
**With an ignored cart there is no archive, so dissolving a notes file destroys
|
|
||||||
the annotations outright.** *Both documents are loom's; this is where an adopter
|
|
||||||
can see the collision.*
|
|
||||||
|
|
||||||
## 2026-09-07 — declined for now: reference-only adoption `quince`
|
## 2026-09-07 — declined for now: reference-only adoption `quince`
|
||||||
|
|
||||||
**`externals` offers two ways out of the confidentiality rule.** *We implement
|
**`externals` offers two ways out of the confidentiality rule.** *We implement
|
||||||
@@ -1041,27 +967,6 @@ it wrong.*
|
|||||||
configured one.* **It only pays if it is the same everywhere**, *which is not ours
|
configured one.* **It only pays if it is the same everywhere**, *which is not ours
|
||||||
to decide and is with `bedrock`.*
|
to decide and is with `bedrock`.*
|
||||||
|
|
||||||
## 2026-09-08 — the lock records visibility, and the word it will not use `sorrel`
|
|
||||||
|
|
||||||
**Decided:** *the lock carries what the source could be read as when it was
|
|
||||||
fetched, and `check` audits it against this repository's visibility now.*
|
|
||||||
|
|
||||||
**Believed to advance:** *access is verified once, at fetch, and the copy is
|
|
||||||
durable.* **Whether an adoption is still legitimate rests on the relative
|
|
||||||
visibility of two repositories — a fact somebody can change with a checkbox a year
|
|
||||||
later, without ever seeing the adoption.** *Recording it turns a silent permanent
|
|
||||||
hazard into something that runs.*
|
|
||||||
|
|
||||||
**The value is `public` or `not-public`, and never `private`.** *An anonymous
|
|
||||||
request tells those two apart and nothing finer* — **so it cannot see two
|
|
||||||
repositories private to different people, which is the case where adopting between
|
|
||||||
private repositories genuinely widens access.** *The word `private` would claim
|
|
||||||
precision the signal does not have.*
|
|
||||||
|
|
||||||
**Belief that could be shown wrong:** *that the coarse signal is worth having.*
|
|
||||||
**If the cases that matter here are all private-to-private, this alarm will never
|
|
||||||
fire and the field is ceremony.**
|
|
||||||
|
|
||||||
## 2026-09-08 — a probe is not a fetch, and confusing them clears alarms `sorrel`
|
## 2026-09-08 — a probe is not a fetch, and confusing them clears alarms `sorrel`
|
||||||
|
|
||||||
**Recorded because the bug was one line and the trap is permanent.**
|
**Recorded because the bug was one line and the trap is permanent.**
|
||||||
@@ -1092,3 +997,147 @@ three times, and then declined.*
|
|||||||
|
|
||||||
*Recorded as a working note rather than a decision: **when a word could be read
|
*Recorded as a working note rather than a decision: **when a word could be read
|
||||||
narrowly or broadly, this repository has evidence that I pick narrow.***
|
narrowly or broadly, this repository has evidence that I pick narrow.***
|
||||||
|
|
||||||
|
## 2026-09-08 — published: what the tool guarantees `tansy`
|
||||||
|
|
||||||
|
**`.loom/published/guarantees.md`**, *and step 4 of `publication` was run: `200`
|
||||||
|
anonymously, off no credential of ours.*
|
||||||
|
|
||||||
|
**The earlier decision did not reverse; its condition fired.** *`.loom/published/`
|
||||||
|
was recorded as deferred rather than declined, on the condition that somebody
|
||||||
|
depends on the tool's behaviour rather than reading its help.* **A docs site whose
|
||||||
|
build calls `add`, `check` and `apply` is that consumer.**
|
||||||
|
|
||||||
|
*The delta is not the command list — that is a copy of what the code owns.*
|
||||||
|
**`--help` says what the tool does; a published page says what will keep being
|
||||||
|
true**, *and a reader cannot learn from a binary which of its behaviours survives
|
||||||
|
the next version.*
|
||||||
|
|
||||||
|
**The page includes what is not promised**, *which is the half a reimplementation
|
||||||
|
needs most:* **the command surface, the orientation file's format across
|
||||||
|
versions, the precision of the visibility signal, and that anything is checked
|
||||||
|
when nobody is looking.**
|
||||||
|
|
||||||
|
## 2026-09-08 — we do not promise the surface; we promise the change lands `tansy`
|
||||||
|
|
||||||
|
**A consumer's README tells a person to type `loomctl external add loom/<repo>
|
||||||
|
<doc>.md`.** *Nothing parses it — which is exactly why no check would catch a
|
||||||
|
rename.* **The thing that moved would not be a document anybody adopted.**
|
||||||
|
|
||||||
|
**Promising the surface would freeze the CLI. So the promise is narrower and
|
||||||
|
runs:**
|
||||||
|
|
||||||
|
> **We do not promise the surface holds. We promise a change to it lands on the
|
||||||
|
> page you already lock.**
|
||||||
|
|
||||||
|
*`guarantees.md` carries an append-only `Surface changes` section*, **so a rename
|
||||||
|
reports `200` to every consumer the day it happens.**
|
||||||
|
|
||||||
|
**Belief that could be shown wrong:** *that anybody remembers to write in it.*
|
||||||
|
**Nothing enforces the section** — *the same weakness as a facet nobody updates.*
|
||||||
|
|
||||||
|
## 2026-09-08 — two ETags can be compared and never ordered `tansy`
|
||||||
|
|
||||||
|
**Found by accident, and it is a consequence of a rule we published this
|
||||||
|
morning.**
|
||||||
|
|
||||||
|
*The docs site stamped a hand-written guide with the `ETag` it was read against,
|
||||||
|
and its banner said `written against an older guarantees`.* **It was backwards:
|
||||||
|
the guide was ahead of the site's copy, not behind.**
|
||||||
|
|
||||||
|
**And it cannot be fixed by trying harder.** *An `ETag` is opaque — that is the
|
||||||
|
point of it, and we guarantee we never interpret one.* **So a consumer can know
|
||||||
|
that two versions disagree and can never know which is behind.**
|
||||||
|
|
||||||
|
*The banner now claims no direction.* **Anybody building freshness on this
|
||||||
|
inherits the same limit**, *and it belongs in the log because it follows from the
|
||||||
|
guarantee rather than from anybody's code.*
|
||||||
|
|
||||||
|
*Consequence nobody predicted: reconciling cleared the banner with no
|
||||||
|
acknowledgement, which is correct — an acknowledgement is for a guide that is
|
||||||
|
behind, and this one was ahead.*
|
||||||
|
|
||||||
|
## 2026-09-08 — compacted, and it barely compressed `tansy`
|
||||||
|
|
||||||
|
**A compaction is itself a decision, so this is the entry `recording-decisions`
|
||||||
|
asks for.** *Six entries dropped, fifty kept. The uncompacted log is in git
|
||||||
|
history, which is where a reader who needs it goes.*
|
||||||
|
|
||||||
|
**Dropped, each because a competent reader can now recover it from the artifact,
|
||||||
|
and here is which artifact:**
|
||||||
|
|
||||||
|
- *`what this tool is`* — **`.loom/published/guarantees.md` and `README.md`**
|
||||||
|
- *`the lock, and what it holds`* — **`guarantees.md` documents the format**
|
||||||
|
- *`unlocked is a state`* — **`guarantees.md`, and `add` refuses in code**
|
||||||
|
- *`--help is the documentation surface`* — **`README.md` says so and points there**
|
||||||
|
- *`the lock records visibility, and the word it will not use`* — **`guarantees.md`
|
||||||
|
carries the field and the refusal of the word `private`**
|
||||||
|
- *`conversion now destroys, so the log is the only record`* — **`cart/v2`, adopted
|
||||||
|
here, and `cart.usages.md` names `wal.md` as the mechanism**
|
||||||
|
|
||||||
|
> **Every one of them became droppable by being published.** *Nothing was
|
||||||
|
> summarised away; the content moved into a document somebody else can lock, which
|
||||||
|
> is a stronger place for it than a log only we read.*
|
||||||
|
|
||||||
|
## What did not compress, and why that is the finding
|
||||||
|
|
||||||
|
**Fifty entries survived, and the reason is the rule rather than sentiment.**
|
||||||
|
*Almost all of them are one of the four kinds that may never be dropped:*
|
||||||
|
|
||||||
|
**Declines** — *`init`, `published check`, a separate `adopt` verb, a plugin
|
||||||
|
boundary, an audience declaration, reference-only adoption, resolving `404` over
|
||||||
|
ssh, a second orientation file, worktrees, a spec, fixing `annotating`.* **Not one
|
||||||
|
is recoverable from the code, because the code is what they are absent from.**
|
||||||
|
|
||||||
|
**Measurements** — *the `ETag` is a blob hash on gitea and not on GitHub; three
|
||||||
|
hosts and one partial clone; only gitea resolves its own short raw URL; a refused
|
||||||
|
write names the token's scopes; a private repository over HTTPS with a read
|
||||||
|
token.* **Facts about other people's systems, which no artifact here holds.**
|
||||||
|
|
||||||
|
**Supersessions** — *publication is not publicness; a cart is not committed; `add`
|
||||||
|
does not replace; `git` is not needed for `list` only; the private path is
|
||||||
|
exercised.* **Each is a change of mind, which is most of what a reader wants.**
|
||||||
|
|
||||||
|
**Beliefs shown wrong** — *the specimen's hash-as-lock; `others` read as
|
||||||
|
`everyone`; a probe treated as a fetch; a banner that claimed a direction two
|
||||||
|
opaque strings cannot support.*
|
||||||
|
|
||||||
|
> **The log is long because the work was exploratory, not because it is padded.**
|
||||||
|
> *A project that mostly built things would compact to a page. This one mostly
|
||||||
|
> found out it was wrong about things, and that is the part the code cannot
|
||||||
|
> hold.*
|
||||||
|
|
||||||
|
**Belief that could be shown wrong:** *that fifty is readable.* **It is today.**
|
||||||
|
*The next remedy is not another compaction — it is the guide `bedrock` needed,
|
||||||
|
and it is not needed yet.*
|
||||||
|
|
||||||
|
## 2026-09-08 — a `404` at adoption has a third reading, and it is resolvable
|
||||||
|
|
||||||
|
**`externals` names two readings of a `404` — withdrawn, or access lost — and
|
||||||
|
they are the two a **locked** document can have.** *Adoption by name has a third:
|
||||||
|
**a document that was never there under that name**.*
|
||||||
|
|
||||||
|
*Found in use: `loomctl external add jeffry/homelab-cluster database` reported the
|
||||||
|
ambiguity for what was a missing `s`.*
|
||||||
|
|
||||||
|
**The tool was reporting an ambiguity it had the means to resolve.** *For the
|
||||||
|
by-name form it knows the repository, so on a `404` it now lists the published
|
||||||
|
surface:*
|
||||||
|
|
||||||
|
```
|
||||||
|
loomctl: jeffry/homelab-cluster publishes no "database.md". It publishes:
|
||||||
|
databases.md gitea.md private-access.md ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**And it only claims that when the listing succeeds.** *If listing fails too, the
|
||||||
|
repository itself is unreachable and the original ambiguity is the honest
|
||||||
|
answer* — **the same discipline as reporting `public` and `not-public` rather than
|
||||||
|
`private`: say the thing you verified.**
|
||||||
|
|
||||||
|
**Not a gap against `externals`.** *The third reading cannot occur where that
|
||||||
|
document is speaking, which is `check` against a lock.* **It appears only at
|
||||||
|
adoption, which is ours.**
|
||||||
|
|
||||||
|
**Belief that could be shown wrong:** *that an extra round trip on a failure is
|
||||||
|
free.* **It is one partial clone on a path nobody takes twice**, *and if adoption
|
||||||
|
against large repositories becomes common the listing should be bounded.*
|
||||||
|
|||||||
Vendored
+1
-1
@@ -11,4 +11,4 @@ git.hypertheory-labs.dev/loom/bedrock/recording-decisions.md https://git.hyperth
|
|||||||
git.hypertheory-labs.dev/loom/bedrock/sibling-facets.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/sibling-facets.md "a46446a34ccb8bfc533d3cce19f4c88548c4fa04" public
|
git.hypertheory-labs.dev/loom/bedrock/sibling-facets.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/sibling-facets.md "a46446a34ccb8bfc533d3cce19f4c88548c4fa04" public
|
||||||
git.hypertheory-labs.dev/loom/bedrock/starting.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/starting.md "b9eefba0f4668a496ccfc6a1377277f0721456d2" public
|
git.hypertheory-labs.dev/loom/bedrock/starting.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/starting.md "b9eefba0f4668a496ccfc6a1377277f0721456d2" public
|
||||||
git.hypertheory-labs.dev/loom/cart/cart.md https://git.hypertheory-labs.dev/loom/cart/raw/branch/main/.loom/published/cart.md "15331f1a9cc81bf61a44830cfbb7c274f4c2b119" public
|
git.hypertheory-labs.dev/loom/cart/cart.md https://git.hypertheory-labs.dev/loom/cart/raw/branch/main/.loom/published/cart.md "15331f1a9cc81bf61a44830cfbb7c274f4c2b119" public
|
||||||
git.hypertheory-labs.dev/loom/externals/externals.md https://git.hypertheory-labs.dev/loom/externals/raw/branch/main/.loom/published/externals.md "a7586eb52caf275d9bcedbbd8042c43e5aaad0b9" public
|
git.hypertheory-labs.dev/loom/externals/externals.md https://git.hypertheory-labs.dev/loom/externals/raw/branch/main/.loom/published/externals.md "50673ccffc14d57150ac0a9027b0712d9dcf940d"
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ what to decide are not.**
|
|||||||
|
|
||||||
- **where it was fetched from** — *resolved, as above*
|
- **where it was fetched from** — *resolved, as above*
|
||||||
- **the publisher's `ETag`** — *verbatim*
|
- **the publisher's `ETag`** — *verbatim*
|
||||||
|
- **the visibility the source could be read at, when it was fetched**
|
||||||
|
|
||||||
**It is committed**, because the thing it locks is committed, and *a lock that
|
**It is committed**, because the thing it locks is committed, and *a lock that
|
||||||
travels separately from what it locks is the drift this is meant to prevent.*
|
travels separately from what it locks is the drift this is meant to prevent.*
|
||||||
@@ -71,6 +72,26 @@ travels separately from what it locks is the drift this is meant to prevent.*
|
|||||||
> asserts your copy is the one being served, which is the thing you were going to
|
> asserts your copy is the one being served, which is the thing you were going to
|
||||||
> check.
|
> check.
|
||||||
|
|
||||||
|
### Why visibility is in the lock and not left to the moment
|
||||||
|
|
||||||
|
**Access is checked once and the copy is durable.** *A token gets you the read;
|
||||||
|
nothing revisits it afterwards.* **So the adoption's legitimacy rests on the
|
||||||
|
relative visibility of two repositories — and that is changeable by a checkbox, a
|
||||||
|
year later, by somebody who never saw the adoption.**
|
||||||
|
|
||||||
|
> **Record `public` or `not-public`. Never `private`.** *An anonymous request can
|
||||||
|
> tell you a repository is not public. It cannot tell two repositories private to
|
||||||
|
> **different people** apart* — **which is exactly the case where private into
|
||||||
|
> private genuinely widens access.** *Record the word you can verify.*
|
||||||
|
|
||||||
|
**Checking it costs one request per run, not one per document**, *because the only
|
||||||
|
thing that must be current is **your own** visibility.* **Re-check a source only
|
||||||
|
when the alarm would fire** — *you are public, it was recorded not-public* — *and
|
||||||
|
if it has since gone public, update the lock and say nothing.*
|
||||||
|
|
||||||
|
*A stored visibility decays in both directions, which is why the alarm re-checks
|
||||||
|
rather than trusting the record.*
|
||||||
|
|
||||||
## Freshness is a conditional request
|
## Freshness is a conditional request
|
||||||
|
|
||||||
**Locked on the publisher's `ETag`, verbatim — never a hash you compute.** *A
|
**Locked on the publisher's `ETag`, verbatim — never a hash you compute.** *A
|
||||||
|
|||||||
Vendored
+25
-1
@@ -2,6 +2,7 @@ package external
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -50,7 +51,30 @@ func AddByName(root, ownerRepo, name string, out io.Writer) error {
|
|||||||
}
|
}
|
||||||
raw = fmt.Sprintf(raw, branch)
|
raw = fmt.Sprintf(raw, branch)
|
||||||
}
|
}
|
||||||
return Add(root, raw, "", out)
|
err = Add(root, raw, "", out)
|
||||||
|
|
||||||
|
// A 404 here has a reading the convention does not list, because it can only
|
||||||
|
// happen at adoption: the name is wrong. We know the repository, so rather
|
||||||
|
// than reporting an ambiguity we can resolve, look.
|
||||||
|
var nf *NotFoundError
|
||||||
|
if errors.As(err, &nf) {
|
||||||
|
var names strings.Builder
|
||||||
|
if lerr := List(ctx.CloneURL(ownerRepo), &names); lerr == nil {
|
||||||
|
return fmt.Errorf("%s publishes no %q. It publishes:\n%s",
|
||||||
|
ownerRepo, name, indent(names.String()))
|
||||||
|
}
|
||||||
|
// Listing failed too, so the repository itself is unreachable and the
|
||||||
|
// original ambiguity stands.
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func indent(s string) string {
|
||||||
|
var b strings.Builder
|
||||||
|
for _, line := range strings.Split(strings.TrimRight(s, "\n"), "\n") {
|
||||||
|
fmt.Fprintf(&b, " %s\n", line)
|
||||||
|
}
|
||||||
|
return strings.TrimRight(b.String(), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListByName enumerates a repository named against the current context.
|
// ListByName enumerates a repository named against the current context.
|
||||||
|
|||||||
Vendored
+14
-2
@@ -253,6 +253,19 @@ func warnIfNotPublic(root, raw, vis string, out io.Writer) {
|
|||||||
fmt.Fprintf(out, " record only the dependency, which loomctl cannot do yet.\n")
|
fmt.Fprintf(out, " record only the dependency, which loomctl cannot do yet.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotFoundError is a 404, which over HTTP carries more than one reading.
|
||||||
|
//
|
||||||
|
// The convention names two — withdrawn, or access lost — because those are the
|
||||||
|
// two a locked document can have. Adoption by name has a third: a document that
|
||||||
|
// was never there under that name. Callers that know the repository can tell
|
||||||
|
// them apart; this type is how they get the chance.
|
||||||
|
type NotFoundError struct{ URL string }
|
||||||
|
|
||||||
|
func (e *NotFoundError) Error() string {
|
||||||
|
return fmt.Sprintf("404 unresolved: %s was withdrawn, or this credential cannot see it — "+
|
||||||
|
"over HTTP these are the same response", e.URL)
|
||||||
|
}
|
||||||
|
|
||||||
type fetched struct {
|
type fetched struct {
|
||||||
data []byte
|
data []byte
|
||||||
url string
|
url string
|
||||||
@@ -281,8 +294,7 @@ func fetch(cfg *config.Config, raw, ifNoneMatch string) (*fetched, string, error
|
|||||||
}
|
}
|
||||||
return &fetched{data: b, url: resp.Request.URL.String()}, resp.Header.Get("ETag"), nil
|
return &fetched{data: b, url: resp.Request.URL.String()}, resp.Header.Get("ETag"), nil
|
||||||
case http.StatusNotFound:
|
case http.StatusNotFound:
|
||||||
return nil, "", fmt.Errorf("404 unresolved: %s was withdrawn, or this credential cannot see it — "+
|
return nil, "", &NotFoundError{URL: raw}
|
||||||
"over HTTP these are the same response", raw)
|
|
||||||
default:
|
default:
|
||||||
return nil, "", fmt.Errorf("%s: %s", resp.Status, raw)
|
return nil, "", fmt.Errorf("%s: %s", resp.Status, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user