Add rclone support for remote access

This commit is contained in:
Arun Prakash Jana 2019-11-24 21:22:44 +05:30
parent c4483a8956
commit e6f9d6d2d0
No known key found for this signature in database
GPG key ID: A75979F35C080412
4 changed files with 65 additions and 36 deletions

View file

@ -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
```

7
nnn.1
View file

@ -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

View file

@ -112,7 +112,8 @@
#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';

View file

@ -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 */