add file size and checksum
This commit is contained in:
parent
2ce6c44407
commit
f6f4258609
10
Makefile
10
Makefile
@ -1,10 +1,12 @@
|
||||
LDFLAGS?=--ldflags '-extldflags "-static"'
|
||||
LDFLAGS?=--ldflags '-extldflags "-static"' --ldflags="-X 'main.commit=$(shell git rev-parse HEAD)' -X 'main.version=$(shell git describe --tags)' -X 'main.date=$(shell date '+%Y-%m-%d %T.%s%z')'"
|
||||
export CGO_ENABLED=0
|
||||
|
||||
build: jx
|
||||
.PHONY=jx-cli
|
||||
|
||||
jx:
|
||||
build: jx-cli
|
||||
|
||||
jx-cli:
|
||||
go build -o jx $(LDFLAGS) ./cmd/cli/main.go
|
||||
|
||||
test:
|
||||
test: jx-cli
|
||||
go test ./...
|
||||
|
@ -14,6 +14,7 @@ _ "errors"
|
||||
_ "gopkg.in/yaml.v3"
|
||||
"decl/internal/resource"
|
||||
"decl/internal/source"
|
||||
"decl/internal/target"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -21,7 +22,14 @@ const (
|
||||
FormatJson = "json"
|
||||
)
|
||||
|
||||
var (
|
||||
version string
|
||||
commit string
|
||||
date string
|
||||
)
|
||||
|
||||
var GlobalOformat *string
|
||||
var GlobalOutput *string
|
||||
var GlobalQuiet *bool
|
||||
|
||||
var ImportMerge *bool
|
||||
@ -52,6 +60,13 @@ var jxSubCommands = []SubCommand {
|
||||
},
|
||||
}
|
||||
|
||||
func VersionUsage() {
|
||||
fmt.Println("jx")
|
||||
fmt.Printf("version: %s\n", version)
|
||||
fmt.Printf("commit: %s\n", commit)
|
||||
fmt.Printf("date: %s\n", date)
|
||||
}
|
||||
|
||||
func LoggerConfig() {
|
||||
var programLevel = new(slog.LevelVar)
|
||||
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}))
|
||||
@ -97,7 +112,7 @@ func ImportSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) {
|
||||
documents = append(documents, loaded...)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch *GlobalOformat {
|
||||
case FormatYaml:
|
||||
encoder = resource.NewYAMLEncoder(output)
|
||||
@ -105,6 +120,14 @@ func ImportSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) {
|
||||
encoder = resource.NewJSONEncoder(output)
|
||||
}
|
||||
|
||||
if *GlobalOutput != "" {
|
||||
_, err := target.TargetTypes.New(*GlobalOutput)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
//outputTarget.EmitResources(
|
||||
}
|
||||
|
||||
if len(documents) == 0 {
|
||||
documents = append(documents, resource.NewDocument())
|
||||
}
|
||||
@ -253,6 +276,8 @@ func main() {
|
||||
for _,subCmd := range jxSubCommands {
|
||||
cmdFlagSet := flag.NewFlagSet(subCmd.Name, flag.ExitOnError)
|
||||
GlobalOformat = cmdFlagSet.String("oformat", "yaml", "Output serialization format")
|
||||
GlobalOutput = cmdFlagSet.String("output", "-", "Output target (default stdout)")
|
||||
GlobalOutput = cmdFlagSet.String("o", "-", "Output target (default stdout)")
|
||||
GlobalQuiet = cmdFlagSet.Bool("quiet", false, "Generate terse output.")
|
||||
|
||||
switch subCmd.Name {
|
||||
@ -260,16 +285,19 @@ func main() {
|
||||
cmdFlagSet.Usage = func() {
|
||||
fmt.Println("jx diff source [source2]")
|
||||
cmdFlagSet.PrintDefaults()
|
||||
VersionUsage()
|
||||
}
|
||||
case "apply":
|
||||
cmdFlagSet.Usage = func() {
|
||||
fmt.Println("jx diff source [source2]")
|
||||
cmdFlagSet.PrintDefaults()
|
||||
VersionUsage()
|
||||
}
|
||||
case "import":
|
||||
cmdFlagSet.Usage = func() {
|
||||
fmt.Println("jx import source [source2]")
|
||||
cmdFlagSet.PrintDefaults()
|
||||
VersionUsage()
|
||||
}
|
||||
}
|
||||
slog.Info("command", "command", subCmd)
|
||||
@ -278,6 +306,10 @@ func main() {
|
||||
log.Fatal(e)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
flag.PrintDefaults()
|
||||
VersionUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,17 @@ func NewDocument() *Document {
|
||||
return &Document{}
|
||||
}
|
||||
|
||||
func (d *Document) Filter(filter ResourceSelector) []*Declaration {
|
||||
resources := make([]*Declaration, 0, len(d.ResourceDecls))
|
||||
for i := range d.ResourceDecls {
|
||||
filterResource := &d.ResourceDecls[i]
|
||||
if filter(filterResource) {
|
||||
resources = append(resources, &d.ResourceDecls[i])
|
||||
}
|
||||
}
|
||||
return resources
|
||||
}
|
||||
|
||||
func (d *Document) Clone() *Document {
|
||||
clone := NewDocument()
|
||||
clone.ResourceDecls = make([]Declaration, len(d.ResourceDecls))
|
||||
|
@ -96,6 +96,7 @@ resources:
|
||||
ctime: %s
|
||||
mtime: %s
|
||||
sha256: ea33e2082ca777f82dc9571b08df95d81925eed04e1bdbac7cdc6dc52d330eca
|
||||
size: 82
|
||||
filetype: "regular"
|
||||
state: present
|
||||
`, file, fileContent, aTime.Format(time.RFC3339Nano), cTime.Format(time.RFC3339Nano), mTime.Format(time.RFC3339Nano))
|
||||
@ -185,3 +186,39 @@ resources:
|
||||
assert.YAMLEq(t, string(document), string(marshalledYAML))
|
||||
|
||||
}
|
||||
|
||||
func TestDocumentResourceFilter(t *testing.T) {
|
||||
document := `
|
||||
---
|
||||
resources:
|
||||
- type: user
|
||||
attributes:
|
||||
name: "testuser"
|
||||
uid: 10022
|
||||
home: "/home/testuser"
|
||||
state: present
|
||||
- type: file
|
||||
attributes:
|
||||
path: "foo.txt"
|
||||
state: present
|
||||
- type: file
|
||||
attributes:
|
||||
path: "bar.txt"
|
||||
state: present
|
||||
`
|
||||
|
||||
d := NewDocument()
|
||||
assert.NotNil(t, d)
|
||||
docReader := strings.NewReader(document)
|
||||
|
||||
e := d.Load(docReader)
|
||||
assert.Nil(t, e)
|
||||
|
||||
resources := d.Filter(func(d *Declaration) bool {
|
||||
if d.Type == "file" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
assert.Equal(t, 2, len(resources))
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"log/slog"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/user"
|
||||
@ -55,15 +56,20 @@ type File struct {
|
||||
|
||||
Content string `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
Sha256 string `json:"sha256,omitempty" yaml:"sha256,omitempty"`
|
||||
Size int64 `json:"size,omitempty" yaml:"size,omitempty"`
|
||||
Target string `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
FileType FileType `json:"filetype" yaml:"filetype"`
|
||||
State string `json:"state" yaml:"state"`
|
||||
}
|
||||
|
||||
type ResourceFileInfo struct {
|
||||
resource *File
|
||||
}
|
||||
|
||||
func NewFile() *File {
|
||||
currentUser, _ := user.Current()
|
||||
group, _ := user.LookupGroupId(currentUser.Gid)
|
||||
f := &File{Owner: currentUser.Username, Group: group.Name, Mode: "0666", FileType: RegularFile}
|
||||
f := &File{Owner: currentUser.Username, Group: group.Name, Mode: "0644", FileType: RegularFile}
|
||||
slog.Info("NewFile()", "file", f)
|
||||
return f
|
||||
}
|
||||
@ -78,6 +84,8 @@ func (f *File) Clone() Resource {
|
||||
Ctime: f.Ctime,
|
||||
Mtime: f.Mtime,
|
||||
Content: f.Content,
|
||||
Sha256: f.Sha256,
|
||||
Size: f.Size,
|
||||
Target: f.Target,
|
||||
FileType: f.FileType,
|
||||
State: f.State,
|
||||
@ -127,10 +135,12 @@ func (f *File) Apply() error {
|
||||
return gidErr
|
||||
}
|
||||
|
||||
slog.Info("File.Mode", "mode", f.Mode)
|
||||
mode, modeErr := strconv.ParseInt(f.Mode, 8, 64)
|
||||
if modeErr != nil {
|
||||
return modeErr
|
||||
}
|
||||
slog.Info("File.Mode Parse", "mode", mode, "err", modeErr)
|
||||
|
||||
//e := os.Stat(f.path)
|
||||
//if os.IsNotExist(e) {
|
||||
@ -199,6 +209,43 @@ func (f *File) NormalizePath() error {
|
||||
return fileAbsErr
|
||||
}
|
||||
|
||||
func (f *File) FileInfo() fs.FileInfo {
|
||||
return &ResourceFileInfo{ resource: f }
|
||||
}
|
||||
|
||||
func (f *ResourceFileInfo) Name() string {
|
||||
return filepath.Base(f.resource.Path)
|
||||
}
|
||||
|
||||
func (f *ResourceFileInfo) Size() int64 {
|
||||
return f.resource.Size
|
||||
}
|
||||
|
||||
func (f *ResourceFileInfo) Mode() (mode os.FileMode) {
|
||||
if fileMode, fileModeErr := strconv.ParseInt(f.resource.Mode, 8, 64); fileModeErr == nil {
|
||||
mode |= os.FileMode(fileMode)
|
||||
} else {
|
||||
panic(fileModeErr)
|
||||
}
|
||||
mode |= f.resource.FileType.GetMode()
|
||||
return
|
||||
}
|
||||
|
||||
func (f *ResourceFileInfo) ModTime() time.Time {
|
||||
return f.resource.Mtime
|
||||
}
|
||||
|
||||
func (f *ResourceFileInfo) IsDir() bool {
|
||||
if f.resource.FileType == DirectoryFile {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *ResourceFileInfo) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) UpdateAttributesFromFileInfo(info os.FileInfo) error {
|
||||
if info != nil {
|
||||
f.Mtime = info.ModTime()
|
||||
@ -223,6 +270,7 @@ func (f *File) UpdateAttributesFromFileInfo(info os.FileInfo) error {
|
||||
f.Group = fileGroup.Name
|
||||
}
|
||||
}
|
||||
f.Size = info.Size()
|
||||
f.Mode = fmt.Sprintf("%04o", info.Mode().Perm())
|
||||
f.FileType.SetMode(info.Mode())
|
||||
return nil
|
||||
@ -309,3 +357,22 @@ func (f *FileType) SetMode(mode os.FileMode) {
|
||||
*f = BlockDeviceFile
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileType) GetMode() (mode os.FileMode) {
|
||||
switch *f {
|
||||
case RegularFile:
|
||||
case DirectoryFile:
|
||||
mode |= os.ModeDir
|
||||
case SymbolicLinkFile:
|
||||
mode |= os.ModeSymlink
|
||||
case NamedPipeFile:
|
||||
mode |= os.ModeNamedPipe
|
||||
case SocketFile:
|
||||
mode |= os.ModeSocket
|
||||
case CharacterDeviceFile:
|
||||
mode |= os.ModeCharDevice
|
||||
case BlockDeviceFile:
|
||||
mode |= os.ModeDevice
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
@ -49,6 +50,7 @@ func TestReadFile(t *testing.T) {
|
||||
test line 1
|
||||
test line 2
|
||||
sha256: f2082f984f1bf1a7886e2af32ccc9ca474fbff3553d131204b070c438114dd51
|
||||
size: 23
|
||||
filetype: "regular"
|
||||
state: present
|
||||
`
|
||||
@ -261,3 +263,20 @@ func TestFileReadStat(t *testing.T) {
|
||||
assert.Nil(t, testReadErr)
|
||||
assert.Equal(t, linkTargetFile, testRead.Target)
|
||||
}
|
||||
|
||||
func TestFileResourceFileInfo(t *testing.T) {
|
||||
testFile := filepath.Join(TempDir, "testuri.txt")
|
||||
|
||||
f := NewFile()
|
||||
assert.NotNil(t, f)
|
||||
|
||||
f.Path = testFile
|
||||
f.Mode = "0600"
|
||||
f.State = "present"
|
||||
assert.Nil(t, f.Apply())
|
||||
|
||||
f.Read(context.Background())
|
||||
|
||||
fi := f.FileInfo()
|
||||
assert.Equal(t, os.FileMode(0600), fi.Mode().Perm())
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ import (
|
||||
_ "net/url"
|
||||
)
|
||||
|
||||
type ResourceSelector func(r *Declaration) bool
|
||||
|
||||
type Resource interface {
|
||||
Type() string
|
||||
URI() string
|
||||
|
@ -45,6 +45,7 @@ func TestSchemaValidateJSON(t *testing.T) {
|
||||
test line 1
|
||||
test line 2
|
||||
sha256: f2082f984f1bf1a7886e2af32ccc9ca474fbff3553d131204b070c438114dd51
|
||||
size: 23
|
||||
filetype: "regular"
|
||||
state: present
|
||||
`
|
||||
|
Loading…
Reference in New Issue
Block a user