chore: clean up — remove core.go re-export, pkg/mnt, go-io/go-log deps
Removed: - core.go (top-level re-export layer, no longer needed) - pkg/mnt/ (absorbed into pkg/core/mnt.go) - pkg/log/ (absorbed into pkg/core/log.go) - go-io dependency (absorbed into pkg/core/io.go) - go-log dependency (absorbed into pkg/core/error.go + log.go) Remaining: single package pkg/core/ with 14 source files. Only dependency: testify (test-only). Production code: zero external dependencies. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
16a985ad5c
commit
8f2e3d9457
11 changed files with 10 additions and 508 deletions
108
core.go
108
core.go
|
|
@ -1,108 +0,0 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package core is the Core framework for Go.
|
||||
//
|
||||
// Single import, single struct, everything accessible:
|
||||
//
|
||||
// import core "forge.lthn.ai/core/go"
|
||||
//
|
||||
// c, _ := core.New(
|
||||
// core.WithAssets(myEmbed),
|
||||
// core.WithService(myFactory),
|
||||
// )
|
||||
//
|
||||
// // DI
|
||||
// svc, _ := core.ServiceFor[*MyService](c, "name")
|
||||
//
|
||||
// // Mount
|
||||
// content, _ := c.Mnt().ReadString("persona/secops/developer.md")
|
||||
// c.Mnt().Extract(targetDir, data)
|
||||
//
|
||||
// // IPC
|
||||
// c.ACTION(msg)
|
||||
package core
|
||||
|
||||
import (
|
||||
di "forge.lthn.ai/core/go/pkg/core"
|
||||
)
|
||||
|
||||
// --- Types ---
|
||||
|
||||
// Core is the central application container.
|
||||
type Core = di.Core
|
||||
|
||||
// Option configures a Core instance.
|
||||
type Option = di.Option
|
||||
|
||||
// Message is the IPC message type.
|
||||
type Message = di.Message
|
||||
|
||||
// Sub is a scoped view of an embedded filesystem.
|
||||
type Sub = di.Sub
|
||||
|
||||
// ExtractOptions configures template extraction.
|
||||
type ExtractOptions = di.ExtractOptions
|
||||
|
||||
// Startable is implemented by services with startup logic.
|
||||
type Startable = di.Startable
|
||||
|
||||
// Stoppable is implemented by services with shutdown logic.
|
||||
type Stoppable = di.Stoppable
|
||||
|
||||
// LocaleProvider provides locale filesystems for i18n.
|
||||
type LocaleProvider = di.LocaleProvider
|
||||
|
||||
// ServiceRuntime is the base for services with typed options.
|
||||
type ServiceRuntime[T any] = di.ServiceRuntime[T]
|
||||
|
||||
// --- Constructor + Options ---
|
||||
|
||||
// New creates a new Core instance.
|
||||
var New = di.New
|
||||
|
||||
// WithService registers a service factory.
|
||||
var WithService = di.WithService
|
||||
|
||||
// WithName registers a named service factory.
|
||||
var WithName = di.WithName
|
||||
|
||||
// WithAssets mounts an embedded filesystem.
|
||||
var WithAssets = di.WithAssets
|
||||
|
||||
// WithMount mounts an embedded filesystem at a subdirectory.
|
||||
var WithMount = di.WithMount
|
||||
|
||||
// WithServiceLock prevents late service registration.
|
||||
var WithServiceLock = di.WithServiceLock
|
||||
|
||||
// WithApp sets the GUI runtime.
|
||||
var WithApp = di.WithApp
|
||||
|
||||
// Mount creates a scoped view of an embed.FS at basedir.
|
||||
var Mount = di.Mount
|
||||
|
||||
// --- Generic Functions ---
|
||||
|
||||
// ServiceFor retrieves a typed service by name.
|
||||
func ServiceFor[T any](c *Core, name string) (T, error) {
|
||||
return di.ServiceFor[T](c, name)
|
||||
}
|
||||
|
||||
// E creates a structured error.
|
||||
var E = di.E
|
||||
|
||||
// --- Configuration (core.Etc) ---
|
||||
|
||||
// Etc is the configuration and feature flags store.
|
||||
type Etc = di.Etc
|
||||
|
||||
// NewEtc creates a standalone configuration store.
|
||||
var NewEtc = di.NewEtc
|
||||
|
||||
// Var is a typed optional variable (set/unset/get).
|
||||
type Var[T any] = di.Var[T]
|
||||
|
||||
// NewVar creates a Var with the given value.
|
||||
func NewVar[T any](val T) Var[T] {
|
||||
return di.NewVar(val)
|
||||
}
|
||||
9
go.mod
9
go.mod
|
|
@ -2,14 +2,13 @@ module forge.lthn.ai/core/go
|
|||
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
forge.lthn.ai/core/go-io v0.1.6
|
||||
forge.lthn.ai/core/go-log v0.0.4
|
||||
github.com/stretchr/testify v1.11.1
|
||||
)
|
||||
require github.com/stretchr/testify v1.11.1
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
10
go.sum
10
go.sum
|
|
@ -1,15 +1,17 @@
|
|||
forge.lthn.ai/core/go-io v0.1.6 h1:RByYeP829HFqR2yLg5iBM5dGHKzPFYc+udl/Y1DZIRs=
|
||||
forge.lthn.ai/core/go-io v0.1.6/go.mod h1:3MSuQZuzhCi6aefECQ/LxhM8ooVLam1KgEvgeEjYZVc=
|
||||
forge.lthn.ai/core/go-log v0.0.4 h1:KTuCEPgFmuM8KJfnyQ8vPOU1Jg654W74h8IJvfQMfv0=
|
||||
forge.lthn.ai/core/go-log v0.0.4/go.mod h1:r14MXKOD3LF/sI8XUJQhRk/SZHBE7jAFVuCfgkXoZPw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
|
|
|
|||
|
|
@ -1,194 +0,0 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package mnt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// ExtractOptions configures template extraction.
|
||||
type ExtractOptions struct {
|
||||
// TemplateFilters identifies template files by substring match.
|
||||
// Default: [".tmpl"]
|
||||
TemplateFilters []string
|
||||
|
||||
// IgnoreFiles is a set of filenames to skip during extraction.
|
||||
IgnoreFiles map[string]struct{}
|
||||
|
||||
// RenameFiles maps original filenames to new names.
|
||||
RenameFiles map[string]string
|
||||
}
|
||||
|
||||
// Extract copies a template directory from an fs.FS to targetDir,
|
||||
// processing Go text/template in filenames and file contents.
|
||||
//
|
||||
// Files containing a template filter substring (default: ".tmpl") have
|
||||
// their contents processed through text/template with the given data.
|
||||
// The filter is stripped from the output filename.
|
||||
//
|
||||
// Directory and file names can contain Go template expressions:
|
||||
// {{.Name}}/main.go → myproject/main.go
|
||||
//
|
||||
// Data can be any struct or map[string]string for template substitution.
|
||||
func Extract(fsys fs.FS, targetDir string, data any, opts ...ExtractOptions) error {
|
||||
opt := ExtractOptions{
|
||||
TemplateFilters: []string{".tmpl"},
|
||||
IgnoreFiles: make(map[string]struct{}),
|
||||
RenameFiles: make(map[string]string),
|
||||
}
|
||||
if len(opts) > 0 {
|
||||
if len(opts[0].TemplateFilters) > 0 {
|
||||
opt.TemplateFilters = opts[0].TemplateFilters
|
||||
}
|
||||
if opts[0].IgnoreFiles != nil {
|
||||
opt.IgnoreFiles = opts[0].IgnoreFiles
|
||||
}
|
||||
if opts[0].RenameFiles != nil {
|
||||
opt.RenameFiles = opts[0].RenameFiles
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure target directory exists
|
||||
targetDir, err := filepath.Abs(targetDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(targetDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Categorise files
|
||||
var dirs []string
|
||||
var templateFiles []string
|
||||
var standardFiles []string
|
||||
|
||||
err = fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == "." {
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() {
|
||||
dirs = append(dirs, path)
|
||||
return nil
|
||||
}
|
||||
filename := filepath.Base(path)
|
||||
if _, ignored := opt.IgnoreFiles[filename]; ignored {
|
||||
return nil
|
||||
}
|
||||
if isTemplate(filename, opt.TemplateFilters) {
|
||||
templateFiles = append(templateFiles, path)
|
||||
} else {
|
||||
standardFiles = append(standardFiles, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create directories (names may contain templates)
|
||||
for _, dir := range dirs {
|
||||
target := renderPath(filepath.Join(targetDir, dir), data)
|
||||
if err := os.MkdirAll(target, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Process template files
|
||||
for _, path := range templateFiles {
|
||||
tmpl, err := template.ParseFS(fsys, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetFile := renderPath(filepath.Join(targetDir, path), data)
|
||||
|
||||
// Strip template filters from filename
|
||||
dir := filepath.Dir(targetFile)
|
||||
name := filepath.Base(targetFile)
|
||||
for _, filter := range opt.TemplateFilters {
|
||||
name = strings.ReplaceAll(name, filter, "")
|
||||
}
|
||||
if renamed := opt.RenameFiles[name]; renamed != "" {
|
||||
name = renamed
|
||||
}
|
||||
targetFile = filepath.Join(dir, name)
|
||||
|
||||
f, err := os.Create(targetFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tmpl.Execute(f, data); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// Copy standard files
|
||||
for _, path := range standardFiles {
|
||||
name := filepath.Base(path)
|
||||
if renamed := opt.RenameFiles[name]; renamed != "" {
|
||||
path = filepath.Join(filepath.Dir(path), renamed)
|
||||
}
|
||||
target := renderPath(filepath.Join(targetDir, path), data)
|
||||
if err := copyFile(fsys, path, target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTemplate(filename string, filters []string) bool {
|
||||
for _, f := range filters {
|
||||
if strings.Contains(filename, f) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func renderPath(path string, data any) string {
|
||||
if data == nil {
|
||||
return path
|
||||
}
|
||||
tmpl, err := template.New("path").Parse(path)
|
||||
if err != nil {
|
||||
return path
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
return path
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func copyFile(fsys fs.FS, source, target string) error {
|
||||
s, err := fsys.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d, err := os.Create(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, err = io.Copy(d, s)
|
||||
return err
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package mnt provides mount operations for the Core framework.
|
||||
//
|
||||
// Mount operations attach data to/from binaries and watch live filesystems:
|
||||
//
|
||||
// - FS: mount an embed.FS subdirectory for scoped access
|
||||
// - Extract: extract a template directory with variable substitution
|
||||
// - Watch: observe filesystem changes (file watcher)
|
||||
//
|
||||
// Zero external dependencies. All operations use stdlib only.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// sub, _ := mnt.FS(myEmbed, "lib/persona")
|
||||
// content, _ := sub.ReadFile("secops/developer.md")
|
||||
//
|
||||
// mnt.Extract(sub, "/tmp/workspace", map[string]string{"Name": "myproject"})
|
||||
package mnt
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Sub wraps an embed.FS with a basedir for scoped access.
|
||||
// All paths are relative to basedir.
|
||||
type Sub struct {
|
||||
basedir string
|
||||
fs embed.FS
|
||||
}
|
||||
|
||||
// FS creates a scoped view of an embed.FS anchored at basedir.
|
||||
// Returns error if basedir doesn't exist in the embedded filesystem.
|
||||
func FS(efs embed.FS, basedir string) (*Sub, error) {
|
||||
s := &Sub{fs: efs, basedir: basedir}
|
||||
// Verify the basedir exists
|
||||
if _, err := s.ReadDir("."); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Sub) path(name string) string {
|
||||
return filepath.ToSlash(filepath.Join(s.basedir, name))
|
||||
}
|
||||
|
||||
// Open opens the named file for reading.
|
||||
func (s *Sub) Open(name string) (fs.File, error) {
|
||||
return s.fs.Open(s.path(name))
|
||||
}
|
||||
|
||||
// ReadDir reads the named directory.
|
||||
func (s *Sub) ReadDir(name string) ([]fs.DirEntry, error) {
|
||||
return s.fs.ReadDir(s.path(name))
|
||||
}
|
||||
|
||||
// ReadFile reads the named file.
|
||||
func (s *Sub) ReadFile(name string) ([]byte, error) {
|
||||
return s.fs.ReadFile(s.path(name))
|
||||
}
|
||||
|
||||
// ReadString reads the named file as a string.
|
||||
func (s *Sub) ReadString(name string) (string, error) {
|
||||
data, err := s.ReadFile(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// Sub returns a new Sub anchored at a subdirectory within this Sub.
|
||||
func (s *Sub) Sub(subDir string) (*Sub, error) {
|
||||
return FS(s.fs, s.path(subDir))
|
||||
}
|
||||
|
||||
// Embed returns the underlying embed.FS.
|
||||
func (s *Sub) Embed() embed.FS {
|
||||
return s.fs
|
||||
}
|
||||
|
||||
// BaseDir returns the basedir this Sub is anchored at.
|
||||
func (s *Sub) BaseDir() string {
|
||||
return s.basedir
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package mnt_test
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/mnt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
//go:embed testdata
|
||||
var testFS embed.FS
|
||||
|
||||
func TestFS_Good(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "testdata", sub.BaseDir())
|
||||
}
|
||||
|
||||
func TestFS_Bad_InvalidDir(t *testing.T) {
|
||||
_, err := mnt.FS(testFS, "nonexistent")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSub_ReadFile_Good(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := sub.ReadFile("hello.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hello world\n", string(data))
|
||||
}
|
||||
|
||||
func TestSub_ReadString_Good(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
content, err := sub.ReadString("hello.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hello world\n", content)
|
||||
}
|
||||
|
||||
func TestSub_ReadDir_Good(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
entries, err := sub.ReadDir(".")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, len(entries) >= 1)
|
||||
}
|
||||
|
||||
func TestSub_Sub_Good(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
nested, err := sub.Sub("subdir")
|
||||
require.NoError(t, err)
|
||||
|
||||
content, err := nested.ReadString("nested.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "nested content\n", content)
|
||||
}
|
||||
|
||||
func TestExtract_Good(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata/template")
|
||||
require.NoError(t, err)
|
||||
|
||||
targetDir := t.TempDir()
|
||||
err = mnt.Extract(sub, targetDir, map[string]string{
|
||||
"Name": "myproject",
|
||||
"Module": "forge.lthn.ai/core/myproject",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check template was processed
|
||||
readme, err := os.ReadFile(targetDir + "/README.md")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(readme), "myproject project")
|
||||
|
||||
// Check go.mod template was processed
|
||||
gomod, err := os.ReadFile(targetDir + "/go.mod")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(gomod), "module forge.lthn.ai/core/myproject")
|
||||
|
||||
// Check non-template was copied as-is
|
||||
main, err := os.ReadFile(targetDir + "/main.go")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "package main\n", string(main))
|
||||
}
|
||||
|
||||
func TestExtract_Good_NoData(t *testing.T) {
|
||||
sub, err := mnt.FS(testFS, "testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
targetDir := t.TempDir()
|
||||
err = mnt.Extract(sub, targetDir, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := os.ReadFile(targetDir + "/hello.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hello world\n", string(data))
|
||||
}
|
||||
1
pkg/mnt/testdata/hello.txt
vendored
1
pkg/mnt/testdata/hello.txt
vendored
|
|
@ -1 +0,0 @@
|
|||
hello world
|
||||
1
pkg/mnt/testdata/subdir/nested.txt
vendored
1
pkg/mnt/testdata/subdir/nested.txt
vendored
|
|
@ -1 +0,0 @@
|
|||
nested content
|
||||
1
pkg/mnt/testdata/template/README.md.tmpl
vendored
1
pkg/mnt/testdata/template/README.md.tmpl
vendored
|
|
@ -1 +0,0 @@
|
|||
{{.Name}} project
|
||||
1
pkg/mnt/testdata/template/go.mod.tmpl
vendored
1
pkg/mnt/testdata/template/go.mod.tmpl
vendored
|
|
@ -1 +0,0 @@
|
|||
module {{.Module}}
|
||||
1
pkg/mnt/testdata/template/main.go
vendored
1
pkg/mnt/testdata/template/main.go
vendored
|
|
@ -1 +0,0 @@
|
|||
package main
|
||||
Loading…
Add table
Reference in a new issue