#!/usr/bin/env python import argparse, sys, os, subprocess, time, re, json from subprocess import call, Popen, PIPE, STDOUT import threading import readline from tabulate import tabulate import glob from io import StringIO ROOTURL="{{ rooturl }}" SHARE="{{ name }}" TOKEN="{{ token }}" class Completer(object): def __init__(self, choices = []): self.choices = choices self.space = re.compile('.*\s+$', re.M) def _listdir(self, path): "List directory 'root' appending the path separator to subdirs." files = [] for name in os.listdir(path): file_path = os.path.join(path, name) if os.path.isdir(file_path): name += os.sep files.append(name) return files def _complete_path(self, path=None): "Perform completion of filesystem path." if not path: return self._listdir('.') path = os.path.expanduser(path) dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [os.path.join(dirname, p) for p in self._listdir(tmp) if p.startswith(rest)] # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in self._listdir(path)] # exact file match terminates this completion return [path + ' '] def complete(self, text, state): "Generic readline completion entry point." buffer = readline.get_line_buffer() if len(self.choices) == 0: return (self._complete_path(buffer) + [None])[state] # show all commands if len(buffer) == 0: return [c + ' ' for c in self.choices][state] # resolve command to the implementation function cmd = buffer.strip() results = [c + ' ' for c in self.choices if c.startswith(cmd)] + [None] return results[state] def download_file(file, opts): print("Download "+file['name']) cmd = [ 'curl','--create-dirs', '-o', file['name'], '%s%s/%s/%s/%s'%( opts.rooturl, "download", opts.share, opts.token, file['url'] ), ] p = Popen( cmd, stderr = PIPE, ) for char in iter(lambda: p.stderr.read(1), ''): if not char: return sys.stderr.write(char) sys.stderr.flush() return def menu(opts): commands = [ 'Download', 'Upload' ] print_title("Main") for i,command in enumerate(commands): print(" %d. %s"%( i+1, command, )) comp = Completer(choices = ["1","2"]) readline.set_completer(comp.complete) choice = user_input("Number of action: ").strip() if choice == "1": menu_download(opts) if choice == "2": menu_upload(opts) if choice == "": sys.exit(0) def menu_download(opts): while True: print_title("Download files") files = json.loads(run_command("file/details", opts)) file_table = [] for f in files: file_table.append((f['name'], float(f['size'].replace(",","")), f['mtime'])) print(tabulate(file_table, headers = ("Name", "Size [Mb]", "Modified"))) name_list = [x['name'] for x in files] comp = Completer(choices = name_list) # we want to treat '/' as part of a word, so override the delimiters readline.set_completer(comp.complete) print("\n[Empty to return, * globs]") choice = user_input('Download file: ').strip() if choice == "": return if "*" in choice: choice = choice.replace('*','.*') choice_re = re.compile(choice) choices = [i for i,x in enumerate(name_list) if choice_re.match(x)] else: if choice not in name_list: print("No such file") continue choices = [ name_list.index(choice) ] for choice in choices: download_file(files[choice], opts) def menu_upload(opts): while True: print_title("Upload") comp = Completer(choices = []) # we want to treat '/' as part of a word, so override the delimiters readline.set_completer(comp.complete) print("\n[Empty to return, * globs]") choice = user_input('Upload file: ').strip() if choice == "": return if "*" in choice: choices = glob.glob(choice) else: if not os.path.exists(choice): print("No such file") continue choices = [ choice ] for choice in choices: upload_file(choice, opts) def parse_options(): parser = argparse.ArgumentParser(description='Flees client') parser.add_argument('-s', action="store", type=int, dest="split", default = 32, help = "Split size in megabytes [%(default)s]" ) parser.add_argument('--rooturl', action="store", dest="rooturl", default = ROOTURL, help = "Address of Flees server [%(default)s]" ) parser.add_argument('--share', action="store", dest="share", default = SHARE, help = "Name of Flees share [%(default)s]" ) parser.add_argument('--token', action="store", dest="token", default = TOKEN, help = "API token for the share [%(default)s]" ) return parser.parse_args() def print_title(title): print("%s\n%s\n"%( title, "="*len(title) )) def read_output(stream): for char in iter(lambda: stream.read(1), ''): if not char: break sys.stderr.write(char) sys.stderr.flush() stream.close() def run_command(command, opts): p = Popen( [ 'curl','-s', '%s%s/%s/%s'%(opts.rooturl, command, opts.share, opts.token) ], stdout=PIPE, stderr=PIPE ) stdout_data, stderr_data = p.communicate() return stdout_data def run_loop(opts): while True: menu(opts) def upload_file(file, opts): print("Upload "+file) p = Popen( "curl -s %s%s/%s/%s | python -u - -s %d %s"%( opts.rooturl, "script/upload_split", opts.share, opts.token, opts.split, file ), stdout = PIPE, shell = True ) read_output(p.stdout) return cmd1 = [ 'curl','-s', '%s%s/%s/%s'%( opts.rooturl, "script/upload_split", opts.share, opts.token, ), ] cmd2 = [ 'python', '-', '-s', str(opts.split), file ] p1 = Popen( cmd1, stderr = PIPE, stdout = PIPE, ) script, stderr = p1.communicate() p2 = Popen( cmd2, stdin = PIPE, stdout = PIPE, stderr = PIPE, bufsize = 1 ) p2.stdin.write(script) p2.stdin.close() for char in iter(lambda: p2.stderr.read(1), ''): if not char: break sys.stderr.write(char) sys.stderr.flush() #~ read_output(p2.stdout) #~ tin = threading.Thread( #~ target=write_input, args=(p2.stdin, script) #~ ) #~ tout = threading.Thread( #~ target=read_output, args=(p2.stdout,) #~ ) #~ terr = threading.Thread( #~ target=read_output, args=(p2.stderr,) #~ ) #~ for t in (tin, tout, terr): #~ t.daemon = True #~ t.start() #~ p2.wait() return def user_input(arg): try: return raw_input(arg) except NameError: return input(arg) def write_input(stream, string): stream.write(string) stream.close() if __name__ == "__main__": readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") opts = parse_options() run_loop(opts)