haiv

Hastebin CLI

Aug 12th, 2019 (edited)
474
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.09 KB | None | 0 0
  1. #!/usr/bin/env python
  2. """
  3. NAME
  4.  
  5.    hb - Uploads data to a hastebin server
  6.  
  7. SYNOPSYS
  8.  
  9.    hb [OPTION]... [FILE]...
  10.  
  11. DESCRIPTION
  12.  
  13.    When invoked without any file name, hb will reads from standard
  14.    input. If the caller supplies the file names, each of them will be
  15.    uploaded separately. Upon completion, hb will print to the standard
  16.    output the URL for each upload.
  17.  
  18.    -h, --help
  19.        Displays help and exit
  20.  
  21. CONFIGURATION
  22.  
  23.    By default, hb will upload to http://localhost:7777. If you
  24.    want to upload to a different server, there are three ways to
  25.    configure it.
  26.  
  27.    The first is to create a configuration file in the same directory
  28.    of the script and name it `hb.json`. In a multiple-user
  29.    environment, this configuration is meant to be global to all
  30.    the users.
  31.  
  32.    The second is to create a per-user configuration file in
  33.    `~/.hb.json`.
  34.  
  35.    Below is an example of such configuration file:
  36.  
  37.        {
  38.            "HASTE_SERVER": "http://my-hastebin.com"
  39.        }
  40.  
  41.    The third is to use an environment variable. Here is an example
  42.    for the bash shell:
  43.  
  44.        export HASTE_SERVER=http://my-hastebin.com
  45.  
  46.    Below is the order of look-up to find the server, with the
  47.    environment variable having the highest precedence:
  48.  
  49.        1. The environment variable
  50.        2. The global configuration file
  51.        3. The per-user configuration file
  52.        4. If all failed, use http://localhost:7777
  53.  
  54. LOG
  55.  
  56.    hb keeps a log of all the URLs in ~/.hb.log
  57.  
  58. AUTHOR
  59.  
  60.    Written by Hai Vu (haivu2004 at gmail dot com)
  61.  
  62. """
  63. import collections
  64. import json
  65. import logging
  66. import os
  67. import pathlib
  68. import sys
  69. import urllib.request
  70.  
  71.  
  72. logging.basicConfig(level=os.getenv('LOGLEVEL', 'WARN'))
  73. LOGGER = logging.getLogger(__name__)
  74.  
  75. CONFIG = {
  76.     'HASTE_SERVER': 'http://localhost:7777'
  77. }
  78.  
  79.  
  80. def read_config_file(path):
  81.     """
  82.    Reads the user configuration from `path` and returns a dictionary.
  83.    If the configuration file is not found, returns an empty
  84.    dictionary.
  85.    """
  86.     try:
  87.         with open(path, encoding='utf-8') as file_handle:
  88.             config = json.load(file_handle)
  89.     except FileNotFoundError:
  90.         config = dict()
  91.  
  92.     return config
  93.  
  94.  
  95. def get_server_url():
  96.     """
  97.    Returns the server URL in the following search order. See the
  98.    document above for search order.
  99.    """
  100.     user_config = read_config_file(pathlib.Path('~/.hb.json').expanduser())
  101.     global_config_path = pathlib.Path(__file__).with_name('hb.json')
  102.     global_config = read_config_file(global_config_path)
  103.  
  104.     all_configs = collections.ChainMap(
  105.         os.environ,
  106.         user_config,
  107.         global_config,
  108.         CONFIG)
  109.  
  110.     server_url = all_configs['HASTE_SERVER']
  111.     if server_url.endswith('/'):
  112.         server_url = server_url.rstrip('/')
  113.     LOGGER.debug('Server URL: %s', server_url)
  114.     return server_url
  115.  
  116.  
  117. def truncate(text):
  118.     """
  119.    given some text, truncate it to a certain size for display and
  120.    replace all the new lines with spaces
  121.    """
  122.     return text[:40].replace('\n', ' ')
  123.  
  124.  
  125. def upload(url, data):
  126.     """
  127.    Upload the data to the hastebin server. The `url` parameter indicates the
  128.    server's URL, e.g. 'https://hastebin.com'. The `data` parameter can either
  129.    be a string, a bytes stream, or a file-like object serving raw bytes. Upon
  130.    completion, the function returns a dictionary in which the key `key` will
  131.    provide the token for locating the paste, e.g. `{"key": "xyz"}`. The caller
  132.    can combine the server url with this key to create the full URL for
  133.    accessing the paste, e.g. https://hastebin.com/xyz.
  134.    """
  135.  
  136.     url = f'{url}/documents'
  137.     if isinstance(data, str):
  138.         data = data.encode('utf-8')
  139.  
  140.     request = urllib.request.Request(url, data)
  141.     with urllib.request.urlopen(request) as response:
  142.         output = json.load(response)
  143.         return output
  144.  
  145.  
  146. def upload_wrapper(url, filename=None):
  147.     """
  148.    Uploads a file and perform other administrative tasks
  149.    """
  150.     if filename is None:
  151.         data = sys.stdin.read()
  152.         preview = truncate(data)
  153.     else:
  154.         data = open(filename, 'rb')
  155.         preview = truncate(data.read(40).decode('utf-8'))
  156.         data.seek(0)
  157.  
  158.     output = upload(url, data)
  159.     output_url = f'{url}/{output["key"]}'
  160.  
  161.     log_file = pathlib.Path('~/.hb.log').expanduser()
  162.     with open(log_file, 'a', encoding='utf-8') as file_handle:
  163.         if filename is None:
  164.             filename = 'stdin'
  165.         output = f'{filename} - {output_url} - {preview}'
  166.         print(output)
  167.         file_handle.write(output)
  168.         file_handle.write('\n')
  169.  
  170.  
  171. def show_usage():
  172.     """
  173.    Show the usage
  174.    """
  175.     print(__doc__)
  176.  
  177.  
  178. def main():
  179.     """ Entry """
  180.     server_url = get_server_url()
  181.     if len(sys.argv) > 1:
  182.         if sys.argv[1] in {'-h', '--help'}:
  183.             show_usage()
  184.             return
  185.  
  186.         for filename in sys.argv[1:]:
  187.             upload_wrapper(server_url, filename)
  188.     else:
  189.         upload_wrapper(server_url)
  190.  
  191.  
  192. if __name__ == '__main__':
  193.     main()
Add Comment
Please, Sign In to add comment