Compare commits

...

2 Commits

Author SHA1 Message Date
99e89d60d4 latest
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2022-12-04 04:48:23 +04:00
5f5f51c014 latest 2022-12-04 04:33:24 +04:00
13 changed files with 174 additions and 128 deletions

2
.golangci.yaml Normal file
View File

@ -0,0 +1,2 @@
run:
tests: false

View File

@ -4,20 +4,24 @@ export PATH := $(PATH):$(GOPATH)/bin
PROTOC_GEN_GO := $(GOPATH)/bin/protoc-gen-go PROTOC_GEN_GO := $(GOPATH)/bin/protoc-gen-go
ARCH := $(shell uname -m) ARCH := $(shell uname -m)
VERSION := $(shell git describe --always --dirty=-dirty) GITREV := $(shell git describe --always --dirty=-dirty)
GOLDFLAGS += -X main.Version=$(VERSION) GOLDFLAGS += -X main.Version=0.1.0
GOLDFLAGS += -X main.Gitrev=$(GITREV)
GOFLAGS := -ldflags "$(GOLDFLAGS)" GOFLAGS := -ldflags "$(GOLDFLAGS)"
default: run default: run
run: ./mfer.cmd run: ./mfer.cmd
./$< ./$<
./$< gen ./$< gen --ignore-dotfiles
$(PROTOC_GEN_GO): $(PROTOC_GEN_GO):
test -e $(PROTOC_GEN_GO) || go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest test -e $(PROTOC_GEN_GO) || go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
fixme:
@grep -nir fixme . | grep -v Makefile
devprereqs: devprereqs:
which gofumpt || go install -v mvdan.cc/gofumpt@latest which gofumpt || go install -v mvdan.cc/gofumpt@latest
which golangci-lint || go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@latest which golangci-lint || go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@latest
@ -25,15 +29,16 @@ devprereqs:
mfer.cmd: $(PROTOC_GEN_GO) mfer/*.go internal/*/*.go cmd/*/*.go mfer.cmd: $(PROTOC_GEN_GO) mfer/*.go internal/*/*.go cmd/*/*.go
protoc --version protoc --version
cd mfer && go generate . cd mfer && go generate .
cd cmd/mfer && go build -o ../../mfer.cmd $(GOFLAGS) . cd cmd/mfer && go build -tags urfave_cli_no_docs -o ../../mfer.cmd $(GOFLAGS) .
clean: clean:
rm -rfv mfer/*.pb.go ./mfer rm -rfv mfer/*.pb.go mfer.cmd cmd/mfer/mfer
fmt: prereqs fmt: devprereqs
gofumpt -l -w mfer internal cmd gofumpt -l -w mfer internal cmd
golangci-lint run --fix golangci-lint run --fix
prettier -w *.json *.md -prettier -w *.json
-prettier -w *.md
lint: lint:
golangci-lint run golangci-lint run

View File

@ -128,8 +128,7 @@ The manifest file would do several important things:
- a command line option to zero/omit mtime/ctime, as well as manifest - a command line option to zero/omit mtime/ctime, as well as manifest
timestamp, and sort all directory listings so that manifest file timestamp, and sort all directory listings so that manifest file
generation is deterministic/reproducible generation is deterministic/reproducible
- URL format `mfer fetch - URL format `mfer fetch https://exmaple.com/manifestdirectory/?key=5539AD00DE4C42F3AFE11575052443F4DF2A55C2`
https://exmaple.com/manifestdirectory/?key=5539AD00DE4C42F3AFE11575052443F4DF2A55C2`
to assert in the URL which PGP signing key should be used in the manifest, to assert in the URL which PGP signing key should be used in the manifest,
so that shared URLs have a cryptographic trust root so that shared URLs have a cryptographic trust root
- a "well-known" key in the manifest that maps well known keys (could reuse - a "well-known" key in the manifest that maps well known keys (could reuse

View File

@ -9,8 +9,9 @@ import (
var ( var (
Appname string = "mfer" Appname string = "mfer"
Version string Version string
Gitrev string
) )
func main() { func main() {
os.Exit(cli.Run(Appname, Version)) os.Exit(cli.Run(Appname, Version, Gitrev))
} }

14
internal/cli/check.go Normal file
View File

@ -0,0 +1,14 @@
package cli
import (
"errors"
log "github.com/visionmedia/go-cli-log"
"github.com/urfave/cli/v2"
)
func (mfa *CLIApp) checkManifestOperation(c *cli.Context) error {
log.Error(errors.New("unimplemented"))
return nil
}

View File

@ -13,10 +13,11 @@ func init() {
} }
} }
func Run(Appname, Version string) int { func Run(Appname, Version, Gitrev string) int {
m := &CLIApp{} m := &CLIApp{}
m.appname = Appname m.appname = Appname
m.version = Version m.version = Version
m.gitrev = Gitrev
m.exitCode = 0 m.exitCode = 0
m.run() m.run()

12
internal/cli/fetch.go Normal file
View File

@ -0,0 +1,12 @@
package cli
import (
"fmt"
"github.com/urfave/cli/v2"
)
func (mfa *CLIApp) fetchManifestOperation(c *cli.Context) error {
fmt.Println("fetchManifestOperation()")
return nil
}

36
internal/cli/gen.go Normal file
View File

@ -0,0 +1,36 @@
package cli
import (
"fmt"
"git.eeqj.de/sneak/mfer/mfer"
"github.com/davecgh/go-spew/spew"
"github.com/urfave/cli/v2"
)
func (mfa *CLIApp) generateManifestOperation(c *cli.Context) error {
fmt.Println("generateManifestOperation()")
myArgs := c.Args()
spew.Dump(myArgs)
fmt.Printf("%#v\n", c.Args().First())
if c.Args().Len() > 0 {
fmt.Printf("%#v\n", c.Args().Get(1))
}
//fmt.Printf("called with arg: %s\n", c.String("input"))
opts := &mfer.ManifestScanOptions{
IgnoreDotfiles: c.Bool("IgnoreDotfiles"),
FollowSymLinks: c.Bool("FollowSymLinks"),
}
// FIXME add command flags for ignoring dotfiles and following symlinks
mf, err := mfer.NewFromPath(c.String("input"), opts)
if err != nil {
panic(err)
}
spew.Dump(mf)
return nil
}

View File

@ -1,51 +0,0 @@
package cli
import (
"git.eeqj.de/sneak/mfer/mfer"
"github.com/spf13/afero"
)
type Job struct {
innerpb *mfer.MFFileInner
outerpb *mfer.MFFile
fileCount int64
totalSize int64
afs afero.Fs
}
func (m *Job) scanForFiles() error {
m.innerpb = &mfer.MFFileInner{}
m.innerpb.Version = mfer.MFFileInner_ONE
return nil
}
/*
walkErr := filepath.Walk(m.sourcePath, func(itemPath string, info os.FileInfo, err error) error {
// we do not include the manifest file in the manifest
if itemPath == "index.mf" {
return nil
}
fpi := mfer.MFFilePath{}
fpi.Path = itemPath
fpi.Size = info.Size()
m.innerpb.Files = append(m.innerpb.Files, &fpi)
m.fileCount++
m.totalSize += fpi.Size
return nil
})
if walkErr != nil {
log.Fatal(walkErr)
return walkErr
}
fmt.Printf("%#v\n", m.innerpb)
fmt.Printf("filecount = %#v\n", m.fileCount)
fmt.Printf("totalsize = %#v\n", m.totalSize)
return nil
}
*/

View File

@ -1,15 +1,12 @@
package cli package cli
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"time" "time"
log "github.com/visionmedia/go-cli-log" log "github.com/visionmedia/go-cli-log"
"git.eeqj.de/sneak/mfer/mfer"
"github.com/davecgh/go-spew/spew"
"github.com/pterm/pterm" "github.com/pterm/pterm"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -17,10 +14,9 @@ import (
type CLIApp struct { type CLIApp struct {
appname string appname string
version string version string
buildarch string gitrev string
startupTime time.Time startupTime time.Time
exitCode int exitCode int
errorString string
app *cli.App app *cli.App
} }
@ -40,29 +36,58 @@ func (mfa *CLIApp) disableStyling() {
pterm.Fatal.Prefix.Text = "" pterm.Fatal.Prefix.Text = ""
} }
func (mfa *CLIApp) VersionString() string {
return fmt.Sprintf("%s (%s)", mfa.version, mfa.gitrev)
}
func (mfa *CLIApp) run() { func (mfa *CLIApp) run() {
mfa.startupTime = time.Now()
if NO_COLOR { if NO_COLOR {
// shoutout to rob pike who thinks it's juvenile // shoutout to rob pike who thinks it's juvenile
mfa.disableStyling() mfa.disableStyling()
} }
mfa.printBanner()
mfa.app = &cli.App{ mfa.app = &cli.App{
Name: mfa.appname, Name: mfa.appname,
Usage: "Manifest generator", Usage: "Manifest generator",
Version: mfa.version, Version: mfa.VersionString(),
EnableBashCompletion: true, EnableBashCompletion: true,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose",
Usage: "Verbosity level",
Aliases: []string{"v"},
},
&cli.BoolFlag{
Name: "quiet",
Usage: "don't produce output except on error",
Aliases: []string{"q"},
},
},
Commands: []*cli.Command{ Commands: []*cli.Command{
{ {
Name: "generate", Name: "generate",
Aliases: []string{"gen"}, Aliases: []string{"gen"},
Usage: "Generate manifest file", Usage: "Generate manifest file",
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
if !c.Bool("quiet") {
mfa.printBanner()
}
return mfa.generateManifestOperation(c) return mfa.generateManifestOperation(c)
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.BoolFlag{
Name: "FollowSymLinks",
Aliases: []string{"follow-symlinks"},
Usage: "Resolve encountered symlinks",
},
&cli.BoolFlag{
Name: "IgnoreDotfiles",
Aliases: []string{"ignore-dotfiles"},
Usage: "Ignore any dot (hidden) files encountered",
},
// FIXME this should be a positional arg
&cli.StringFlag{ &cli.StringFlag{
Name: "input", Name: "input",
Value: ".", Value: ".",
@ -81,51 +106,37 @@ func (mfa *CLIApp) run() {
Name: "check", Name: "check",
Usage: "Validate files using manifest file", Usage: "Validate files using manifest file",
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
return mfa.validateManifestOperation(c) if !c.Bool("quiet") {
mfa.printBanner()
}
return mfa.checkManifestOperation(c)
},
},
{
Name: "version",
Usage: "Show version",
Action: func(c *cli.Context) error {
fmt.Printf("%s\n", mfa.VersionString())
return nil
},
},
{
Name: "fetch",
Usage: "fetch manifest and referenced files",
Action: func(c *cli.Context) error {
if !c.Bool("quiet") {
mfa.printBanner()
}
return mfa.fetchManifestOperation(c)
}, },
}, },
}, },
} }
mfa.app.HideVersion = true
err := mfa.app.Run(os.Args) err := mfa.app.Run(os.Args)
if err != nil { if err != nil {
mfa.exitCode = 1 mfa.exitCode = 1
log.Error(err) log.Error(err)
} }
} }
func (mfa *CLIApp) validateManifestOperation(c *cli.Context) error {
log.Error(errors.New("unimplemented"))
return nil
}
func (mfa *CLIApp) generateManifestOperation(c *cli.Context) error {
fmt.Println("generateManifestOperation()")
fmt.Printf("called with arg: %s\n", c.String("input"))
opts := &mfer.ManifestScanOptions{
IgnoreDotfiles: true,
FollowSymLinks: false,
}
mf, err := mfer.NewFromPath(c.String("input"), opts)
if err != nil {
panic(err)
}
spew.Dump(mf)
/*
mgj, err := NewMFGenerationJobFromFilesystem(c.String("input"))
if err != nil {
log.Fatal(err)
return err
}
mgj.scanForFiles()
//mgj.outputFile = c.String("output")
*/
return nil
}

View File

@ -4,10 +4,10 @@ import (
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/davecgh/go-spew/spew"
"github.com/spf13/afero" "github.com/spf13/afero"
) )
@ -28,6 +28,10 @@ type Manifest struct {
TotalFileSize int64 TotalFileSize int64
} }
func (m *Manifest) String() string {
return fmt.Sprintf("<Manifest count=%d totalSize=%d>", len(m.Files), m.TotalFileSize)
}
type ManifestScanOptions struct { type ManifestScanOptions struct {
IgnoreDotfiles bool IgnoreDotfiles bool
FollowSymLinks bool FollowSymLinks bool
@ -39,13 +43,11 @@ func NewFromPath(inputPath string, options *ManifestScanOptions) (*Manifest, err
return nil, err return nil, err
} }
afs := afero.NewBasePathFs(afero.NewOsFs(), abs) afs := afero.NewBasePathFs(afero.NewOsFs(), abs)
spew.Dump(afs)
m, err := NewFromFS(afs, options) m, err := NewFromFS(afs, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.SourceFSRoot = abs m.SourceFSRoot = abs
spew.Dump(m)
return m, nil return m, nil
} }
@ -54,13 +56,16 @@ func NewFromFS(fs afero.Fs, options *ManifestScanOptions) (*Manifest, error) {
SourceFS: fs, SourceFS: fs,
ScanOptions: options, ScanOptions: options,
} }
m.Scan() err := m.Scan()
if err != nil {
return nil, err
}
return m, nil return m, nil
} }
func (m *Manifest) Scan() { func (m *Manifest) Scan() error {
afero.Walk(m.SourceFS, "./", func(path string, info fs.FileInfo, err error) error { // FIXME scan and whatever function does the hashing should take ctx
oe := afero.Walk(m.SourceFS, "./", func(path string, info fs.FileInfo, err error) error {
if m.ScanOptions.IgnoreDotfiles && strings.HasPrefix(path, ".") { if m.ScanOptions.IgnoreDotfiles && strings.HasPrefix(path, ".") {
// FIXME make this check all path components BUG // FIXME make this check all path components BUG
return nil return nil
@ -71,10 +76,6 @@ func (m *Manifest) Scan() {
return nil return nil
} }
fmt.Printf("path = %s\n", path)
spew.Dump(path)
spew.Dump(info)
fileinfo, staterr := m.SourceFS.Stat(path) fileinfo, staterr := m.SourceFS.Stat(path)
if staterr != nil { if staterr != nil {
panic(staterr) panic(staterr)
@ -86,12 +87,28 @@ func (m *Manifest) Scan() {
} }
m.Files = append(m.Files, nf) m.Files = append(m.Files, nf)
m.TotalFileSize = m.TotalFileSize + info.Size() m.TotalFileSize = m.TotalFileSize + info.Size()
fmt.Printf("total file count now %i\n", len(m.Files))
fmt.Printf("total file size now %i\n", m.TotalFileSize)
return nil return nil
}) })
if oe != nil {
return oe
}
return nil
}
func (m *Manifest) WriteToFile(path string) error {
// FIXME refuse to overwrite without -f if file exists
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
return m.Write(f)
} }
func (m *Manifest) Write(output io.Writer) error { func (m *Manifest) Write(output io.Writer) error {
return nil // FIXME implement
panic("nope")
return nil // nolint:all
} }

View File

@ -14,12 +14,12 @@ message MFFile {
} }
// required mffile root attributes 1xx // required mffile root attributes 1xx
Version version = 1; Version version = 101;
bytes innerMessage = 2; bytes innerMessage = 102;
// these are used solely to detect corruption/truncation // these are used solely to detect corruption/truncation
// and not for cryptographic integrity. // and not for cryptographic integrity.
int64 size = 3; int64 size = 103;
bytes sha256 = 4; bytes sha256 = 104;
// 2xx for optional manifest root attributes // 2xx for optional manifest root attributes
// think we might use gosignify instead of gpg: // think we might use gosignify instead of gpg:
@ -59,10 +59,10 @@ message MFFileInner {
NONE = 0; NONE = 0;
ONE = 1; // only one for now ONE = 1; // only one for now
} }
Version version = 1; Version version = 100;
// required manifest attributes: // required manifest attributes:
repeated MFFilePath files = 2; repeated MFFilePath files = 101;
// optional manifest attributes 2xx: // optional manifest attributes 2xx:
optional Timestamp createdAt = 201; optional Timestamp createdAt = 201;

View File

@ -9,5 +9,4 @@ var (
) )
func TestManifestGeneration(t *testing.T) { func TestManifestGeneration(t *testing.T) {
} }