Toot-Mastodon-CLI-TUI-clien.../toot/console.py

226 lines
5.7 KiB
Python
Raw Normal View History

2017-04-15 14:53:08 +02:00
# -*- coding: utf-8 -*-
2017-04-17 09:58:36 +02:00
from __future__ import unicode_literals
from __future__ import print_function
2017-04-12 16:42:04 +02:00
import os
import sys
2017-04-19 14:47:30 +02:00
import logging
2017-04-12 16:42:04 +02:00
from argparse import ArgumentParser, FileType
2017-04-19 14:47:30 +02:00
from collections import namedtuple
from toot import config, api, commands, ConsoleError, CLIENT_NAME, CLIENT_WEBSITE
from toot.output import print_error
2017-04-19 14:47:30 +02:00
VISIBILITY_CHOICES = ['public', 'unlisted', 'private', 'direct']
2017-04-19 14:47:30 +02:00
def visibility(value):
"""Validates the visibilty parameter"""
if value not in VISIBILITY_CHOICES:
raise ValueError("Invalid visibility value")
2017-04-19 14:47:30 +02:00
return value
2017-04-19 14:47:30 +02:00
Command = namedtuple("Command", ["name", "description", "require_auth", "arguments"])
COMMANDS = [
Command(
name="login",
description="Log into a Mastodon instance",
arguments=[],
require_auth=False,
),
Command(
name="login_2fa",
description="Log in using two factor authentication (experimental)",
arguments=[],
require_auth=False,
),
Command(
name="logout",
description="Log out, delete stored access keys",
arguments=[],
require_auth=False,
),
Command(
name="auth",
description="Show stored credentials",
arguments=[],
require_auth=False,
),
Command(
name="whoami",
description="Display logged in user details",
arguments=[],
require_auth=True,
),
2017-04-19 15:29:40 +02:00
Command(
name="whois",
description="Display user details",
arguments=[
(["account"], {
"help": "account name or numeric ID"
}),
],
require_auth=True,
),
2017-04-19 14:47:30 +02:00
Command(
name="post",
description="Post a status text to your timeline",
arguments=[
(["text"], {
"help": "The status text to post.",
}),
(["-m", "--media"], {
"type": FileType('rb'),
"help": "path to the media file to attach"
}),
(["-v", "--visibility"], {
"type": visibility,
"default": "public",
"help": 'post visibility, one of: %s' % ", ".join(VISIBILITY_CHOICES),
})
],
require_auth=True,
),
Command(
name="upload",
description="Upload an image or video file",
arguments=[
(["file"], {
"help": "Path to the file to upload",
"type": FileType('rb')
})
],
require_auth=True,
),
Command(
name="search",
description="Search for users or hashtags",
arguments=[
(["query"], {
"help": "the search query",
}),
(["-r", "--resolve"], {
"action": 'store_true',
"default": False,
"help": "Resolve non-local accounts",
}),
],
require_auth=True,
),
Command(
name="follow",
description="Follow an account",
arguments=[
(["account"], {
"help": "account name, e.g. 'Gargron' or 'polymerwitch@toot.cat'",
}),
],
require_auth=True,
),
Command(
name="unfollow",
description="Unfollow an account",
arguments=[
(["account"], {
"help": "account name, e.g. 'Gargron' or 'polymerwitch@toot.cat'",
}),
],
require_auth=True,
),
Command(
name="timeline",
description="Show recent items in your public timeline",
arguments=[],
require_auth=True,
),
Command(
name="curses",
description="An experimental timeline app.",
arguments=[],
require_auth=True,
2017-04-19 14:47:30 +02:00
),
]
2017-04-12 16:42:04 +02:00
def print_usage():
2017-04-19 14:47:30 +02:00
print(CLIENT_NAME)
2017-04-12 16:42:04 +02:00
print("")
print("Usage:")
2017-04-19 14:47:30 +02:00
max_name_len = max(len(command.name) for command in COMMANDS)
for command in COMMANDS:
print(" toot", command.name.ljust(max_name_len + 2), command.description)
2017-04-12 16:42:04 +02:00
print("")
2017-04-15 12:12:33 +02:00
print("To get help for each command run:")
print(" toot <command> --help")
print("")
2017-04-19 14:47:30 +02:00
print(CLIENT_WEBSITE)
2017-04-12 16:42:04 +02:00
2017-04-19 14:47:30 +02:00
def get_argument_parser(name, command):
parser = ArgumentParser(
prog='toot %s' % name,
description=command.description,
epilog=CLIENT_WEBSITE)
2017-04-12 16:42:04 +02:00
2017-04-19 14:47:30 +02:00
for args, kwargs in command.arguments:
parser.add_argument(*args, **kwargs)
2017-04-12 16:42:04 +02:00
2017-04-19 14:47:30 +02:00
return parser
2017-04-12 16:42:04 +02:00
2017-04-15 12:12:33 +02:00
2017-04-19 14:47:30 +02:00
def run_command(app, user, name, args):
command = next((c for c in COMMANDS if c.name == name), None)
2017-04-12 16:42:04 +02:00
2017-04-19 14:47:30 +02:00
if not command:
print_error("Unknown command '{}'\n".format(name))
print_usage()
2017-04-16 17:15:05 +02:00
return
2017-04-19 14:47:30 +02:00
parser = get_argument_parser(name, command)
parsed_args = parser.parse_args(args)
2017-04-13 13:52:28 +02:00
2017-04-19 14:47:30 +02:00
if command.require_auth and (not user or not app):
print_error("This command requires that you are logged in.")
2017-04-16 15:07:27 +02:00
print_error("Please run `toot login` first.")
2017-04-13 13:52:28 +02:00
return
2017-04-19 14:47:30 +02:00
fn = commands.__dict__.get(name)
2017-04-13 13:52:28 +02:00
2017-04-19 15:29:40 +02:00
if not fn:
raise NotImplementedError("Command '{}' does not have an implementation.".format(name))
2017-04-19 14:47:30 +02:00
return fn(app, user, parsed_args)
2017-04-13 13:52:28 +02:00
def main():
2017-04-12 16:42:04 +02:00
if os.getenv('TOOT_DEBUG'):
logging.basicConfig(level=logging.DEBUG)
2017-04-19 11:03:44 +02:00
# If something is piped in, append it to commandline arguments
if not sys.stdin.isatty():
sys.argv.append(sys.stdin.read())
2017-04-19 14:47:30 +02:00
command_name = sys.argv[1] if len(sys.argv) > 1 else None
args = sys.argv[2:]
2017-04-12 16:42:04 +02:00
2017-04-19 14:47:30 +02:00
if not command_name:
2017-04-13 13:52:28 +02:00
return print_usage()
2017-04-19 14:47:30 +02:00
user = config.load_user()
app = config.load_app(user.instance) if user else None
2017-04-13 13:52:28 +02:00
try:
2017-04-19 14:47:30 +02:00
run_command(app, user, command_name, args)
2017-04-13 13:52:28 +02:00
except ConsoleError as e:
print_error(str(e))
2017-04-19 14:47:30 +02:00
except api.ApiError as e:
2017-04-16 17:15:05 +02:00
print_error(str(e))