mirror of
https://github.com/Adembc/lazyssh.git
synced 2026-07-14 12:13:34 +02:00
add makefile
This commit is contained in:
+1
-1
@@ -32,4 +32,4 @@ go.work.sum
|
||||
# .vscode/
|
||||
brainstorm
|
||||
.idea
|
||||
lazyssh
|
||||
bin
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
allow-parallel-runners: true
|
||||
|
||||
issues:
|
||||
# disable the default set of exclude rules
|
||||
exclude-use-default: false
|
||||
|
||||
exclude-rules:
|
||||
# disable some linters for api packages
|
||||
- path: "api/*"
|
||||
linters:
|
||||
- lll
|
||||
|
||||
# disable some linters for internal packages
|
||||
- path: "internal/*"
|
||||
linters:
|
||||
- dupl
|
||||
- lll
|
||||
|
||||
# exclude some linters for the test directory and test files
|
||||
- path: test/.*|.*_test\.go
|
||||
linters:
|
||||
- dupl
|
||||
- errcheck
|
||||
- goconst
|
||||
- gocyclo
|
||||
- gosec
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- copyloopvar
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- ginkgolinter
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goheader
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- revive
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
|
||||
linters-settings:
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- experimental
|
||||
- opinionated
|
||||
- performance
|
||||
- style
|
||||
disabled-checks:
|
||||
- assignOp
|
||||
- filepathJoin
|
||||
- paramTypeCombine
|
||||
- rangeValCopy
|
||||
- unnamedResult
|
||||
- whyNoLint
|
||||
|
||||
goimports:
|
||||
local-prefixes: github.com/kubeflow/notebooks/workspaces/backend
|
||||
|
||||
goheader:
|
||||
template: |-
|
||||
Copyright 2024.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
revive:
|
||||
rules:
|
||||
- name: comment-spacings
|
||||
+11
-4
@@ -2,18 +2,25 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/adapters/data/memory"
|
||||
"github.com/Adembc/lazyssh/internal/adapters/ui"
|
||||
"github.com/Adembc/lazyssh/internal/core/services"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "develop"
|
||||
gitCommit = "unknown"
|
||||
buildTime = time.Now().Format("2006-01-02 15:04:05")
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
serverInMemoryRepo := memory.NewServerRepository()
|
||||
serverService := services.NewServerService(serverInMemoryRepo)
|
||||
tui := ui.NewTUI(serverService)
|
||||
tui := ui.NewTUI(serverService, version, gitCommit, buildTime)
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: ui.AppName,
|
||||
@@ -25,7 +32,7 @@ func main() {
|
||||
rootCmd.SilenceUsage = true
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ go 1.24.4
|
||||
require (
|
||||
github.com/gdamore/tcell/v2 v2.8.1
|
||||
github.com/rivo/tview v0.0.0-20250625164341-a4a78f1e05cb
|
||||
github.com/spf13/cobra v1.9.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -13,9 +14,8 @@ require (
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/term v0.34.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
)
|
||||
|
||||
@@ -58,8 +58,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -68,8 +69,9 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@@ -78,8 +80,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
)
|
||||
|
||||
type serverRepository struct {
|
||||
}
|
||||
type serverRepository struct{}
|
||||
|
||||
var servers = []domain.Server{
|
||||
{Alias: "web-01", Host: "192.168.1.10", User: "root", Port: 22, Key: "~/.ssh/id_rsa", Tags: []string{"prod", "web"}, Status: "online", LastSeen: time.Now().Add(-2 * time.Hour)},
|
||||
@@ -58,7 +58,6 @@ func (r *serverRepository) ListServers(query string) ([]domain.Server, error) {
|
||||
}
|
||||
}
|
||||
return filteredServers, nil
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// UpdateServer updates an existing server with new details.
|
||||
|
||||
@@ -4,7 +4,6 @@ import "time"
|
||||
|
||||
const (
|
||||
AppName = "lazyssh"
|
||||
AppVersion = "v0.0.1"
|
||||
RepoURL = "github.com/adembc/lazyssh"
|
||||
SplashScreenDuration = 1 * time.Second
|
||||
Banner = `
|
||||
|
||||
@@ -2,6 +2,7 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
@@ -87,10 +88,10 @@ func (t *tui) handleServerEdit() {
|
||||
func (t *tui) handleServerSave(server domain.Server, original *domain.Server) {
|
||||
if original != nil {
|
||||
// Edit mode
|
||||
t.serverService.UpdateServer(*original, server)
|
||||
_ = t.serverService.UpdateServer(*original, server)
|
||||
} else {
|
||||
// Add mode
|
||||
t.serverService.AddServer(server)
|
||||
_ = t.serverService.AddServer(server)
|
||||
}
|
||||
|
||||
t.refreshServerList()
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type AppHeader struct {
|
||||
*tview.Flex
|
||||
version string
|
||||
repoURL string
|
||||
version string
|
||||
buildTime string
|
||||
gitCommit string
|
||||
repoURL string
|
||||
}
|
||||
|
||||
func NewAppHeader(version, repoURL string) *AppHeader {
|
||||
func NewAppHeader(version, gitCommit, buildTime, repoURL string) *AppHeader {
|
||||
header := &AppHeader{
|
||||
Flex: tview.NewFlex(),
|
||||
version: version,
|
||||
repoURL: repoURL,
|
||||
Flex: tview.NewFlex(),
|
||||
version: version,
|
||||
repoURL: repoURL,
|
||||
buildTime: buildTime,
|
||||
gitCommit: gitCommit,
|
||||
}
|
||||
header.build()
|
||||
return header
|
||||
@@ -57,7 +62,24 @@ func (h *AppHeader) buildCenterSection(bg tcell.Color) *tview.TextView {
|
||||
SetDynamicColors(true).
|
||||
SetTextAlign(tview.AlignCenter)
|
||||
center.SetBackgroundColor(bg)
|
||||
center.SetText("[black:#2ECC71::b] " + h.version + " [-] [black:#3B82F6::b] TUI [-]")
|
||||
|
||||
commit := shortCommit(h.gitCommit)
|
||||
|
||||
// Build tag-like chips for version, commit, and build time
|
||||
versionTag := makeTag(h.version, "#22C55E") // green
|
||||
commitTag := ""
|
||||
if commit != "" {
|
||||
commitTag = makeTag(commit, "#A78BFA") // violet
|
||||
}
|
||||
timeTag := makeTag(formatBuildTime(h.buildTime), "#3B82F6") // blue
|
||||
|
||||
text := versionTag
|
||||
if commitTag != "" {
|
||||
text += " " + commitTag
|
||||
}
|
||||
text += " " + timeTag
|
||||
|
||||
center.SetText(text)
|
||||
return center
|
||||
}
|
||||
|
||||
@@ -77,3 +99,48 @@ func (h *AppHeader) createSeparator() *tview.TextView {
|
||||
separator.SetText("[#444444]" + strings.Repeat("─", 200) + "[-]")
|
||||
return separator
|
||||
}
|
||||
|
||||
// shortCommit returns first 7 chars of commit if it looks valid; otherwise empty string.
|
||||
func shortCommit(c string) string {
|
||||
c = strings.TrimSpace(c)
|
||||
if c == "" || c == "unknown" || c == "(devel)" {
|
||||
return ""
|
||||
}
|
||||
if len(c) > 7 {
|
||||
return c[:7]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// formatBuildTime tries to parse common time formats and returns a concise human-readable string.
|
||||
func formatBuildTime(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return "unknown"
|
||||
}
|
||||
layouts := []string{
|
||||
"2006-01-02 15:04:05",
|
||||
time.RFC3339,
|
||||
time.RFC1123,
|
||||
time.RFC1123Z,
|
||||
}
|
||||
var t time.Time
|
||||
var err error
|
||||
for _, l := range layouts {
|
||||
t, err = time.Parse(l, s)
|
||||
if err == nil {
|
||||
return t.Format("Mon, 02 Jan 2006 15:04")
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// makeTag returns a rectangular-looking colored chip for the given text.
|
||||
func makeTag(text, bg string) string {
|
||||
text = strings.TrimSpace(text)
|
||||
if text == "" {
|
||||
return ""
|
||||
}
|
||||
return "[black:" + bg + "::b] " + text + " [-]"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
|
||||
@@ -2,12 +2,13 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type ServerFormMode int
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
// buildSplash creates a splash screen with a spinner; returns primitive and a stop function
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/core/ports"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
"time"
|
||||
)
|
||||
|
||||
type tui struct {
|
||||
version string
|
||||
commit string
|
||||
buildDate string
|
||||
|
||||
app *tview.Application
|
||||
serverService ports.ServerService
|
||||
|
||||
@@ -25,21 +30,23 @@ type tui struct {
|
||||
searchVisible bool
|
||||
}
|
||||
|
||||
func NewTUI(ss ports.ServerService) *tui {
|
||||
func NewTUI(ss ports.ServerService, version, commit, buildDate string) *tui {
|
||||
return &tui{
|
||||
app: tview.NewApplication(),
|
||||
serverService: ss,
|
||||
version: version,
|
||||
commit: commit,
|
||||
buildDate: buildDate,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (t *tui) Run() error {
|
||||
|
||||
t.app.EnableMouse(true)
|
||||
t.initializeTheme().buildComponents().buildLayout().bindEvents().loadInitialData().loadSplashScreen()
|
||||
|
||||
return t.app.Run()
|
||||
}
|
||||
|
||||
func (t *tui) initializeTheme() *tui {
|
||||
tview.Styles.PrimitiveBackgroundColor = tcell.Color232
|
||||
tview.Styles.ContrastBackgroundColor = tcell.Color235
|
||||
@@ -51,8 +58,9 @@ func (t *tui) initializeTheme() *tui {
|
||||
tview.Styles.GraphicsColor = tcell.Color238
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *tui) buildComponents() *tui {
|
||||
t.header = NewAppHeader(AppVersion, RepoURL)
|
||||
t.header = NewAppHeader(t.version, t.commit, t.buildDate, RepoURL)
|
||||
t.searchBar = NewSearchBar().
|
||||
OnSearch(t.handleSearchInput).
|
||||
OnEscape(t.hideSearchBar)
|
||||
@@ -63,8 +71,8 @@ func (t *tui) buildComponents() *tui {
|
||||
t.statusBar = NewStatusBar()
|
||||
return t
|
||||
}
|
||||
func (t *tui) buildLayout() *tui {
|
||||
|
||||
func (t *tui) buildLayout() *tui {
|
||||
t.left = tview.NewFlex().SetDirection(tview.FlexRow).
|
||||
AddItem(t.hintBar, 1, 0, false).
|
||||
AddItem(t.serverList, 0, 1, true)
|
||||
@@ -82,10 +90,12 @@ func (t *tui) buildLayout() *tui {
|
||||
AddItem(t.statusBar, 1, 0, false)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *tui) bindEvents() *tui {
|
||||
t.root.SetInputCapture(t.handleGlobalKeys)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *tui) loadInitialData() *tui {
|
||||
servers, _ := t.serverService.ListServers("")
|
||||
t.serverList.UpdateServers(servers)
|
||||
@@ -103,5 +113,4 @@ func (t *tui) loadSplashScreen() *tui {
|
||||
})
|
||||
})
|
||||
return t
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Adembc/lazyssh/internal/core/domain"
|
||||
)
|
||||
|
||||
func statusIcon(s string) string {
|
||||
|
||||
@@ -18,7 +18,6 @@ func NewServerService(sr ports.ServerRepository) *serverService {
|
||||
|
||||
// ListServers returns a list of servers.
|
||||
func (s *serverService) ListServers(query string) ([]domain.Server, error) {
|
||||
|
||||
// do any relevant business logic here if needed
|
||||
servers, err := s.serverRepository.ListServers(query)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,4 +1,210 @@
|
||||
build:
|
||||
go build -o lazyssh ./cmd
|
||||
run:
|
||||
go run ./cmd
|
||||
# Makefile for LazySSH project
|
||||
|
||||
##@ General
|
||||
|
||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||
ifeq (,$(shell go env GOBIN))
|
||||
GOBIN=$(shell go env GOPATH)/bin
|
||||
else
|
||||
GOBIN=$(shell go env GOBIN)
|
||||
endif
|
||||
|
||||
# Setting SHELL to bash allows bash commands to be executed by recipes.
|
||||
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
|
||||
SHELL = /usr/bin/env bash -o pipefail
|
||||
.SHELLFLAGS = -ec
|
||||
|
||||
# Default target
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# Project variables
|
||||
PROJECT_NAME ?= $(shell basename $(CURDIR))
|
||||
VERSION ?= v0.0.1
|
||||
BUILD_TIME ?= $(shell date -u '+%Y-%m-%d_%H:%M:%S')
|
||||
GIT_COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||||
|
||||
# Build variables
|
||||
BINARY_NAME ?= lazyssh
|
||||
OUTPUT_DIR ?= ./bin
|
||||
CMD_DIR ?= ./cmd
|
||||
PKG_LIST := $(shell go list ./...)
|
||||
|
||||
# LDFLAGS for version information
|
||||
LDFLAGS = -ldflags "-X main.version=$(VERSION) -X main.buildTime=$(BUILD_TIME) -X main.gitCommit=$(GIT_COMMIT)"
|
||||
|
||||
##@ Dependencies
|
||||
|
||||
## Location to install dependencies to
|
||||
LOCALBIN ?= $(shell pwd)/bin
|
||||
$(LOCALBIN):
|
||||
mkdir -p $(LOCALBIN)
|
||||
|
||||
# Tool versions
|
||||
GOLANGCI_LINT_VERSION ?= v1.61.0
|
||||
GOFUMPT_VERSION ?= v0.7.0
|
||||
STATICCHECK_VERSION ?= 2024.1.1
|
||||
|
||||
# Tool binaries
|
||||
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
|
||||
GOFUMPT = $(LOCALBIN)/gofumpt
|
||||
STATICCHECK = $(LOCALBIN)/staticcheck
|
||||
|
||||
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
|
||||
# $1 - target path with name of binary
|
||||
# $2 - package url which can be installed
|
||||
# $3 - specific version of package
|
||||
define go-install-tool
|
||||
@[ -f "$(1)-$(3)" ] || { \
|
||||
set -e; \
|
||||
package=$(2)@$(3) ;\
|
||||
echo "Downloading $${package}" ;\
|
||||
rm -f $(1) || true ;\
|
||||
GOBIN=$(LOCALBIN) go install $${package} ;\
|
||||
mv $(1) $(1)-$(3) ;\
|
||||
} ;\
|
||||
ln -sf $(1)-$(3) $(1)
|
||||
endef
|
||||
|
||||
.PHONY: tools
|
||||
tools: golangci-lint gofumpt staticcheck ## Install all development tools
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary
|
||||
$(GOLANGCI_LINT): $(LOCALBIN)
|
||||
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
|
||||
|
||||
.PHONY: gofumpt
|
||||
gofumpt: $(GOFUMPT) ## Download gofumpt locally if necessary
|
||||
$(GOFUMPT): $(LOCALBIN)
|
||||
$(call go-install-tool,$(GOFUMPT),mvdan.cc/gofumpt,$(GOFUMPT_VERSION))
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck: $(STATICCHECK) ## Download staticcheck locally if necessary
|
||||
$(STATICCHECK): $(LOCALBIN)
|
||||
$(call go-install-tool,$(STATICCHECK),honnef.co/go/tools/cmd/staticcheck,$(STATICCHECK_VERSION))
|
||||
|
||||
##@ Development
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: gofumpt ## Format Go code
|
||||
$(GOFUMPT) -l -w .
|
||||
go fmt ./...
|
||||
|
||||
.PHONY: vet
|
||||
vet: ## Run go vet against code
|
||||
go vet ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint ## Run golangci-lint linter
|
||||
$(GOLANGCI_LINT) run
|
||||
|
||||
.PHONY: lint-fix
|
||||
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
|
||||
$(GOLANGCI_LINT) run --fix
|
||||
|
||||
.PHONY: check
|
||||
check: staticcheck ## Run staticcheck analyzer
|
||||
$(STATICCHECK) ./...
|
||||
|
||||
.PHONY: quality
|
||||
quality: fmt vet ## Run all code quality checks (i will add lint and check)
|
||||
|
||||
##@ Testing
|
||||
|
||||
.PHONY: test
|
||||
test: ## Run unit tests
|
||||
go test -race -coverprofile=coverage.out ./...
|
||||
|
||||
.PHONY: test-verbose
|
||||
test-verbose: ## Run unit tests with verbose output
|
||||
go test -race -v -coverprofile=coverage.out ./...
|
||||
|
||||
.PHONY: test-short
|
||||
test-short: ## Run unit tests (short mode)
|
||||
go test -race -short ./...
|
||||
|
||||
.PHONY: coverage
|
||||
coverage: test ## Run tests and show coverage
|
||||
go tool cover -html=coverage.out -o coverage.html
|
||||
@echo "Coverage report generated: coverage.html"
|
||||
|
||||
.PHONY: benchmark
|
||||
benchmark: ## Run benchmarks
|
||||
go test -bench=. -benchmem ./...
|
||||
|
||||
##@ Building
|
||||
|
||||
.PHONY: deps
|
||||
deps: ## Download dependencies
|
||||
go mod download
|
||||
go mod verify
|
||||
|
||||
.PHONY: tidy
|
||||
tidy: ## Tidy up dependencies
|
||||
go mod tidy
|
||||
|
||||
.PHONY: build
|
||||
build: quality $(OUTPUT_DIR) ## Build binary
|
||||
go build $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME) $(CMD_DIR)
|
||||
|
||||
.PHONY: build-all
|
||||
build-all: quality $(OUTPUT_DIR) ## Build binaries for all platforms
|
||||
GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME)-linux-amd64 $(CMD_DIR)
|
||||
GOOS=linux GOARCH=arm64 go build $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME)-linux-arm64 $(CMD_DIR)
|
||||
GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME)-darwin-amd64 $(CMD_DIR)
|
||||
GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME)-darwin-arm64 $(CMD_DIR)
|
||||
GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME)-windows-amd64.exe $(CMD_DIR)
|
||||
|
||||
.PHONY: install
|
||||
install: build ## Install binary to GOBIN
|
||||
cp $(OUTPUT_DIR)/$(BINARY_NAME) $(GOBIN)/
|
||||
|
||||
$(OUTPUT_DIR):
|
||||
mkdir -p $(OUTPUT_DIR)
|
||||
|
||||
##@ Running
|
||||
|
||||
.PHONY: run
|
||||
run: ## Run application from source
|
||||
go run $(CMD_DIR)/main.go
|
||||
|
||||
.PHONY: run-race
|
||||
run-race: ## Run application from source with race detector
|
||||
go run -race $(CMD_DIR)/main.go
|
||||
|
||||
##@ Maintenance
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Clean build artifacts and caches
|
||||
go clean -cache -testcache -modcache
|
||||
rm -rf $(OUTPUT_DIR)
|
||||
rm -rf $(LOCALBIN)
|
||||
rm -f coverage.out coverage.html
|
||||
|
||||
.PHONY: clean-build
|
||||
clean-build: ## Clean only build artifacts
|
||||
rm -rf $(OUTPUT_DIR)
|
||||
rm -f coverage.out coverage.html
|
||||
|
||||
.PHONY: update-deps
|
||||
update-deps: ## Update all dependencies
|
||||
go get -u ./...
|
||||
go mod tidy
|
||||
|
||||
.PHONY: security
|
||||
security: ## Run security checks
|
||||
go list -json -deps ./... | grep -v "$$GOROOT" | jq -r '.Module | select(.Path != null) | .Path' | sort -u | xargs go list -json -m | jq -r 'select(.Replace == null) | "\(.Path)@\(.Version)"' | xargs -I {} sh -c 'echo "Checking {}" && go list -json -m {} | jq -r .Dir' >/dev/null
|
||||
|
||||
.PHONY: version
|
||||
version: ## Display version information
|
||||
@echo "Project: $(PROJECT_NAME)"
|
||||
@echo "Version: $(VERSION)"
|
||||
@echo "Build Time: $(BUILD_TIME)"
|
||||
@echo "Git Commit: $(GIT_COMMIT)"
|
||||
@echo "Go Version: $(shell go version)"
|
||||
|
||||
##@ Help
|
||||
|
||||
.PHONY: help
|
||||
help: ## Display this help
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
Reference in New Issue
Block a user