<commit_before>package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"sort"
	"time"

	"github.com/AlexanderThaller/logger"
	"github.com/jinzhu/now"
	"github.com/juju/errgo"
)

type Command struct {
	Action        string
	Args          []string
	DataPath      string
	EndTime       time.Time
	Project       string
	SCM           string
	SCMAutoCommit bool
	SCMAutoPush   bool
	StartTime     time.Time
	TimeStamp     time.Time
	Value         string
	NoSubprojects bool
}

const (
	CommitMessageTimeStampFormat = RecordTimeStampFormat
	DateFormat                   = "2006-01-02"
)

const (
	ActionDone             = "done"
	ActionList             = "list"
	ActionListDates        = "dates"
	ActionListNotes        = "notes"
	ActionListProjects     = "projects"
	ActionListTodos        = "todos"
	ActionListTracks       = "tracks"
	ActionListActiveTracks = "activetracks"
	ActionNote             = "note"
	ActionRename           = "rename"
	ActionTodo             = "todo"
	ActionMerge            = "merge"
	ActionTrack            = "track"
	ActionStopTracking     = "stoptrack"
	ActionListSubprojects  = "subprojects"
)

func NewCommand() *Command {
	return new(Command)
}

func (com *Command) Run() error {
	if com.DataPath == "" {
		return errgo.New("the datapath can not be empty")
	}

	switch com.Action {
	case ActionDone:
		return com.runDone()
	case ActionNote:
		return com.runNote()
	case ActionListDates:
		return com.runListDates()
	case ActionList:
		return com.runList()
	case ActionListNotes:
		return com.runListNotes()
	case ActionListProjects:
		return com.runListProjects()
	case ActionListTodos:
		return com.runListTodos()
	case ActionListTracks:
		return com.runListTracks()
	case ActionTodo:
		return com.runTodo()
	case ActionRename:
		return com.runRename()
	case ActionMerge:
		return com.runMerge()
	case ActionTrack:
		return com.runTrack()
	case ActionStopTracking:
		return com.runStopTrack()
	case ActionListActiveTracks:
		return com.runListActiveTracks()
	case ActionListSubprojects:
		return com.runListSubprojects()
	default:
		return errgo.New("Do not recognize the action: " + com.Action)
	}
}

func (com *Command) runListSubprojects() error {
	if com.Project == "" {
		return errgo.New("we need a valid project to list subprojects")
	}
	if !com.checkProjectExists(com.Project) {
		return errgo.New("no project with the name " + com.Project)
	}

	subprojects, err := com.getProjectSubprojects(com.Project)
	if err != nil {
		return err
	}

	for _, project := range subprojects {<commit_msg>added command to print duration for tracks for given project.<commit_after>package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"sort"
	"time"

	"github.com/AlexanderThaller/logger"
	"github.com/jinzhu/now"
	"github.com/juju/errgo"
)

type Command struct {
	Action        string
	Args          []string
	DataPath      string
	EndTime       time.Time
	Project       string
	SCM           string
	SCMAutoCommit bool
	SCMAutoPush   bool
	StartTime     time.Time
	TimeStamp     time.Time
	Value         string
	NoSubprojects bool
}

const (
	CommitMessageTimeStampFormat = RecordTimeStampFormat
	DateFormat                   = "2006-01-02"
)

const (
	ActionDone               = "done"
	ActionList               = "list"
	ActionListDates          = "dates"
	ActionListNotes          = "notes"
	ActionListProjects       = "projects"
	ActionListTodos          = "todos"
	ActionListTracks         = "tracks"
	ActionListActiveTracks   = "activetracks"
	ActionNote               = "note"
	ActionRename             = "rename"
	ActionTodo               = "todo"
	ActionMerge              = "merge"
	ActionTrack              = "track"
	ActionStopTracking       = "stoptrack"
	ActionListSubprojects    = "subprojects"
	ActionListTracksDuration = "duration"
)

func NewCommand() *Command {
	return new(Command)
}

func (com *Command) Run() error {
	if com.DataPath == "" {
		return errgo.New("the datapath can not be empty")
	}

	switch com.Action {
	case ActionDone:
		return com.runDone()
	case ActionNote:
		return com.runNote()
	case ActionListDates:
		return com.runListDates()
	case ActionList:
		return com.runList()
	case ActionListNotes:
		return com.runListNotes()
	case ActionListProjects:
		return com.runListProjects()
	case ActionListTodos:
		return com.runListTodos()
	case ActionListTracks:
		return com.runListTracks()
	case ActionTodo:
		return com.runTodo()
	case ActionRename:
		return com.runRename()
	case ActionMerge:
		return com.runMerge()
	case ActionTrack:
		return com.runTrack()
	case ActionStopTracking:
		return com.runStopTrack()
	case ActionListActiveTracks:
		return com.runListActiveTracks()
	case ActionListSubprojects:
		return com.runListSubprojects()
	case ActionListTracksDuration:
		return com.runListTracksDuration()
	default:
		return errgo.New("Do not recognize the action: " + com.Action)
	}
}

func (com *Command) runListTracksDuration() error {
	tracks, err := com.getProjectTracks(com.Project)
	if err != nil {
		return err
	}

	starttracks := make(map[string]Track)
	durations := make(map[string]time.Duration)
	active := make(map[string]bool)
	for _, track := range tracks {
		if !active[track.Value] {
			starttracks[track.Value] = track
			active[track.Value] = true
			continue
		}

		startrack := starttracks[track.Value]
		duration := track.TimeStamp.Sub(startrack.TimeStamp)
		durations[track.Value] += duration
		active[track.Value] = false
	}

	for value, duration := range durations {
		fmt.Println(value, "-", duration)
	}

	return nil
}

func (com *Command) runListSubprojects() error {
	if com.Project == "" {
		return errgo.New("we need a valid project to list subprojects")
	}
	if !com.checkProjectExists(com.Project) {
		return errgo.New("no project with the name " + com.Project)
	}

	subprojects, err := com.getProjectSubprojects(com.Project)
	if err != nil {
		return err
	}

	for _, project := range subprojects {
{'fraction_non_alphanumeric': 0.09968328054675779, 'fraction_numerical': 0.002667111185197533, 'mean_word_length': 3.231311706629055, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '44704', 'n_tokens_mistral': 2095, 'n_tokens_neox': 2006, 'n_words': 472}