mirror of
https://github.com/abraunegg/onedrive
synced 2024-05-02 14:12:52 +02:00
parent
3f08e271af
commit
98624267c5
34
README.md
34
README.md
|
@ -264,6 +264,38 @@ Enter the response uri:
|
|||
|
||||
```
|
||||
|
||||
### Testing your configuration
|
||||
You are able to test your configuration by utilising the `--dry-run` CLI option. No files will be downloaded, uploaded or removed, however the application will display what 'would' have occurred. For example:
|
||||
```text
|
||||
onedrive --synchronize --verbose --dry-run
|
||||
DRY-RUN Configured. Output below shows what 'would' have occurred.
|
||||
Loading config ...
|
||||
Using Config Dir: /home/user/.config/onedrive
|
||||
Initializing the OneDrive API ...
|
||||
Opening the item database ...
|
||||
All operations will be performed in: /home/user/OneDrive
|
||||
Initializing the Synchronization Engine ...
|
||||
Account Type: personal
|
||||
Default Drive ID: <redacted>
|
||||
Default Root ID: <redacted>
|
||||
Remaining Free Space: 5368709120
|
||||
Fetching details for OneDrive Root
|
||||
OneDrive Root exists in the database
|
||||
Syncing changes from OneDrive ...
|
||||
Applying changes of Path ID: <redacted>
|
||||
Uploading differences of .
|
||||
Processing root
|
||||
The directory has not changed
|
||||
Uploading new items of .
|
||||
OneDrive Client requested to create remote path: ./newdir
|
||||
The requested directory to create was not found on OneDrive - creating remote directory: ./newdir
|
||||
Successfully created the remote directory ./newdir on OneDrive
|
||||
Uploading new file ./newdir/newfile.txt ... done.
|
||||
Remaining free space: 5368709076
|
||||
Applying changes of Path ID: <redacted>
|
||||
```
|
||||
|
||||
**Note:** `--dry-run` can only be used with `--synchronize`. It cannot be used with `--monitor` and will be ignored.
|
||||
|
||||
### Show your configuration
|
||||
To validate your configuration the application will use, utilise the following:
|
||||
|
@ -664,6 +696,8 @@ Options:
|
|||
Only download remote changes
|
||||
--disable-upload-validation
|
||||
Disable upload validation when uploading to OneDrive
|
||||
--dry-run
|
||||
Perform a trial sync with no changes made
|
||||
--enable-logging
|
||||
Enable client activity to a separate log file
|
||||
--force-http-1.1
|
||||
|
|
|
@ -51,6 +51,9 @@ Display the sync status of the client \- no sync will be performed.
|
|||
\fB\-d \-\-download\-only\fP
|
||||
Only download remote changes
|
||||
.TP
|
||||
\fB\-\-dry\-run\fP
|
||||
Perform a trial sync with no changes made. Can ONLY be used with --synchronize. Will be ignored for --monitor
|
||||
.TP
|
||||
\fB\-\-enable\-logging\fP
|
||||
Enable client activity to a separate log file
|
||||
.TP
|
||||
|
|
|
@ -7,6 +7,7 @@ final class Config
|
|||
public string refreshTokenFilePath;
|
||||
public string deltaLinkFilePath;
|
||||
public string databaseFilePath;
|
||||
public string databaseFilePathDryRun;
|
||||
public string uploadStateFilePath;
|
||||
public string syncListFilePath;
|
||||
|
||||
|
@ -19,6 +20,7 @@ final class Config
|
|||
refreshTokenFilePath = configDirName ~ "/refresh_token";
|
||||
deltaLinkFilePath = configDirName ~ "/delta_link";
|
||||
databaseFilePath = configDirName ~ "/items.sqlite3";
|
||||
databaseFilePathDryRun = configDirName ~ "/items-dryrun.sqlite3";
|
||||
uploadStateFilePath = configDirName ~ "/resume_upload";
|
||||
userConfigFilePath = configDirName ~ "/config";
|
||||
syncListFilePath = configDirName ~ "/sync_list";
|
||||
|
|
72
src/main.d
72
src/main.d
|
@ -43,6 +43,8 @@ int main(string[] args)
|
|||
// 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
|
||||
|
@ -102,6 +104,7 @@ int main(string[] args)
|
|||
"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,
|
||||
|
@ -144,6 +147,8 @@ int main(string[] args)
|
|||
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
|
||||
|
@ -202,6 +207,11 @@ int main(string[] args)
|
|||
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 ...");
|
||||
|
@ -214,6 +224,16 @@ int main(string[] args)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// dry-run database setup
|
||||
if (dryRun) {
|
||||
// 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
|
||||
log.vdebug("Copying items.sqlite3 to items-dryrun.sqlite3 to use for dry run operations");
|
||||
copy(cfg.databaseFilePath,cfg.databaseFilePathDryRun);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -285,18 +305,27 @@ int main(string[] args)
|
|||
|
||||
// upgrades
|
||||
if (exists(configDirName ~ "/items.db")) {
|
||||
remove(configDirName ~ "/items.db");
|
||||
if (!dryRun) {
|
||||
safeRemove(configDirName ~ "/items.db");
|
||||
}
|
||||
log.logAndNotify("Database schema changed, resync needed");
|
||||
resync = true;
|
||||
}
|
||||
|
||||
if (resync || logout) {
|
||||
log.vlog("Deleting the saved status ...");
|
||||
safeRemove(cfg.databaseFilePath);
|
||||
safeRemove(cfg.deltaLinkFilePath);
|
||||
safeRemove(cfg.uploadStateFilePath);
|
||||
if (!dryRun) {
|
||||
safeRemove(cfg.databaseFilePath);
|
||||
safeRemove(cfg.deltaLinkFilePath);
|
||||
safeRemove(cfg.uploadStateFilePath);
|
||||
}
|
||||
if (logout) {
|
||||
safeRemove(cfg.refreshTokenFilePath);
|
||||
if (!dryRun) {
|
||||
safeRemove(cfg.refreshTokenFilePath);
|
||||
} else {
|
||||
// simulate file being removed / unavailable
|
||||
simulateNoRefreshTokenFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,7 +390,7 @@ int main(string[] args)
|
|||
}
|
||||
|
||||
// Initialize OneDrive, check for authorization
|
||||
oneDrive = new OneDriveApi(cfg, debugHttp, forceHTTP11);
|
||||
oneDrive = new OneDriveApi(cfg, debugHttp, forceHTTP11, dryRun, simulateNoRefreshTokenFile);
|
||||
oneDrive.printAccessToken = printAccessToken;
|
||||
if (!oneDrive.init()) {
|
||||
log.error("Could not initialize the OneDrive API");
|
||||
|
@ -390,9 +419,17 @@ int main(string[] args)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// initialize system
|
||||
// Initialize the item database
|
||||
log.vlog("Opening the item database ...");
|
||||
itemDb = new ItemDatabase(cfg.databaseFilePath);
|
||||
if (!dryRun) {
|
||||
// Load the items.sqlite3 file as the database
|
||||
log.vdebug("Using database file: ", cfg.databaseFilePath);
|
||||
itemDb = new ItemDatabase(cfg.databaseFilePath);
|
||||
} else {
|
||||
// Load the items-dryrun.sqlite3 file as the database
|
||||
log.vdebug("Using database file: ", cfg.databaseFilePathDryRun);
|
||||
itemDb = new ItemDatabase(cfg.databaseFilePathDryRun);
|
||||
}
|
||||
|
||||
log.vlog("All operations will be performed in: ", syncDir);
|
||||
if (!exists(syncDir)) {
|
||||
|
@ -416,9 +453,9 @@ int main(string[] args)
|
|||
selectiveSync.load(cfg.syncListFilePath);
|
||||
selectiveSync.setMask(cfg.getValue("skip_file"));
|
||||
|
||||
// Initialise the sync engine
|
||||
// Initialize the sync engine
|
||||
log.logAndNotify("Initializing the Synchronization Engine ...");
|
||||
auto sync = new SyncEngine(cfg, oneDrive, itemDb, selectiveSync);
|
||||
auto sync = new SyncEngine(cfg, oneDrive, itemDb, selectiveSync, dryRun);
|
||||
|
||||
try {
|
||||
if (!initSyncEngine(sync)) {
|
||||
|
@ -612,8 +649,21 @@ int main(string[] args)
|
|||
}
|
||||
}
|
||||
|
||||
// workaround for segfault in std.net.curl.Curl.shutdown() on exit
|
||||
// Workaround for segfault in std.net.curl.Curl.shutdown() on exit
|
||||
oneDrive.http.shutdown();
|
||||
|
||||
// Make sure the .wal file is incorporated into the main db before we exit
|
||||
destroy(itemDb);
|
||||
|
||||
// --dry-run temp database cleanup
|
||||
if (dryRun) {
|
||||
if (exists(cfg.databaseFilePathDryRun)) {
|
||||
// remove the file
|
||||
log.vdebug("Removing items-dryrun.sqlite3 as dry run operations complete");
|
||||
safeRemove(cfg.databaseFilePathDryRun);
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import progress;
|
|||
import config;
|
||||
static import log;
|
||||
shared bool debugResponse = false;
|
||||
shared bool dryRun = false;
|
||||
shared bool simulateNoRefreshTokenFile = false;
|
||||
|
||||
private immutable {
|
||||
// Client Identifier
|
||||
|
@ -64,7 +66,7 @@ final class OneDriveApi
|
|||
// if true, every new access token is printed
|
||||
bool printAccessToken;
|
||||
|
||||
this(Config cfg, bool debugHttp, bool forceHTTP11)
|
||||
this(Config cfg, bool debugHttp, bool forceHTTP11, bool dryRun, bool simulateNoRefreshTokenFile)
|
||||
{
|
||||
this.cfg = cfg;
|
||||
http = HTTP();
|
||||
|
@ -104,6 +106,14 @@ final class OneDriveApi
|
|||
// 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) {
|
||||
.dryRun = true;
|
||||
}
|
||||
if (simulateNoRefreshTokenFile) {
|
||||
.simulateNoRefreshTokenFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool init()
|
||||
|
@ -117,12 +127,28 @@ final class OneDriveApi
|
|||
}
|
||||
} catch (Exception e) {}
|
||||
|
||||
try {
|
||||
refreshToken = readText(cfg.refreshTokenFilePath);
|
||||
} catch (FileException e) {
|
||||
return authorize();
|
||||
if (!.dryRun) {
|
||||
// original code
|
||||
try {
|
||||
refreshToken = readText(cfg.refreshTokenFilePath);
|
||||
} catch (FileException e) {
|
||||
return authorize();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// --dry-run
|
||||
if (!.simulateNoRefreshTokenFile) {
|
||||
try {
|
||||
refreshToken = readText(cfg.refreshTokenFilePath);
|
||||
} catch (FileException e) {
|
||||
return authorize();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// --dry-run & --logout
|
||||
return authorize();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool authorize()
|
||||
|
@ -361,7 +387,9 @@ final class OneDriveApi
|
|||
accessToken = "bearer " ~ response["access_token"].str();
|
||||
refreshToken = response["refresh_token"].str();
|
||||
accessTokenExpiration = Clock.currTime() + dur!"seconds"(response["expires_in"].integer());
|
||||
std.file.write(cfg.refreshTokenFilePath, refreshToken);
|
||||
if (!.dryRun) {
|
||||
std.file.write(cfg.refreshTokenFilePath, refreshToken);
|
||||
}
|
||||
if (printAccessToken) writeln("New access token: ", accessToken);
|
||||
}
|
||||
|
||||
|
|
806
src/sync.d
806
src/sync.d
File diff suppressed because it is too large
Load diff
|
@ -14,7 +14,7 @@ import std.uri;
|
|||
import qxor;
|
||||
static import log;
|
||||
|
||||
private string deviceName;
|
||||
shared string deviceName;
|
||||
|
||||
static this()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue