mirror of
https://github.com/abraunegg/onedrive
synced 2024-06-15 20:25:18 +02:00
config options for command line switches (#449)
* config options for command line switches to allow for better config handling in docker containers
This commit is contained in:
parent
e5a9747d7b
commit
ea22d8fef5
54
README.md
54
README.md
|
@ -454,8 +454,12 @@ To re-authorise the client, follow the steps below:
|
|||
|
||||
The application will now sync with OneDrive with the new credentials.
|
||||
|
||||
## Additional Configuration
|
||||
Additional configuration is optional.
|
||||
## Configuration
|
||||
|
||||
Configuration is determined by three layer: the default values, values set in the configuration file, and values passed in via the command line. The default values provide a reasonable default, and configuration is optionally.
|
||||
|
||||
Most command line options have a respective configuration file setting.
|
||||
|
||||
If you want to change the defaults, you can copy and edit the included config file into your `~/.config/onedrive` directory:
|
||||
```text
|
||||
mkdir -p ~/.config/onedrive
|
||||
|
@ -464,13 +468,9 @@ nano ~/.config/onedrive/config
|
|||
```
|
||||
This file does not get created by default, and should only be created if you want to change the 'default' operational parameters.
|
||||
|
||||
Available options:
|
||||
* `sync_dir`: directory where the files will be synced
|
||||
* `skip_file`: any files or directories that match this pattern will be skipped during sync
|
||||
* `skip_dotfiles`: skip any .files or .folders during sync
|
||||
* `skip_symlinks`: any files or directories that are symlinked will be skipped during sync
|
||||
* `monitor_interval`: time interval in seconds by which the monitor process will process local and remote changes
|
||||
* `min_notif_changes`: minimum number of pending incoming changes to trigger a desktop notification
|
||||
See the [config](config) file for the full list of options, and below under "All available commands" for all possible keys and there default values.
|
||||
|
||||
Comments regarding some of the options:
|
||||
|
||||
### sync_dir
|
||||
Example: `sync_dir="~/MyDirToSync"`
|
||||
|
@ -715,46 +715,60 @@ Options:
|
|||
Set the directory used to store the configuration files
|
||||
--create-directory ARG
|
||||
Create a directory on OneDrive - no sync will be performed.
|
||||
--destination-directory ARG
|
||||
Destination directory for renamed or move on OneDrive - no sync will be performed.
|
||||
--debug-https
|
||||
Debug OneDrive HTTPS communication.
|
||||
--destination-directory ARG
|
||||
Destination directory for renamed or move on OneDrive - no sync will be performed.
|
||||
--disable-notifications
|
||||
Do not use desktop notifications in monitor mode.
|
||||
--disable-upload-validation
|
||||
Disable upload validation when uploading to OneDrive
|
||||
--display-config
|
||||
Display what options the client will use as currently configured - no sync will be performed.
|
||||
--display-sync-status
|
||||
Display the sync status of the client - no sync will be performed.
|
||||
-d --download-only
|
||||
--download-only -d
|
||||
Only download remote changes
|
||||
--disable-upload-validation
|
||||
Disable upload validation when uploading to OneDrive
|
||||
--dry-run
|
||||
Perform a trial sync with no changes made
|
||||
Perform a trial sync with no changes made
|
||||
--enable-logging
|
||||
Enable client activity to a separate log file
|
||||
--force-http-1.1
|
||||
Force the use of HTTP 1.1 for all operations
|
||||
--get-O365-drive-id ARG
|
||||
Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library
|
||||
--help -h
|
||||
This help information.
|
||||
--local-first
|
||||
Synchronize from the local directory source first, before downloading changes from OneDrive.
|
||||
--log-dir ARG
|
||||
Directory where logging output is saved to, needs to end with a slash.
|
||||
--logout
|
||||
Logout the current user
|
||||
-m --monitor
|
||||
--min-notif-changes ARG
|
||||
Minimum number of pending incoming changes necessary to trigger a desktop notification
|
||||
--monitor -m
|
||||
Keep monitoring for local and remote changes
|
||||
--monitor-fullscan-frequency ARG
|
||||
Number of sync runs before performing a full local scan of the synced directory
|
||||
--monitor-interval ARG
|
||||
Number of seconds by which each sync operation is undertaken when idle under monitor mode.
|
||||
--monitor-log-frequency ARG
|
||||
Frequency of logging in monitor mode
|
||||
--no-remote-delete
|
||||
Do not delete local file 'deletes' from OneDrive when using --upload-only
|
||||
--print-token
|
||||
Print the access token, useful for debugging
|
||||
--resync
|
||||
Forget the last saved state, perform a full sync
|
||||
--remove-directory ARG
|
||||
Remove a directory on OneDrive - no sync will be performed.
|
||||
--resync
|
||||
Forget the last saved state, perform a full sync
|
||||
--single-directory ARG
|
||||
Specify a single local directory within the OneDrive root to sync.
|
||||
--skip-dot-files
|
||||
Skip dot files and folders from syncing
|
||||
--skip-file ARG
|
||||
Skip any files that match this pattern from syncing
|
||||
--skip-symlinks
|
||||
Skip syncing of symlinks
|
||||
--source-directory ARG
|
||||
|
@ -765,12 +779,10 @@ Options:
|
|||
Perform a synchronization
|
||||
--upload-only
|
||||
Only upload to OneDrive, do not sync changes from OneDrive locally
|
||||
-v+ --verbose
|
||||
--verbose -v+
|
||||
Print more details, useful for debugging (repeat for extra debugging)
|
||||
--version
|
||||
Print the version and exit
|
||||
-h --help
|
||||
This help information.
|
||||
```
|
||||
|
||||
### File naming
|
||||
|
|
36
config
36
config
|
@ -1,6 +1,30 @@
|
|||
# Directory where the files will be synced
|
||||
sync_dir = "~/OneDrive"
|
||||
# Skip files and directories that match this pattern
|
||||
skip_file = "~*|.~*|*.tmp"
|
||||
# Wait time (seconds) between sync operations in monitor mode
|
||||
monitor_interval = "45"
|
||||
# Configuration for OneDrive Linux Client
|
||||
# This file contains the list of supported configuration fields
|
||||
# with their default values.
|
||||
# All values need to be enclosed in quotes
|
||||
# For explanations see the README.md or the man page.
|
||||
#
|
||||
# sync_dir = "~/OneDrive"
|
||||
# skip_file = "~*|.~*|*.tmp"
|
||||
# monitor_interval = "45"
|
||||
# skip_dir = ""
|
||||
# log_dir = "/var/log/onedrive/"
|
||||
# drive_id = ""
|
||||
# upload_only = "false"
|
||||
# check_nomount = "false"
|
||||
# check_nosync = "false"
|
||||
# download_only = "false"
|
||||
# disable_notifications = "false"
|
||||
# disable_upload_validation = "false"
|
||||
# enable_logging = "false"
|
||||
# force_http_11 = "false"
|
||||
# local_first = "false"
|
||||
# no_remote_delete = "false"
|
||||
# skip_symlinks = "false"
|
||||
# debug_https = "false"
|
||||
# skip_dotfiles = "false"
|
||||
# dry_run = "false"
|
||||
# monitor_interval = "45"
|
||||
# min_notif_changes = "5"
|
||||
# monitor_log_frequency = "5"
|
||||
# monitor_fullscan_frequency = "10"
|
||||
|
|
|
@ -16,13 +16,17 @@ onedrive \- folder synchronization with OneDrive
|
|||
.SH DESCRIPTION
|
||||
A complete tool to interact with OneDrive on Linux.
|
||||
.SH OPTIONS
|
||||
Without any option given, no sync is done and the program exits.
|
||||
Without any option given, no sync is done and the program exits.
|
||||
.TP
|
||||
\fB\-\-check\-for\-nomount\fP
|
||||
Check for the presence of .nosync in the syncdir root. If found, do not perform sync.
|
||||
.br
|
||||
Configuration file key: \fBcheck_nomount\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-check\-for\-nosync\fP
|
||||
Check for the presence of .nosync in each directory. If found, skip directory from sync.
|
||||
.br
|
||||
Configuration file key: \fBcheck_nosync\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-confdir\fP ARG
|
||||
Set the directory used to store the configuration files
|
||||
|
@ -35,12 +39,18 @@ Destination directory for renamed or move on OneDrive \- no sync will be perform
|
|||
.TP
|
||||
\fB\-\-debug\-https\fP
|
||||
Debug OneDrive HTTPS communication.
|
||||
.br
|
||||
Configuration file key: \fBdebug_https\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-disable\-notifications\fP
|
||||
Do not use desktop notifications in monitor mode
|
||||
.br
|
||||
Configuration file key: \fBdisable_notifications\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-disable\-upload\-validation\fP
|
||||
Disable upload validation when uploading to OneDrive
|
||||
.br
|
||||
Configuration file key: \fBdisable_upload_validation\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-display\-config\fP
|
||||
Display what options the client will use as currently configured \- no sync will be performed.
|
||||
|
@ -50,30 +60,64 @@ Display the sync status of the client \- no sync will be performed.
|
|||
.TP
|
||||
\fB\-d \-\-download\-only\fP
|
||||
Only download remote changes
|
||||
.br
|
||||
Configuration file key: \fBdownload_only\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-dry\-run\fP
|
||||
Perform a trial sync with no changes made. Can ONLY be used with --synchronize. Will be ignored for --monitor
|
||||
.br
|
||||
Configuration file key: \fBdry_run\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-enable\-logging\fP
|
||||
Enable client activity to a separate log file
|
||||
.br
|
||||
Configuration file key: \fBenable_logging\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-force\-http\-1.1\fP
|
||||
Force the use of HTTP 1.1 for all operations
|
||||
.br
|
||||
Configuration file key: \fBforce_http_11\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-get\-O365\-drive\-id\fP ARG
|
||||
Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library
|
||||
.TP
|
||||
\fB\-\-local\-first\fP
|
||||
Synchronize from the local directory source first, before downloading changes from OneDrive.
|
||||
.br
|
||||
Configuration file key: \fBlocal_first\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-logout\fP
|
||||
Logout the current user
|
||||
.TP
|
||||
\fB\-\-log\-dir\fP ARG
|
||||
defines the directory where logging output is saved to, needs to end with a slash
|
||||
.br
|
||||
Configuration file key: \fBlog_dir\fP (default: \fB/var/log/onedrive/\fP)
|
||||
.TP
|
||||
\fB\-\-min-notif-changes\fP
|
||||
the minimum number of pending incoming changes necessary to trigger
|
||||
a desktop notification
|
||||
.br
|
||||
Configuration file key: \fBmin_notif_changes\fP (default: \fB5\fP)
|
||||
.TP
|
||||
\fB\-m \-\-monitor\fP
|
||||
Keep monitoring for local and remote changes
|
||||
.TP
|
||||
\fB\-\-monitor\-interval\fP ARG
|
||||
The number of seconds by which each sync operation is undertaken when
|
||||
idle under monitor mode
|
||||
.br
|
||||
Configuration file key: \fBmonitor_interval\fP (default: \fB45\fP)
|
||||
.TP
|
||||
\fB\-\-monitor\-fullscan-frequency\fP ARG
|
||||
Number of sync runs before performing a full local scan of the synced directory
|
||||
.br
|
||||
Configuration file key: \fBmonitor_fullscan_frequency\fP (default: \fB10\fP)
|
||||
.TP
|
||||
\fB\-\-no\-remote\-delete\fP
|
||||
Do not delete local file 'deletes' from OneDrive when using \fB\-\-upload\-only\fR
|
||||
.br
|
||||
Configuration file key: \fBno_remote_delete\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-print\-token\fP
|
||||
Print the access token, useful for debugging
|
||||
|
@ -89,21 +133,34 @@ Specify a single local directory within the OneDrive root to sync.
|
|||
.TP
|
||||
\fB\-\-skip\-dot\-files\fP
|
||||
Skip dot files and folders from syncing
|
||||
.br
|
||||
Configuration file key: \fBskip_dotfiles\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-skip\-file\fP
|
||||
Skip any files that match this pattern from syncing
|
||||
.br
|
||||
Configuration file key: \fBskip_file\fP (default: \fB~*|.~*|*.tmp\fP)
|
||||
.TP
|
||||
\fB\-\-skip\-symlinks\fP
|
||||
Skip syncing of symlinks
|
||||
.br
|
||||
Configuration file key: \fBskip_symlinks\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-\-source\-directory\fP ARG
|
||||
Source directory to rename or move on OneDrive \- no sync will be performed.
|
||||
.TP
|
||||
\fB\-\-syncdir\fP ARG
|
||||
Set the directory used to sync the files that are synced
|
||||
.br
|
||||
Configuration file key: \fBsync_dir\fP (default: \fB~/OneDrive\fP)
|
||||
.TP
|
||||
\fB\-\-synchronize\fP
|
||||
Perform a synchronization
|
||||
.TP
|
||||
\fB\-\-upload\-only\fP
|
||||
Only upload to OneDrive, do not sync changes from OneDrive locally
|
||||
.br
|
||||
Configuration file key: \fBupload_only\fP (default: \fBfalse\fP)
|
||||
.TP
|
||||
\fB\-v \-\-verbose\fP
|
||||
Print more details, useful for debugging. Given two times (or more)
|
||||
|
@ -141,27 +198,8 @@ cp\ @DOCDIR@/config\ ~/.config/onedrive/config
|
|||
\fP
|
||||
.fi
|
||||
|
||||
Available options:
|
||||
.TP
|
||||
\fBsync_dir\fP
|
||||
directory where the files will be synced
|
||||
.TP
|
||||
\fBskip_file\fP
|
||||
any files that match this pattern will be skipped during sync
|
||||
.TP
|
||||
\fBskip_symlinks\fP
|
||||
skip symbolic links during sync, defaults to \fB"false"\fP
|
||||
.TP
|
||||
\fBmonitor_interval\fP
|
||||
the number of seconds by which each sync operation is undertaken when
|
||||
idle under monitor mode, defaults to \fB"45"\fP
|
||||
.TP
|
||||
\fBmin_notif_changes\fP
|
||||
the minimum number of pending incoming changes necessary to trigger
|
||||
a desktop notification, defaults to \fB"5"\fP
|
||||
.TP
|
||||
\fBlog_dir\fP
|
||||
defines the directory where logging output is saved to, needs to end with a slash
|
||||
For the supported options see the above list of command line options
|
||||
for the availability of a configuration key.
|
||||
.PP
|
||||
Pattern are case insensitive.
|
||||
\fB*\fP and \fB?\fP wildcards characters are supported.
|
||||
|
|
400
src/config.d
400
src/config.d
|
@ -1,4 +1,6 @@
|
|||
import std.file, std.string, std.regex, std.stdio;
|
||||
import core.stdc.stdlib: EXIT_SUCCESS, EXIT_FAILURE, exit;
|
||||
import std.file, std.string, std.regex, std.stdio, std.process, std.algorithm.searching, std.getopt, std.conv;
|
||||
import std.algorithm.sorting: sort;
|
||||
import selective;
|
||||
static import log;
|
||||
|
||||
|
@ -10,13 +12,108 @@ final class Config
|
|||
public string databaseFilePathDryRun;
|
||||
public string uploadStateFilePath;
|
||||
public string syncListFilePath;
|
||||
public string homePath;
|
||||
public string configDirName;
|
||||
|
||||
private string userConfigFilePath;
|
||||
// hashmap for the values found in the user config file
|
||||
private string[string] values;
|
||||
// ARGGGG D is stupid and cannot make hashmap initializations!!!
|
||||
// private string[string] foobar = [ "aa": "bb" ] does NOT work!!!
|
||||
private string[string] stringValues;
|
||||
private bool[string] boolValues;
|
||||
private long[string] longValues;
|
||||
|
||||
this(string configDirName)
|
||||
|
||||
this(string confdirOption)
|
||||
{
|
||||
// default configuration
|
||||
stringValues["sync_dir"] = "~/OneDrive";
|
||||
stringValues["skip_file"] = "~*|.~*|*.tmp";
|
||||
stringValues["skip_dir"] = "";
|
||||
stringValues["log_dir"] = "/var/log/onedrive/";
|
||||
stringValues["drive_id"] = "";
|
||||
boolValues["upload_only"] = false;
|
||||
boolValues["check_nomount"] = false;
|
||||
boolValues["check_nosync"] = false;
|
||||
boolValues["download_only"] = false;
|
||||
boolValues["disable_notifications"] = false;
|
||||
boolValues["disable_upload_validation"] = false;
|
||||
boolValues["enable_logging"] = false;
|
||||
boolValues["force_http_11"] = false;
|
||||
boolValues["local_first"] = false;
|
||||
boolValues["no_remote_delete"] = false;
|
||||
boolValues["skip_symlinks"] = false;
|
||||
boolValues["debug_https"] = false;
|
||||
boolValues["skip_dotfiles"] = false;
|
||||
boolValues["dry_run"] = false;
|
||||
longValues["verbose"] = log.verbose; // might be initialized by the first getopt call!
|
||||
longValues["monitor_interval"] = 45,
|
||||
longValues["min_notif_changes"] = 5;
|
||||
longValues["monitor_log_frequency"] = 5;
|
||||
// Number of n sync runs before performing a full local scan of sync_dir
|
||||
// By default 10 which means every ~7.5 minutes a full disk scan of sync_dir will occur
|
||||
longValues["monitor_fullscan_frequency"] = 10;
|
||||
|
||||
// Determine the users home directory.
|
||||
// Need to avoid using ~ here as expandTilde() below does not interpret correctly when running under init.d or systemd scripts
|
||||
// Check for HOME environment variable
|
||||
if (environment.get("HOME") != ""){
|
||||
// Use HOME environment variable
|
||||
log.vdebug("homePath: HOME environment variable set");
|
||||
homePath = environment.get("HOME");
|
||||
} else {
|
||||
if ((environment.get("SHELL") == "") && (environment.get("USER") == "")){
|
||||
// No shell is set or username - observed case when running as systemd service under CentOS 7.x
|
||||
log.vdebug("homePath: WARNING - no HOME environment variable set");
|
||||
log.vdebug("homePath: WARNING - no SHELL environment variable set");
|
||||
log.vdebug("homePath: WARNING - no USER environment variable set");
|
||||
homePath = "/root";
|
||||
} else {
|
||||
// A shell & valid user is set, but no HOME is set, use ~ which can be expanded
|
||||
log.vdebug("homePath: WARNING - no HOME environment variable set");
|
||||
homePath = "~";
|
||||
}
|
||||
}
|
||||
|
||||
// Output homePath calculation
|
||||
log.vdebug("homePath: ", homePath);
|
||||
|
||||
|
||||
// Determine the correct configuration directory to use
|
||||
string configDirBase;
|
||||
if (confdirOption != "") {
|
||||
// A CLI 'confdir' was passed in
|
||||
log.vdebug("configDirName: CLI override to set configDirName to: ", confdirOption);
|
||||
if (canFind(confdirOption,"~")) {
|
||||
// A ~ was found
|
||||
log.vdebug("configDirName: A '~' was found in configDirName, using the calculated 'homePath' to replace '~'");
|
||||
configDirName = homePath ~ strip(confdirOption,"~","~");
|
||||
} else {
|
||||
configDirName = confdirOption;
|
||||
}
|
||||
} else {
|
||||
// Determine the base directory relative to which user specific configuration files should be stored.
|
||||
if (environment.get("XDG_CONFIG_HOME") != ""){
|
||||
log.vdebug("configDirBase: XDG_CONFIG_HOME environment variable set");
|
||||
configDirBase = environment.get("XDG_CONFIG_HOME");
|
||||
} else {
|
||||
// XDG_CONFIG_HOME does not exist on systems where X11 is not present - ie - headless systems / servers
|
||||
log.vdebug("configDirBase: WARNING - no XDG_CONFIG_HOME environment variable set");
|
||||
configDirBase = homePath ~ "/.config";
|
||||
}
|
||||
|
||||
// Output configDirBase calculation
|
||||
log.vdebug("configDirBase: ", configDirBase);
|
||||
// Set the default application configuration directory
|
||||
log.vdebug("configDirName: Configuring application to use default config path");
|
||||
// configDirBase contains the correct path so we do not need to check for presence of '~'
|
||||
configDirName = configDirBase ~ "/onedrive";
|
||||
}
|
||||
|
||||
|
||||
log.vlog("Using Config Dir: ", configDirName);
|
||||
if (!exists(configDirName)) mkdirRecurse(configDirName);
|
||||
|
||||
refreshTokenFilePath = configDirName ~ "/refresh_token";
|
||||
deltaLinkFilePath = configDirName ~ "/delta_link";
|
||||
databaseFilePath = configDirName ~ "/items.sqlite3";
|
||||
|
@ -26,39 +123,8 @@ final class Config
|
|||
syncListFilePath = configDirName ~ "/sync_list";
|
||||
}
|
||||
|
||||
bool init()
|
||||
bool initialize()
|
||||
{
|
||||
// Default configuration directory
|
||||
setValue("sync_dir", "~/OneDrive");
|
||||
// Skip Directories - no directories are skipped by default
|
||||
setValue("skip_dir", "");
|
||||
// 'skilion' configuration was: .*|~*
|
||||
// Skip files that start with ~
|
||||
// Skip files that start with .~ (like .~lock.* files generated by LibreOffice)
|
||||
// Skip files that end in .tmp
|
||||
setValue("skip_file", "~*|.~*|*.tmp");
|
||||
// By default skip dot files & folders are not skipped
|
||||
setValue("skip_dotfiles", "false");
|
||||
// By default symlinks are not skipped (using string type
|
||||
// instead of boolean because hashmap only stores string types)
|
||||
setValue("skip_symlinks", "false");
|
||||
// Configure the monitor mode loop - the number of seconds by which
|
||||
// each sync operation is undertaken when idle under monitor mode
|
||||
setValue("monitor_interval", "45");
|
||||
// Configure the default logging directory to be /var/log/onedrive/
|
||||
setValue("log_dir", "/var/log/onedrive/");
|
||||
// Configure a default empty value for drive_id
|
||||
setValue("drive_id", "");
|
||||
// Minimal changes that trigger a log and notification on sync
|
||||
setValue("min_notif_changes", "5");
|
||||
// Frequency of log messages in monitor, ie after n sync runs ship out a log message
|
||||
setValue("monitor_log_frequency", "5");
|
||||
// Number of n sync runs before performing a full local scan of sync_dir
|
||||
// By default 10 which means every ~7.5 minutes a full disk scan of sync_dir will occur
|
||||
setValue("monitor_fullscan_frequency", "10");
|
||||
// Check if we should ignore a directory if a special file (.nosync) is present
|
||||
setValue("check_nosync", "false");
|
||||
|
||||
if (!load(userConfigFilePath)) {
|
||||
// What was the reason for failure?
|
||||
if (!exists(userConfigFilePath)) {
|
||||
|
@ -72,9 +138,169 @@ final class Config
|
|||
return true;
|
||||
}
|
||||
|
||||
string getValue(string key)
|
||||
|
||||
void update_from_args(string[] args)
|
||||
{
|
||||
auto p = key in values;
|
||||
|
||||
// Add additional options that are NOT configurable via config file
|
||||
stringValues["create_directory"] = "";
|
||||
stringValues["destination_directory"] = "";
|
||||
stringValues["get_o365_drive_id"] = "";
|
||||
stringValues["remove_directory"] = "";
|
||||
stringValues["single_directory"] = "";
|
||||
stringValues["source_directory"] = "";
|
||||
boolValues["display_config"] = false;
|
||||
boolValues["display_sync_status"] = false;
|
||||
boolValues["resync"] = false;
|
||||
boolValues["print_token"] = false;
|
||||
boolValues["logout"] = false;
|
||||
boolValues["monitor"] = false;
|
||||
boolValues["synchronize"] = false;
|
||||
|
||||
|
||||
// Application Startup option validation
|
||||
try {
|
||||
string tmpStr;
|
||||
bool tmpBol;
|
||||
long tmpVerb;
|
||||
auto opt = getopt(
|
||||
args,
|
||||
std.getopt.config.bundling,
|
||||
std.getopt.config.caseSensitive,
|
||||
"check-for-nomount",
|
||||
"Check for the presence of .nosync in the syncdir root. If found, do not perform sync.",
|
||||
&boolValues["check_nomount"],
|
||||
"check-for-nosync",
|
||||
"Check for the presence of .nosync in each directory. If found, skip directory from sync.",
|
||||
&boolValues["check_nosync"],
|
||||
"create-directory",
|
||||
"Create a directory on OneDrive - no sync will be performed.",
|
||||
&stringValues["create_directory"],
|
||||
"debug-https",
|
||||
"Debug OneDrive HTTPS communication.",
|
||||
&boolValues["debug_https"],
|
||||
"destination-directory",
|
||||
"Destination directory for renamed or move on OneDrive - no sync will be performed.",
|
||||
&stringValues["destination_directory"],
|
||||
"disable-notifications",
|
||||
"Do not use desktop notifications in monitor mode.",
|
||||
&boolValues["disable_notifications"],
|
||||
"disable-upload-validation",
|
||||
"Disable upload validation when uploading to OneDrive",
|
||||
&boolValues["disable_upload_validation"],
|
||||
"display-config",
|
||||
"Display what options the client will use as currently configured - no sync will be performed.",
|
||||
&boolValues["display_config"],
|
||||
"display-sync-status",
|
||||
"Display the sync status of the client - no sync will be performed.",
|
||||
&boolValues["display_sync_status"],
|
||||
"download-only|d",
|
||||
"Only download remote changes",
|
||||
&boolValues["download_only"],
|
||||
"dry-run",
|
||||
"Perform a trial sync with no changes made",
|
||||
&boolValues["dry_run"],
|
||||
"enable-logging",
|
||||
"Enable client activity to a separate log file",
|
||||
&boolValues["enable_logging"],
|
||||
"force-http-1.1",
|
||||
"Force the use of HTTP 1.1 for all operations",
|
||||
&boolValues["force_http_11"],
|
||||
"get-O365-drive-id",
|
||||
"Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library",
|
||||
&stringValues["get_o365_drive_id"],
|
||||
"local-first",
|
||||
"Synchronize from the local directory source first, before downloading changes from OneDrive.",
|
||||
&boolValues["local_first"],
|
||||
"log-dir",
|
||||
"Directory where logging output is saved to, needs to end with a slash.",
|
||||
&stringValues["log_dir"],
|
||||
"logout",
|
||||
"Logout the current user",
|
||||
&boolValues["logout"],
|
||||
"min-notif-changes",
|
||||
"Minimum number of pending incoming changes necessary to trigger a desktop notification",
|
||||
&longValues["min_notif_changes"],
|
||||
"monitor|m",
|
||||
"Keep monitoring for local and remote changes",
|
||||
&boolValues["monitor"],
|
||||
"monitor-interval",
|
||||
"Number of seconds by which each sync operation is undertaken when idle under monitor mode.",
|
||||
&longValues["monitor_interval"],
|
||||
"monitor-fullscan-frequency",
|
||||
"Number of sync runs before performing a full local scan of the synced directory",
|
||||
&longValues["monitor_fullscan_frequency"],
|
||||
"monitor-log-frequency",
|
||||
"Frequency of logging in monitor mode",
|
||||
&longValues["monitor_log_frequency"],
|
||||
"no-remote-delete",
|
||||
"Do not delete local file 'deletes' from OneDrive when using --upload-only",
|
||||
&boolValues["no_remote_delete"],
|
||||
"print-token",
|
||||
"Print the access token, useful for debugging",
|
||||
&boolValues["print_token"],
|
||||
"resync",
|
||||
"Forget the last saved state, perform a full sync",
|
||||
&boolValues["resync"],
|
||||
"remove-directory",
|
||||
"Remove a directory on OneDrive - no sync will be performed.",
|
||||
&stringValues["remove_directory"],
|
||||
"single-directory",
|
||||
"Specify a single local directory within the OneDrive root to sync.",
|
||||
&stringValues["single_directory"],
|
||||
"skip-dot-files",
|
||||
"Skip dot files and folders from syncing",
|
||||
&boolValues["skip_dotfiles"],
|
||||
"skip-file",
|
||||
"Skip any files that match this pattern from syncing",
|
||||
&stringValues["skip_file"],
|
||||
"skip-symlinks",
|
||||
"Skip syncing of symlinks",
|
||||
&boolValues["skip_symlinks"],
|
||||
"source-directory",
|
||||
"Source directory to rename or move on OneDrive - no sync will be performed.",
|
||||
&stringValues["source_directory"],
|
||||
"syncdir",
|
||||
"Specify the local directory used for synchronization to OneDrive",
|
||||
&stringValues["sync_dir"],
|
||||
"synchronize",
|
||||
"Perform a synchronization",
|
||||
&boolValues["synchronize"],
|
||||
"upload-only",
|
||||
"Only upload to OneDrive, do not sync changes from OneDrive locally",
|
||||
&boolValues["upload_only"],
|
||||
// duplicated from main.d to get full help output!
|
||||
"confdir",
|
||||
"Set the directory used to store the configuration files",
|
||||
&tmpStr,
|
||||
"verbose|v+",
|
||||
"Print more details, useful for debugging (repeat for extra debugging)",
|
||||
&tmpVerb,
|
||||
"version",
|
||||
"Print the version and exit",
|
||||
&tmpBol
|
||||
|
||||
);
|
||||
if (opt.helpWanted) {
|
||||
outputLongHelp(opt.options);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} catch (GetOptException e) {
|
||||
log.error(e.msg);
|
||||
log.error("Try 'onedrive -h' for more information");
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (Exception e) {
|
||||
// error
|
||||
log.error(e.msg);
|
||||
log.error("Try 'onedrive -h' for more information");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string getValueString(string key)
|
||||
{
|
||||
auto p = key in stringValues;
|
||||
if (p) {
|
||||
return *p;
|
||||
} else {
|
||||
|
@ -82,19 +308,39 @@ final class Config
|
|||
}
|
||||
}
|
||||
|
||||
string getValue(string key, string value)
|
||||
long getValueLong(string key)
|
||||
{
|
||||
auto p = key in values;
|
||||
auto p = key in longValues;
|
||||
if (p) {
|
||||
return *p;
|
||||
} else {
|
||||
return value;
|
||||
throw new Exception("Missing config value: " ~ key);
|
||||
}
|
||||
}
|
||||
|
||||
void setValue(string key, string value)
|
||||
bool getValueBool(string key)
|
||||
{
|
||||
values[key] = value;
|
||||
auto p = key in boolValues;
|
||||
if (p) {
|
||||
return *p;
|
||||
} else {
|
||||
throw new Exception("Missing config value: " ~ key);
|
||||
}
|
||||
}
|
||||
|
||||
void setValueBool(string key, bool value)
|
||||
{
|
||||
boolValues[key] = value;
|
||||
}
|
||||
|
||||
void setValueString(string key, string value)
|
||||
{
|
||||
stringValues[key] = value;
|
||||
}
|
||||
|
||||
void setValueLong(string key, long value)
|
||||
{
|
||||
longValues[key] = value;
|
||||
}
|
||||
|
||||
private bool load(string filename)
|
||||
|
@ -109,13 +355,26 @@ final class Config
|
|||
if (!c.empty) {
|
||||
c.popFront(); // skip the whole match
|
||||
string key = c.front.dup;
|
||||
auto p = key in values;
|
||||
auto p = key in boolValues;
|
||||
if (p) {
|
||||
c.popFront();
|
||||
setValue(key, c.front.dup);
|
||||
// only accept "true" as true value. TODO Should we support other formats?
|
||||
setValueBool(key, c.front.dup == "true" ? true : false);
|
||||
} else {
|
||||
log.log("Unknown key in config file: ", key);
|
||||
return false;
|
||||
auto pp = key in stringValues;
|
||||
if (pp) {
|
||||
c.popFront();
|
||||
setValueString(key, c.front.dup);
|
||||
} else {
|
||||
auto ppp = key in longValues;
|
||||
if (ppp) {
|
||||
c.popFront();
|
||||
setValueLong(key, to!long(c.front.dup));
|
||||
} else {
|
||||
log.log("Unknown key in config file: ", key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.log("Malformed config line: ", line);
|
||||
|
@ -126,10 +385,55 @@ final class Config
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void outputLongHelp(Option[] opt)
|
||||
{
|
||||
auto argsNeedingOptions = [
|
||||
"--confdir",
|
||||
"--create-directory",
|
||||
"--destination-directory",
|
||||
"--get-O365-drive-id",
|
||||
"--log-dir",
|
||||
"--min-notif-changes",
|
||||
"--monitor-interval",
|
||||
"--monitor-log-frequency",
|
||||
"--monitor-fullscan-frequency",
|
||||
"--remove-directory",
|
||||
"--single-directory",
|
||||
"--skip-file",
|
||||
"--source-directory",
|
||||
"--syncdir" ];
|
||||
writeln(`OneDrive - a client for OneDrive Cloud Services
|
||||
|
||||
Usage:
|
||||
onedrive [options] --synchronize
|
||||
Do a one time synchronization
|
||||
onedrive [options] --monitor
|
||||
Monitor filesystem and sync regularly
|
||||
onedrive [options] --display-config
|
||||
Display the currently used configuration
|
||||
onedrive [options] --display-sync-status
|
||||
Query OneDrive service and report on pending changes
|
||||
onedrive -h | --help
|
||||
Show this help screen
|
||||
onedrive --version
|
||||
Show version
|
||||
|
||||
Options:
|
||||
`);
|
||||
foreach (it; opt.sort!("a.optLong < b.optLong")) {
|
||||
writefln(" %s%s%s%s\n %s",
|
||||
it.optLong,
|
||||
it.optShort == "" ? "" : " " ~ it.optShort,
|
||||
argsNeedingOptions.canFind(it.optLong) ? " ARG" : "",
|
||||
it.required ? " (required)" : "", it.help);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
auto cfg = new Config("");
|
||||
cfg.load("config");
|
||||
assert(cfg.getValue("sync_dir") == "~/OneDrive");
|
||||
assert(cfg.getValue("empty", "default") == "default");
|
||||
assert(cfg.getValueString("sync_dir") == "~/OneDrive");
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ version(Notifications) {
|
|||
}
|
||||
|
||||
// enable verbose logging
|
||||
int verbose;
|
||||
long verbose;
|
||||
bool writeLogFile = false;
|
||||
|
||||
private bool doNotifications;
|
||||
|
|
427
src/main.d
427
src/main.d
|
@ -19,114 +19,26 @@ int main(string[] args)
|
|||
// Disable buffering on stdout
|
||||
stdout.setvbuf(0, _IONBF);
|
||||
|
||||
// Application Option Variables
|
||||
// Add a check mounts option to resolve https://github.com/abraunegg/onedrive/issues/8
|
||||
bool checkMount = false;
|
||||
// Check if we should ignore a directory if a special file (.nosync) is present - https://github.com/abraunegg/onedrive/issues/163
|
||||
bool checkNoSync = false;
|
||||
// configuration directory
|
||||
string configDirName;
|
||||
// Create a single root directory on OneDrive
|
||||
string createDirectory;
|
||||
// The destination directory if we are using the OneDrive client to rename a directory
|
||||
string destinationDirectory;
|
||||
// Debug the HTTPS submit operations if required
|
||||
bool debugHttp = false;
|
||||
// Do not use notifications in monitor mode
|
||||
bool disableNotifications = false;
|
||||
// Display application configuration but do not sync
|
||||
bool displayConfiguration = false;
|
||||
// Display sync status
|
||||
bool displaySyncStatus = false;
|
||||
// only download remote changes
|
||||
bool downloadOnly = false;
|
||||
// Does the user want to disable upload validation - https://github.com/abraunegg/onedrive/issues/205
|
||||
// SharePoint will associate some metadata from the library the file is uploaded to directly in the file - thus change file size & checksums
|
||||
bool disableUploadValidation = false;
|
||||
// Perform only a dry run - not applicable for --monitor mode
|
||||
bool dryRun = false;
|
||||
// Do we enable a log file
|
||||
bool enableLogFile = false;
|
||||
// Force the use of HTTP 1.1 to overcome curl => 7.62.0 where some operations are now sent via HTTP/2
|
||||
// Whilst HTTP/2 operations are handled, in some cases the handling of this outside of the client is not being done correctly (router, other) thus the client breaks
|
||||
// This flag then allows the user to downgrade all HTTP operations to HTTP 1.1 for maximum network path compatibility
|
||||
bool forceHTTP11 = false;
|
||||
// SharePoint / Office 365 Shared Library name to query
|
||||
string o365SharedLibraryName;
|
||||
// Local sync - Upload local changes first before downloading changes from OneDrive
|
||||
bool localFirst = false;
|
||||
// remove the current user and sync state
|
||||
bool logout = false;
|
||||
// enable monitor mode
|
||||
bool monitor = false;
|
||||
// Add option for no remote delete
|
||||
bool noRemoteDelete = false;
|
||||
// print the access token
|
||||
bool printAccessToken = false;
|
||||
// force a full resync
|
||||
bool resync = false;
|
||||
// Remove a single directory on OneDrive
|
||||
string removeDirectory;
|
||||
// This allows for selective directory syncing instead of everything under ~/OneDrive/
|
||||
string singleDirectory;
|
||||
// Skip dot files & folders - eg .file or /.folder/
|
||||
bool skipDotFiles = false;
|
||||
// Add option to skip symlinks
|
||||
bool skipSymlinks = false;
|
||||
// The source directory if we are using the OneDrive client to rename a directory
|
||||
string sourceDirectory;
|
||||
// override the sync directory
|
||||
string syncDirName;
|
||||
// Configure a flag to perform a sync
|
||||
// This is beneficial so that if just running the client itself - without any options, or sync check, the client does not perform a sync
|
||||
bool synchronize = false;
|
||||
// Upload Only
|
||||
bool uploadOnly = false;
|
||||
// enable verbose logging
|
||||
bool verbose = false;
|
||||
// print the version and exit
|
||||
bool printVersion = false;
|
||||
|
||||
// Application Startup option validation
|
||||
string confdirOption;
|
||||
|
||||
try {
|
||||
// print the version and exit
|
||||
bool printVersion = false;
|
||||
auto opt = getopt(
|
||||
args,
|
||||
std.getopt.config.passThrough,
|
||||
std.getopt.config.bundling,
|
||||
std.getopt.config.caseSensitive,
|
||||
"check-for-nomount", "Check for the presence of .nosync in the syncdir root. If found, do not perform sync.", &checkMount,
|
||||
"check-for-nosync", "Check for the presence of .nosync in each directory. If found, skip directory from sync.", &checkNoSync,
|
||||
"confdir", "Set the directory used to store the configuration files", &configDirName,
|
||||
"create-directory", "Create a directory on OneDrive - no sync will be performed.", &createDirectory,
|
||||
"destination-directory", "Destination directory for renamed or move on OneDrive - no sync will be performed.", &destinationDirectory,
|
||||
"debug-https", "Debug OneDrive HTTPS communication.", &debugHttp,
|
||||
"disable-notifications", "Do not use desktop notifications in monitor mode.", &disableNotifications,
|
||||
"display-config", "Display what options the client will use as currently configured - no sync will be performed.", &displayConfiguration,
|
||||
"display-sync-status", "Display the sync status of the client - no sync will be performed.", &displaySyncStatus,
|
||||
"download-only|d", "Only download remote changes", &downloadOnly,
|
||||
"disable-upload-validation", "Disable upload validation when uploading to OneDrive", &disableUploadValidation,
|
||||
"dry-run", "Perform a trial sync with no changes made", &dryRun,
|
||||
"enable-logging", "Enable client activity to a separate log file", &enableLogFile,
|
||||
"force-http-1.1", "Force the use of HTTP 1.1 for all operations", &forceHTTP11,
|
||||
"get-O365-drive-id", "Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library", &o365SharedLibraryName,
|
||||
"local-first", "Synchronize from the local directory source first, before downloading changes from OneDrive.", &localFirst,
|
||||
"logout", "Logout the current user", &logout,
|
||||
"monitor|m", "Keep monitoring for local and remote changes", &monitor,
|
||||
"no-remote-delete", "Do not delete local file 'deletes' from OneDrive when using --upload-only", &noRemoteDelete,
|
||||
"print-token", "Print the access token, useful for debugging", &printAccessToken,
|
||||
"resync", "Forget the last saved state, perform a full sync", &resync,
|
||||
"remove-directory", "Remove a directory on OneDrive - no sync will be performed.", &removeDirectory,
|
||||
"single-directory", "Specify a single local directory within the OneDrive root to sync.", &singleDirectory,
|
||||
"skip-dot-files", "Skip dot files and folders from syncing", &skipDotFiles,
|
||||
"skip-symlinks", "Skip syncing of symlinks", &skipSymlinks,
|
||||
"source-directory", "Source directory to rename or move on OneDrive - no sync will be performed.", &sourceDirectory,
|
||||
"syncdir", "Specify the local directory used for synchronization to OneDrive", &syncDirName,
|
||||
"synchronize", "Perform a synchronization", &synchronize,
|
||||
"upload-only", "Only upload to OneDrive, do not sync changes from OneDrive locally", &uploadOnly,
|
||||
"confdir", "Set the directory used to store the configuration files", &confdirOption,
|
||||
"verbose|v+", "Print more details, useful for debugging (repeat for extra debugging)", &log.verbose,
|
||||
"version", "Print the version and exit", &printVersion
|
||||
);
|
||||
if (opt.helpWanted) {
|
||||
outputLongHelp(opt.options);
|
||||
args ~= "--help";
|
||||
}
|
||||
if (printVersion) {
|
||||
std.stdio.write("onedrive ", import("version"));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} catch (GetOptException e) {
|
||||
|
@ -140,92 +52,28 @@ int main(string[] args)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Main function variables
|
||||
string homePath = "";
|
||||
string configDirBase = "";
|
||||
// Debug the HTTPS response operations if required
|
||||
bool debugHttpSubmit;
|
||||
// Are we able to reach the OneDrive Service
|
||||
bool online = false;
|
||||
// simulateNoRefreshTokenFile in case of --dry-run & --logout
|
||||
bool simulateNoRefreshTokenFile = false;
|
||||
|
||||
// Determine the users home directory.
|
||||
// Need to avoid using ~ here as expandTilde() below does not interpret correctly when running under init.d or systemd scripts
|
||||
// Check for HOME environment variable
|
||||
if (environment.get("HOME") != ""){
|
||||
// Use HOME environment variable
|
||||
log.vdebug("homePath: HOME environment variable set");
|
||||
homePath = environment.get("HOME");
|
||||
} else {
|
||||
if ((environment.get("SHELL") == "") && (environment.get("USER") == "")){
|
||||
// No shell is set or username - observed case when running as systemd service under CentOS 7.x
|
||||
log.vdebug("homePath: WARNING - no HOME environment variable set");
|
||||
log.vdebug("homePath: WARNING - no SHELL environment variable set");
|
||||
log.vdebug("homePath: WARNING - no USER environment variable set");
|
||||
homePath = "/root";
|
||||
} else {
|
||||
// A shell & valid user is set, but no HOME is set, use ~ which can be expanded
|
||||
log.vdebug("homePath: WARNING - no HOME environment variable set");
|
||||
homePath = "~";
|
||||
}
|
||||
}
|
||||
|
||||
// Output homePath calculation
|
||||
log.vdebug("homePath: ", homePath);
|
||||
|
||||
// Determine the base directory relative to which user specific configuration files should be stored.
|
||||
if (environment.get("XDG_CONFIG_HOME") != ""){
|
||||
log.vdebug("configDirBase: XDG_CONFIG_HOME environment variable set");
|
||||
configDirBase = environment.get("XDG_CONFIG_HOME");
|
||||
} else {
|
||||
// XDG_CONFIG_HOME does not exist on systems where X11 is not present - ie - headless systems / servers
|
||||
log.vdebug("configDirBase: WARNING - no XDG_CONFIG_HOME environment variable set");
|
||||
configDirBase = homePath ~ "/.config";
|
||||
}
|
||||
|
||||
// Output configDirBase calculation
|
||||
log.vdebug("configDirBase: ", configDirBase);
|
||||
|
||||
// Determine the correct configuration directory to use
|
||||
if (configDirName != "") {
|
||||
// A CLI 'confdir' was passed in
|
||||
log.vdebug("configDirName: CLI override to set configDirName to: ", configDirName);
|
||||
if (canFind(configDirName,"~")) {
|
||||
// A ~ was found
|
||||
log.vdebug("configDirName: A '~' was found in configDirName, using the calculated 'homePath' to replace '~'");
|
||||
configDirName = homePath ~ strip(configDirName,"~","~");
|
||||
}
|
||||
} else {
|
||||
// Set the default application configuration directory
|
||||
log.vdebug("configDirName: Configuring application to use default config path");
|
||||
// configDirBase contains the correct path so we do not need to check for presence of '~'
|
||||
configDirName = configDirBase ~ "/onedrive";
|
||||
}
|
||||
|
||||
if (printVersion) {
|
||||
std.stdio.write("onedrive ", import("version"));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// dry-run notification
|
||||
if (dryRun) {
|
||||
log.log("DRY-RUN Configured. Output below shows what 'would' have occurred.");
|
||||
}
|
||||
|
||||
// load application configuration
|
||||
log.vlog("Loading config ...");
|
||||
log.vlog("Using Config Dir: ", configDirName);
|
||||
if (!exists(configDirName)) mkdirRecurse(configDirName);
|
||||
auto cfg = new config.Config(configDirName);
|
||||
if(!cfg.init()){
|
||||
// load configuration file if available
|
||||
auto cfg = new config.Config(confdirOption);
|
||||
if (!cfg.initialize()) {
|
||||
// There was an error loading the configuration
|
||||
// Error message already printed
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// update configuration from command line args
|
||||
cfg.update_from_args(args);
|
||||
|
||||
// dry-run notification
|
||||
if (cfg.getValueBool("dry_run")) {
|
||||
log.log("DRY-RUN Configured. Output below shows what 'would' have occurred.");
|
||||
}
|
||||
|
||||
|
||||
// Are we able to reach the OneDrive Service
|
||||
bool online = false;
|
||||
|
||||
// dry-run database setup
|
||||
if (dryRun) {
|
||||
if (cfg.getValueBool("dry_run")) {
|
||||
// Make a copy of the original items.sqlite3 for use as the dry run copy if it exists
|
||||
if (exists(cfg.databaseFilePath)) {
|
||||
// copy the file
|
||||
|
@ -234,58 +82,29 @@ int main(string[] args)
|
|||
}
|
||||
}
|
||||
|
||||
// command line parameters to override default 'config' & take precedence
|
||||
// Set the client to skip specific directories if .nosync is found AND ONLY if --check-for-nosync was passed in
|
||||
if (checkNoSync) {
|
||||
log.vdebug("CLI override to set check_nosync to: true");
|
||||
cfg.setValue("check_nosync", "true");
|
||||
}
|
||||
|
||||
// Set the client to skip dot files & folders if --skip-dot-files was passed in
|
||||
if (skipDotFiles) {
|
||||
// The user passed in an alternate skip_dotfiles as to what was either in 'config' file or application default
|
||||
log.vdebug("CLI override to set skip_dotfiles to: true");
|
||||
cfg.setValue("skip_dotfiles", "true");
|
||||
}
|
||||
|
||||
// Set the client to skip symbolic links if --skip-symlinks was passed in
|
||||
if (skipSymlinks) {
|
||||
// The user passed in an alternate skip_symlinks as to what was either in 'config' file or application default
|
||||
log.vdebug("CLI override to set skip_symlinks to: true");
|
||||
cfg.setValue("skip_symlinks", "true");
|
||||
}
|
||||
|
||||
// Set the OneDrive Local Sync Directory if was passed in via --syncdir
|
||||
if (syncDirName) {
|
||||
// The user passed in an alternate sync_dir as to what was either in 'config' file or application default
|
||||
// Do not expandTilde here as we do not know if we reliably can
|
||||
log.vdebug("CLI override to set sync_dir to: ", syncDirName);
|
||||
cfg.setValue("sync_dir", syncDirName);
|
||||
}
|
||||
|
||||
// sync_dir environment handling to handle ~ expansion properly
|
||||
string syncDir;
|
||||
if ((environment.get("SHELL") == "") && (environment.get("USER") == "")){
|
||||
log.vdebug("sync_dir: No SHELL or USER environment variable configuration detected");
|
||||
// No shell or user set, so expandTilde() will fail - usually headless system running under init.d / systemd or potentially Docker
|
||||
// Does the 'currently configured' sync_dir include a ~
|
||||
if (canFind(cfg.getValue("sync_dir"),"~")) {
|
||||
if (canFind(cfg.getValueString("sync_dir"), "~")) {
|
||||
// A ~ was found
|
||||
log.vdebug("sync_dir: A '~' was found in sync_dir, using the calculated 'homePath' to replace '~'");
|
||||
syncDir = homePath ~ strip(cfg.getValue("sync_dir"),"~","~");
|
||||
syncDir = cfg.homePath ~ strip(cfg.getValueString("sync_dir"), "~");
|
||||
} else {
|
||||
// No ~ found in sync_dir, use as is
|
||||
log.vdebug("sync_dir: Getting syncDir from config value sync_dir");
|
||||
syncDir = cfg.getValue("sync_dir");
|
||||
syncDir = cfg.getValueString("sync_dir");
|
||||
}
|
||||
} else {
|
||||
// A shell and user is set, expand any ~ as this will be expanded correctly if present
|
||||
log.vdebug("sync_dir: Getting syncDir from config value sync_dir");
|
||||
if (canFind(cfg.getValue("sync_dir"),"~")) {
|
||||
if (canFind(cfg.getValueString("sync_dir"), "~")) {
|
||||
log.vdebug("sync_dir: A '~' was found in configured sync_dir, automatically expanding as SHELL and USER environment variable is set");
|
||||
syncDir = expandTilde(cfg.getValue("sync_dir"));
|
||||
syncDir = expandTilde(cfg.getValueString("sync_dir"));
|
||||
} else {
|
||||
syncDir = cfg.getValue("sync_dir");
|
||||
syncDir = cfg.getValueString("sync_dir");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,50 +112,47 @@ int main(string[] args)
|
|||
log.vdebug("syncDir: ", syncDir);
|
||||
|
||||
// Configure logging if enabled
|
||||
if (enableLogFile){
|
||||
if (cfg.getValueBool("enable_logging")){
|
||||
// Read in a user defined log directory or use the default
|
||||
string logDir = cfg.getValue("log_dir");
|
||||
string logDir = cfg.getValueString("log_dir");
|
||||
log.vlog("Using logfile dir: ", logDir);
|
||||
log.init(logDir);
|
||||
}
|
||||
|
||||
// Configure whether notifications are used
|
||||
log.setNotifications(monitor && !disableNotifications);
|
||||
log.setNotifications(cfg.getValueBool("monitor") && !cfg.getValueBool("disable_notifications"));
|
||||
|
||||
// upgrades
|
||||
if (exists(configDirName ~ "/items.db")) {
|
||||
if (!dryRun) {
|
||||
safeRemove(configDirName ~ "/items.db");
|
||||
if (exists(cfg.configDirName ~ "/items.db")) {
|
||||
if (!cfg.getValueBool("dry_run")) {
|
||||
safeRemove(cfg.configDirName ~ "/items.db");
|
||||
}
|
||||
log.logAndNotify("Database schema changed, resync needed");
|
||||
resync = true;
|
||||
cfg.setValueBool("resync", true);
|
||||
}
|
||||
|
||||
if (resync || logout) {
|
||||
if (cfg.getValueBool("resync") || cfg.getValueBool("logout")) {
|
||||
log.vlog("Deleting the saved status ...");
|
||||
if (!dryRun) {
|
||||
if (!cfg.getValueBool("dry_run")) {
|
||||
safeRemove(cfg.databaseFilePath);
|
||||
safeRemove(cfg.deltaLinkFilePath);
|
||||
safeRemove(cfg.uploadStateFilePath);
|
||||
}
|
||||
if (logout) {
|
||||
if (!dryRun) {
|
||||
if (cfg.getValueBool("logout")) {
|
||||
if (!cfg.getValueBool("dry_run")) {
|
||||
safeRemove(cfg.refreshTokenFilePath);
|
||||
} else {
|
||||
// simulate file being removed / unavailable
|
||||
simulateNoRefreshTokenFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display current application configuration, no application initialisation
|
||||
if (displayConfiguration){
|
||||
string userConfigFilePath = configDirName ~ "/config";
|
||||
string userSyncList = configDirName ~ "/sync_list";
|
||||
if (cfg.getValueBool("display_config")){
|
||||
string userConfigFilePath = cfg.configDirName ~ "/config";
|
||||
string userSyncList = cfg.configDirName ~ "/sync_list";
|
||||
// Display application version
|
||||
std.stdio.write("onedrive version = ", import("version"));
|
||||
// Display all of the pertinent configuration options
|
||||
writeln("Config path = ", configDirName);
|
||||
writeln("Config path = ", cfg.configDirName);
|
||||
|
||||
// Does a config file exist or are we using application defaults
|
||||
if (exists(userConfigFilePath)){
|
||||
|
@ -346,19 +162,19 @@ int main(string[] args)
|
|||
}
|
||||
|
||||
// Config Options
|
||||
writeln("Config option 'check_nosync' = ", cfg.getValue("check_nosync"));
|
||||
writeln("Config option 'check_nosync' = ", cfg.getValueBool("check_nosync"));
|
||||
writeln("Config option 'sync_dir' = ", syncDir);
|
||||
writeln("Config option 'skip_dir' = ", cfg.getValue("skip_dir"));
|
||||
writeln("Config option 'skip_file' = ", cfg.getValue("skip_file"));
|
||||
writeln("Config option 'skip_dotfiles' = ", cfg.getValue("skip_dotfiles"));
|
||||
writeln("Config option 'skip_symlinks' = ", cfg.getValue("skip_symlinks"));
|
||||
writeln("Config option 'monitor_interval' = ", cfg.getValue("monitor_interval"));
|
||||
writeln("Config option 'min_notif_changes' = ", cfg.getValue("min_notif_changes"));
|
||||
writeln("Config option 'log_dir' = ", cfg.getValue("log_dir"));
|
||||
writeln("Config option 'skip_dir' = ", cfg.getValueString("skip_dir"));
|
||||
writeln("Config option 'skip_file' = ", cfg.getValueString("skip_file"));
|
||||
writeln("Config option 'skip_dotfiles' = ", cfg.getValueBool("skip_dotfiles"));
|
||||
writeln("Config option 'skip_symlinks' = ", cfg.getValueBool("skip_symlinks"));
|
||||
writeln("Config option 'monitor_interval' = ", cfg.getValueLong("monitor_interval"));
|
||||
writeln("Config option 'min_notif_changes' = ", cfg.getValueLong("min_notif_changes"));
|
||||
writeln("Config option 'log_dir' = ", cfg.getValueString("log_dir"));
|
||||
|
||||
// Is config option drive_id configured?
|
||||
if (cfg.getValue("drive_id", "") != ""){
|
||||
writeln("Config option 'drive_id' = ", cfg.getValue("drive_id"));
|
||||
if (cfg.getValueString("drive_id") != ""){
|
||||
writeln("Config option 'drive_id' = ", cfg.getValueString("drive_id"));
|
||||
}
|
||||
|
||||
// Is sync_list configured?
|
||||
|
@ -385,14 +201,14 @@ int main(string[] args)
|
|||
} catch (CurlException e) {
|
||||
// No network connection to OneDrive Service
|
||||
log.error("No network connection to Microsoft OneDrive Service");
|
||||
if (!monitor) {
|
||||
if (!cfg.getValueBool("monitor")) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize OneDrive, check for authorization
|
||||
oneDrive = new OneDriveApi(cfg, debugHttp, forceHTTP11, dryRun, simulateNoRefreshTokenFile);
|
||||
oneDrive.printAccessToken = printAccessToken;
|
||||
oneDrive = new OneDriveApi(cfg);
|
||||
oneDrive.printAccessToken = cfg.getValueBool("print_token");
|
||||
if (!oneDrive.init()) {
|
||||
log.error("Could not initialize the OneDrive API");
|
||||
// workaround for segfault in std.net.curl.Curl.shutdown() on exit
|
||||
|
@ -402,13 +218,14 @@ int main(string[] args)
|
|||
|
||||
// if --synchronize or --monitor not passed in, exit & display help
|
||||
auto performSyncOK = false;
|
||||
if (synchronize || monitor) {
|
||||
|
||||
if (cfg.getValueBool("synchronize") || cfg.getValueBool("monitor")) {
|
||||
performSyncOK = true;
|
||||
}
|
||||
|
||||
// create-directory, remove-directory, source-directory, destination-directory
|
||||
// are activities that dont perform a sync no error message for these items either
|
||||
if (((createDirectory != "") || (removeDirectory != "")) || ((sourceDirectory != "") && (destinationDirectory != "")) || (o365SharedLibraryName != "") || (displaySyncStatus == true)) {
|
||||
if (((cfg.getValueString("create_directory") != "") || (cfg.getValueString("remove_directory") != "")) || ((cfg.getValueString("source_directory") != "") && (cfg.getValueString("destination_directory") != "")) || (cfg.getValueString("get_o365_drive_id") != "") || cfg.getValueBool("display_sync_status")) {
|
||||
performSyncOK = true;
|
||||
}
|
||||
|
||||
|
@ -420,7 +237,7 @@ int main(string[] args)
|
|||
}
|
||||
|
||||
// if --synchronize && --monitor passed in, exit & display help as these conflict with each other
|
||||
if (synchronize && monitor) {
|
||||
if (cfg.getValueBool("synchronize") && cfg.getValueBool("monitor")) {
|
||||
writeln("\nERROR: --synchronize and --monitor cannot be used together\n");
|
||||
writeln("Refer to --help to determine which command option you should use.\n");
|
||||
oneDrive.http.shutdown();
|
||||
|
@ -429,7 +246,7 @@ int main(string[] args)
|
|||
|
||||
// Initialize the item database
|
||||
log.vlog("Opening the item database ...");
|
||||
if (!dryRun) {
|
||||
if (!cfg.getValueBool("dry_run")) {
|
||||
// Load the items.sqlite3 file as the database
|
||||
log.vdebug("Using database file: ", cfg.databaseFilePath);
|
||||
itemDb = new ItemDatabase(cfg.databaseFilePath);
|
||||
|
@ -462,15 +279,15 @@ int main(string[] args)
|
|||
|
||||
// Configure skip_dir & skip_file from config entries
|
||||
log.vdebug("Configuring skip_dir ...");
|
||||
log.vdebug("skip_dir: ", cfg.getValue("skip_dir"));
|
||||
selectiveSync.setDirMask(cfg.getValue("skip_dir"));
|
||||
log.vdebug("skip_dir: ", cfg.getValueString("skip_dir"));
|
||||
selectiveSync.setDirMask(cfg.getValueString("skip_dir"));
|
||||
log.vdebug("Configuring skip_file ...");
|
||||
log.vdebug("skip_file: ", cfg.getValue("skip_file"));
|
||||
selectiveSync.setFileMask(cfg.getValue("skip_file"));
|
||||
log.vdebug("skip_file: ", cfg.getValueString("skip_file"));
|
||||
selectiveSync.setFileMask(cfg.getValueString("skip_file"));
|
||||
|
||||
// Initialize the sync engine
|
||||
log.logAndNotify("Initializing the Synchronization Engine ...");
|
||||
auto sync = new SyncEngine(cfg, oneDrive, itemDb, selectiveSync, dryRun);
|
||||
auto sync = new SyncEngine(cfg, oneDrive, itemDb, selectiveSync);
|
||||
|
||||
try {
|
||||
if (!initSyncEngine(sync)) {
|
||||
|
@ -478,21 +295,21 @@ int main(string[] args)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
} catch (CurlException e) {
|
||||
if (!monitor) {
|
||||
log.log("\nNo Internet connection.");
|
||||
if (!cfg.getValueBool("monitor")) {
|
||||
log.log("\nNo internet connection.");
|
||||
oneDrive.http.shutdown();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// We should only set noRemoteDelete in an upload-only scenario
|
||||
if ((uploadOnly)&&(noRemoteDelete)) sync.setNoRemoteDelete();
|
||||
if ((cfg.getValueBool("upload_only"))&&(cfg.getValueBool("no_remote_delete"))) sync.setNoRemoteDelete();
|
||||
|
||||
// Do we configure to disable the upload validation routine
|
||||
if(disableUploadValidation) sync.setDisableUploadValidation();
|
||||
if (cfg.getValueBool("disable_upload_validation")) sync.setDisableUploadValidation();
|
||||
|
||||
// Do we need to validate the syncDir to check for the presence of a '.nosync' file
|
||||
if (checkMount) {
|
||||
if (cfg.getValueBool("check_nomount")) {
|
||||
// we were asked to check the mounts
|
||||
if (exists(syncDir ~ "/.nosync")) {
|
||||
log.logAndNotify("ERROR: .nosync file found. Aborting synchronization process to safeguard data.");
|
||||
|
@ -502,53 +319,53 @@ int main(string[] args)
|
|||
}
|
||||
|
||||
// Do we need to create or remove a directory?
|
||||
if ((createDirectory != "") || (removeDirectory != "")) {
|
||||
if ((cfg.getValueString("create_directory") != "") || (cfg.getValueString("remove_directory") != "")) {
|
||||
|
||||
if (createDirectory != "") {
|
||||
if (cfg.getValueString("create_directory") != "") {
|
||||
// create a directory on OneDrive
|
||||
sync.createDirectoryNoSync(createDirectory);
|
||||
sync.createDirectoryNoSync(cfg.getValueString("create_directory"));
|
||||
}
|
||||
|
||||
if (removeDirectory != "") {
|
||||
if (cfg.getValueString("remove_directory") != "") {
|
||||
// remove a directory on OneDrive
|
||||
sync.deleteDirectoryNoSync(removeDirectory);
|
||||
sync.deleteDirectoryNoSync(cfg.getValueString("remove_directory"));
|
||||
}
|
||||
}
|
||||
|
||||
// Are we renaming or moving a directory?
|
||||
if ((sourceDirectory != "") && (destinationDirectory != "")) {
|
||||
if ((cfg.getValueString("source_directory") != "") && (cfg.getValueString("destination_directory") != "")) {
|
||||
// We are renaming or moving a directory
|
||||
sync.renameDirectoryNoSync(sourceDirectory, destinationDirectory);
|
||||
sync.renameDirectoryNoSync(cfg.getValueString("source_directory"), cfg.getValueString("destination_directory"));
|
||||
}
|
||||
|
||||
// Are we obtaining the Office 365 Drive ID for a given Office 365 SharePoint Shared Library?
|
||||
if (o365SharedLibraryName != ""){
|
||||
sync.querySiteCollectionForDriveID(o365SharedLibraryName);
|
||||
if (cfg.getValueString("get_o365_drive_id") != ""){
|
||||
sync.querySiteCollectionForDriveID(cfg.getValueString("get_o365_drive_id"));
|
||||
}
|
||||
|
||||
// Are we displaying the sync status of the client?
|
||||
if (displaySyncStatus) {
|
||||
if (cfg.getValueBool("display_sync_status")) {
|
||||
string remotePath = "/";
|
||||
string localPath = ".";
|
||||
|
||||
// Are we doing a single directory check?
|
||||
if (singleDirectory != ""){
|
||||
if (cfg.getValueString("single_directory") != ""){
|
||||
// Need two different path strings here
|
||||
remotePath = singleDirectory;
|
||||
localPath = singleDirectory;
|
||||
remotePath = cfg.getValueString("single_directory");
|
||||
localPath = cfg.getValueString("single_directory");
|
||||
}
|
||||
sync.queryDriveForChanges(remotePath);
|
||||
}
|
||||
|
||||
// Are we performing a sync, resync or monitor operation?
|
||||
if ((synchronize) || (resync) || (monitor)) {
|
||||
if ((cfg.getValueBool("synchronize")) || (cfg.getValueBool("resync")) || (cfg.getValueBool("monitor"))) {
|
||||
|
||||
if ((synchronize) || (resync)) {
|
||||
if ((cfg.getValueBool("synchronize")) || (cfg.getValueBool("resync"))) {
|
||||
if (online) {
|
||||
// Check user entry for local path - the above chdir means we are already in ~/OneDrive/ thus singleDirectory is local to this path
|
||||
if (singleDirectory != ""){
|
||||
if (cfg.getValueString("single_directory") != ""){
|
||||
// Does the directory we want to sync actually exist?
|
||||
if (!exists(singleDirectory)){
|
||||
if (!exists(cfg.getValueString("single_directory"))){
|
||||
// the requested directory does not exist ..
|
||||
log.logAndNotify("ERROR: The requested local directory does not exist. Please check ~/OneDrive/ for requested path");
|
||||
oneDrive.http.shutdown();
|
||||
|
@ -556,14 +373,13 @@ int main(string[] args)
|
|||
}
|
||||
}
|
||||
|
||||
// Perform the sync
|
||||
performSync(sync, singleDirectory, downloadOnly, localFirst, uploadOnly, LOG_NORMAL, true);
|
||||
performSync(sync, cfg.getValueString("single_directory"), cfg.getValueBool("download_only"), cfg.getValueBool("local_first"), cfg.getValueBool("upload_only"), LOG_NORMAL, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (monitor) {
|
||||
if (cfg.getValueBool("monitor")) {
|
||||
log.logAndNotify("Initializing monitor ...");
|
||||
log.log("OneDrive monitor interval (seconds): ", to!long(cfg.getValue("monitor_interval")));
|
||||
log.log("OneDrive monitor interval (seconds): ", cfg.getValueLong("monitor_interval"));
|
||||
Monitor m = new Monitor(selectiveSync);
|
||||
m.onDirCreated = delegate(string path) {
|
||||
log.vlog("[M] Directory created: ", path);
|
||||
|
@ -615,19 +431,17 @@ int main(string[] args)
|
|||
signal(SIGTERM, &exitHandler);
|
||||
|
||||
// initialise the monitor class
|
||||
if (cfg.getValue("skip_symlinks") == "true") skipSymlinks = true;
|
||||
if (cfg.getValue("check_nosync") == "true") checkNoSync = true;
|
||||
if (!downloadOnly) m.init(cfg, verbose, skipSymlinks, checkNoSync);
|
||||
if (!cfg.getValueBool("download_only")) m.init(cfg, cfg.getValueLong("verbose") > 0, cfg.getValueBool("skip_symlinks"), cfg.getValueBool("check_nosync"));
|
||||
// monitor loop
|
||||
immutable auto checkInterval = dur!"seconds"(to!long(cfg.getValue("monitor_interval")));
|
||||
immutable auto logInterval = to!long(cfg.getValue("monitor_log_frequency"));
|
||||
immutable auto fullScanFrequency = to!long(cfg.getValue("monitor_fullscan_frequency"));
|
||||
immutable auto checkInterval = dur!"seconds"(cfg.getValueLong("monitor_interval"));
|
||||
immutable auto logInterval = cfg.getValueLong("monitor_log_frequency");
|
||||
immutable auto fullScanFrequency = cfg.getValueLong("monitor_fullscan_frequency");
|
||||
auto lastCheckTime = MonoTime.currTime();
|
||||
auto logMonitorCounter = 0;
|
||||
auto fullScanCounter = 0;
|
||||
bool fullScanRequired = true;
|
||||
while (true) {
|
||||
if (!downloadOnly) m.update(online);
|
||||
if (!cfg.getValueBool("download_only")) m.update(online);
|
||||
auto currTime = MonoTime.currTime();
|
||||
if (currTime - lastCheckTime > checkInterval) {
|
||||
// log monitor output suppression
|
||||
|
@ -653,8 +467,8 @@ int main(string[] args)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
try {
|
||||
performSync(sync, singleDirectory, downloadOnly, localFirst, uploadOnly, (logMonitorCounter == logInterval ? MONITOR_LOG_QUIET : MONITOR_LOG_SILENT), fullScanRequired);
|
||||
if (!downloadOnly) {
|
||||
performSync(sync, cfg.getValueString("single_directory"), cfg.getValueBool("download_only"), cfg.getValueBool("local_first"), cfg.getValueBool("upload_only"), (logMonitorCounter == logInterval ? MONITOR_LOG_QUIET : MONITOR_LOG_SILENT), fullScanRequired);
|
||||
if (!cfg.getValueBool("download_only")) {
|
||||
// discard all events that may have been generated by the sync
|
||||
m.update(false);
|
||||
}
|
||||
|
@ -685,7 +499,7 @@ int main(string[] args)
|
|||
destroy(itemDb);
|
||||
|
||||
// --dry-run temp database cleanup
|
||||
if (dryRun) {
|
||||
if (cfg.getValueBool("dry_run")) {
|
||||
if (exists(cfg.databaseFilePathDryRun)) {
|
||||
// remove the file
|
||||
log.vdebug("Removing items-dryrun.sqlite3 as dry run operations complete");
|
||||
|
@ -825,41 +639,4 @@ extern(C) nothrow @nogc @system void exitHandler(int value) {
|
|||
} catch(Exception e) {}
|
||||
exit(0);
|
||||
}
|
||||
void outputLongHelp(Option[] opt)
|
||||
{
|
||||
auto argsNeedingOptions = [
|
||||
"--confdir",
|
||||
"--create-directory",
|
||||
"--destination-directory",
|
||||
"--get-O365-drive-id",
|
||||
"--remove-directory",
|
||||
"--single-directory",
|
||||
"--source-directory",
|
||||
"--syncdir" ];
|
||||
writeln(`OneDrive - a client for OneDrive Cloud Services
|
||||
|
||||
Usage:
|
||||
onedrive [options] --synchronize
|
||||
Do a one time synchronization
|
||||
onedrive [options] --monitor
|
||||
Monitor filesystem and sync regularly
|
||||
onedrive [options] --display-config
|
||||
Display the currently used configuration
|
||||
onedrive [options] --display-sync-status
|
||||
Query OneDrive service and report on pending changes
|
||||
onedrive -h | --help
|
||||
Show this help screen
|
||||
onedrive --version
|
||||
Show version
|
||||
|
||||
Options:
|
||||
`);
|
||||
foreach (it; opt) {
|
||||
writefln(" %s%s%s%s\n %s",
|
||||
it.optShort == "" ? "" : it.optShort ~ " ",
|
||||
it.optLong,
|
||||
argsNeedingOptions.canFind(it.optLong) ? " ARG" : "",
|
||||
it.required ? " (required)" : "", it.help);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ import progress;
|
|||
import config;
|
||||
static import log;
|
||||
shared bool debugResponse = false;
|
||||
shared bool dryRun = false;
|
||||
shared bool simulateNoRefreshTokenFile = false;
|
||||
private bool dryRun = false;
|
||||
private bool simulateNoRefreshTokenFile = false;
|
||||
|
||||
private immutable {
|
||||
// Client Identifier
|
||||
|
@ -66,7 +66,7 @@ final class OneDriveApi
|
|||
// if true, every new access token is printed
|
||||
bool printAccessToken;
|
||||
|
||||
this(Config cfg, bool debugHttp, bool forceHTTP11, bool dryRun, bool simulateNoRefreshTokenFile)
|
||||
this(Config cfg)
|
||||
{
|
||||
this.cfg = cfg;
|
||||
http = HTTP();
|
||||
|
@ -94,36 +94,36 @@ final class OneDriveApi
|
|||
http.maxRedirects(5);
|
||||
|
||||
// Do we enable curl debugging?
|
||||
if (debugHttp) {
|
||||
if (cfg.getValueBool("debug_https")) {
|
||||
http.verbose = true;
|
||||
.debugResponse = true;
|
||||
}
|
||||
|
||||
// What version of HTTP protocol do we use?
|
||||
// Curl >= 7.62.0 defaults to http2 for a significant number of operations
|
||||
if (forceHTTP11) {
|
||||
if (cfg.getValueBool("force_http_11")) {
|
||||
log.vdebug("Downgrading all HTTP operations to HTTP 1.1");
|
||||
// Downgrade to HTTP 1.1 - yes version = 2 is HTTP 1.1
|
||||
http.handle.set(CurlOption.http_version,2);
|
||||
}
|
||||
|
||||
// Do we set the dryRun handlers?
|
||||
if (dryRun) {
|
||||
if (cfg.getValueBool("dry_run")) {
|
||||
.dryRun = true;
|
||||
}
|
||||
if (simulateNoRefreshTokenFile) {
|
||||
.simulateNoRefreshTokenFile = true;
|
||||
if (cfg.getValueBool("logout")) {
|
||||
.simulateNoRefreshTokenFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool init()
|
||||
{
|
||||
try {
|
||||
driveId = cfg.getValue("drive_id");
|
||||
driveId = cfg.getValueString("drive_id");
|
||||
if (driveId.length) {
|
||||
driveUrl = driveByIdUrl ~ driveId;
|
||||
itemByIdUrl = driveUrl ~ "/items";
|
||||
itemByPathUrl = driveUrl ~ "/root:/";
|
||||
itemByIdUrl = driveUrl ~ "/items";
|
||||
itemByPathUrl = driveUrl ~ "/root:/";
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
|
||||
|
|
20
src/sync.d
20
src/sync.d
|
@ -208,7 +208,7 @@ final class SyncEngine
|
|||
// sync engine dryRun flag
|
||||
private bool dryRun = false;
|
||||
|
||||
this(Config cfg, OneDriveApi onedrive, ItemDatabase itemdb, SelectiveSync selectiveSync, bool dryRun)
|
||||
this(Config cfg, OneDriveApi onedrive, ItemDatabase itemdb, SelectiveSync selectiveSync)
|
||||
{
|
||||
assert(onedrive && itemdb && selectiveSync);
|
||||
this.cfg = cfg;
|
||||
|
@ -216,7 +216,7 @@ final class SyncEngine
|
|||
this.itemdb = itemdb;
|
||||
this.selectiveSync = selectiveSync;
|
||||
// session = UploadSession(onedrive, cfg.uploadStateFilePath);
|
||||
this.dryRun = dryRun;
|
||||
this.dryRun = cfg.getValueBool("dry_run");
|
||||
}
|
||||
|
||||
void reset()
|
||||
|
@ -243,7 +243,7 @@ final class SyncEngine
|
|||
// OneDrive responded with 400 error: Bad Request
|
||||
log.error("\nERROR: OneDrive returned a 'HTTP 400 Bad Request' - Cannot Initialize Sync Engine");
|
||||
// Check this
|
||||
if (cfg.getValue("drive_id").length) {
|
||||
if (cfg.getValueString("drive_id").length) {
|
||||
log.error("ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect\n");
|
||||
}
|
||||
// Must exit here
|
||||
|
@ -614,7 +614,7 @@ final class SyncEngine
|
|||
if (("value" in changes) != null) {
|
||||
auto nrChanges = count(changes["value"].array);
|
||||
|
||||
if (nrChanges >= to!long(cfg.getValue("min_notif_changes"))) {
|
||||
if (nrChanges >= cfg.getValueLong("min_notif_changes")) {
|
||||
log.logAndNotify("Processing ", nrChanges, " changes");
|
||||
} else {
|
||||
// There are valid changes
|
||||
|
@ -768,7 +768,7 @@ final class SyncEngine
|
|||
// Check if this is a directory to skip
|
||||
if (!unwanted) {
|
||||
// Only check path if config is != ""
|
||||
if (cfg.getValue("skip_dir") != "") {
|
||||
if (cfg.getValueString("skip_dir") != "") {
|
||||
unwanted = selectiveSync.isDirNameExcluded(item.name);
|
||||
if (unwanted) log.vlog("Skipping item - excluded by skip_dir config: ", item.name);
|
||||
}
|
||||
|
@ -812,7 +812,7 @@ final class SyncEngine
|
|||
}
|
||||
|
||||
// skip downloading dot files if configured
|
||||
if (cfg.getValue("skip_dotfiles") == "true") {
|
||||
if (cfg.getValueBool("skip_dotfiles")) {
|
||||
if (isDotFile(path)) {
|
||||
log.vlog("Skipping item - .file or .folder: ", path);
|
||||
unwanted = true;
|
||||
|
@ -1480,7 +1480,7 @@ final class SyncEngine
|
|||
// path is less than maxPathLength
|
||||
|
||||
// skip dot files if configured
|
||||
if (cfg.getValue("skip_dotfiles") == "true") {
|
||||
if (cfg.getValueBool("skip_dotfiles")) {
|
||||
if (isDotFile(path)) {
|
||||
log.vlog("Skipping item - .file or .folder: ", path);
|
||||
return;
|
||||
|
@ -1488,7 +1488,7 @@ final class SyncEngine
|
|||
}
|
||||
|
||||
// Do we need to check for .nosync? Only if --check-for-nosync was passed in
|
||||
if (cfg.getValue("check_nosync") == "true") {
|
||||
if (cfg.getValueBool("check_nosync")) {
|
||||
if (exists(path ~ "/.nosync")) {
|
||||
log.vlog("Skipping item - .nosync found & --check-for-nosync enabled: ", path);
|
||||
return;
|
||||
|
@ -1497,7 +1497,7 @@ final class SyncEngine
|
|||
|
||||
if (isSymlink(path)) {
|
||||
// if config says so we skip all symlinked items
|
||||
if (cfg.getValue("skip_symlinks") == "true") {
|
||||
if (cfg.getValueBool("skip_symlinks")) {
|
||||
log.vlog("Skipping item - skip symbolic links configured: ", path);
|
||||
return;
|
||||
|
||||
|
@ -1532,7 +1532,7 @@ final class SyncEngine
|
|||
if (isDir(path)) {
|
||||
log.vdebug("Checking path: ", path);
|
||||
// Only check path if config is != ""
|
||||
if (cfg.getValue("skip_dir") != "") {
|
||||
if (cfg.getValueString("skip_dir") != "") {
|
||||
if (selectiveSync.isDirNameExcluded(strip(path,"./"))) {
|
||||
log.vlog("Skipping item - excluded by skip_dir config: ", path);
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue