Compare commits
1
Commits
a5093c1efc
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7b169b87e |
@@ -1110,3 +1110,34 @@ opaque strings cannot support.*
|
|||||||
**Belief that could be shown wrong:** *that fifty is readable.* **It is today.**
|
**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,
|
*The next remedy is not another compaction — it is the guide `bedrock` needed,
|
||||||
and it is not needed yet.*
|
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
+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