216 lines
6.0 KiB
Go
216 lines
6.0 KiB
Go
package projecttxt
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type ProjectList struct {
|
|
Projects []*Project `json:"projects"`
|
|
}
|
|
|
|
func NewProjectList() *ProjectList {
|
|
return &ProjectList{}
|
|
}
|
|
|
|
func (projectlist *ProjectList) Size() int {
|
|
return len(projectlist.Projects)
|
|
}
|
|
|
|
func (projectlist *ProjectList) GetProjectSlice() []*Project {
|
|
return projectlist.Projects
|
|
}
|
|
|
|
func (projectlist *ProjectList) GetProjectsWithContext(context string) *ProjectList {
|
|
return projectlist.Filter(func(p *Project) bool {
|
|
return p.HasContext(context)
|
|
})
|
|
}
|
|
|
|
func (projectlist *ProjectList) GetProjectsWithProjectTag(projectTag string) *ProjectList {
|
|
return projectlist.Filter(func(p *Project) bool {
|
|
return p.HasProjectTag(projectTag)
|
|
})
|
|
}
|
|
|
|
// Filter filters the current TimerList for the given predicate (a function that takes a timer as input and returns a
|
|
// bool), and returns a new ProjectList. The original ProjectList is not modified.
|
|
func (projectlist *ProjectList) Filter(predicate func(*Project) bool) *ProjectList {
|
|
var newList ProjectList
|
|
for _, t := range projectlist.Projects {
|
|
if predicate(t) {
|
|
newList.AddProject(t)
|
|
}
|
|
}
|
|
return &newList
|
|
}
|
|
|
|
// AddProject prepends a Project to the current ProjectList and takes care to set the ProjectId correctly
|
|
func (projectlist *ProjectList) AddProject(project *Project) {
|
|
// The new project will be id 1
|
|
project.Id = 1
|
|
// All other projects get their id incremented
|
|
for _, p := range projectlist.Projects {
|
|
p.Id++
|
|
}
|
|
// Now prepend the project to the slice
|
|
projectlist.Projects = append(projectlist.Projects, &Project{})
|
|
copy(projectlist.Projects[1:], projectlist.Projects[0:])
|
|
projectlist.Projects[0] = project
|
|
}
|
|
|
|
// GetProject returns the Project with the given project 'id' form the ProjectList.
|
|
// Returns an error if Project could not be found.
|
|
func (projectlist *ProjectList) GetProject(id int) (*Project, error) {
|
|
for i := range projectlist.Projects {
|
|
if projectlist.Projects[i].Id == id {
|
|
return projectlist.Projects[i], nil
|
|
}
|
|
}
|
|
return nil, errors.New("project not found")
|
|
}
|
|
|
|
// RemoveProjectById removes any Project with given Project 'id' from the ProjectList.
|
|
// Returns an error if no Project was removed.
|
|
func (projectlist *ProjectList) RemoveProjectById(id int) error {
|
|
var newList ProjectList
|
|
found := false
|
|
for _, p := range projectlist.Projects {
|
|
if p.Id != id {
|
|
newList.AddProject(p)
|
|
} else {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
return errors.New("project not found")
|
|
}
|
|
*projectlist = newList
|
|
return nil
|
|
}
|
|
|
|
// RemoveProject removes any Project from the ProjectList with the same String representation as the given Project.
|
|
// Returns an error if no Project was removed.
|
|
func (projectlist *ProjectList) RemoveProject(project Project) error {
|
|
var newList ProjectList
|
|
found := false
|
|
for _, p := range projectlist.Projects {
|
|
if p.String() != project.String() {
|
|
newList.AddProject(p)
|
|
} else {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
return errors.New("project not found")
|
|
}
|
|
*projectlist = newList
|
|
return nil
|
|
}
|
|
|
|
// ArchiveProjctToFile removes the project from the active list and concatenates it to
|
|
// the passed in filename
|
|
// Return an err if any part of that fails
|
|
func (projectlist *ProjectList) ArchiveProjectToFile(project Project, filename string) error {
|
|
if err := projectlist.RemoveProject(project); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
_, err = f.WriteString(project.String() + "\n")
|
|
return err
|
|
}
|
|
|
|
// LoadFromFile loads a ProjectList from *os.File.
|
|
// Note: This will clear the current TimerList and overwrite it's contents with whatever is in *os.File.
|
|
func (projectlist *ProjectList) LoadFromFile(file *os.File) error {
|
|
projectlist.Projects = []*Project{} // Empty projectlist
|
|
projectId := 1
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
text := strings.Trim(scanner.Text(), "\t\n\r") // Read Line
|
|
// Ignore blank lines
|
|
if text == "" {
|
|
continue
|
|
}
|
|
project, err := ParseProject(text)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
project.Id = projectId
|
|
projectlist.AddProject(project)
|
|
projectId++
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WriteToFile writes a ProjectList to *os.File
|
|
func (projectlist *ProjectList) WriteToFile(file *os.File) error {
|
|
writer := bufio.NewWriter(file)
|
|
_, err := writer.WriteString(projectlist.String())
|
|
writer.Flush()
|
|
return err
|
|
}
|
|
|
|
// LoadFromFilename loads a ProjectList from the filename.
|
|
func (projectlist *ProjectList) LoadFromFilename(filename string) error {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
return projectlist.LoadFromFile(file)
|
|
}
|
|
|
|
// WriteToFilename writes a ProjectList to the specified file (most likely called "project.txt").
|
|
func (projectlist *ProjectList) WriteToFilename(filename string) error {
|
|
return ioutil.WriteFile(filename, []byte(projectlist.String()), 0640)
|
|
}
|
|
|
|
// String returns a complete list of projects in project.txt format.
|
|
func (projectlist ProjectList) String() string {
|
|
var ret string
|
|
for _, project := range projectlist.Projects {
|
|
ret += fmt.Sprintf("%s\n", project.String())
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// LoadFromFile loads and returns a ProjectList from *os.File.
|
|
func LoadFromFile(file *os.File) (*ProjectList, error) {
|
|
projectlist := ProjectList{}
|
|
if err := projectlist.LoadFromFile(file); err != nil {
|
|
return nil, err
|
|
}
|
|
return &projectlist, nil
|
|
}
|
|
|
|
// WriteToFile writes a ProjectList to *os.File.
|
|
func WriteToFile(projectlist *ProjectList, file *os.File) error {
|
|
return projectlist.WriteToFile(file)
|
|
}
|
|
|
|
// LoadFromFilename loads and returns a ProjectList from a file (most likely called "project.txt")
|
|
func LoadFromFilename(filename string) (*ProjectList, error) {
|
|
projectlist := ProjectList{}
|
|
if err := projectlist.LoadFromFilename(filename); err != nil {
|
|
return nil, err
|
|
}
|
|
return &projectlist, nil
|
|
}
|
|
|
|
// WriteToFilename write a ProjectList to the specified file (most likely called "project.txt")
|
|
func WriteToFilename(projectlist *ProjectList, filename string) error {
|
|
return projectlist.WriteToFilename(filename)
|
|
}
|