Project Amber CLI client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.3 KiB

package main
import "git.tdem.in/tdemin/amber_cli/internal/tasks"
func mergeLists(remoteTasks, localTasks []tasks.Task) (result, toSync, toUpdate, toDelete []tasks.Task) {
var longestLength int
rlen, llen := len(remoteTasks), len(localTasks)
if rlen > llen {
longestLength = rlen
} else {
longestLength = llen
}
result = make([]tasks.Task, 0, longestLength)
toSync = make([]tasks.Task, 0, longestLength)
toUpdate = make([]tasks.Task, 0, longestLength)
toDelete = make([]tasks.Task, 0, longestLength)
// TODO: mergeLists: this is ported from Amber Web. This algorithm
// might not be fully correct and looks very ugly in Go, thanks to
// the lack of stuff like map(), etc. In fact, it doesn't even look
// that great in TypeScript; nonetheless, at least we have
// Array.prototype.find()...
// first passthrough, remote tasks come first
for _, remote := range remoteTasks {
var matchingLocal *tasks.Task
// find matching task from locals
for _, local := range localTasks {
if local.ID == remote.ID {
matchingLocal = &local
break
}
}
// local task found? compare modtimes
if matchingLocal != nil {
if matchingLocal.Mtime.After(remote.Mtime) {
result = append(result, *matchingLocal)
toUpdate = append(toUpdate, *matchingLocal)
} else {
result = append(result, remote)
}
} else {
// local task not found, save remote
result = append(result, remote)
}
}
// second passthrough with local tasks
for _, local := range localTasks {
var alreadyPushed = false
for _, rest := range result {
if rest.ID == local.ID {
alreadyPushed = true
break
}
}
if !alreadyPushed {
var matchingRemote *tasks.Task
for _, remote := range remoteTasks {
if local.ID == remote.ID {
matchingRemote = &remote
break
}
}
if matchingRemote != nil {
// compare modtimes
if local.Mtime.After(matchingRemote.Mtime) {
result = append(result, local)
toUpdate = append(toUpdate, local)
} else {
result = append(result, *matchingRemote)
}
if local.ToRemove {
toDelete = append(toDelete, local)
}
} else {
if local.ToSync {
result = append(result, local)
toSync = append(toSync, local)
}
}
}
}
return result, toSync, toUpdate, toDelete
}
func doMerge() {
// TODO: doMerge: this algorithm is ported from Amber Web and might not be
// correct.
remote, err := hc.GetTasks()
if err != nil {
// FIXME: doMerge: check for 401, etc
return
}
result, toSync, toUpdate, toDelete := mergeLists(remote, db.AllTasks())
if err := db.ReplaceList(result); err != nil {
// FIXME: doMerge: write logs, etc
return
}
// all of the tasks in the lists have already been pushed to the DB, so
// no worries
for _, t := range toSync {
_, err := hc.PostTask(&t)
if err != nil {
// FIXME: doMerge: report that as not fatal
} else {
t.ToSync = false
t.Update()
}
}
for _, t := range toUpdate {
err := hc.UpdateTask(&t)
if err != nil {
// FIXME: doMerge: report that as not fatal
} else {
t.ToSync = false
t.Update()
}
}
for _, t := range toDelete {
_, err := hc.DeleteTask(&t)
if err != nil {
// FIXME: doMerge: report that as not fatal
} else {
t.ToRemove = false
t.Remove()
// TODO: doMerge: remove the child tasks
}
}
}