micro-gen/main.go
Vasiliy Tolstov f902777e5b update
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-09-26 19:44:12 +03:00

141 lines
3.2 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/storage/memory"
yamlcodec "go.unistack.org/micro-codec-yaml/v3"
flagconfig "go.unistack.org/micro-config-flag/v3"
"go.unistack.org/micro/v3/config"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/logger/slog"
)
type Config struct {
DstDir string `default:"." flag:"name=dstdir,desc='destination dir',default='.'"`
Action string `default:"update" flag:"name=action,desc='action',default='update'"`
Clean bool `default:"false" flag:"name=clean,desc='cleaup destination dir',default='false'"`
}
func main() {
var err error
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := &Config{}
log := slog.NewLogger()
if err = log.Init(); err != nil {
log.Fatal(ctx, err)
}
logger.DefaultLogger = log
if err = config.Load(ctx, []config.Config{
config.NewConfig(config.Struct(cfg)),
flagconfig.NewConfig(config.Struct(cfg), config.Codec(yamlcodec.NewCodec())),
}); err != nil {
log.Fatal(ctx, err)
}
if cfg.DstDir == "" || cfg.DstDir == "." {
if cfg.DstDir, err = os.Getwd(); err != nil {
log.Fatal(ctx, err)
}
log.Info(ctx, "dstdir not specified, use current dir: %s", cfg.DstDir)
}
flagUrl := strings.Join(flag.Args(), " ")
u, err := url.Parse(flagUrl)
if err != nil {
log.Fatal(ctx, err)
}
var rev string
if idx := strings.Index(u.Path, "@"); idx > 0 {
rev = u.Path[idx+1:]
}
cloneOpts := &git.CloneOptions{
URL: flagUrl,
Progress: os.Stdout,
}
if len(rev) == 0 {
cloneOpts.SingleBranch = true
cloneOpts.Depth = 1
}
if err := cloneOpts.Validate(); err != nil {
log.Fatal(ctx, err)
}
log.Info(ctx, `try to fetch `+flagUrl)
repo, err := git.CloneContext(ctx, memory.NewStorage(), nil, cloneOpts)
if err != nil {
log.Fatal(ctx, err)
}
ref, err := repo.Head()
if err != nil {
log.Fatal(ctx, "failed to get head: %v", err)
}
fmt.Println(ref.Hash())
commit, err := repo.CommitObject(ref.Hash())
if err != nil {
log.Fatal(ctx, "failed to get commit: %v", err)
}
tree, err := commit.Tree()
if err != nil {
log.Fatal(ctx, err)
}
if err := os.MkdirAll(cfg.DstDir, os.FileMode(0o755)); err != nil {
log.Fatal(ctx, "failed to create dir: %v", err)
}
if cfg.Clean {
if err := cleanDir(ctx, cfg.DstDir); err != nil {
log.Fatal(ctx, "failed to clean dir: %v", err)
}
}
err = tree.Files().ForEach(func(file *object.File) error {
if file == nil {
return fmt.Errorf("file pointer is nil")
}
fmode, err := file.Mode.ToOSFileMode()
if err != nil {
return err
}
switch file.Mode {
case filemode.Executable:
return writeFile(ctx, file, cfg.DstDir, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fmode)
case filemode.Dir:
return os.MkdirAll(filepath.Join(cfg.DstDir, file.Name), fmode)
case filemode.Regular:
return writeFile(ctx, file, cfg.DstDir, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fmode)
default:
return fmt.Errorf("unsupported filetype %v for %s", file.Mode, file.Name)
}
})
if err != nil {
log.Fatal(ctx, "failed to exctract file: %v", err)
}
}