all repos

mugit @ 5935eaa

馃惍 git server that your cow will love
3 files changed, 115 insertions(+), 49 deletions(-)
cli: repo description
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-02-03 00:54:39 +0200
Authored at: 2026-02-03 00:37:15 +0200
Change ID: qszlnmvzvqvsxnqrnpuvzuoskmpuortr
Parent: 8417128
M internal/cli/cli.go
路路路
        2
        2
         

      
        3
        3
         import (

      
        4
        4
         	"context"

      
        5
        
        -	"log/slog"

      
        6
        
        -	"net"

      
        7
        
        -	"net/http"

      
        8
        
        -	"os"

      
        9
        
        -	"os/signal"

      
        10
        
        -	"strconv"

      
        11
        
        -	"syscall"

      
        
        5
        +	"fmt"

      
        12
        6
         

      
        
        7
        +	securejoin "github.com/cyphar/filepath-securejoin"

      
        13
        8
         	"github.com/urfave/cli/v3"

      
        14
        9
         	"olexsmir.xyz/mugit/internal/config"

      
        15
        
        -	"olexsmir.xyz/mugit/internal/handlers"

      
        16
        
        -	"olexsmir.xyz/mugit/internal/mirror"

      
        17
        
        -	"olexsmir.xyz/mugit/internal/ssh"

      
        
        10
        +	"olexsmir.xyz/mugit/internal/git"

      
        18
        11
         )

      
        19
        12
         

      
        20
        13
         type Cli struct {

      路路路
        68
        61
         							},

      
        69
        62
         						},

      
        70
        63
         					},

      
        
        64
        +					{

      
        
        65
        +						Name:   "description",

      
        
        66
        +						Usage:  "get or set repo description",

      
        
        67
        +						Action: c.repoDescriptionAction,

      
        
        68
        +						Arguments: []cli.Argument{

      
        
        69
        +							&cli.StringArg{Name: "name"},

      
        
        70
        +						},

      
        
        71
        +					},

      
        71
        72
         				},

      
        72
        73
         			},

      
        73
        74
         		},

      路路路
        75
        76
         	return cmd.Run(ctx, args)

      
        76
        77
         }

      
        77
        78
         

      
        78
        
        -func (c *Cli) serveAction(ctx context.Context, cmd *cli.Command) error {

      
        79
        
        -	httpServer := &http.Server{

      
        80
        
        -		Addr:    net.JoinHostPort(c.cfg.Server.Host, strconv.Itoa(c.cfg.Server.Port)),

      
        81
        
        -		Handler: handlers.InitRoutes(c.cfg),

      
        82
        
        -	}

      
        83
        
        -	go func() {

      
        84
        
        -		slog.Info("starting http server", "host", c.cfg.Server.Host, "port", c.cfg.Server.Port)

      
        85
        
        -		if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {

      
        86
        
        -			slog.Error("HTTP server error", "err", err)

      
        87
        
        -		}

      
        88
        
        -	}()

      
        89
        
        -

      
        90
        
        -	if c.cfg.SSH.Enable {

      
        91
        
        -		sshServer := ssh.NewServer(c.cfg)

      
        92
        
        -		go func() {

      
        93
        
        -			slog.Info("starting ssh server", "port", c.cfg.SSH.Port)

      
        94
        
        -			if err := sshServer.Start(); err != nil {

      
        95
        
        -				slog.Error("ssh server error", "err", err)

      
        96
        
        -			}

      
        97
        
        -		}()

      
        98
        
        -	}

      
        99
        
        -

      
        100
        
        -	if c.cfg.Mirror.Enable {

      
        101
        
        -		mirrorer := mirror.NewWorker(c.cfg)

      
        102
        
        -		go func() {

      
        103
        
        -			slog.Info("starting mirroring worker")

      
        104
        
        -			mirrorer.Start(context.TODO())

      
        105
        
        -		}()

      
        
        79
        +func (c *Cli) openRepo(name string) (*git.Repo, error) {

      
        
        80
        +	path, err := securejoin.SecureJoin(c.cfg.Repo.Dir, name)

      
        
        81
        +	if err != nil {

      
        
        82
        +		return nil, err

      
        106
        83
         	}

      
        107
        84
         

      
        108
        
        -	sigChan := make(chan os.Signal, 1)

      
        109
        
        -	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

      
        110
        
        -

      
        111
        
        -	sig := <-sigChan

      
        112
        
        -	slog.Info("received signal, starting graceful shutdown", "signal", sig)

      
        113
        
        -

      
        114
        
        -	if err := httpServer.Shutdown(context.TODO()); err != nil {

      
        115
        
        -		slog.Error("HTTP server shutdown error", "err", err)

      
        116
        
        -	} else {

      
        117
        
        -		slog.Info("HTTP server shutdown complete")

      
        
        85
        +	repo, err := git.Open(path, "")

      
        
        86
        +	if err != nil {

      
        
        87
        +		return nil, fmt.Errorf("failed to open repo: %w", err)

      
        118
        88
         	}

      
        119
        89
         

      
        120
        
        -	return nil

      
        
        90
        +	return repo, nil

      
        121
        91
         }

      
M internal/cli/repo.go
路路路
        48
        48
         

      
        49
        49
         	return nil

      
        50
        50
         }

      
        
        51
        +

      
        
        52
        +func (c *Cli) repoDescriptionAction(ctx context.Context, cmd *cli.Command) error {

      
        
        53
        +	name := cmd.StringArg("name")

      
        
        54
        +	if name == "" {

      
        
        55
        +		return fmt.Errorf("no name provided")

      
        
        56
        +	}

      
        
        57
        +

      
        
        58
        +	name = strings.TrimRight(name, ".git") + ".git"

      
        
        59
        +

      
        
        60
        +	repo, err := c.openRepo(name)

      
        
        61
        +	if err != nil {

      
        
        62
        +		return fmt.Errorf("failed to open repo: %w", err)

      
        
        63
        +	}

      
        
        64
        +

      
        
        65
        +	newDesc := cmd.Args().Get(0)

      
        
        66
        +	if newDesc != "" {

      
        
        67
        +		if err := repo.SetDescription(newDesc); err != nil {

      
        
        68
        +			return fmt.Errorf("failed to set description: %w", err)

      
        
        69
        +		}

      
        
        70
        +	}

      
        
        71
        +

      
        
        72
        +	desc, err := repo.Description()

      
        
        73
        +	if err != nil {

      
        
        74
        +		return fmt.Errorf("failed to get description: %w", err)

      
        
        75
        +	}

      
        
        76
        +

      
        
        77
        +	if desc == "" {

      
        
        78
        +		fmt.Println("No description set")

      
        
        79
        +	} else {

      
        
        80
        +		fmt.Println(desc)

      
        
        81
        +	}

      
        
        82
        +

      
        
        83
        +	return nil

      
        
        84
        +}

      
A internal/cli/serve.go
路路路
        
        1
        +package cli

      
        
        2
        +

      
        
        3
        +import (

      
        
        4
        +	"context"

      
        
        5
        +	"log/slog"

      
        
        6
        +	"net"

      
        
        7
        +	"net/http"

      
        
        8
        +	"os"

      
        
        9
        +	"os/signal"

      
        
        10
        +	"strconv"

      
        
        11
        +	"syscall"

      
        
        12
        +

      
        
        13
        +	"github.com/urfave/cli/v3"

      
        
        14
        +	"olexsmir.xyz/mugit/internal/handlers"

      
        
        15
        +	"olexsmir.xyz/mugit/internal/mirror"

      
        
        16
        +	"olexsmir.xyz/mugit/internal/ssh"

      
        
        17
        +)

      
        
        18
        +

      
        
        19
        +func (c *Cli) serveAction(ctx context.Context, cmd *cli.Command) error {

      
        
        20
        +	httpServer := &http.Server{

      
        
        21
        +		Addr:    net.JoinHostPort(c.cfg.Server.Host, strconv.Itoa(c.cfg.Server.Port)),

      
        
        22
        +		Handler: handlers.InitRoutes(c.cfg),

      
        
        23
        +	}

      
        
        24
        +	go func() {

      
        
        25
        +		slog.Info("starting http server", "host", c.cfg.Server.Host, "port", c.cfg.Server.Port)

      
        
        26
        +		if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {

      
        
        27
        +			slog.Error("HTTP server error", "err", err)

      
        
        28
        +		}

      
        
        29
        +	}()

      
        
        30
        +

      
        
        31
        +	if c.cfg.SSH.Enable {

      
        
        32
        +		sshServer := ssh.NewServer(c.cfg)

      
        
        33
        +		go func() {

      
        
        34
        +			slog.Info("starting ssh server", "port", c.cfg.SSH.Port)

      
        
        35
        +			if err := sshServer.Start(); err != nil {

      
        
        36
        +				slog.Error("ssh server error", "err", err)

      
        
        37
        +			}

      
        
        38
        +		}()

      
        
        39
        +	}

      
        
        40
        +

      
        
        41
        +	if c.cfg.Mirror.Enable {

      
        
        42
        +		mirrorer := mirror.NewWorker(c.cfg)

      
        
        43
        +		go func() {

      
        
        44
        +			slog.Info("starting mirroring worker")

      
        
        45
        +			mirrorer.Start(context.TODO())

      
        
        46
        +		}()

      
        
        47
        +	}

      
        
        48
        +

      
        
        49
        +	sigChan := make(chan os.Signal, 1)

      
        
        50
        +	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

      
        
        51
        +

      
        
        52
        +	sig := <-sigChan

      
        
        53
        +	slog.Info("received signal, starting graceful shutdown", "signal", sig)

      
        
        54
        +

      
        
        55
        +	if err := httpServer.Shutdown(context.TODO()); err != nil {

      
        
        56
        +		slog.Error("HTTP server shutdown error", "err", err)

      
        
        57
        +	} else {

      
        
        58
        +		slog.Info("HTTP server shutdown complete")

      
        
        59
        +	}

      
        
        60
        +

      
        
        61
        +	return nil

      
        
        62
        +}