1#! /usr/bin/env python 2 3# This script uploads a directory to Wandbox (http://melpon.org/wandbox), 4# which is an online compiler environment, and prints a permalink to the 5# uploaded code. We use this to provide a "Try it online" version of the 6# library to make the barrier to entry as low as possible. 7# 8# This script was adapted from the script proposed in 9# https://github.com/melpon/wandbox/issues/153. 10# 11# To know how to use this script: ./wandbox.py --help 12# 13# Copyright Louis Dionne 2015 14# Distributed under the Boost Software License, Version 1.0. 15# (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 16 17import argparse 18import fnmatch 19import json 20import os 21import re 22import urllib2 23 24 25# Strips C and C++ comments from the given string. 26# 27# Copied from https://stackoverflow.com/a/241506/627587. 28def strip_comments(text): 29 def replacer(match): 30 s = match.group(0) 31 if s.startswith('/'): 32 return " " # note: a space and not an empty string 33 else: 34 return s 35 pattern = re.compile( 36 r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', 37 re.DOTALL | re.MULTILINE 38 ) 39 return re.sub(pattern, replacer, text) 40 41 42# Post the given JSON data to Wandbox's API, and return the result 43# as a JSON object. 44def upload(options): 45 request = urllib2.Request('https://melpon.org/wandbox/api/compile.json') 46 request.add_header('Content-Type', 'application/json') 47 response = urllib2.urlopen(request, json.dumps(options)) 48 return json.loads(response.read()) 49 50 51# Returns a list of the '.hpp' headers in the given directory and in 52# subdirectories. 53# 54# The path must be absolute, and the returned paths are all absolute too. 55def headers(path): 56 return [ 57 os.path.join(dir, file) 58 for (dir, _, files) in os.walk(path) 59 for file in fnmatch.filter(files, "*.hpp") 60 ] 61 62 63def main(): 64 parser = argparse.ArgumentParser(description= 65 """Upload a directory to Wandbox (http://melpon.org/wandbox). 66 67 On success, the program prints a permalink to the uploaded 68 directory on Wandbox and returns 0. On error, it prints the 69 response from the Wandbox API and returns 1. 70 71 Note that the comments are stripped from all the headers in the 72 uploaded directory. 73 """ 74 ) 75 parser.add_argument('directory', type=str, help= 76 """A directory to upload to Wandbox. 77 78 The path may be either absolute or relative to the current directory. 79 However, the names of the files uploaded to Wandbox will all be 80 relative to this directory. This way, one can easily specify the 81 directory to be '/some/project/include', and the uploaded files 82 will be uploaded as-if they were rooted at '/some/project/include' 83 """) 84 parser.add_argument('main', type=str, help= 85 """The main source file. 86 87 The path may be either absolute or relative to the current directory. 88 """ 89 ) 90 args = parser.parse_args() 91 directory = os.path.abspath(args.directory) 92 if not os.path.exists(directory): 93 raise Exception("'%s' is not a valid directory" % args.directory) 94 95 cpp = os.path.abspath(args.main) 96 if not os.path.exists(cpp): 97 raise Exception("'%s' is not a valid file name" % args.main) 98 99 response = upload({ 100 'code': open(cpp).read(), 101 'codes': [{ 102 'file': os.path.relpath(header, directory), 103 #'code': strip_comments(open(header).read()) 104 'code': open(header).read() 105 } for header in headers(directory)], 106 'options': 'boost-nothing,c++11', 107 'compiler': 'gcc-4.9.2', 108 'save': True, 109 'compiler-option-raw': '-I.' 110 }) 111 112 if 'status' in response and response['status'] == '0': 113 print response['url'] 114 return 0 115 else: 116 print response 117 return 1 118 119 120exit(main()) 121