Skip to content

Commit

Permalink
Merge pull request #27 from Halleck45/feat_watch
Browse files Browse the repository at this point in the history
feat: new --watch option
  • Loading branch information
Halleck45 committed Mar 23, 2024
2 parents d57abeb + 0655bc3 commit c81d892
Show file tree
Hide file tree
Showing 16 changed files with 378 additions and 41 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
Expand All @@ -57,6 +59,7 @@ require (
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
github.com/yuin/goldmark v1.7.0 // indirect
github.com/yuin/goldmark-emoji v1.0.2 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ github.com/evandro-slv/go-cli-charts v0.0.0-20191022204244-4ef8459d5f4d h1:6//xY
github.com/evandro-slv/go-cli-charts v0.0.0-20191022204244-4ef8459d5f4d/go.mod h1:KqPtENPp5GIJlV5oaDkDbakg3lXDUD1VVB9mJDReRLM=
github.com/flosch/pongo2/v5 v5.0.0 h1:ZauMp+iPZzh2aI1QM2UwRb0lXD4BoFcvBuWqefkIuq0=
github.com/flosch/pongo2/v5 v5.0.0/go.mod h1:6ysKu++8ANFXmc3x6uA6iVaS+PKUoDfdX3yPcv8TIzY=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-python/gpython v0.2.0 h1:MW7m7pFnbpzHL88vhAdIhT1pgG1QUZ0Q5jcF94z5MBI=
github.com/go-python/gpython v0.2.0/go.mod h1:fUN4z1X+GFaOwPOoHOAM8MOPnh1NJatWo/cDqGlZDEI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
Expand All @@ -83,6 +85,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 h1:fO9A67/izFYFYky7l1pDP5Dr0BTCRkaQJUG6Jm5ehsk=
github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3/go.mod h1:Ey4uAp+LvIl+s5jRbOHLcZpUDnkjLBROl15fZLwPlTM=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
Expand Down Expand Up @@ -195,6 +199,8 @@ github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GA
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand Down
16 changes: 16 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/halleck45/ast-metrics/src/Engine/Golang"
"github.com/halleck45/ast-metrics/src/Engine/Php"
"github.com/halleck45/ast-metrics/src/Engine/Python"
"github.com/halleck45/ast-metrics/src/Watcher"
"github.com/pterm/pterm"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -69,6 +70,12 @@ func main() {
Usage: "Generate an Markdown report file",
Category: "Report",
},
// Watch mode
&cli.BoolFlag{
Name: "watch",
Usage: "Re-run the analysis when files change",
Category: "Global options",
},
},
Action: func(cCtx *cli.Context) error {

Expand Down Expand Up @@ -130,6 +137,15 @@ func main() {

// Run command
command := Command.NewAnalyzeCommand(configuration, outWriter, runners, isInteractive)

// Watch mode
configuration.Watching = cCtx.Bool("watch")
err = Watcher.NewCommandWatcher(configuration).Start(command)
if err != nil {
pterm.Error.Println("Cannot watch files: " + err.Error())
}

// Execute command
err = command.Execute()
if err != nil {
pterm.Error.Println(err.Error())
Expand Down
5 changes: 5 additions & 0 deletions src/Analyzer/Activity/BusFactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ func (busFactor *BusFactor) Calculate(aggregate *Analyzer.Aggregated) {
files := aggregate.ConcernedFiles
commits := make(map[string]int)
for _, file := range files {

if file.Commits == nil {
continue
}

for _, commit := range file.Commits.Commits {

// Exclude commits with no author or from noreply@github.com
Expand Down
22 changes: 13 additions & 9 deletions src/Cli/ComponentClassTable.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ type ComponentTableClass struct {

// index of cols
var cols = map[string]int{
"Name": 0,
"Commits": 1,
"Authors": 2,
"Methods": 3,
"LLoc": 4,
"Cyclomatic": 5,
"Halstead Length": 6,
"Halstead Volume": 7,
"Maintainability": 8,
"Name": 0,
"Commits": 1,
"Authors": 2,
"Methods": 3,
"LLoc": 4,
"Cyclomatic": 5,
"Halstead Length": 6,
"Halstead Volume": 7,
"Maintainability": 8,
}

func NewComponentTableClass(isInteractive bool, files []*pb.File) *ComponentTableClass {
Expand Down Expand Up @@ -245,6 +245,10 @@ func (v *ComponentTableClass) Update(msg tea.Msg) {
case "n":
v.SortByName()
}
case DoRefreshModel:
// refresh the model
v.files = msg.files
v.Init()
}

v.table, _ = v.table.Update(msg)
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/ComponentFileTable.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (v *ComponentFileTable) Render() string {
func (v *ComponentFileTable) Init() {

columns := []table.Column{
{Title: "File", Width: 75},
{Title: "File", Width: 70},
{Title: "Commits", Width: 9},
{Title: "Authors", Width: 9},
{Title: "LOC", Width: 9},
Expand Down
4 changes: 4 additions & 0 deletions src/Cli/Screen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package Cli

import (
tea "github.com/charmbracelet/bubbletea"
"github.com/halleck45/ast-metrics/src/Analyzer"
pb "github.com/halleck45/ast-metrics/src/NodeType"
)

type Screen interface {
Expand All @@ -11,4 +13,6 @@ type Screen interface {

// Returns the name of the screen
GetScreenName() string

Reset(files []*pb.File, projectAggregated Analyzer.ProjectAggregated)
}
9 changes: 9 additions & 0 deletions src/Cli/ScreenByProgrammingLangage.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func (m modelByProgrammingLanguage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "q", "ctrl+c", "esc":
return NewScreenHome(true, m.files, m.projectAggregated).GetModel(), tea.ClearScreen
}
case DoRefreshModel:
// refresh the model
m.files = msg.files
m.projectAggregated = msg.projectAggregated
}

m.componentTableClass.Update(msg)
Expand All @@ -53,6 +57,11 @@ func (m modelByProgrammingLanguage) View() string {
"\n\n" + m.componentTableClass.Render()).Render()
}

func (v *ScreenByProgrammingLanguage) Reset(files []*pb.File, projectAggregated Analyzer.ProjectAggregated) {
v.files = files
v.projectAggregated = projectAggregated
}

func (v ScreenByProgrammingLanguage) GetScreenName() string {
// @todo use dynamic emoji
emoji := " "
Expand Down
77 changes: 69 additions & 8 deletions src/Cli/ScreenHome.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

tea "github.com/charmbracelet/bubbletea"
"github.com/fsnotify/fsnotify"
"github.com/halleck45/ast-metrics/src/Analyzer"
pb "github.com/halleck45/ast-metrics/src/NodeType"
"github.com/muesli/termenv"
Expand All @@ -20,6 +21,13 @@ type ScreenHome struct {
isInteractive bool
files []*pb.File
projectAggregated Analyzer.ProjectAggregated
// program
tea *tea.Program
// modelChoices
modelChoices modelChoices
// watchers
FileWatcher *fsnotify.Watcher
currentModel tea.Model
}

// modelChoices is the model for the home view
Expand All @@ -30,6 +38,14 @@ type modelChoices struct {

// array of screens
screens []Screen

// Watcher
FileWatcher *fsnotify.Watcher
}

type DoRefreshModel struct {
files []*pb.File
projectAggregated Analyzer.ProjectAggregated
}

// NewScreenHome creates a new ScreenHome
Expand All @@ -42,25 +58,55 @@ func NewScreenHome(isInteractive bool, files []*pb.File, projectAggregated Analy
}

// Render renders the home view and runs the Tea program
func (r ScreenHome) Render() {
func (r *ScreenHome) Render() {

if r.tea != nil {
// If already running, just return
// send an update msg
//r.tea.Send(DoRefreshModel{files: r.files, projectAggregated: r.projectAggregated})
return
}

// Prepare list of accepted screens
m := modelChoices{files: r.files, projectAggregated: r.projectAggregated}
m := modelChoices{files: r.files, projectAggregated: r.projectAggregated, FileWatcher: r.FileWatcher}
fillInScreens(&m)
r.currentModel = m

if !r.isInteractive {
// If not interactive
fmt.Println("No interactive mode detected. Please use the reports options (--report-html=<path>) to visualize the results.")
fmt.Println("No interactive mode detected.")
return
}

options := tea.WithAltScreen()
if _, err := tea.NewProgram(m, options).Run(); err != nil {
r.tea = tea.NewProgram(m, options)
if _, err := r.tea.Run(); err != nil {
fmt.Println("Error running program:", err)
r.tea.RestoreTerminal()
os.Exit(1)
}
}

func (r *ScreenHome) Reset(files []*pb.File, projectAggregated Analyzer.ProjectAggregated) {

r.files = files
r.projectAggregated = projectAggregated

// Update all screens
for _, s := range r.modelChoices.screens {
s.Reset(files, projectAggregated)
}

if r.tea == nil {
return
}

// Send update command to tea application
// @todo : traiter sur tous les écrans
r.tea.Send(DoRefreshModel{files: files, projectAggregated: projectAggregated})
r.currentModel.Update(DoRefreshModel{files: files, projectAggregated: projectAggregated})
}

// Get Tea model
func (r ScreenHome) GetModel() modelChoices {

Expand All @@ -75,7 +121,8 @@ func (r ScreenHome) GetModel() modelChoices {
func fillInScreens(modelChoices *modelChoices) {

if len(modelChoices.screens) > 0 {
return
// we need to refresh screen only when --watch is set
// return
}

// Create the table screen
Expand All @@ -86,8 +133,8 @@ func fillInScreens(modelChoices *modelChoices) {

// Create the screen list
modelChoices.screens = []Screen{
summaryScreen,
viewTableClass,
&summaryScreen,
&viewTableClass,
}

// Append one screen per programming language
Expand All @@ -98,7 +145,7 @@ func fillInScreens(modelChoices *modelChoices) {
viewByProgrammingLanguage.files = modelChoices.files
viewByProgrammingLanguage.projectAggregated = modelChoices.projectAggregated

modelChoices.screens = append(modelChoices.screens, viewByProgrammingLanguage)
modelChoices.screens = append(modelChoices.screens, &viewByProgrammingLanguage)
}
}

Expand Down Expand Up @@ -139,6 +186,12 @@ func (m modelChoices) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if msg, ok := msg.(tea.KeyMsg); ok {
k := msg.String()
if k == "q" || k == "esc" || k == "ctrl+c" {

// Check if we have a file watcher
if m.FileWatcher != nil {
m.FileWatcher.Close()
}

return m, tea.Quit
}
}
Expand All @@ -147,6 +200,14 @@ func (m modelChoices) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
fillInScreens(&m)

switch msg := msg.(type) {
case DoRefreshModel:
// refresh the model, and the models of the sub screens
m.files = msg.files
m.projectAggregated = msg.projectAggregated
for _, s := range m.screens {
s.GetModel().Update(msg)
}

case tea.KeyMsg:
switch msg.String() {
case "j", "down":
Expand Down
10 changes: 10 additions & 0 deletions src/Cli/ScreenSummary.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,23 @@ func (m modelScreenSummary) Init() tea.Cmd {
return nil
}

func (m *ScreenSummary) Reset(files []*pb.File, projectAggregated Analyzer.ProjectAggregated) {
m.files = files
m.projectAggregated = projectAggregated
}

func (m modelScreenSummary) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c", "esc":
return NewScreenHome(true, m.files, m.projectAggregated).GetModel(), tea.ClearScreen
}
case DoRefreshModel:
// refresh the model
m.files = msg.files
m.projectAggregated = msg.projectAggregated
return m, nil
}
return m, nil
}
Expand Down
9 changes: 9 additions & 0 deletions src/Cli/ScreenTableClass.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "q", "ctrl+c", "esc":
return NewScreenHome(true, m.files, m.projectAggregated).GetModel(), tea.ClearScreen
}
case DoRefreshModel:
// refresh the model
m.files = msg.files
m.projectAggregated = msg.projectAggregated
}

m.table.Update(msg)
Expand All @@ -52,6 +56,11 @@ func (v ScreenTableClass) GetScreenName() string {
return "Classes and object oriented statistics"
}

func (v *ScreenTableClass) Reset(files []*pb.File, projectAggregated Analyzer.ProjectAggregated) {
v.files = files
v.projectAggregated = projectAggregated
}

func (v ScreenTableClass) GetModel() tea.Model {
table := NewComponentTableClass(v.isInteractive, v.files)
m := model{table: table, sortColumnIndex: 0, files: v.files, projectAggregated: v.projectAggregated}
Expand Down

0 comments on commit c81d892

Please sign in to comment.