Refactored import/export
This commit is contained in:
parent
df06d63fa8
commit
631343388d
6 changed files with 54 additions and 28 deletions
17
README.md
17
README.md
|
@ -151,7 +151,7 @@ zeit erase 14037730-5c2d-44ff-b70e-81f1dcd4eb5f
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Display statistics
|
### Statistics
|
||||||
|
|
||||||
![zeit stats](documentation/zeit_stats.png)
|
![zeit stats](documentation/zeit_stats.png)
|
||||||
|
|
||||||
|
@ -159,6 +159,7 @@ zeit erase 14037730-5c2d-44ff-b70e-81f1dcd4eb5f
|
||||||
zeit stats
|
zeit stats
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Import tracked activities
|
### Import tracked activities
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
@ -167,7 +168,7 @@ zeit import --help
|
||||||
|
|
||||||
The following formats are supported as of right now:
|
The following formats are supported as of right now:
|
||||||
|
|
||||||
#### Tyme 3 JSON
|
#### `tyme`: Tyme 3 JSON
|
||||||
|
|
||||||
It is possible to import JSON exports from [Tyme 3](https://www.tyme-app.com).
|
It is possible to import JSON exports from [Tyme 3](https://www.tyme-app.com).
|
||||||
It is important that the JSON is exported with the following options set/unset:
|
It is important that the JSON is exported with the following options set/unset:
|
||||||
|
@ -192,9 +193,10 @@ then import them again into *zeit*.
|
||||||
Import a Tyme 3 JSON export:
|
Import a Tyme 3 JSON export:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
zeit import --tyme ./tyme.export.json
|
zeit import --format tyme ./tyme.export.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Export tracked activities
|
### Export tracked activities
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
@ -203,7 +205,12 @@ zeit export --help
|
||||||
|
|
||||||
The following formats are supported as of right now:
|
The following formats are supported as of right now:
|
||||||
|
|
||||||
#### Tyme 3 JSON
|
#### `zeit`: *zeit* JSON
|
||||||
|
|
||||||
|
The *zeit* internal JSON format. Basically a dump of the database including
|
||||||
|
only tracked activities.
|
||||||
|
|
||||||
|
#### `tyme`: Tyme 3 JSON
|
||||||
|
|
||||||
It is possible to export JSON compatible to the Tyme 3 JSON format. Fields that
|
It is possible to export JSON compatible to the Tyme 3 JSON format. Fields that
|
||||||
are not available in *zeit* will be filled with dummy values, e.g.
|
are not available in *zeit* will be filled with dummy values, e.g.
|
||||||
|
@ -214,5 +221,5 @@ are not available in *zeit* will be filled with dummy values, e.g.
|
||||||
Export a Tyme 3 JSON:
|
Export a Tyme 3 JSON:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
zeit export --tyme --project "my project" --since "2020-04-01T15:04:05+07:00" --until "2020-04-04T15:04:05+07:00"
|
zeit export --format tyme --project "my project" --since "2020-04-01T15:04:05+07:00" --until "2020-04-04T15:04:05+07:00"
|
||||||
```
|
```
|
||||||
|
|
|
@ -154,10 +154,10 @@ func (entry *Entry) GetOutput() (string) {
|
||||||
return fmt.Sprintf("%s %s on %s from %s to %s (%sh)", color.FgGray.Render(entry.ID), color.FgLightWhite.Render(entry.Task), color.FgLightWhite.Render(entry.Project), color.FgLightWhite.Render(entry.Begin.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(entry.Finish.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(trackDiffOut.Format("15:04")))
|
return fmt.Sprintf("%s %s on %s from %s to %s (%sh)", color.FgGray.Render(entry.ID), color.FgLightWhite.Render(entry.Task), color.FgLightWhite.Render(entry.Project), color.FgLightWhite.Render(entry.Begin.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(entry.Finish.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(trackDiffOut.Format("15:04")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFilteredEntries(entries *[]Entry, project string, task string, since time.Time, until time.Time) ([]*Entry, error) {
|
func GetFilteredEntries(entries []Entry, project string, task string, since time.Time, until time.Time) ([]Entry, error) {
|
||||||
var filteredEntries []*Entry
|
var filteredEntries []Entry
|
||||||
|
|
||||||
for _, entry := range *entries {
|
for _, entry := range entries {
|
||||||
if project != "" && GetIdFromName(entry.Project) != GetIdFromName(project) {
|
if project != "" && GetIdFromName(entry.Project) != GetIdFromName(project) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ func GetFilteredEntries(entries *[]Entry, project string, task string, since tim
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredEntries = append(filteredEntries, &entry)
|
filteredEntries = append(filteredEntries, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredEntries, nil
|
return filteredEntries, nil
|
||||||
|
|
41
z/export.go
41
z/export.go
|
@ -4,21 +4,30 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
"encoding/json"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var exportSince string
|
var exportSince string
|
||||||
var exportUntil string
|
var exportUntil string
|
||||||
|
|
||||||
func exportTymeJson(user string, entries []*Entry) (string, error) {
|
func exportZeitJson(user string, entries []Entry) (string, error) {
|
||||||
|
stringified, err := json.Marshal(entries)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
tyme := Tyme{}
|
return string(stringified), nil
|
||||||
err := tyme.FromEntries(entries)
|
}
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tyme.Stringify(), nil
|
func exportTymeJson(user string, entries []Entry) (string, error) {
|
||||||
|
tyme := Tyme{}
|
||||||
|
err := tyme.FromEntries(entries)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tyme.Stringify(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var exportCmd = &cobra.Command{
|
var exportCmd = &cobra.Command{
|
||||||
|
@ -57,34 +66,40 @@ var exportCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredEntries []*Entry
|
var filteredEntries []Entry
|
||||||
filteredEntries, err = GetFilteredEntries(&entries, project, task, since, until)
|
filteredEntries, err = GetFilteredEntries(entries, project, task, since, until)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s %+v\n", CharError, err)
|
fmt.Printf("%s %+v\n", CharError, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var output string = ""
|
var output string = ""
|
||||||
if formatTymeJson == true {
|
switch(format) {
|
||||||
|
case "zeit":
|
||||||
|
output, err = exportZeitJson(user, filteredEntries)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s %+v\n", CharError, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
case "tyme":
|
||||||
output, err = exportTymeJson(user, filteredEntries)
|
output, err = exportTymeJson(user, filteredEntries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s %+v\n", CharError, err)
|
fmt.Printf("%s %+v\n", CharError, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
fmt.Printf("%s specify an export format; see `zeit export --help` for more info\n", CharError)
|
fmt.Printf("%s specify an export format; see `zeit export --help` for more info\n", CharError)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s\n", output)
|
fmt.Printf("%s\n", output)
|
||||||
|
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(exportCmd)
|
rootCmd.AddCommand(exportCmd)
|
||||||
exportCmd.Flags().BoolVar(&formatTymeJson, "tyme", false, "Export to Tyme 3 JSON")
|
exportCmd.Flags().StringVar(&format, "format", "", "Format to export, possible values: zeit, tyme")
|
||||||
exportCmd.Flags().StringVar(&exportSince, "since", "", "Date/time to start the export from")
|
exportCmd.Flags().StringVar(&exportSince, "since", "", "Date/time to start the export from")
|
||||||
exportCmd.Flags().StringVar(&exportUntil, "until", "", "Date/time to export until")
|
exportCmd.Flags().StringVar(&exportUntil, "until", "", "Date/time to export until")
|
||||||
exportCmd.Flags().StringVarP(&project, "project", "p", "", "Project to be exported")
|
exportCmd.Flags().StringVarP(&project, "project", "p", "", "Project to be exported")
|
||||||
|
|
11
z/import.go
11
z/import.go
|
@ -59,13 +59,18 @@ var importCmd = &cobra.Command{
|
||||||
|
|
||||||
user := GetCurrentUser()
|
user := GetCurrentUser()
|
||||||
|
|
||||||
if formatTymeJson == true {
|
switch(format) {
|
||||||
|
case "zeit":
|
||||||
|
// TODO:
|
||||||
|
fmt.Printf("%s not yet implemented\n", CharError)
|
||||||
|
os.Exit(1)
|
||||||
|
case "tyme":
|
||||||
entries, err = importTymeJson(user, args[0])
|
entries, err = importTymeJson(user, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s %+v\n", CharError, err)
|
fmt.Printf("%s %+v\n", CharError, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
fmt.Printf("%s specify an import format; see `zeit import --help` for more info\n", CharError)
|
fmt.Printf("%s specify an import format; see `zeit import --help` for more info\n", CharError)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -104,7 +109,7 @@ var importCmd = &cobra.Command{
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(importCmd)
|
rootCmd.AddCommand(importCmd)
|
||||||
importCmd.Flags().BoolVar(&formatTymeJson, "tyme", false, "Import from Tyme 3 JSON export")
|
importCmd.Flags().StringVar(&format, "format", "", "Format to import, possible values: zeit, tyme")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
database, err = InitDatabase()
|
database, err = InitDatabase()
|
||||||
|
|
|
@ -14,6 +14,7 @@ var project string
|
||||||
var task string
|
var task string
|
||||||
var notes string
|
var notes string
|
||||||
|
|
||||||
|
var format string
|
||||||
var force bool
|
var force bool
|
||||||
|
|
||||||
const(
|
const(
|
||||||
|
|
|
@ -8,8 +8,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var formatTymeJson bool
|
|
||||||
|
|
||||||
type TymeEntry struct {
|
type TymeEntry struct {
|
||||||
Billing string `json:"billing"` // "UNBILLED",
|
Billing string `json:"billing"` // "UNBILLED",
|
||||||
Category string `json:"category"` // "Client",
|
Category string `json:"category"` // "Client",
|
||||||
|
@ -50,7 +48,7 @@ func (tyme *Tyme) Load(filename string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tyme *Tyme) FromEntries(entries []*Entry) error {
|
func (tyme *Tyme) FromEntries(entries []Entry) error {
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
duration := decimal.NewFromFloat(entry.Finish.Sub(entry.Begin).Minutes())
|
duration := decimal.NewFromFloat(entry.Finish.Sub(entry.Begin).Minutes())
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue