command line options

This commit is contained in:
skilion 2015-09-14 19:21:06 +02:00
parent 424e77e4b5
commit ff07f13cd6
4 changed files with 96 additions and 53 deletions

View file

@ -1,5 +1,5 @@
DC = dmd
DFLAGS = -debug -g -gs -od./bin -of./bin/$@ -L-lcurl -L-lsqlite3 -L-ldl
DFLAGS = -unittest -debug -g -gs -od./bin -of./bin/$@ -L-lcurl -L-lsqlite3 -L-ldl
SOURCES = \
/usr/include/dlang/dmd/core/sys/posix/poll.d \

View file

@ -1,6 +1,6 @@
import std.regex, std.stdio, std.file;
import std.file, std.regex, std.stdio;
final class Config
struct Config
{
private string filename;
private string[string] values;
@ -8,12 +8,16 @@ final class Config
this(string filename)
{
this.filename = filename;
load();
}
string get(string key)
{
return values[key];
import core.exception;
try {
return values[key];
} catch (RangeError e) {
throw new Exception("Missing config value: " ~ key);
}
}
void set(string key, string value)
@ -24,16 +28,17 @@ final class Config
void load()
{
values = null;
scope (failure) return;
auto file = File(filename, "r");
auto r = regex("(?:^\\s*)(\\w+)(?:\\s*=\\s*\")(.*)(?:\"\\s*$)");
foreach (line; file.byLine()) {
auto c = matchFirst(line, r);
if (!c.empty) {
c.popFront(); // skip whole match
c.popFront(); // skip the whole match
string key = c.front.dup;
c.popFront();
values[key] = c.front.dup;
} else {
writeln("Malformed config line: ", line);
}
}
}
@ -53,7 +58,7 @@ final class Config
unittest
{
auto cfg = new Config("/tmp/test.conf");
auto cfg = Config(tempDir() ~ "/test.conf");
cfg.set("test1", "1");
cfg.set("test2", "2");
cfg.set("test1", "3");

View file

@ -1,46 +1,89 @@
import std.file;
import std.getopt, std.file, std.process, std.stdio;
import config, monitor, onedrive, sync;
private string configFile = "./onedrive.conf";
private string refreshTokenFile = "refresh_token";
string ver = "1.0";
void main()
void main(string[] args)
{
auto cfg = new Config(configFile);
auto onedrive = new OneDriveApi(cfg.get("client_id"), cfg.get("client_secret"));
onedrive.onRefreshToken = (string refreshToken) { std.file.write(refreshTokenFile, refreshToken); };
bool monitor, resync, resetLocal, resetRemote, verbose;
try {
string refreshToken = readText(refreshTokenFile);
writeln("OneDrive Client for Linux v", ver);
auto opt = getopt(
args,
"monitor|m", "Keep monitoring for local and remote changes.", &monitor,
"resync", "Perform a full synchronization.", &resync,
"verbose|v", "Print more details, useful for debugging.", &verbose
);
if (opt.helpWanted) {
defaultGetoptPrinter("Available options:", opt.options);
return;
}
} catch (GetOptException e) {
writeln(e.msg);
writeln("Try 'onedrive -h' for more information.");
return;
}
string homeDirName = environment["HOME"];
string configDirName = environment.get("XDG_CONFIG_HOME", homeDirName ~ "/.config") ~ "/onedrive";
string configFilePath = configDirName ~ "/config";
string refreshTokenFilePath = configDirName ~ "/refresh_token";
string statusTokenFilePath = configDirName ~ "/status_token";
string databaseFilePath = configDirName ~ "/database";
if (resync || resetLocal || resetRemote) {
if (verbose) writeln("Deleting the current status ...");
if (exists(databaseFilePath)) remove(databaseFilePath);
if (exists(statusTokenFilePath)) remove(statusTokenFilePath);
}
if (verbose) writeln("Loading config ...");
auto cfg = config.Config(configFilePath);
cfg.load();
if (verbose) writeln("Initializing the OneDrive API ...");
auto onedrive = new OneDriveApi(cfg, verbose);
onedrive.onRefreshToken = (string refreshToken) {
std.file.write(refreshTokenFilePath, refreshToken);
};
try {
string refreshToken = readText(refreshTokenFilePath);
onedrive.setRefreshToken(refreshToken);
} catch (FileException e) {
onedrive.authorize();
}
// TODO check if the token is valid
if (verbose) writeln("Initializing the Synchronization Engine ...");
auto sync = new SyncEngine(cfg, onedrive);
sync.applyDifferences();
sync.uploadDifferences();
Monitor m;
import std.stdio;
m.onDirCreated = delegate(string path) {
writeln("Directory created: ", path);
sync.createFolderItem(path);
sync.uploadDifferences(path);
};
m.onFileChanged = delegate(string path) {
writeln("File changed: ", path);
sync.uploadDifference2(path);
};
m.onDelete = delegate(string path) {
sync.deleteByPath(path);
};
m.onMove = delegate(string from, string to) {
sync.moveItem(from, to);
};
m.init();
string syncDir = cfg.get("sync_dir");
chdir(syncDir);
m.addRecursive("test");
while (true) m.update();
if (monitor) {
if (verbose) writeln("Monitoring for changes ...");
Monitor m;
m.onDirCreated = delegate(string path) {
if (verbose) writeln("[M] Directory created: ", path);
sync.createFolderItem(path);
sync.uploadDifferences(path);
};
m.onFileChanged = delegate(string path) {
if (verbose) writeln("[M] File changed: ", path);
sync.uploadDifference2(path);
};
m.onDelete = delegate(string path) {
if (verbose) writeln("[M] Item deleted: ", path);
sync.deleteByPath(path);
};
m.onMove = delegate(string from, string to) {
if (verbose) writeln("[M] Item moved: ", from, " -> ", to);
sync.moveItem(from, to);
};
m.init();
string syncDir = cfg.get("sync_dir");
chdir(syncDir);
m.addRecursive("test");
while (true) m.update();
// TODO download changes
}
}

View file

@ -1,6 +1,5 @@
module onedrive;
import std.datetime, std.json, std.net.curl, std.path, std.string, std.uni, std.uri;
import config;
private immutable {
string authUrl = "https://login.live.com/oauth20_authorize.srf";
@ -30,18 +29,14 @@ final class OneDriveApi
private SysTime accessTokenExpiration;
private HTTP http;
void function(string) onRefreshToken; // called when a new refresh_token is received
void delegate(string) onRefreshToken; // called when a new refresh_token is received
this(string clientId, string clientSecret)
this(Config cfg, bool verbose)
{
this.clientId = clientId;
this.clientSecret = clientSecret;
this.clientId = cfg.get("client_id");
this.clientSecret = cfg.get("client_secret");
http = HTTP();
//debug http.verbose = true;
// HACK: prevent SIGPIPE
//import etc.c.signal, etc.c.curl;
//http.handle.set(CurlOption.nosignal, 0);
//signal(/*SIGPIPE*/ 13, /*SIG_IGN*/ cast(void function(int)) 1);
http.verbose = verbose;
}
~this()
@ -53,8 +48,8 @@ final class OneDriveApi
{
import std.stdio, std.regex;
string url = authUrl ~ "?client_id=" ~ clientId ~ "&scope=wl.offline_access onedrive.readwrite&response_type=code&redirect_url=" ~ redirectUrl;
writeln("Authorize this app visiting:");
writeln(url);
writeln("Authorize this app visiting:\n");
writeln(url, "\n");
while (true) {
char[] response;
@ -62,7 +57,7 @@ final class OneDriveApi
readln(response);
auto c = matchFirst(response, r"(?:code=)(([\w\d]+-){4}[\w\d]+)");
if (!c.empty) {
c.popFront(); // skip whole match
c.popFront(); // skip the whole match
redeemToken(c.front);
break;
}