- манифест читается так, как записан: решётка внутри строки не открывает комментарий, скобка внутри комментария не закрывает массив, имя внутри комментария не становится подпиской; новый ключ встаёт после массива, а не внутрь него - всё записываемое проходит через manifest.Quote — обратный слэш в пути делал файл, который инструмент сам не читает - маркер локальной части переехал в doc и пропускает огороженные блоки: процитированный в примере маркер больше не считается границей, а копия без маркера не перезаписывается молча - лишний позиционный аргумент отсекается: flag прекращал разбор и прятал флаги после себя, из-за чего pull, list и check игнорировали --for - заведены тесты проверок копий, включая молчание на исправной копии
108 lines
2.9 KiB
Go
108 lines
2.9 KiB
Go
package cli
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
|
|
"git.vakhrushev.me/av/convy/internal/project"
|
|
)
|
|
|
|
// convy pull reassembles what the manifest lists. It never reports what
|
|
// changed: after a pull that is shown by git diff, and the decision to accept,
|
|
// to fix or to roll back is taken by a person before the commit. A second
|
|
// mechanism for comparing files, standing next to git, would answer the same
|
|
// question worse.
|
|
|
|
func runPull(env Env, args []string) ExitCode {
|
|
fs := flag.NewFlagSet("convy pull", flag.ContinueOnError)
|
|
fs.SetOutput(env.Err)
|
|
root := fs.String("root", "", "root of the project; it is looked up upwards by default")
|
|
forComponent := fs.String("for", "", "component to reassemble; every one of them by default")
|
|
if err := fs.Parse(args); err != nil {
|
|
return Usage
|
|
}
|
|
if code := noStrayArgs(env, "convy pull", fs.Args()); code != OK {
|
|
return code
|
|
}
|
|
|
|
o, code := openProject(env, *root)
|
|
if code != OK {
|
|
return code
|
|
}
|
|
defer o.Close()
|
|
|
|
if err := distinctDirs(o.Manifest); err != nil {
|
|
fmt.Fprintln(env.Err, err)
|
|
return Usage
|
|
}
|
|
names, code := components(env, o.Manifest, *forComponent)
|
|
if code != OK {
|
|
return code
|
|
}
|
|
|
|
failed := 0
|
|
written := 0
|
|
for i, name := range names {
|
|
c := o.Manifest.Components[name]
|
|
if i > 0 {
|
|
fmt.Fprintln(env.Out)
|
|
}
|
|
fmt.Fprintf(env.Out, "%s → %s\n", name, c.Dir)
|
|
if c.Dir == "" {
|
|
fmt.Fprintln(env.Err, " the component names no dir, and a copy has to be written somewhere")
|
|
failed++
|
|
continue
|
|
}
|
|
if len(c.Topics) == 0 {
|
|
fmt.Fprintln(env.Out, " subscribed to nothing yet")
|
|
}
|
|
|
|
// The path column is sized to the component rather than guessed: a
|
|
// name that overruns a fixed width breaks every row below it.
|
|
width := len(c.Dir) + 1 + len(project.ReadingName)
|
|
for _, topic := range c.Topics {
|
|
width = max(width, len(c.Dir)+len(topic)+4)
|
|
}
|
|
|
|
for _, topic := range c.Topics {
|
|
made, err := project.Assemble(o.Suite, o.Root, c, topic)
|
|
if err != nil {
|
|
fmt.Fprintf(env.Err, " %s: %s\n", topic, err)
|
|
failed++
|
|
continue
|
|
}
|
|
written++
|
|
fmt.Fprintf(env.Out, " %-*s %s%s\n", width, made.Path, plural(len(made.Layers), "layer"), kept(made))
|
|
}
|
|
|
|
guide, err := project.Reading(o.LangRoot, o.Suite.Manifest.Language.Reading, o.Root, c.Dir)
|
|
if err != nil {
|
|
fmt.Fprintf(env.Err, " %s\n", err)
|
|
failed++
|
|
continue
|
|
}
|
|
fmt.Fprintf(env.Out, " %-*s the guide to reading a rule\n", width, guide)
|
|
}
|
|
|
|
fmt.Fprintf(env.Out, "\n%s assembled", plural(written, "file"))
|
|
if failed > 0 {
|
|
fmt.Fprintf(env.Out, ", %s\n", plural(failed, "failure"))
|
|
return Failed
|
|
}
|
|
fmt.Fprintln(env.Out)
|
|
fmt.Fprintln(env.Out, "git diff says what changed")
|
|
return OK
|
|
}
|
|
|
|
// kept notes that a local part was carried over, because that is the one thing
|
|
// a reassembly could have destroyed and did not.
|
|
func kept(c project.Copy) string {
|
|
switch {
|
|
case c.Created:
|
|
return ", new"
|
|
case c.Kept:
|
|
return ", local part kept"
|
|
}
|
|
return ""
|
|
}
|