манифесты стали данными, заведён convy sync
- убраны комментарии из suite.toml и .conventions.toml: файл, который машина переписывает, комментарий через круг не проносит; объяснения ушли в README рядом, который suite init теперь заводит - удалена текстовая правка манифеста целиком — 520 строк ручного лексера TOML вместе со всем классом ошибок порчи данных - запись идёт из структур энкодером; ключ, которого инструмент не знает, запись останавливает, а не теряется молча - convy sync сверяет манифест и подводит под него раскладку файлов: чего не хватает — собирает, что осиротело — удаляет, копию с локальной частью не трогает никогда
This commit is contained in:
+18
-55
@@ -5,42 +5,16 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"git.vakhrushev.me/av/convy/internal/manifest"
|
||||
"git.vakhrushev.me/av/convy/internal/source"
|
||||
"git.vakhrushev.me/av/convy/internal/suite"
|
||||
)
|
||||
|
||||
// projectSkeleton is what a project manifest starts as. It is written as text
|
||||
// with its comments in place for the same reason the suite manifest is: the
|
||||
// file is read far more often than a tool touches it, and what a component is
|
||||
// for is not deducible from three keys.
|
||||
const projectSkeleton = `# What this repository takes from a conventions suite.
|
||||
#
|
||||
# Two manifests exist in the model, each named after what it describes:
|
||||
# suite.toml in a suite describes the suite itself; .conventions.toml here
|
||||
# describes the subscription — where the copies come from and who takes what.
|
||||
#
|
||||
# Copies are committed. Nothing is fetched on the fly, and the answer to "what
|
||||
# did it look like last time" is given by git rather than by a lock file.
|
||||
|
||||
# Where the copies come from: a path on disk, relative to this file or absolute,
|
||||
# or a git repository over http or https. A trailing #branch, #tag or #commit
|
||||
# pins a revision.
|
||||
source = %s
|
||||
|
||||
# ─── Components ─────────────────────────────────────────────────────────────
|
||||
#
|
||||
# A component is a region of the repository where every selected layer holds at
|
||||
# once: one language, one set of tools, one kind of application. Each one has
|
||||
# its own directory, and the directories differ — that is the only thing that
|
||||
# tells two copies of one topic apart.
|
||||
#
|
||||
# lang and stack choose the layers: a layer travels when the axis it declares is
|
||||
# among them, and a layer declaring no axis travels always. topics is the
|
||||
# subscription itself, by the names the suite gives its topics.
|
||||
`
|
||||
// A project manifest is data, and the tool rewrites it whole on every
|
||||
// subscription. So it carries no comment: what a component is for is said in
|
||||
// the documentation, which stays put, rather than in a file that a machine
|
||||
// re-encodes behind the author's back.
|
||||
|
||||
func runInit(env Env, args []string) ExitCode {
|
||||
fs := flag.NewFlagSet("convy init", flag.ContinueOnError)
|
||||
@@ -105,27 +79,25 @@ func runInit(env Env, args []string) ExitCode {
|
||||
return Failed
|
||||
}
|
||||
|
||||
entries := [][2]string{{"dir", manifest.Quote(given["dir"])}}
|
||||
if list := split(given["lang"]); len(list) > 0 {
|
||||
entries = append(entries, [2]string{"lang", array(list)})
|
||||
}
|
||||
if list := split(given["stack"]); len(list) > 0 {
|
||||
entries = append(entries, [2]string{"stack", array(list)})
|
||||
}
|
||||
entries = append(entries, [2]string{"topics", "[]"})
|
||||
|
||||
body, err := manifest.AddTable(fmt.Appendf(nil, projectSkeleton, manifest.Quote(given["source"])),
|
||||
"components."+given["component"], entries)
|
||||
if err != nil {
|
||||
fmt.Fprintln(env.Err, err)
|
||||
return Failed
|
||||
}
|
||||
if err := os.MkdirAll(where, 0o755); err != nil {
|
||||
fmt.Fprintln(env.Err, err)
|
||||
return Failed
|
||||
}
|
||||
name := filepath.Join(where, manifest.ProjectName)
|
||||
if err := os.WriteFile(name, body, 0o644); err != nil {
|
||||
m := &manifest.Project{
|
||||
Source: given["source"],
|
||||
Components: map[string]manifest.Component{
|
||||
given["component"]: {
|
||||
Dir: given["dir"],
|
||||
Lang: split(given["lang"]),
|
||||
Stack: split(given["stack"]),
|
||||
Topics: []string{},
|
||||
},
|
||||
},
|
||||
Path: name,
|
||||
Root: where,
|
||||
}
|
||||
if err := m.Save(); err != nil {
|
||||
fmt.Fprintln(env.Err, err)
|
||||
return Failed
|
||||
}
|
||||
@@ -181,12 +153,3 @@ func initFields() []Field {
|
||||
Optional: true,
|
||||
}}
|
||||
}
|
||||
|
||||
// array writes a TOML array of strings.
|
||||
func array(values []string) string {
|
||||
parts := make([]string, len(values))
|
||||
for i, v := range values {
|
||||
parts[i] = manifest.Quote(v)
|
||||
}
|
||||
return "[" + strings.Join(parts, ", ") + "]"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user