исправлены находки ревью проектной стороны
- манифест читается так, как записан: решётка внутри строки не открывает комментарий, скобка внутри комментария не закрывает массив, имя внутри комментария не становится подпиской; новый ключ встаёт после массива, а не внутрь него - всё записываемое проходит через manifest.Quote — обратный слэш в пути делал файл, который инструмент сам не читает - маркер локальной части переехал в doc и пропускает огороженные блоки: процитированный в примере маркер больше не считается границей, а копия без маркера не перезаписывается молча - лишний позиционный аргумент отсекается: flag прекращал разбор и прятал флаги после себя, из-за чего pull, list и check игнорировали --for - заведены тесты проверок копий, включая молчание на исправной копии
This commit is contained in:
+26
-28
@@ -24,10 +24,10 @@ import (
|
||||
"git.vakhrushev.me/av/convy/internal/suite"
|
||||
)
|
||||
|
||||
// LocalMarker is the one piece of markup inside a copy that means something to
|
||||
// the tool. It is single and nameless, so there is no name to be orphaned by a
|
||||
// rename.
|
||||
const LocalMarker = "<!-- conv:local -->"
|
||||
// LocalMarker is the boundary between what the suite wrote and what the
|
||||
// repository wrote. It is defined once, next to the parsing that has to respect
|
||||
// it, and named again here because assembly is where it is placed.
|
||||
const LocalMarker = doc.LocalMarker
|
||||
|
||||
// Copy is the outcome of assembling one topic for one component.
|
||||
type Copy struct {
|
||||
@@ -68,6 +68,7 @@ func Assemble(s *suite.Suite, root string, c manifest.Component, topic string) (
|
||||
made.Layers = append(made.Layers, d.Path)
|
||||
}
|
||||
|
||||
local := LocalMarker + "\n"
|
||||
existing, err := os.ReadFile(name)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
@@ -75,12 +76,12 @@ func Assemble(s *suite.Suite, root string, c manifest.Component, topic string) (
|
||||
case err != nil:
|
||||
return Copy{}, err
|
||||
default:
|
||||
if err := ours(rel, string(existing), topic); err != nil {
|
||||
kept, err := ours(rel, string(existing), topic)
|
||||
if err != nil {
|
||||
return Copy{}, err
|
||||
}
|
||||
local = kept
|
||||
}
|
||||
|
||||
local := localPart(string(existing))
|
||||
made.Kept = strings.TrimSpace(strings.TrimPrefix(local, LocalMarker)) != ""
|
||||
|
||||
body := Render(topic, layers, s.Vocab) + "\n\n" + local
|
||||
@@ -123,37 +124,34 @@ func Reading(langRoot, path, root, dir string) (string, error) {
|
||||
return rel, nil
|
||||
}
|
||||
|
||||
// ours refuses to overwrite a file that is not a copy of this topic. A file
|
||||
// whose origin key was taken away has stopped being a copy and become a
|
||||
// document of the repository, and the tool has no business rewriting it.
|
||||
func ours(rel, existing, topic string) error {
|
||||
// ours decides whether a file standing in the way may be rewritten, and returns
|
||||
// the part of it that survives: everything from the marker down.
|
||||
//
|
||||
// Three ways it may not. A file whose origin key was taken away has stopped
|
||||
// being a copy and become a document of the repository. A file carrying the
|
||||
// origin of another topic is another copy that would be buried by this one. And
|
||||
// a file with no marker cannot be rewritten either — the marker is always
|
||||
// placed by the assembler, so a copy without one was edited by hand, and
|
||||
// everything in it counts as suite text that assembly would silently replace.
|
||||
func ours(rel, existing, topic string) (string, error) {
|
||||
d, err := doc.Parse(rel, existing)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s is in the way and cannot be read: %w", rel, err)
|
||||
return "", fmt.Errorf("%s is in the way and cannot be read: %w", rel, err)
|
||||
}
|
||||
switch {
|
||||
case d.Front.Origin == "" && d.Front.Topic == "" && d.Front.Prefix == "":
|
||||
return fmt.Errorf("%s carries no origin key: it is a document of the repository rather than a copy, and assembly would overwrite it", rel)
|
||||
return "", fmt.Errorf("%s carries no origin key: it is a document of the repository rather than a copy, and assembly would overwrite it", rel)
|
||||
case d.Front.Origin == "":
|
||||
return fmt.Errorf("%s carries no origin key, while it does carry the front matter of a suite file: it looks like a layer put here by hand", rel)
|
||||
return "", fmt.Errorf("%s carries no origin key, while it does carry the front matter of a suite file: it looks like a layer put here by hand", rel)
|
||||
case d.Front.Origin != topic:
|
||||
return fmt.Errorf("%s is a copy of the topic %q, and the topic %q would be assembled into the same file", rel, d.Front.Origin, topic)
|
||||
return "", fmt.Errorf("%s is a copy of the topic %q, and the topic %q would be assembled into the same file", rel, d.Front.Origin, topic)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// localPart returns everything from the marker down, together with the marker.
|
||||
// A file that has none gets one: the marker is placed by the assembler, and a
|
||||
// copy without it has nowhere to put a derogation.
|
||||
func localPart(existing string) string {
|
||||
lines := strings.Split(existing, "\n")
|
||||
for i, line := range lines {
|
||||
if strings.TrimSpace(line) != LocalMarker {
|
||||
continue
|
||||
}
|
||||
return strings.TrimRight(strings.Join(lines[i:], "\n"), "\n") + "\n"
|
||||
marker := d.Marker()
|
||||
if marker == 0 {
|
||||
return "", fmt.Errorf("%s carries no %s marker, and the assembler always leaves one: whatever is in the file was written above the boundary and would be replaced without trace", rel, LocalMarker)
|
||||
}
|
||||
return LocalMarker + "\n"
|
||||
return strings.TrimRight(d.Below(marker), "\n") + "\n", nil
|
||||
}
|
||||
|
||||
// Render lays out the part of a copy that comes from the suite: the front
|
||||
|
||||
Reference in New Issue
Block a user