def __init__(self, vim): self.vim = vim self.inited = False self.bufs = {} self.wd2bufnum = {} self.pinnedRoots = set() self.picked_nodes = defaultdict(set) self.cut_nodes, self.copied_nodes = defaultdict(set), defaultdict(set) self.bookmarkUI = None self.helpUI = None self.sortUI = None self.askUI = None self.onuiquit = None self.onuiquitNumArgs = 0 self.fs = FS() self.rclone = None self.initVimVariables() self.initKeymaps() Shell.mkdir(default.variables['NETRRootDir']) self.rifle = Rifle(self.vim, VimVar('NETRRifleFile')) ignore_pat = list(VimVar('NETRIgnore')) self.vim.vars['NETRemoteCacheDir'] = os.path.expanduser( VimVar('NETRemoteCacheDir')) if '.*' not in ignore_pat: ignore_pat.append('.*') self.vim.vars['NETRIgnore'] = ignore_pat
def __init__(self, vim, path): self.vim = vim self.rules = [] if not os.path.isfile(path): Shell.cp( '{}/../../../config/rifle.conf'.format( os.path.dirname(__file__)), path) with open(path, 'r') as f: for i, line in enumerate(f): line = line.strip() if len(line) == 0 or line[0] == '#': continue sp = line.split('=') if len(sp) != 2: VimErrorMsg( self.vim, 'invalid rule: rifle.conf line {}'.format(i + 1)) continue tests = [] for test in sp[0].strip().split(','): testSp = [e for e in test.split(' ') if e != ''] tests.append(globals()[testSp[0]](testSp[1])) command = sp[1].strip() self.rules.append((tests, command))
def do_test(fn=None, fn_remote=None): """ Note on the mecahnism of testing rclone on localhost: 1. Tester run rclone to create a "local" remote named netrtest (must be exact this name) 2. In default.py, the vim variable 'NETRemoteRoots' is set to {test_remote_name: test_remote_dir}, which defaults to {'netrtest', '/tmp/netrtest/remote'}. 3. 'NETRemoteRoots' is passed to Rclone constructor, so that the rpath of the netrtest remote is mapped to '/tmp/netrtest/remote'. 4. This just works in netranger. In cmd line, running 'rclone lsl netranger:/' still shows you the content of the root directory of the localhost. """ old_cwd = os.getcwd() Shell.run('rm -rf {}'.format(test_dir)) def prepare_test_dir(dirname): Shell.mkdir(dirname) os.chdir(dirname) Shell.mkdir('dir/subdir') Shell.mkdir('dir/subdir/subsubdir') Shell.mkdir('dir/subdir2') Shell.touch('dir/a') Shell.touch('.a') Shell.mkdir('dir2/') # The following should be removed when rclone fix "not copying empty directories" bug. Shell.touch('dir/subdir/subsubdir/placeholder') Shell.touch('dir/subdir2/placeholder') Shell.touch('dir/subdir2/placeholder') prepare_test_dir(test_local_dir) if fn is not None: nvim.command('silent tabe {}'.format(test_local_dir)) fn() nvim.command('bwipeout') print('== {} success =='.format(str(fn.__name__))) prepare_test_dir(test_remote_dir) if fn_remote is not None: nvim.command('NETRemoteList') found_remote = False for i, line in enumerate(nvim.current.buffer): if re.findall('.+(netrtest)', line): nvim.command('call cursor({}, 1)'.format(i + 1)) found_remote = True break assert found_remote, 'You must set up an rclone remote named "{}" to test remote function'.format( test_remote_name) nvim.input('l') nvim.command('NETRemotePull') nvim.command('call cursor(2, 1)') fn_remote() nvim.command('bwipeout') print('== {} success =='.format(str(fn_remote.__name__))) os.chdir(old_cwd)
def exec_fs_server_cmd(self, cmd, src_arr, dst=None, on_exit=None): src = ' '.join(['"{}"'.format(s) for s in src_arr]) if dst: dst = '"{}"'.format(dst) cmd = 'python {} {} {} {}'.format(FS.FScmds, cmd, src, dst) Shell.run_async(cmd, on_exit=on_exit) else: cmd = 'python {} {} {}'.format(FS.FScmds, cmd, src) Shell.run_async(cmd, on_exit=on_exit)
def test_detect_fs_change(): Shell.touch('newfile') nvim.command('split new') nvim.command('quit') assert_num_content_line(3) nvim.input('l') Shell.rm('newfile') nvim.input('h') assert_num_content_line(2)
def init(self): self.inited = True self.initVimVariables() self.initKeymaps() self.rclone = None self.bookmarkUI = None self.helpUI = None self.isEditing = False self.onuiquit = None self.onuiquitNumArgs = 0 Shell.mkdir(default.variables['NETRRootDir']) self.rifle = Rifle(self.vim, self.vim.vars['NETRRifleFile'])
def ls(self, dirname, cheap_remote_ls=False): if not cheap_remote_ls and len(dirname) > len(self.root_dir): local_files = set([ name for name in Shell.run('ls -p {}'.format(dirname)).split('\n') if len(name) > 0 ]) remote_files = set([ name for name in Shell.run('rclone lsf "{}"'.format( self.rpath(dirname))).split('\n') if len(name) > 0 ]) for name in remote_files.difference(local_files): if name[-1] == '/': Shell.mkdir(os.path.join(dirname, name)) else: Shell.touch(os.path.join(dirname, name)) for name in local_files.difference(remote_files): log('rclone copyto "{}" "{}"'.format( os.path.join(dirname, name), os.path.join(self.rpath(dirname), name))) Shell.run('rclone copyto "{}" "{}"'.format( os.path.join(dirname, name), os.path.join(self.rpath(dirname), name))) return super(Rclone, self).ls(dirname)
def __init__(self, lpath, path): Shell.mkdir(lpath) self.lpath = lpath self.child = {} self.cached = False self.path = path if path is None: remotes = Shell.run('rclone listremotes').split(':\n') log(remotes) for remote in remotes: if len(remote)==0: continue self.child[remote] = RcloneDir(os.path.join(lpath, remote), remote+':/') self.cached = True
def lsl(self): info = Shell.run('rclone lsl {} --max-depth 1'.format(self.path)) for line in info.split('\n'): line = line.strip() if len(line)>0: name = line.split()[-1] self.child[name] = RcloneFile(os.path.join(self.lpath, name), os.path.join(self.path, name))
def NETROpen(self): if self.curNode.isHeader: return fullpath = self.curNode.fullpath if self.curNode.isDir: self.set_cwd(fullpath) else: if type(self.fs) is RClone: self.fs.download(fullpath) cmd = self.rifle.decide_open_cmd(fullpath) # TODO: fix white space in fullpath issue if not cmd: if self.vim.vars['NETROpenInBuffer']: self.vim.command('edit {}'.format(fullpath)) else: self.vim.command('tab drop {}'.format(fullpath)) else: Shell.spawn('{} {}'.format(cmd, fullpath))
def __init__(self, vim, cwd, fs, prevcwd=None): self.vim = vim self.cwd = cwd self.fs = fs self.nodes = self.createNodes(cwd) self.nodes.insert(0, Node(self.cwd, self.vim.vars['NETRHiCWD'])) self.initClineNo(prevcwd) self.nodes[self.clineNo].cursor_on() self.mtime = Shell.mtime(cwd)
def test_sort(): # only test extension, mtime, size # extension: [a, a.a, a.b] # size: [a.b, a.a, a] # mtime: [a, a.b, a.a] Shell.run('echo {} > dir/{}'.format('a' * 3, 'a')) Shell.run('echo {} > dir/{}'.format('a' * 2, 'a.a')) Shell.run('echo {} > dir/{}'.format('a' * 1, 'a.b')) time.sleep(0.01) Shell.run('touch dir/a.a') nvim.input(' Se') assert_content('dir', ind=0, hi='dir', level=0) assert_content('a', ind=3, hi='file', level=1) assert_content('a.a', ind=4, hi='file', level=1) assert_content('a.b', ind=5, hi='file', level=1) assert_content('dir2', ind=6, hi='dir', level=0) nvim.input('SE') assert_content('dir2', ind=0, hi='dir', level=0) assert_content('dir', ind=1, hi='dir', level=0) assert_content('a.b', ind=2, hi='file', level=1) assert_content('a.a', ind=3, hi='file', level=1) assert_content('a', ind=4, hi='file', level=1) nvim.input('Ss') assert_content('dir2', ind=0, hi='dir', level=0) assert_content('dir', ind=1, hi='dir', level=0) assert_content('a.b', ind=4, hi='file', level=1) assert_content('a.a', ind=5, hi='file', level=1) assert_content('a', ind=6, hi='file', level=1) nvim.input('SS') assert_content('dir', ind=0, hi='dir', level=0) assert_content('a', ind=1, hi='file', level=1) assert_content('a.a', ind=2, hi='file', level=1) assert_content('a.b', ind=3, hi='file', level=1) assert_content('dir2', ind=6, hi='dir', level=0) nvim.input('Sm') assert_content('dir2', ind=0, hi='dir', level=0) assert_content('dir', ind=1, hi='dir', level=0) assert_content('a', ind=4, hi='file', level=1) assert_content('a.b', ind=5, hi='file', level=1) assert_content('a.a', ind=6, hi='file', level=1) nvim.input('SM') assert_content('dir', ind=0, hi='dir', level=0) assert_content('a.a', ind=1, hi='file', level=1) assert_content('a.b', ind=2, hi='file', level=1) assert_content('a', ind=3, hi='file', level=1) assert_content('dir2', ind=6, hi='dir', level=0)
def __init__(self, root_dir, remote_remap): if root_dir[-1] == '/': root_dir = root_dir[:-1] self.root_dir = root_dir self.rplen = len(root_dir) + 1 for remote, root in remote_remap.items(): if root[-1] != '/': remote_remap[remote] += '/' self.remote_remap = remote_remap Shell.mkdir(root_dir) remotes = set(Shell.run('rclone listremotes').split(':\n')) local_remotes = set(super(Rclone, self).ls(root_dir)) for remote in remotes.difference(local_remotes): Shell.mkdir(os.path.join(root_dir, remote)) for remote in local_remotes.difference(remotes): super(Rclone, self).rm(os.path.join(root_dir, remote), True) self.has_remote = len(remotes) > 0 self.ls_time_stamp = {}
def valid_or_install(cls, vim): import platform import zipfile if Shell.isinPATH('rclone'): return True else: rclone_dir = VimUserInput( 'Rclone not in PATH. Install it at (modify/enter)', os.path.expanduser('~/rclone')) Shell.mkdir(rclone_dir) system = platform.system().lower() processor = 'amd64' if '386' in platform.processor(): processor = '386' else: # Should support arm?? pass url = 'https://downloads.rclone.org/rclone-current-{}-{}.zip'.format( system, processor) zip_fname = os.path.join(rclone_dir, 'rclone.zip') Shell.urldownload(url, zip_fname) zip_ref = zipfile.ZipFile(zip_fname, 'r') zip_ref.extractall(rclone_dir) for entry in zip_ref.NameToInfo: if entry.endswith('rclone'): Shell.cp(os.path.join(rclone_dir, entry), rclone_dir) Shell.chmod(os.path.join(rclone_dir, 'rclone'), 755) zip_ref.close() os.remove(zip_fname) shellrc = VimUserInput( 'Update PATH in (leave blank to set manually later)', Shell.shellrc()) if len(shellrc) > 0: with open(shellrc, 'a') as f: f.write('PATH={}:$PATH\n'.format(rclone_dir)) os.environ['PATH'] += ':' + rclone_dir
def test_size_display(): width = nvim.current.window.width def cLine_ends_with(s): # line[-4:] = [0m return nvim.current.line[:-4].endswith(s) assert cLine_ends_with('3'), 'size display dir fail: {}'.format( 'a' + nvim.current.line[-1] + 'a') Shell.run('echo {} > {}'.format('a' * 1035, 'a' * width + '.pdf')) Shell.run('echo {} > {}'.format('b' * 1024, 'b' * width)) nvim.command('edit .') nvim.input('Gk') assert cLine_ends_with( '~.pdf 1.01 K'), 'size display abbreviation fail: a~.pdf {}'.format( nvim.current.line[-10:]) nvim.input('j') assert cLine_ends_with( 'b~ 1 K'), 'size display abbreviation fail: b~ {}'.format( nvim.current.line[-10:])
def NETROpen(self, open_cmd=None, rifle_cmd=None, use_rifle=True): """ The real work for opening directories is handled in on_bufenter. For openning files, we check if there's rifle rule to open the file. Otherwise, open it in vim. """ curNode = self.curNode if curNode.isINFO: return if open_cmd is None: if curNode.isDir: open_cmd = 'edit' else: open_cmd = VimVar('NETROpenCmd') fullpath = curNode.fullpath if curNode.isDir: if curNode.size == '?' or curNode.size == '': VimErrorMsg('Permission Denied: {}'.format(curNode.name)) return self.vim.command('silent {} {}'.format(open_cmd, fullpath)) # manually call on_bufenter as vim might not trigger BufEnter with the above command self.on_bufenter(self.vim.eval("winnr()")) else: if self.rclone is not None and self.isRemotePath(fullpath): self.rclone.ensure_downloaded(fullpath) if rifle_cmd is None: rifle_cmd = self.rifle.decide_open_cmd(fullpath) if use_rifle and rifle_cmd is not None: Shell.run_async(rifle_cmd.format(fullpath)) else: try: self.vim.command('{} {}'.format(open_cmd, fullpath)) except Exception as e: err_msg = str(e) if 'E325' not in err_msg: VimErrorMsg(err_msg)
def assert_fs(d, expected): """ Test whether 'expected' exists in directory cwd/d, where cwd is /tmp/netrtest/local when testing local functions and cwd is /tmp/netrtest/remote when testing remote functions. """ real = None for i in range(10): real = Shell.run('ls --group-directories-first ' + d).split() if real == expected: return time.sleep(0.05) assert real == expected, 'expected: {}, real: {}'.format(expected, real)
def __init__(self, vim, path): self.vim = vim self.rules = [] if not os.path.isfile(path): Shell.cp(os.path.join(config_dir, 'rifle.conf'), path) with open(path, 'r') as f: for i, line in enumerate(f): try: # remove things after the first # (including) line = line[:line.index('#')] except ValueError: pass line = line.strip() if len(line) == 0: continue sp = line.split('=') if len(sp) != 2: VimErrorMsg( 'invalid rule: rifle.conf line {}. There should be one and only one "=" for each line' .format(i + 1)) continue tests = [] for test in sp[0].strip().split(','): testSp = [e for e in test.split(' ') if e != ''] tests.append(globals()[testSp[0]](testSp[1])) command = sp[1].strip() # simple case, used specify only the command # For sophisicated command like bash -c "command {}" # user should add '{}' themselves if '{}' not in command: command = command + ' {}' self.rules.append((tests, command))
def test_detect_fs_change(): nvim.input(' ') Shell.touch('dir/b') Shell.mkdir('dir3') nvim.command('split new') nvim.command('quit') assert_content('dir', ind=0, hi='dir') assert_content('b', ind=4, level=1, hi='file') assert_content('dir3', ind=6, hi='dir') assert_num_content_line(7) Shell.rm('dir3') nvim.input('lh') assert_num_content_line(6)
def test_bookmark(): bookmarkfile = default.variables['NETRBookmarkFile'] copy = '{}/{}bak'.format(os.path.dirname(bookmarkfile), os.path.basename(bookmarkfile)) if os.path.isfile(bookmarkfile): Shell.run('mv {} {}'.format(bookmarkfile, copy)) Shell.run('rm -f {}'.format(bookmarkfile)) nvim.input('mal') nvim.input("'a") assert_content('dir') nvim.input('lemjrb') nvim.command('exit') nvim.input("'b") assert_content('dir') Shell.run('rm -f {}'.format(bookmarkfile)) if os.path.isfile(copy): Shell.run('mv {} {}'.format(copy, bookmarkfile))
def __init__(self, fullpath): super(HeaderNode, self).__init__(fullpath, Shell.abbrevuser(fullpath), default.color['cwd'], level=0) self.re_stat()
def prepare_test_dir(dirname): Shell.mkdir(dirname) os.chdir(dirname) Shell.mkdir('dir/subdir') Shell.mkdir('dir/subdir/subsubdir') Shell.mkdir('dir/subdir2') Shell.touch('dir/a') Shell.touch('.a') Shell.mkdir('dir2/') # The following should be removed when rclone fix "not copying empty directories" bug. Shell.touch('dir/subdir/subsubdir/placeholder') Shell.touch('dir/subdir2/placeholder') Shell.touch('dir/subdir2/placeholder')
def test_edit(): nvim.input('iz') nvim.input('') assert_fs(lambda: 'zdir' in Shell.run('ls').split()) assert_content('dir2')
def download(self): if self.downloaded: return else: Shell.run('rclone copyto "{}" "{}"'.format(self.path, self.lpath)) self.downloaded = True
def rmf(self, target): Shell.run('rm -r {}'.format(target))
def cp(self, src, dst): if os.path.isdir(src) and src[-1]!='/': src = src+'/' if os.path.isdir(dst) and dst[-1]!='/': dst = dst+'/' Shell.run('cp -r "{}" "{}"'.format(src, dst))
def test_delete(): nvim.input('vD') assert_fs(lambda: Shell.run('ls').split()[0] == 'dir2') nvim.input('XX') assert_fs(lambda: Shell.run('ls') == '')
def __call__(self, fname): return Shell.isinPATH(self.arg)
def do_test(fn, wipe_on_done=True): old_cwd = os.getcwd() test_root = os.path.expanduser('~/netranger_test_dir') Shell.run('rm -rf {}'.format(test_root)) Shell.mkdir(test_root) os.chdir(test_root) Shell.mkdir(os.path.join(test_root, 'dir/subdir')) Shell.mkdir(os.path.join(test_root, 'dir/subdir/subsubdir')) Shell.mkdir(os.path.join(test_root, 'dir/subdir2')) Shell.run('touch {}/dir/a'.format(test_root)) Shell.run('touch {}/.a'.format(test_root)) Shell.mkdir(os.path.join(test_root, 'dir2/')) nvim.command('tabe {}'.format(test_root)) fn() if wipe_on_done: nvim.command('bwipeout') os.chdir(old_cwd) print('== {} success =='.format(str(fn.__name__)))
def is_dirty(self): return Shell.mtime(self.cwd) > self.mtime