better path handling

This commit is contained in:
skilion 2015-09-20 19:07:16 +02:00
parent a877bad3ad
commit 30504d7034
3 changed files with 60 additions and 41 deletions

View file

@ -1,4 +1,4 @@
import std.datetime, std.path;
import std.datetime, std.path, std.string;
import sqlite;
enum ItemType
@ -147,40 +147,46 @@ final class ItemDatabase
bool selectByPath(const(char)[] path, out Item item)
{
if (path == ".") path = "root"; // HACK
path = "root/" ~ path.chompPrefix("."); // HACK
// initialize the search
string[2][] candidates; // [id, parentId]
auto s = db.prepare("SELECT id, parentId FROM item WHERE name = ?");
s.bind(1, baseName(path));
auto r = s.exec();
foreach (row; r) candidates ~= [row[0].dup, row[1].dup];
if (candidates.length > 1) {
path = dirName(path);
if (path != ".") {
s = db.prepare("SELECT parentId FROM item WHERE id = ? AND name = ?");
// discard the candidates that do not have the correct parent
do {
s.bind(2, baseName(path));
string[2][] newCandidates;
newCandidates.reserve(candidates.length);
path = dirName(path);
if (path.length != 0) {
s.bind(2, baseName(path));
foreach (candidate; candidates) {
s.bind(1, candidate[1]);
r = s.exec();
if (!r.empty) {
string[2] c = [candidate[0], r.front[0].idup];
newCandidates ~= c;
}
foreach (candidate; candidates) {
s.bind(1, candidate[1]);
r = s.exec();
if (!r.empty) {
string[2] c = [candidate[0], r.front[0].idup];
newCandidates ~= c;
}
} else {
// reached the root
foreach (candidate; candidates) {
if (!candidate[1]) {
newCandidates ~= candidate;
}
}
assert(newCandidates.length <= 1);
}
candidates = newCandidates;
} while (candidates.length > 1);
path = dirName(path);
} while (path != ".");
}
// reached the root
string[2][] newCandidates;
foreach (candidate; candidates) {
if (!candidate[1]) {
newCandidates ~= candidate;
}
}
candidates = newCandidates;
assert(candidates.length <= 1);
if (candidates.length == 1) return selectById(candidates[0][0], item);
return false;
}
@ -240,13 +246,20 @@ final class ItemDatabase
while (true) {
s.bind(1, id);
auto r = s.exec();
if (r.empty) break;
if (path) path = r.front[0].idup ~ "/" ~ path;
else path = r.front[0].dup;
if (r.empty) {
// no results
break;
} else if (r.front[1]) {
if (path) path = r.front[0].idup ~ "/" ~ path;
else path = r.front[0].idup;
} else {
// root
if (path) path = "./" ~ path;
else path = ".";
break;
}
id = r.front[1].dup;
}
// HACK: skip "root/"
if (path.length < 5) return ".";
return path[5 .. $];
return path;
}
}

View file

@ -19,7 +19,7 @@ class MonitorException: ErrnoException
struct Monitor
{
bool verbose;
// regexes that match files/dirs to skip
// regex that match files/dirs to skip
private Regex!char skipDir, skipFile;
// inotify file descriptor
private int fd;
@ -70,7 +70,7 @@ struct Monitor
{
int wd = inotify_add_watch(fd, toStringz(dirname), mask);
if (wd == -1) throw new MonitorException("inotify_add_watch failed");
wdToDirName[wd] = chompPrefix(dirname ~ "/", "./");
wdToDirName[wd] = dirname ~ "/";
if (verbose) writeln("Monitor directory: ", dirname);
}

View file

@ -1,5 +1,6 @@
import core.exception: RangeError;
import std.algorithm, std.datetime, std.file, std.json, std.path, std.regex, std.stdio;
import std.algorithm, std.datetime, std.file, std.json, std.path, std.regex;
import std.stdio, std.string;
import config, itemdb, onedrive, util;
private bool isItemFolder(const ref JSONValue item)
@ -132,7 +133,7 @@ final class SyncEngine
if (parentId) {
path = itemdb.computePath(parentId) ~ "/" ~ name;
} else {
path = name;
path = ".";
}
ItemType type;
@ -260,6 +261,8 @@ final class SyncEngine
// returns true if the given item corresponds to the local one
private bool isItemSynced(Item item, string path)
{
import std.stdio;
writeln(path);
if (!exists(path)) return false;
final switch (item.type) {
case ItemType.file:
@ -408,8 +411,6 @@ final class SyncEngine
{
if (isDir(path)) {
if (path.matchFirst(skipDir).empty) {
import std.string: chompPrefix;
path = chompPrefix(path, "./");
Item item;
if (!itemdb.selectByPath(path, item)) {
uploadCreateDir(path);
@ -434,7 +435,7 @@ final class SyncEngine
writeln("Creating remote directory: ", path);
JSONValue item = ["name": baseName(path).idup];
item["folder"] = parseJSON("{}");
auto res = onedrive.createByPath(dirName(path), item);
auto res = onedrive.createByPath(path.dirName ~ "/", item);
saveItem(res);
}
@ -511,19 +512,24 @@ final class SyncEngine
void uploadMoveItem(string from, string to)
{
writeln("Moving remote item: ", from, " -> ", to);
Item item;
if (!itemdb.selectByPath(from, item) || !isItemSynced(item, from)) {
Item fromItem, toItem, parentItem;
if (!itemdb.selectByPath(from, fromItem)) {
writeln("Can't move an unsynced item");
return;
}
if (itemdb.selectByPath(to, item)) {
uploadDeleteItem(item, to);
if (itemdb.selectByPath(to, toItem)) {
// the destination has been overridden
uploadDeleteItem(toItem, to);
}
if (!itemdb.selectByPath(to.dirName, parentItem)) {
writeln("Can't move an item to an unsynced directory");
return;
}
JSONValue diff = ["name": baseName(to)];
diff["parentReference"] = JSONValue([
"path": "/drive/root:/" ~ dirName(to)
"id": parentItem.id
]);
auto res = onedrive.updateById(item.id, diff, item.eTag);
auto res = onedrive.updateById(fromItem.id, diff, fromItem.eTag);
saveItem(res);
string id = res["id"].str;
string eTag = res["eTag"].str;