haiv icon

Hastebin CLI

haiv | PRO | 09/11/21 04:50:39 PM UTC (Edited) | 0 ⭐ | 609 👁️ | Never ⏰ | []
Python |

5.09 KB

|

None

|

0 👍

/

0 👎

#!/usr/bin/env python
"""
NAME
 
    hb - Uploads data to a hastebin server
 
SYNOPSYS
 
    hb [OPTION]... [FILE]...
 
DESCRIPTION
 
    When invoked without any file name, hb will reads from standard
    input. If the caller supplies the file names, each of them will be
    uploaded separately. Upon completion, hb will print to the standard
    output the URL for each upload.
 
    -h, --help
        Displays help and exit
 
CONFIGURATION
 
    By default, hb will upload to http://localhost:7777. If you
    want to upload to a different server, there are three ways to
    configure it.
 
    The first is to create a configuration file in the same directory
    of the script and name it `hb.json`. In a multiple-user
    environment, this configuration is meant to be global to all
    the users.
 
    The second is to create a per-user configuration file in
    `~/.hb.json`.
 
    Below is an example of such configuration file:
 
        {
            "HASTE_SERVER": "http://my-hastebin.com"
        }
 
    The third is to use an environment variable. Here is an example
    for the bash shell:
 
        export HASTE_SERVER=http://my-hastebin.com
 
    Below is the order of look-up to find the server, with the
    environment variable having the highest precedence:
 
        1. The environment variable
        2. The global configuration file
        3. The per-user configuration file
        4. If all failed, use http://localhost:7777
 
LOG
 
    hb keeps a log of all the URLs in ~/.hb.log
 
AUTHOR
 
    Written by Hai Vu (haivu2004 at gmail dot com)
 
"""
import collections
import json
import logging
import os
import pathlib
import sys
import urllib.request
 
 
logging.basicConfig(level=os.getenv('LOGLEVEL', 'WARN'))
LOGGER = logging.getLogger(__name__)
 
CONFIG = {
    'HASTE_SERVER': 'http://localhost:7777'
}
 
 
def read_config_file(path):
    """
    Reads the user configuration from `path` and returns a dictionary.
    If the configuration file is not found, returns an empty
    dictionary.
    """
    try:
        with open(path, encoding='utf-8') as file_handle:
            config = json.load(file_handle)
    except FileNotFoundError:
        config = dict()
 
    return config
 
 
def get_server_url():
    """
    Returns the server URL in the following search order. See the
    document above for search order.
    """
    user_config = read_config_file(pathlib.Path('~/.hb.json').expanduser())
    global_config_path = pathlib.Path(__file__).with_name('hb.json')
    global_config = read_config_file(global_config_path)
 
    all_configs = collections.ChainMap(
        os.environ,
        user_config,
        global_config,
        CONFIG)
 
    server_url = all_configs['HASTE_SERVER']
    if server_url.endswith('/'):
        server_url = server_url.rstrip('/')
    LOGGER.debug('Server URL: %s', server_url)
    return server_url
 
 
def truncate(text):
    """
    given some text, truncate it to a certain size for display and
    replace all the new lines with spaces
    """
    return text[:40].replace('\n', ' ')
 
 
def upload(url, data):
    """
    Upload the data to the hastebin server. The `url` parameter indicates the
    server's URL, e.g. 'https://hastebin.com'. The `data` parameter can either
    be a string, a bytes stream, or a file-like object serving raw bytes. Upon
    completion, the function returns a dictionary in which the key `key` will
    provide the token for locating the paste, e.g. `{"key": "xyz"}`. The caller
    can combine the server url with this key to create the full URL for
    accessing the paste, e.g. https://hastebin.com/xyz.
    """
 
    url = f'{url}/documents'
    if isinstance(data, str):
        data = data.encode('utf-8')
 
    request = urllib.request.Request(url, data)
    with urllib.request.urlopen(request) as response:
        output = json.load(response)
        return output
 
 
def upload_wrapper(url, filename=None):
    """
    Uploads a file and perform other administrative tasks
    """
    if filename is None:
        data = sys.stdin.read()
        preview = truncate(data)
    else:
        data = open(filename, 'rb')
        preview = truncate(data.read(40).decode('utf-8'))
        data.seek(0)
 
    output = upload(url, data)
    output_url = f'{url}/{output["key"]}'
 
    log_file = pathlib.Path('~/.hb.log').expanduser()
    with open(log_file, 'a', encoding='utf-8') as file_handle:
        if filename is None:
            filename = 'stdin'
        output = f'{filename} - {output_url} - {preview}'
        print(output)
        file_handle.write(output)
        file_handle.write('\n')
 
 
def show_usage():
    """
    Show the usage
    """
    print(__doc__)
 
 
def main():
    """ Entry """
    server_url = get_server_url()
    if len(sys.argv) > 1:
        if sys.argv[1] in {'-h', '--help'}:
            show_usage()
            return
 
        for filename in sys.argv[1:]:
            upload_wrapper(server_url, filename)
    else:
        upload_wrapper(server_url)
 
 
if __name__ == '__main__':
    main()

Comments