diff --git a/go.mod b/go.mod index 9acb656..fdb399f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,14 @@ module git.entr0py.de/garionion/murphy go 1.17 require ( + github.com/go-co-op/gocron v1.10.0 + github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b github.com/karrick/godirwalk v1.16.1 github.com/mehdioa/nlog v0.0.0-20210327090009-d60bf476a16a github.com/oriser/regroup v0.0.0-20210730155327-fca8d7531263 ) + +require ( + github.com/robfig/cron/v3 v3.0.1 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect +) diff --git a/go.sum b/go.sum index 66fb477..4147988 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-co-op/gocron v1.10.0 h1:m7J8SdUSXLzmxA97ZAmd898Z9lxedoL657mOJHHKoBY= +github.com/go-co-op/gocron v1.10.0/go.mod h1:qtlsoMpHlSdIZ3E/xuZzrrAbeX3u5JtPvWf2TcdutU0= +github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4= +github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/mehdioa/nlog v0.0.0-20210327090009-d60bf476a16a h1:p/otnVjZSfec48nsELzyGDwoAMtD+xoG8a6c5TW8Fuw= @@ -9,10 +13,15 @@ github.com/oriser/regroup v0.0.0-20210730155327-fca8d7531263 h1:Qd1Ml+uEhpesT8Og github.com/oriser/regroup v0.0.0-20210730155327-fca8d7531263/go.mod h1:odkMeLkWS8G6+WP2z3Pn2vkzhPSvBtFhAUYTKXAtZMQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 31c5551..1be26e2 100644 --- a/main.go +++ b/main.go @@ -5,19 +5,21 @@ import ( "git.entr0py.de/garionion/murphy/store" "github.com/mehdioa/nlog" "sync" + "time" ) var log *nlog.Logger const source = "/mnt/clarkson" +const gracePeriod = time.Hour * 24 * 30 func main() { formatter := nlog.NewTextFormatter(true, true) log = nlog.NewLogger(nlog.DebugLevel, formatter) + sourcePaths := []string{source} + s := store.NewStore(log, sourcePaths, gracePeriod) - s := store.NewStore(log) - - scanner.InitScanner(s, source) + scanner.InitScanner(s) wg := new(sync.WaitGroup) wg.Add(2) diff --git a/scanner/scanner.go b/scanner/scanner.go index 2429acb..f3b6b8c 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -2,16 +2,50 @@ package scanner import ( "git.entr0py.de/garionion/murphy/store" + "github.com/go-co-op/gocron" + "github.com/hako/durafmt" "github.com/karrick/godirwalk" "github.com/mehdioa/nlog" "github.com/oriser/regroup" "io/ioutil" "os" "path" + "sync" "time" ) -func scan(p *store.Project) { +func CheckProjects(s *store.Store) { + wg := new(sync.WaitGroup) + for _, source := range s.SourcePath { + wg.Add(1) + go func(source string) { + rootScanner(source, s.GetProjects(), s.Logger, wg) + wg.Done() + }(source) + } + wg.Wait() + + projects := make(map[string]*store.Project) + for _, project := range s.GetProjects() { + if project.LastChange.Add(s.GracePeriod).Before(time.Now()) { + project.Logger.Infof("Project %s was not touched in %v ", project.ProjectName, durafmt.Parse(time.Now().Sub(project.LastChange)).LimitFirstN(2)) + wg.Add(1) + go scan(project, wg) + projects[project.ProjectName] = project + } + } + wg.Wait() + for _, project := range projects { + if project.LastChange.Add(s.GracePeriod).Before(time.Now()) { + project.ShouldMove = true + project.Logger.Infof("Marked Project to be moved") + } + } + //TODO: inform users that projects will be moved +} + +func scan(p *store.Project, group *sync.WaitGroup) { + defer group.Done() log := p.Logger log.Infof("Scanning %s", p.ProjectName) lastModified := time.Time{} @@ -33,25 +67,46 @@ func scan(p *store.Project) { if err != nil { log.Errorf("Error scanning %s: %v", p.ProjectName, err) } - log.Infof("Found last modification time %v", lastModified) + log.Debugf("Found last modification time %v", lastModified) p.LastChange = lastModified } -func NewProject(target, projectName string, createdAt time.Time, logger *nlog.Logger) *store.Project { +func NewProject(target, projectName string, createdAt time.Time, logger *nlog.Logger, wg *sync.WaitGroup) *store.Project { projectLogger := logger.New("Project", nlog.Data{"Project": projectName}) project := &store.Project{TargetPath: target, Created: createdAt, ProjectName: projectName, Logger: projectLogger} - go scan(project) + wg.Add(1) + go scan(project, wg) return project } -func InitScanner(s *store.Store, sourcePath string) { +func InitScanner(s *store.Store) { s.Logger.Infof("Initializing scanner") projects := s.GetProjects() - rootScanner(sourcePath, projects, s.Logger) + wg := new(sync.WaitGroup) + + for _, source := range s.SourcePath { + wg.Add(1) + go func(source string) { + rootScanner(source, projects, s.Logger, wg) + wg.Done() + }(source) + } + wg.Wait() + s.Logger.Infof("Found %d projects", len(projects)) + scheduler := gocron.NewScheduler(time.Local) + _, err := scheduler.Every(1).Day().At("08:00:00").Do(func() { + CheckProjects(s) + }) + if err != nil { + s.Logger.Errorf("Failed to create Scheduler", err) + } + scheduler.StartImmediately() + scheduler.StartAsync() + s.Scheduler = scheduler } -func rootScanner(rootPath string, projects map[string]*store.Project, logger *nlog.Logger) { +func rootScanner(rootPath string, projects map[string]*store.Project, logger *nlog.Logger, wg *sync.WaitGroup) { resorts, err := ioutil.ReadDir(rootPath) if err != nil { logger.Errorf("Error reading directory %s: %v", rootPath, err) @@ -90,7 +145,7 @@ func rootScanner(rootPath string, projects map[string]*store.Project, logger *nl logger.Errorf("Failed to parse date %s: %v, Using Null-Time for %s", createdAtString, err, p.Name()) createdAt = time.Time{} } - scanner := NewProject(projectPath, projectName, createdAt, logger) + scanner := NewProject(projectPath, projectName, createdAt, logger, wg) projects[p.Name()] = scanner } else { logger.Debugf("Ignoring Directory %s", projectPath) diff --git a/store/store.go b/store/store.go index 614799c..ac47d0f 100644 --- a/store/store.go +++ b/store/store.go @@ -1,6 +1,7 @@ package store import ( + "github.com/go-co-op/gocron" "github.com/mehdioa/nlog" "sync" "time" @@ -12,6 +13,7 @@ type Store struct { GracePeriod time.Duration Projects map[string]*Project Logger *nlog.Logger + Scheduler *gocron.Scheduler lock sync.RWMutex } @@ -20,12 +22,12 @@ type Project struct { LastChange time.Time Created time.Time ProjectName string + ShouldMove bool Logger *nlog.Node } -func NewStore(Logger *nlog.Logger) *Store { - store := &Store{Logger: Logger, Projects: make(map[string]*Project)} - +func NewStore(Logger *nlog.Logger, sourcePath []string, gracePeriod time.Duration) *Store { + store := &Store{Logger: Logger, Projects: make(map[string]*Project), SourcePath: sourcePath, GracePeriod: gracePeriod} return store }