]> Sergey Matveev's repositories - nnn.git/commitdiff
Add rclone support for remote access
authorArun Prakash Jana <engineerarun@gmail.com>
Sun, 24 Nov 2019 15:52:44 +0000 (21:22 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Sun, 24 Nov 2019 15:54:32 +0000 (21:24 +0530)
README.md
nnn.1
src/nnn.c
src/nnn.h

index e9d1e7743ac0d35d2b8048cade7e9978388d490f..8fc27b12925df2bea43a493f6a97085ff5a15a91 100644 (file)
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ Add to that an awesome [Wiki](https://github.com/jarun/nnn/wiki)!
 - Convenience
   - Run plugins and commands with custom keybinds
   - FreeDesktop compliant trash (needs trash-cli)
-  - SSHFS mounts (needs sshfs)
+  - Remote mounts (needs sshfs, rclone)
   - Cross-dir file/all/range selection
   - Batch rename selection or dir entries
   - Copy (as), move (as), delete, archive, link selection
@@ -92,7 +92,7 @@ A curses library with wide char support (e.g. ncursesw), libreadline (`make O_NO
 | file, coreutils (cp, mv, rm), xargs | base | file type, copy, move and remove |
 | tar, (un)zip [atool/bsdtar for more formats] | base | create, list, extract tar, gzip, bzip2, zip |
 | archivemount, fusermount(3) | optional | mount, unmount archives |
-| sshfs, fusermount(3) | optional | mount, unmount remotes |
+| sshfs, [rclone](https://rclone.org/), fusermount(3) | optional | mount, unmount remotes |
 | trash-cli | optional | trash files (default action: rm) |
 | vlock (Linux), bashlock (macOS), lock(1) (BSD) | optional | terminal locker (fallback: [cmatrix](https://github.com/abishekvashok/cmatrix)) |
 | advcpmv (Linux) ([integration](https://github.com/jarun/nnn/wiki/Advanced-use-cases#show-cp-mv-progress)) | optional | copy, move progress |
@@ -153,6 +153,7 @@ There is no config file. Associated files are stored under `${XDG_CONFIG_HOME:-$
 | `NNN_USE_EDITOR=1` | open text files in `$VISUAL` (else `$EDITOR`, fallback vi) |
 | `NNN_CONTEXT_COLORS='1234'` | specify per context color [default: '4444' (all blue)] |
 | `NNN_SSHFS_OPTS='sshfs -o reconnect,idmap=user'` | specify SSHFS options |
+| `NNN_RCLONE_OPTS='rclone mount --read-only'` | specify rclone options |
 | `NNN_IDLE_TIMEOUT=300` | idle seconds to lock terminal [default: disabled] |
 | `NNN_COPIER=copier` | clipboard copier script [default: none] |
 | `NNN_TRASH=1` | trash files to the desktop Trash [default: delete] |
@@ -225,7 +226,7 @@ The list below is from the **dev branch**. Press <kbd>?</kbd> in `nnn` to see th
          ! ^]  Shell      ;K :K xK  Execute plugin K
             C  Execute entry  R ^V  Pick plugin
             U  Manage session    =  Launch
-            c  SSHFS mount       u  Unmount
+            c  Remote mount      u  Unmount
          ] ^P  Prompt/run cmd    L  Lock
 ```
 
diff --git a/nnn.1 b/nnn.1
index 393e23961a04d0769531257fe9ef923f774cfd74..870ae5bc8cd17b2ab5f525cfb1201b17f333fa49 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -223,6 +223,13 @@ when dealing with the !, e and p commands respectively. A single combination to
     NOTE: The options must be preceded by `sshfs` and comma-separated without any space between them.
 .Ed
 .Pp
+\fBNNN_RCLONE_OPTS:\fR pass additional options to rclone command:
+.Bd -literal
+    export NNN_RCLONE_OPTS='rclone mount --read-only --no-checksum'
+
+    NOTE: The options must be preceded by `rclone` and max 5 flags are supported.
+.Ed
+.Pp
 \fBNNN_OPENER:\fR specify a custom file opener.
 .Bd -literal
     export NNN_OPENER=mimeopen
index 0b35ae761fa8ffbbc5495aaf6904fcc7fcb9edc6..72b15cc0cf8dd173fe2b800ff0e810f1f7f97aff 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
 #endif
 
 #define _ABSSUB(N, M) (((N) <= (M)) ? ((M) - (N)) : ((N) - (M)))
-#define DOUBLECLICK_INTERVAL_NS 400000000
+#define DOUBLECLICK_INTERVAL_NS (400000000)
+#define XDELAY_INTERVAL_US (350000) /* 350 ms delay */
 #define LEN(x) (sizeof(x) / sizeof(*(x)))
 #undef MIN
 #define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -370,6 +371,7 @@ static bool g_plinit = FALSE;
 #define UTIL_SH_EXEC 8
 #define UTIL_ARCHIVEMOUNT 9
 #define UTIL_SSHFS 10
+#define UTIL_RCLONE 11
 
 /* Utilities to open files, run actions */
 static char * const utils[] = {
@@ -396,6 +398,7 @@ static char * const utils[] = {
        "sh -c",
        "archivemount",
        "sshfs",
+       "rclone",
 };
 
 /* Common strings */
@@ -438,6 +441,8 @@ static char * const utils[] = {
 #define MSG_0_FILES 36
 #define MSG_EXISTS 37
 #define MSG_FEW_COLOUMNS 38
+#define MSG_REMOTE_OPTS 39
+#define MSG_RCLONE_DELAY 40
 
 static const char * const messages[] = {
        "no traversal",
@@ -453,12 +458,12 @@ static const char * const messages[] = {
        "forcibly remove %s file%s (unrecoverable)?",
        "Create context %d?",
        "archive sel?",
-       "'f'(ile) / 'd'(ir) / 's'(ym) / 'h'(ard)?",
+       "'f'ile / 'd'ir / 's'ym / 'h'ard?",
        "cli mode?",
        "overwrite?",
-       "'s'(ave) / 'l'(oad) / 'r'(estore)?",
+       "'s'ave / 'l'oad / 'r'estore?",
        "Quit all contexts?",
-       "host: ",
+       "remote name: ",
        "archive name: ",
        "open with: ",
        "relative path: ",
@@ -479,6 +484,8 @@ static const char * const messages[] = {
        "0 files",
        "entry exists",
        "too few columns!",
+       "'s'shfs / 'r'clone?",
+       "rclone mount may take a while"
 };
 
 /* Supported configuration environment variables */
@@ -677,10 +684,10 @@ static int get_input(const char *prompt)
        return r;
 }
 
-static void xdelay(void)
+static void xdelay(useconds_t delay)
 {
        refresh();
-       usleep(350000); /* 350 ms delay */
+       usleep(delay);
 }
 
 static char confirm_force(bool selection)
@@ -2865,7 +2872,7 @@ static bool load_session(const char *sname, char **path, char **lastdir, char **
        fsession = fopen(spath, "rb");
        if (!fsession) {
                printmsg(messages[MSG_SSN_MISSING]);
-               xdelay();
+               xdelay(XDELAY_INTERVAL_US);
                return FALSE;
        }
 
@@ -2896,7 +2903,7 @@ END:
 
        if (!status) {
                printmsg(messages[MSG_FAILED]);
-               xdelay();
+               xdelay(XDELAY_INTERVAL_US);
        }
 
        return status;
@@ -3139,7 +3146,7 @@ static void find_accessible_parent(char *path, char *newpath, char *lastname, in
        xstrlcpy(path, dir, PATH_MAX);
 
        printmsg(messages[MSG_DIR_ACCESS]);
-       xdelay();
+       xdelay(XDELAY_INTERVAL_US);
 }
 
 static bool execute_file(int cur, char *path, char *newpath, int *presel)
@@ -3263,11 +3270,23 @@ static bool archive_mount(char *name, char *path, char *newpath, int *presel)
        return TRUE;
 }
 
-static bool sshfs_mount(char *newpath, int *presel)
+static bool remote_mount(char *newpath, int *presel)
 {
-       uchar flag = F_NORMAL;
-       int r;
-       char *tmp, *env, *cmd = utils[UTIL_SSHFS];
+       uchar flag = F_CLI;
+       int r, opt = get_input(messages[MSG_REMOTE_OPTS]);
+       char *tmp, *env, *cmd;
+
+       if (opt == 's') {
+               cmd = utils[UTIL_SSHFS];
+               env = xgetenv("NNN_SSHFS_OPTS", cmd);
+       } else if (opt == 'r') {
+               flag |= F_NOWAIT;
+               cmd = utils[UTIL_RCLONE];
+               env = xgetenv("NNN_RCLONE_OPTS", "rclone mount");
+       } else {
+               printwait(messages[MSG_FAILED], presel);
+               return FALSE;
+       }
 
        if (!getutil(cmd)) {
                printwait(messages[MSG_UTIL_MISSING], presel);
@@ -3287,19 +3306,21 @@ static bool sshfs_mount(char *newpath, int *presel)
 
        /* Convert "Host" to "Host:" */
        r = strlen(tmp);
-       tmp[r] = ':';
-       tmp[r + 1] = '\0';
-
-       env = getenv("NNN_SSHFS_OPTS");
-       if (env)
-               flag |= F_MULTI;
-       else
-               env = cmd;
+       if (tmp[r - 1] != ':') { /* Append ':' if missing */
+               tmp[r] = ':';
+               tmp[r + 1] = '\0';
+       }
 
        /* Connect to remote */
-       if (spawn(env, tmp, newpath, NULL, flag)) {
-               printwait(messages[MSG_FAILED], presel);
-               return FALSE;
+       if (opt == 's') {
+               if (spawn(env, tmp, newpath, NULL, flag)) {
+                       printwait(messages[MSG_FAILED], presel);
+                       return FALSE;
+               }
+       } else {
+               spawn(env, tmp, newpath, NULL, flag);
+               printmsg(messages[MSG_RCLONE_DELAY]);
+               xdelay(XDELAY_INTERVAL_US * 10);
        }
 
        return TRUE;
@@ -3311,12 +3332,12 @@ static bool sshfs_mount(char *newpath, int *presel)
  */
 static bool unmount(char *name, char *newpath, int *presel, char *currentpath)
 {
-       char cmd[] = "fusermount3"; /* Arch Linux utility */
+       static char cmd[] = "fusermount3"; /* Arch Linux utility */
        static bool found = FALSE;
        char *tmp = name;
        struct stat sb, psb;
-       bool child = false;
-       bool parent = false;
+       bool child = FALSE;
+       bool parent = FALSE;
 
        /* On Ubuntu it's fusermount */
        if (!found && !getutil(cmd)) {
@@ -4770,7 +4791,7 @@ nochange:
                                inode = sb.st_ino;
                                selstartid = cur;
                                printmsg(messages[MSG_RANGE_SEL_ON]);
-                               xdelay();
+                               xdelay(XDELAY_INTERVAL_US);
                                continue;
                        }
 
@@ -4815,7 +4836,7 @@ nochange:
                        /* Show the range count */
                        //r = selendid - selstartid + 1;
                        //mvprintw(xlines - 1, 0, "+%d\n", r);
-                       //xdelay();
+                       //xdelay(XDELAY_INTERVAL_US);
 
                        //writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */
                        //spawn(copier, NULL, NULL, NULL, F_NOTRACE);
@@ -5167,8 +5188,8 @@ nochange:
                case SEL_ARCHIVEMNT:
                        if (!ndents || !archive_mount(dents[cur].name, path, newpath, &presel))
                                goto nochange; // fallthrough
-               case SEL_SSHFS:
-                       if (sel == SEL_SSHFS && !sshfs_mount(newpath, &presel))
+               case SEL_REMOTE:
+                       if (sel == SEL_REMOTE && !remote_mount(newpath, &presel))
                                goto nochange;
 
                        lastname[0] = '\0';
index ff6f8d97149e04d0b965cc7e13354236b305b83f..40798a0a18b067fa1e37dc30c6d384a7edaee895 100644 (file)
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -90,7 +90,7 @@ enum action {
        SEL_RENAME,
        SEL_RENAMEMUL,
        SEL_ARCHIVEMNT,
-       SEL_SSHFS,
+       SEL_REMOTE,
        SEL_UMOUNT,
        SEL_HELP,
        SEL_EXEC,
@@ -237,7 +237,7 @@ static struct key bindings[] = {
        /* Mount an archive */
        { 'T',            SEL_ARCHIVEMNT },
        /* Connect to server over SSHFS */
-       { 'c',            SEL_SSHFS },
+       { 'c',            SEL_REMOTE },
        /* Disconnect a SSHFS mount point */
        { 'u',            SEL_UMOUNT },
        /* Show help */