seafile/app/seaf-cli

1035 lines
34 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env python3
2019-09-23 18:21:54 +08:00
#-*- coding:utf-8 -*-
2013-10-31 10:50:03 +08:00
# pylint: disable=E1121
'''
2013-02-13 12:57:02 +08:00
seaf-cli is command line interface for seafile client.
Subcommands:
2013-02-18 10:47:18 +08:00
init: create config files for seafile client
start: start and run seafile client as daemon
stop: stop seafile client
list: list local libraries
status: show syncing status
download: download a library from seafile server
(using libary id)
download-by-name: download a library from seafile server
(using library name)
sync: synchronize an existing folder with a library in
seafile server
desync: desynchronize a library with seafile server
create: create a new library
2013-02-18 10:47:18 +08:00
Detail
======
Seafile client stores all its configure information in a config dir. The default location is `~/.ccnet`. All the commands below accept an option `-c <config-dir>`.
init
----
2013-02-18 11:21:11 +08:00
Initialize seafile client. This command initializes the config dir. It also creates sub-directories `seafile-data` and `seafile` under `parent-dir`. `seafile-data` is used to store internal data, while `seafile` is used as the default location put downloaded libraries.
2013-02-18 10:47:18 +08:00
seaf-cli init [-c <config-dir>] -d <parent-dir>
start
-----
Start seafile client. This command starts `seaf-daemon`, which manages all the files.
2013-02-18 10:47:18 +08:00
seaf-cli start [-c <config-dir>]
2013-02-13 12:57:02 +08:00
stop
----
Stop seafile client.
2013-02-18 10:47:18 +08:00
seaf-cli stop [-c <config-dir>]
Download by id
2013-02-19 11:52:48 +08:00
--------
Download a library from seafile server (using library id)
2013-02-13 12:57:02 +08:00
seaf-cli download -l <library-id> -s <seahub-server-url> -d <parent-directory> -u <username> -p <password> [-a <2fa-code>]
Download by name
--------
Download a library from seafile server (using library name)
seaf-cli download -L <library-name> -s <seahub-server-url> -d <parent-directory> -u <username> -p <password> [-a <2fa-code>]
sync
----
2013-02-13 12:57:02 +08:00
Synchronize a library with an existing folder.
seaf-cli sync -l <library-id> -s <seahub-server-url> -d <existing-folder> -u <username> -p <password> [-a <2fa-code>]
desync
------
2013-02-13 12:57:02 +08:00
Desynchronize a library from seafile server
2013-02-18 10:47:18 +08:00
seaf-cli desync -d <existing-folder>
create
------
Create a new library
seaf-cli create -s <seahub-server-url> -n <library-name> -u <username> -p <password> [-a <2fa-code>] -t <description> [-e <library-password>]
'''
import argparse
2013-02-13 12:57:02 +08:00
import os
import json
import subprocess
import re
2013-02-13 12:57:02 +08:00
import sys
import time
2013-02-20 15:13:47 +08:00
import getpass
import random
2019-09-23 18:21:54 +08:00
import urllib.request, urllib.parse, urllib.error
import urllib.request, urllib.error, urllib.parse
from urllib.parse import urlparse
from os.path import abspath, dirname, exists, isdir, join
import seafile
if 'HOME' in os.environ:
DEFAULT_CONF_DIR = "%s/.ccnet" % os.environ['HOME']
DEFAULT_USER_CONF_DIR = "%s/.seafile.conf" % os.environ['HOME']
else:
DEFAULT_CONF_DIR = None
DEFAULT_USER_CONF_DIR = None
2013-02-13 12:57:02 +08:00
seafile_datadir = None
seafile_worktree = None
def _check_seafile():
''' Check seafile daemon have been installed '''
dirs = os.environ['PATH'].split(':')
def exist_in_path(prog):
''' Check whether 'prog' exists in system path '''
for d in dirs:
if d == '':
2013-02-13 12:57:02 +08:00
continue
path = join(d, prog)
if exists(path):
2013-02-13 12:57:02 +08:00
return True
progs = ['seaf-daemon']
for prog in progs:
if not exist_in_path(prog):
2019-09-23 18:21:54 +08:00
print("%s not found in PATH. Have you installed seafile?" % prog)
sys.exit(1)
def _check_daemon_running():
try:
subprocess.check_output(['ps', '-C', 'seaf-daemon'])
print("seaf-daemon is already running")
sys.exit(1)
except subprocess.CalledProcessError:
return
def get_rpc_client(confdir):
return seafile.RpcClient(join(seafile_datadir, 'seafile.sock'))
def _config_valid(conf):
''' Check config directory valid '''
if not exists(conf) or not isdir(conf):
2019-09-23 18:21:54 +08:00
print("%s not exists" % conf)
return False
seafile_ini = conf + "/seafile.ini"
if not exists(seafile_ini):
2019-09-23 18:21:54 +08:00
print("Could not load %s" % seafile_ini)
return False
2013-02-13 12:57:02 +08:00
with open(seafile_ini) as f:
for line in f:
global seafile_datadir, seafile_worktree
seafile_datadir = line.strip()
seafile_worktree = join(
dirname(seafile_datadir), "seafile")
2013-02-13 12:57:02 +08:00
break
if not seafile_datadir or not seafile_worktree:
2019-09-23 18:21:54 +08:00
print("Could not load seafile_datadir and seafile_worktree")
2013-02-13 12:57:02 +08:00
return False
return True
def _conf_dir(args):
''' Determine and return the value of conf_dir '''
conf_dir = DEFAULT_CONF_DIR
if args.confdir:
conf_dir = args.confdir
conf_dir = abspath(conf_dir)
if not _config_valid(conf_dir):
2019-09-23 18:21:54 +08:00
print("Invalid config directory")
sys.exit(1)
else:
get_device_id(conf_dir)
return conf_dir
def _user_config_valid(conf):
if exists(conf):
return True
return False
def _parse_user_config(conf):
try:
from configparser import ConfigParser
from configparser import NoOptionError
except ImportError:
from ConfigParser import ConfigParser
from ConfigParser import NoOptionError
cfg = ConfigParser()
cfg.read(conf)
if len(cfg.sections()) < 1 or cfg.sections()[0] != 'account':
return None, None
try:
server = cfg.get('account', 'server')
user = cfg.get('account', 'user')
return server,user
except NoOptionError:
return None, None
2013-03-11 11:18:14 +08:00
def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False):
'''Run a program and wait it to finish, and return its exit code. The
standard output of this program is supressed.
'''
with open(os.devnull, 'w') as devnull:
if suppress_stdout:
stdout = devnull
else:
stdout = sys.stdout
if suppress_stderr:
stderr = devnull
else:
stderr = sys.stderr
proc = subprocess.Popen(argv,
cwd=cwd,
stdout=stdout,
stderr=stderr,
env=env)
return proc.wait()
def get_env():
env = dict(os.environ)
ld_library_path = os.environ.get('SEAFILE_LD_LIBRARY_PATH', '')
if ld_library_path:
env['LD_LIBRARY_PATH'] = ld_library_path
return env
def urlopen(url, data=None, headers=None):
if data:
2019-09-23 18:21:54 +08:00
data = urllib.parse.urlencode(data).encode('utf-8')
2013-03-11 11:18:14 +08:00
headers = headers or {}
2019-09-23 18:21:54 +08:00
req = urllib.request.Request(url, data=data, headers=headers)
resp = urllib.request.urlopen(req)
2013-03-11 11:18:14 +08:00
return resp.read()
2014-04-30 14:39:03 +08:00
SEAF_CLI_VERSION = ""
def randstring(size):
random.seed(time.time())
s = ''
while len(s) < size:
s += '%x' % random.randint(0, 255)
return s[:size]
device_id = None
def get_device_id(conf_dir):
global device_id
if device_id:
return device_id
idfile = join(seafile_datadir, 'id')
ccnet_conf = join(conf_dir, 'ccnet.conf')
if exists(idfile):
with open(idfile, 'r') as fp:
device_id = fp.read().strip()
return device_id
# Id file doesn't exist. We either migrate it from ccnet.conf ID
# (for existing data), or create it.
if exists(ccnet_conf):
# migrate from existing ccnet.conf ID
with open(ccnet_conf, 'r') as fp:
for line in fp:
m = re.search('ID = (.*)', line)
if m:
device_id = m.group(1)
print('Migrating device id from ccnet conf')
break
if not device_id:
# create a new id
print('New device id created')
device_id = randstring(40)
with open(idfile, 'w') as fp:
fp.write(device_id)
return device_id
2014-04-30 14:39:03 +08:00
def get_token(url, username, password, tfa, conf_dir):
2014-04-30 14:39:03 +08:00
platform = 'linux'
device_id = get_device_id(conf_dir)
2021-07-13 10:29:38 +08:00
device_name = 'terminal-' + os.uname()[1][:25]
2014-04-30 14:39:03 +08:00
client_version = SEAF_CLI_VERSION
platform_version = ''
data = {
'username': username,
'password': password,
'platform': platform,
'device_id': device_id,
'device_name': device_name,
'client_version': client_version,
'platform_version': platform_version,
}
if tfa:
headers = {
'X-SEAFILE-OTP': tfa,
}
else:
headers = None
token_json = urlopen("%s/api2/auth-token/" % url, data=data, headers=headers)
tmp = json.loads(token_json.decode('utf8'))
2013-03-11 11:18:14 +08:00
token = tmp['token']
return token
def get_repo_download_info(url, token):
2013-03-11 11:18:14 +08:00
headers = { 'Authorization': 'Token %s' % token }
repo_info = urlopen(url, headers=headers)
return json.loads(repo_info.decode('utf8'))
2013-02-13 12:57:02 +08:00
def seaf_init(args):
''' Initialize config directories'''
2013-02-13 12:57:02 +08:00
ccnet_conf_dir = DEFAULT_CONF_DIR
if args.confdir:
ccnet_conf_dir = args.confdir
if args.dir:
seafile_path = args.dir
2013-02-27 20:14:27 +08:00
else:
2019-09-23 18:21:54 +08:00
print("Must specify the parent path for put seafile-data")
2013-02-27 20:14:27 +08:00
sys.exit(0)
seafile_path = abspath(seafile_path)
if exists(ccnet_conf_dir):
2019-09-23 18:21:54 +08:00
print("%s already exists" % ccnet_conf_dir)
sys.exit(0)
os.mkdir(ccnet_conf_dir)
logsdir = join(ccnet_conf_dir, 'logs')
if not exists(logsdir):
os.mkdir(logsdir)
if not exists(seafile_path):
2019-09-23 18:21:54 +08:00
print("%s not exists" % seafile_path)
2013-02-13 12:57:02 +08:00
sys.exit(0)
seafile_ini = ccnet_conf_dir + "/seafile.ini"
seafile_data = seafile_path + "/seafile-data"
with open(seafile_ini, 'w') as fp:
fp.write(seafile_data)
2018-08-21 10:35:19 +08:00
if not exists(seafile_data):
os.mkdir(seafile_data)
2019-09-23 18:21:54 +08:00
print("Writen seafile data directory %s to %s" % (seafile_data, seafile_ini))
def seaf_start_all(args):
''' Start seafile daemon '''
seaf_start_seafile(args)
def seaf_start_seafile(args):
''' start seafile daemon '''
conf_dir = _conf_dir(args)
_check_daemon_running()
2019-09-23 18:21:54 +08:00
print("Starting seafile daemon ...")
2013-10-31 10:50:03 +08:00
2013-02-13 12:57:02 +08:00
cmd = [ "seaf-daemon", "--daemon", "-c", conf_dir, "-d", seafile_datadir,
"-w", seafile_worktree ]
2013-03-11 11:18:14 +08:00
if run_argv(cmd, env=get_env()) != 0:
2019-09-23 18:21:54 +08:00
print('Failed to start seafile daemon')
2013-03-11 11:18:14 +08:00
sys.exit(1)
2019-09-23 18:21:54 +08:00
print("Started: seafile daemon ...")
2013-02-19 11:52:48 +08:00
def seaf_stop(args):
'''Stop seafile daemon '''
2013-02-19 11:52:48 +08:00
conf_dir = _conf_dir(args)
2013-02-19 11:52:48 +08:00
seafile_rpc = get_rpc_client(conf_dir)
2013-02-19 11:52:48 +08:00
try:
# TODO: add shutdown rpc in seaf-daemon
seafile_rpc.shutdown()
2013-02-19 11:52:48 +08:00
except:
# ignore NetworkError("Failed to read from socket")
pass
def seaf_list(args):
'''List local libraries'''
conf_dir = _conf_dir(args)
seafile_rpc = get_rpc_client(conf_dir)
repos = seafile_rpc.get_repo_list(-1, -1)
if args.json:
repo_list = []
for repo in repos:
repo_dict = {'name':repo.name, 'id':repo.id, 'path':repo.worktree}
repo_list.append(repo_dict)
json_str = json.dumps(repo_list, ensure_ascii=False)
print(json_str)
else:
print("Name\tID\tPath")
for repo in repos:
print(repo.name, repo.id, repo.worktree)
def seaf_list_remote(args):
'''List remote libraries'''
conf_dir = _conf_dir(args)
server_from_config, user_from_config = None, None
user_config_dir = args.C
if not user_config_dir:
user_config_dir = DEFAULT_USER_CONF_DIR
else:
user_config_dir = abspath(user_config_dir)
if _user_config_valid(user_config_dir):
server_from_config, user_from_config = _parse_user_config(user_config_dir)
url = args.server
if not url and server_from_config:
url = server_from_config
if not url:
2019-09-23 18:21:54 +08:00
print("Seafile server url need to be presented")
sys.exit(1)
seafile_rpc = get_rpc_client(conf_dir)
username = args.username
if not username and user_from_config:
username = user_from_config
if not username:
2019-09-23 18:21:54 +08:00
username = input("Enter username: ")
token = args.token
password = None
tfa = args.tfa
if not token:
password = args.password
if not password:
password = getpass.getpass("Enter password for user %s : " % username)
# curl -d 'username=<USERNAME>&password=<PASSWORD>' http://127.0.0.1:8000/api2/auth-token
token = get_token(url, username, password, tfa, conf_dir)
repos = get_repo_download_info("%s/api2/repos/" % (url), token)
printed = {}
if args.json:
repo_list = []
for repo in repos:
if repo['id'] in printed:
continue
printed[repo['id']] = repo['id']
repo_dict = {'name': repo['name'], 'id':repo['id']}
repo_list.append(repo_dict)
json_str = json.dumps(repo_list, ensure_ascii=False)
print(json_str)
else:
print("Name\tID")
for repo in repos:
if repo['id'] in printed:
continue
printed[repo['id']] = repo['id']
print(repo['name'], repo['id'])
2014-12-15 17:40:14 +08:00
def get_base_url(url):
parse_result = urlparse(url)
scheme = parse_result.scheme
netloc = parse_result.netloc
if scheme and netloc:
return '%s://%s' % (scheme, netloc)
return None
2013-02-13 12:57:02 +08:00
def seaf_download(args):
'''Download a library from seafile server '''
conf_dir = _conf_dir(args)
2013-02-13 12:57:02 +08:00
repo = args.library
if not repo:
2019-09-23 18:21:54 +08:00
print("Library id is required")
sys.exit(1)
server_from_config, user_from_config = None, None
user_config_dir = args.C
if not user_config_dir:
user_config_dir = DEFAULT_USER_CONF_DIR
else:
user_config_dir = abspath(user_config_dir)
if _user_config_valid(user_config_dir):
server_from_config, user_from_config = _parse_user_config(user_config_dir)
2013-02-13 12:57:02 +08:00
url = args.server
if not url and server_from_config:
url = server_from_config
if not url:
2019-09-23 18:21:54 +08:00
print("Seafile server url need to be presented")
sys.exit(1)
2013-02-13 12:57:02 +08:00
download_dir = seafile_worktree
if args.dir:
download_dir = abspath(args.dir)
seafile_rpc = get_rpc_client(conf_dir)
2013-02-19 11:52:48 +08:00
username = args.username
if not username and user_from_config:
username = user_from_config
if not username:
2019-09-23 18:21:54 +08:00
username = input("Enter username: ")
token = args.token
password = None
tfa = args.tfa
if not token:
password = args.password
if not password:
password = getpass.getpass("Enter password for user %s : " % username)
# curl -d 'username=<USERNAME>&password=<PASSWORD>' http://127.0.0.1:8000/api2/auth-token
token = get_token(url, username, password, tfa, conf_dir)
tmp = get_repo_download_info("%s/api2/repos/%s/download-info/" % (url, repo), token)
2013-02-20 10:52:55 +08:00
encrypted = tmp['encrypted']
2013-10-31 10:50:03 +08:00
magic = tmp.get('magic', None)
enc_version = tmp.get('enc_version', None)
random_key = tmp.get('random_key', None)
clone_token = tmp['token']
email = tmp['email']
repo_name = tmp['repo_name']
version = tmp.get('repo_version', 0)
2019-07-24 10:49:44 +08:00
repo_salt = tmp.get('salt', None)
2019-07-24 14:25:20 +08:00
permission = tmp.get('permission', None)
2019-07-24 14:25:20 +08:00
is_readonly = 0
if permission == 'r':
is_readonly = 1
2014-12-15 17:40:14 +08:00
more_info = None
2019-07-24 14:25:20 +08:00
more_info_dict = {}
base_url = get_base_url(url)
if base_url:
2019-07-24 14:25:20 +08:00
more_info_dict.update({'server_url': base_url})
if repo_salt:
more_info_dict.update({'repo_salt': repo_salt})
2019-07-24 14:25:20 +08:00
more_info_dict.update({'is_readonly': is_readonly})
more_info = json.dumps(more_info_dict)
2014-12-15 17:40:14 +08:00
2019-09-23 18:21:54 +08:00
print("Starting to download ...")
print("Library %s will be downloaded to %s" % (repo, download_dir))
2013-02-20 10:52:55 +08:00
if encrypted == 1:
repo_passwd = args.libpasswd if args.libpasswd else getpass.getpass("Enter password for the library: ")
2013-02-20 10:52:55 +08:00
else:
repo_passwd = None
2013-10-31 10:50:03 +08:00
2013-02-13 12:57:02 +08:00
seafile_rpc.download(repo,
version,
2019-09-23 18:21:54 +08:00
repo_name,
download_dir,
2013-02-13 12:57:02 +08:00
clone_token,
2013-02-20 10:52:55 +08:00
repo_passwd, magic,
2014-12-15 17:40:14 +08:00
email, random_key, enc_version, more_info)
2013-10-31 10:50:03 +08:00
def seaf_download_by_name(args):
'''Download a library defined by name from seafile server'''
id = None
conf_dir = _conf_dir(args)
libraryname = args.libraryname
if not libraryname:
2019-09-23 18:21:54 +08:00
print("Library name is required")
sys.exit(1)
server_from_config, user_from_config = None, None
user_config_dir = args.C
if not user_config_dir:
user_config_dir = DEFAULT_USER_CONF_DIR
else:
user_config_dir = abspath(user_config_dir)
if _user_config_valid(user_config_dir):
server_from_config, user_from_config = _parse_user_config(user_config_dir)
url = args.server
if not url and server_from_config:
url = server_from_config
if not url:
2019-09-23 18:21:54 +08:00
print("Seafile server url need to be presented")
sys.exit(1)
seafile_rpc = get_rpc_client(conf_dir)
username = args.username
if not username and user_from_config:
username = user_from_config;
if not username:
2019-09-23 18:21:54 +08:00
username = input("Enter username: ")
args.username = username
token = args.token
password = None
tfa = args.tfa
if not token:
password = args.password
if not password:
password = getpass.getpass("Enter password for user %s : " % username)
args.password = password
# curl -d 'username=<USERNAME>&password=<PASSWORD>' http://127.0.0.1:8000/api2/auth-token
token = get_token(url, username, password, tfa, conf_dir)
tmp = get_repo_download_info("%s/api2/repos/" % (url), token)
for i in tmp:
if libraryname == i['name']:
id = i['id']
if not id:
2019-09-23 18:21:54 +08:00
print("Defined library name not found")
sys.exit(1)
args.library = id
seaf_download(args)
def seaf_sync(args):
2013-02-13 12:57:02 +08:00
''' synchronize a library from seafile server '''
conf_dir = _conf_dir(args)
repo = args.library
if not repo:
2019-09-23 18:21:54 +08:00
print("Library id is required")
sys.exit(1)
server_from_config, user_from_config = None, None
user_config_dir = args.C
if not user_config_dir:
user_config_dir = DEFAULT_USER_CONF_DIR
else:
user_config_dir = abspath(user_config_dir)
if _user_config_valid(user_config_dir):
server_from_config, user_from_config = _parse_user_config(user_config_dir)
url = args.server
if not url and server_from_config:
url = server_from_config
if not url:
2019-09-23 18:21:54 +08:00
print("Seafile server url is required")
sys.exit(1)
folder = args.folder
if not folder:
2019-09-23 18:21:54 +08:00
print("The local directory is required")
2013-10-31 10:50:03 +08:00
sys.exit(1)
folder = abspath(folder)
if not exists(folder):
2019-09-23 18:21:54 +08:00
print("The local directory does not exists")
2013-10-31 10:50:03 +08:00
sys.exit(1)
seafile_rpc = get_rpc_client(conf_dir)
2013-02-19 11:52:48 +08:00
username = args.username
if not username and user_from_config:
username = user_from_config;
if not username:
2019-09-23 18:21:54 +08:00
username = input("Enter username: ")
password = None
token = args.token
tfa = args.tfa
if not token:
password = args.password
if not password:
password = getpass.getpass("Enter password for user %s : " % username)
token = get_token(url, username, password, tfa, conf_dir)
tmp = get_repo_download_info("%s/api2/repos/%s/download-info/" % (url, repo), token)
encrypted = tmp['encrypted']
2013-10-31 10:50:03 +08:00
magic = tmp.get('magic', None)
enc_version = tmp.get('enc_version', None)
random_key = tmp.get('random_key', None)
clone_token = tmp['token']
email = tmp['email']
repo_name = tmp['repo_name']
version = tmp.get('repo_version', 0)
2019-07-24 10:49:44 +08:00
repo_salt = tmp.get('salt', None)
2019-07-24 14:25:20 +08:00
permission = tmp.get('permission', None)
2019-07-24 14:25:20 +08:00
is_readonly = 0
if permission == 'r':
is_readonly = 1
2014-12-15 17:40:14 +08:00
more_info = None
2019-07-24 14:25:20 +08:00
more_info_dict = {}
base_url = get_base_url(url)
if base_url:
2019-07-24 14:25:20 +08:00
more_info_dict.update({'server_url': base_url})
if repo_salt:
more_info_dict.update({'repo_salt': repo_salt})
2019-07-24 14:25:20 +08:00
more_info_dict.update({'is_readonly': is_readonly})
more_info = json.dumps(more_info_dict)
2014-12-15 17:40:14 +08:00
2019-09-23 18:21:54 +08:00
print("Starting to download ...")
2013-02-20 10:52:55 +08:00
if encrypted == 1:
repo_passwd = args.libpasswd if args.libpasswd else getpass.getpass("Enter password for the library: ")
2013-02-20 10:52:55 +08:00
else:
repo_passwd = None
seafile_rpc.clone(repo,
version,
2019-09-23 18:21:54 +08:00
repo_name,
2013-02-20 10:52:55 +08:00
folder,
clone_token,
2013-02-20 10:52:55 +08:00
repo_passwd, magic,
2014-12-15 17:40:14 +08:00
email, random_key, enc_version, more_info)
def seaf_desync(args):
'''Desynchronize a library from seafile server'''
conf_dir = _conf_dir(args)
repo_path = args.folder
if not repo_path:
2019-09-23 18:21:54 +08:00
print("Must specify the local path of the library")
sys.exit(1)
repo_path = abspath(repo_path)
seafile_rpc = get_rpc_client(conf_dir)
2013-02-18 11:21:11 +08:00
repos = seafile_rpc.get_repo_list(-1, -1)
repo = None
for r in repos:
2019-09-23 18:21:54 +08:00
if r.worktree == repo_path:
repo = r
break
2019-09-23 18:21:54 +08:00
if repo is not None:
2019-10-29 15:50:20 +08:00
if sys.version_info[0] == 2:
repo.name = repo.name.encode('utf8')
2019-09-23 18:21:54 +08:00
print("Desynchronize %s" % repo.name)
seafile_rpc.remove_repo(repo.id)
else:
2019-09-23 18:21:54 +08:00
print("%s is not a library" % args.folder)
def seaf_config(args):
'''Configure the seafile client'''
conf_dir = _conf_dir(args)
config_key = args.key
if not config_key:
2019-09-23 18:21:54 +08:00
print("Must specify configuration key")
sys.exit(1)
config_value = args.value
seafile_rpc = get_rpc_client(conf_dir)
if config_value:
# set configuration key
seafile_rpc.seafile_set_config(config_key, config_value)
else:
# print configuration key
val = seafile_rpc.seafile_get_config(config_key)
2019-09-23 18:21:54 +08:00
print("%s = %s" % (config_key, val))
2013-02-17 15:49:53 +08:00
def seaf_status(args):
'''Show status'''
2013-02-18 11:21:11 +08:00
conf_dir = _conf_dir(args)
2013-02-18 11:21:11 +08:00
seafile_rpc = get_rpc_client(conf_dir)
2013-02-17 15:49:53 +08:00
tasks = seafile_rpc.get_clone_tasks()
2019-10-17 14:54:10 +08:00
print('# {:<50s}\t{:<20s}\t{:<20s}'.format('Name', 'Status', 'Progress'))
2013-02-17 15:49:53 +08:00
for task in tasks:
2019-10-29 15:50:20 +08:00
if sys.version_info[0] == 2:
task.repo_name = task.repo_name.encode('utf8')
2013-02-17 15:49:53 +08:00
if task.state == "fetch":
tx_task = seafile_rpc.find_transfer_task(task.repo_id)
2019-10-17 14:54:10 +08:00
try:
print('{:<50s}\t{:<20s}\t{:<.1f}%, {:<.1f}KB/s'.format(task.repo_name, 'downloading',
tx_task.block_done / tx_task.block_total * 100,
tx_task.rate / 1024.0))
except ZeroDivisionError: pass
2013-02-17 15:49:53 +08:00
elif task.state == "error":
2019-10-17 14:54:10 +08:00
err = seafile_rpc.sync_error_id_to_str(task.error)
print('{:<50s}\t{:<20s}\t{:<20s}'.format(task.repo_name, 'error', err))
elif task.state == 'done':
2013-02-18 11:21:11 +08:00
# will be shown in repo status
pass
2013-02-17 15:49:53 +08:00
else:
2019-10-17 14:54:10 +08:00
print('{:<50s}\t{:<20s}'.format(task.repo_name, task.state))
2013-02-17 15:49:53 +08:00
repos = seafile_rpc.get_repo_list(-1, -1)
for repo in repos:
auto_sync_enabled = seafile_rpc.is_auto_sync_enabled()
if not auto_sync_enabled or not repo.auto_sync:
2019-10-17 14:54:10 +08:00
print('{:<50s}\t{:<20s}'.format(repo.name, 'auto sync disabled'))
2013-02-18 11:21:11 +08:00
continue
2019-10-17 14:54:10 +08:00
task = seafile_rpc.get_repo_sync_task(repo.id)
2019-10-24 13:45:49 +08:00
if task is None:
2019-10-17 14:54:10 +08:00
print('{:<50s}\t{:<20s}'.format(repo.name, 'waiting for sync'))
elif task.state == 'uploading':
tx_task = seafile_rpc.find_transfer_task(repo.id)
try:
print('{:<50s}\t{:<20s}\t{:<.1f}%, {:<.1f}KB/s'.format(repo.name, 'uploading',
tx_task.block_done / tx_task.block_total * 100,
tx_task.rate / 1024.0))
except ZeroDivisionError: pass
elif task.state == 'downloading':
tx_task = seafile_rpc.find_transfer_task(repo.id)
try:
if tx_task.rt_state == 'data':
print('{:<50s}\t{:<20s}\t{:<.1f}%, {:<.1f}KB/s'.format(repo.name, 'downloading files',
tx_task.block_done / tx_task.block_total * 100,
tx_task.rate / 1024.0))
if tx_task.rt_state == 'fs':
print('{:<50s}\t{:<20s}\t{:<.1f}%'.format(repo.name, 'downloading file list',
tx_task.fs_objects_done / tx_task.fs_objects_total * 100))
except ZeroDivisionError: pass
elif task.state == 'error':
2019-10-28 14:40:09 +08:00
err = seafile_rpc.sync_error_id_to_str(task.error)
print('{:<50s}\t{:<20s}\t{:<20s}'.format(repo.name, 'error', err))
2013-02-17 15:49:53 +08:00
else:
2019-10-17 14:54:10 +08:00
print('{:<50s}\t{:<20s}'.format(repo.name, task.state))
def create_repo(url, token, args):
headers = { 'Authorization': 'Token %s' % token }
data = {
'name': args.name,
'desc': args.desc,
}
if args.libpasswd:
data['passwd'] = args.libpasswd
repo_info_json = urlopen(url, data=data, headers=headers)
repo_info = json.loads(repo_info_json.decode('utf8'))
return repo_info['repo_id']
def seaf_create(args):
'''Create a library'''
conf_dir = _conf_dir(args)
server_from_config, user_from_config = None, None
user_config_dir = args.C
if not user_config_dir:
user_config_dir = DEFAULT_USER_CONF_DIR
else:
user_config_dir = abspath(user_config_dir)
if _user_config_valid(user_config_dir):
server_from_config, user_from_config = _parse_user_config(user_config_dir)
# check username and password
username = args.username
if not username and user_from_config:
username = user_from_config;
if not username:
2019-09-23 18:21:54 +08:00
username = input("Enter username: ")
url = args.server
if not url and server_from_config:
url = server_from_config
if not url:
2019-09-23 18:21:54 +08:00
print("Seafile server url need to be presented")
sys.exit(1)
token = args.token
password = None
tfa = args.tfa
if not token:
password = args.password
if not password:
password = getpass.getpass("Enter password for user %s " % username)
# curl -d 'username=<USERNAME>&password=<PASSWORD>' http://127.0.0.1:8000/api2/auth-token
token = get_token(url, username, password, tfa, conf_dir)
repo_id = create_repo("%s/api2/repos/" % (url), token, args)
2019-09-23 18:21:54 +08:00
print(repo_id)
def main():
''' Main entry '''
_check_seafile()
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(title='subcommands', description='')
confdir_required = DEFAULT_CONF_DIR is None
# init
parser_init = subparsers.add_parser('init', help='Initialize config directory')
2013-02-13 12:57:02 +08:00
parser_init.set_defaults(func=seaf_init)
parser_init.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
2013-02-13 12:57:02 +08:00
parser_init.add_argument('-d', '--dir', help='the parent directory to put seafile-data', type=str)
# start
parser_start = subparsers.add_parser('start',
help='Start seafile daemon')
parser_start.set_defaults(func=seaf_start_all)
parser_start.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
2013-02-13 12:57:02 +08:00
2013-02-19 11:52:48 +08:00
# stop
parser_stop = subparsers.add_parser('stop',
help='Stop seafile daemon')
2013-02-19 11:52:48 +08:00
parser_stop.set_defaults(func=seaf_stop)
parser_stop.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
# list
parser_list = subparsers.add_parser('list', help='List local libraries')
parser_list.set_defaults(func=seaf_list)
parser_list.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_list.add_argument('--json', help='output json format result', action='store_true')
2013-02-18 11:21:11 +08:00
# list-remote
parser_download = subparsers.add_parser('list-remote', help='List remote libraries')
parser_download.set_defaults(func=seaf_list_remote)
parser_download.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_download.add_argument('-C', help='the user config directory', type=str)
parser_download.add_argument('-s', '--server', help='URL for seafile server', type=str)
parser_download.add_argument('-u', '--username', help='username', type=str)
parser_download.add_argument('-p', '--password', help='password', type=str)
parser_download.add_argument('-T', '--token', help='token', type=str)
parser_download.add_argument('-a', '--tfa', help='two-factor authentication', type=str)
parser_download.add_argument('--json', help='output json format result', action='store_true')
2013-02-17 15:49:53 +08:00
# status
parser_status = subparsers.add_parser('status', help='Show syncing status')
2013-02-17 15:49:53 +08:00
parser_status.set_defaults(func=seaf_status)
parser_status.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
# download
2013-02-13 12:57:02 +08:00
parser_download = subparsers.add_parser('download',
help='Download a library from seafile server')
parser_download.set_defaults(func=seaf_download)
parser_download.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_download.add_argument('-C', help='the user config directory', type=str)
2013-02-17 15:49:53 +08:00
parser_download.add_argument('-l', '--library', help='library id', type=str)
2013-02-13 12:57:02 +08:00
parser_download.add_argument('-s', '--server', help='URL for seafile server', type=str)
parser_download.add_argument('-d', '--dir', help='the directory to put the library', type=str)
2013-02-19 11:52:48 +08:00
parser_download.add_argument('-u', '--username', help='username', type=str)
2013-02-13 12:57:02 +08:00
parser_download.add_argument('-p', '--password', help='password', type=str)
parser_download.add_argument('-T', '--token', help='token', type=str)
parser_download.add_argument('-a', '--tfa', help='two-factor authentication', type=str)
parser_download.add_argument('-e', '--libpasswd', help='library password', type=str)
# download-by-name
parser_download = subparsers.add_parser('download-by-name',
help='Download a library defined by name from seafile server')
parser_download.set_defaults(func=seaf_download_by_name)
parser_download.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_download.add_argument('-C', help='the user config directory', type=str)
parser_download.add_argument('-L', '--libraryname', help='library name', type=str)
parser_download.add_argument('-s', '--server', help='URL for seafile server', type=str)
parser_download.add_argument('-d', '--dir', help='the directory to put the library', type=str)
parser_download.add_argument('-u', '--username', help='username', type=str)
parser_download.add_argument('-p', '--password', help='password', type=str)
parser_download.add_argument('-T', '--token', help='token', type=str)
parser_download.add_argument('-a', '--tfa', help='two-factor authentication', type=str)
parser_download.add_argument('-e', '--libpasswd', help='library password', type=str)
# sync
parser_sync = subparsers.add_parser('sync',
2013-02-13 12:57:02 +08:00
help='Sync a library with an existing foler')
parser_sync.set_defaults(func=seaf_sync)
parser_sync.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_sync.add_argument('-C', help='the user config directory', type=str)
2013-02-17 15:49:53 +08:00
parser_sync.add_argument('-l', '--library', help='library id', type=str)
2013-02-13 12:57:02 +08:00
parser_sync.add_argument('-s', '--server', help='URL for seafile server', type=str)
2013-02-19 11:52:48 +08:00
parser_sync.add_argument('-u', '--username', help='username', type=str)
2013-02-13 12:57:02 +08:00
parser_sync.add_argument('-p', '--password', help='password', type=str)
parser_sync.add_argument('-T', '--token', help='token', type=str)
parser_sync.add_argument('-a', '--tfa', help='two-factor authentication', type=str)
2013-02-13 12:57:02 +08:00
parser_sync.add_argument('-d', '--folder', help='the existing local folder', type=str)
parser_sync.add_argument('-e', '--libpasswd', help='library password', type=str)
# desync
parser_desync = subparsers.add_parser('desync',
2013-02-13 12:57:02 +08:00
help='Desync a library with seafile server')
parser_desync.set_defaults(func=seaf_desync)
parser_desync.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
2013-02-13 12:57:02 +08:00
parser_desync.add_argument('-d', '--folder', help='the local folder', type=str)
# create
parser_create = subparsers.add_parser('create',
help='Create a library')
parser_create.set_defaults(func=seaf_create)
parser_create.add_argument('-n', '--name', help='library name', type=str)
parser_create.add_argument('-t', '--desc', help='library description', type=str)
parser_create.add_argument('-e', '--libpasswd', help='library password', type=str)
parser_create.add_argument('-s', '--server', help='URL for seafile server', type=str)
parser_create.add_argument('-u', '--username', help='username', type=str)
parser_create.add_argument('-p', '--password', help='password', type=str)
parser_create.add_argument('-T', '--token', help='token', type=str)
parser_create.add_argument('-a', '--tfa', help='two-factor authentication', type=str)
parser_create.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_create.add_argument('-C', help='the user config directory', type=str)
# config
parser_config = subparsers.add_parser('config',
help='Configure seafile client')
parser_config.set_defaults(func=seaf_config)
parser_config.add_argument('-c', '--confdir', help='the config directory', type=str, required=confdir_required)
parser_config.add_argument('-k', '--key', help='configuration key', type=str)
parser_config.add_argument('-v', '--value', help='configuration value (if provided, key is set to this value)', type=str, required=False)
2013-03-08 11:14:36 +08:00
if len(sys.argv) == 1:
2019-09-23 18:21:54 +08:00
print(parser.format_help())
2013-03-08 11:14:36 +08:00
return
args = parser.parse_args()
args.func(args)
if __name__ == '__main__':
main()
# print('device id is {}'.format(get_device_id(DEFAULT_CONF_DIR)))