From b828542a0824e94576c84c0bc3afe0f5b59b722b Mon Sep 17 00:00:00 2001 From: Alan Hamlett Date: Mon, 23 Oct 2017 21:54:21 -0700 Subject: [PATCH] allow passing all string arguments wrapped in extra quotes --- tests/test_arguments.py | 19 ++++++++++++++++++- wakatime/arguments.py | 35 +++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/tests/test_arguments.py b/tests/test_arguments.py index a5ca881..28ef204 100644 --- a/tests/test_arguments.py +++ b/tests/test_arguments.py @@ -82,6 +82,23 @@ class ArgumentsTestCase(utils.TestCase): self.patched['wakatime.offlinequeue.Queue.push'].assert_not_called() self.patched['wakatime.offlinequeue.Queue.pop'].assert_called_once_with() + def test_argument_parsing_strips_quotes(self): + response = Response() + response.status_code = 500 + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + + now = u(int(time.time())) + config = 'tests/samples/configs/good_config.cfg' + entity = 'tests/samples/codefiles/python.py' + plugin = '"abcplugin\\"withquotes"' + args = ['--file', '"' + entity + '"', '--config', config, '--time', now, '--plugin', plugin] + + retval = execute(args) + self.assertEquals(retval, API_ERROR) + + expected = 'abcplugin"withquotes' + self.assertEqual(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][2], expected) + def test_lineno_and_cursorpos(self): response = Response() response.status_code = 0 @@ -509,7 +526,7 @@ class ArgumentsTestCase(utils.TestCase): args = ['--file', entity, '--config', config, '--time', now, '--alternate-language', 'JAVA'] retval = execute(args) - self.assertEquals(retval, 102) + self.assertEquals(retval, API_ERROR) language = u('Java') self.assertEqual(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0].get('language'), language) diff --git a/wakatime/arguments.py b/wakatime/arguments.py index 5a07cc0..9b461e1 100644 --- a/wakatime/arguments.py +++ b/wakatime/arguments.py @@ -18,6 +18,7 @@ import re import time import traceback from .__about__ import __version__ +from .compat import basestring from .configs import parseConfigFile from .constants import AUTH_ERROR from .packages import argparse @@ -26,6 +27,8 @@ from .packages import argparse class FileAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): + if isinstance(values, basestring) and values.startswith('"'): + values = re.sub(r'\\"', '"', values.strip('"')) try: if os.path.isfile(values): values = os.path.realpath(values) @@ -37,7 +40,7 @@ class FileAction(argparse.Action): class StoreWithoutQuotes(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): - if values.startswith('"'): + if isinstance(values, basestring) and values.startswith('"'): values = re.sub(r'\\"', '"', values.strip('"')) setattr(namespace, self.dest, values) @@ -57,7 +60,7 @@ def parseArguments(): 'url, domain, or app when --entity-type is not file') parser.add_argument('--file', dest='file', action=FileAction, help=argparse.SUPPRESS) - parser.add_argument('--key', dest='key', + parser.add_argument('--key', dest='key', action=StoreWithoutQuotes, help='your wakatime api key; uses api_key from '+ '~/.wakatime.cfg by default') parser.add_argument('--write', dest='is_write', @@ -68,17 +71,17 @@ def parseArguments(): help='optional text editor plugin name and version '+ 'for User-Agent header') parser.add_argument('--time', dest='timestamp', metavar='time', - type=float, + type=float, action=StoreWithoutQuotes, help='optional floating-point unix epoch timestamp; '+ 'uses current time by default') - parser.add_argument('--lineno', dest='lineno', + parser.add_argument('--lineno', dest='lineno', action=StoreWithoutQuotes, help='optional line number; current line being edited') - parser.add_argument('--cursorpos', dest='cursorpos', + parser.add_argument('--cursorpos', dest='cursorpos', action=StoreWithoutQuotes, help='optional cursor position in the current file') - parser.add_argument('--entity-type', dest='entity_type', + parser.add_argument('--entity-type', dest='entity_type', action=StoreWithoutQuotes, help='entity type for this heartbeat. can be one of "file", '+ '"domain", or "app"; defaults to file.') - parser.add_argument('--proxy', dest='proxy', + parser.add_argument('--proxy', dest='proxy', action=StoreWithoutQuotes, help='optional proxy configuration. Supports HTTPS '+ 'and SOCKS proxies. For example: '+ 'https://user:pass@host:port or '+ @@ -88,17 +91,17 @@ def parseArguments(): action='store_true', help='disables SSL certificate verification for HTTPS '+ 'requests. By default, SSL certificates are verified.') - parser.add_argument('--project', dest='project', + parser.add_argument('--project', dest='project', action=StoreWithoutQuotes, help='optional project name') - parser.add_argument('--alternate-project', dest='alternate_project', + parser.add_argument('--alternate-project', dest='alternate_project', action=StoreWithoutQuotes, help='optional alternate project name; auto-discovered project '+ 'takes priority') - parser.add_argument('--alternate-language', dest='alternate_language', + parser.add_argument('--alternate-language', dest='alternate_language', action=StoreWithoutQuotes, help=argparse.SUPPRESS) - parser.add_argument('--language', dest='language', + parser.add_argument('--language', dest='language', action=StoreWithoutQuotes, help='optional language name; if valid, takes priority over '+ 'auto-detected language') - parser.add_argument('--hostname', dest='hostname', help='hostname of '+ + parser.add_argument('--hostname', dest='hostname', action=StoreWithoutQuotes, help='hostname of '+ 'current machine.') parser.add_argument('--disableoffline', dest='offline', action='store_false', @@ -118,14 +121,14 @@ def parseArguments(): parser.add_argument('--extra-heartbeats', dest='extra_heartbeats', action='store_true', help='reads extra heartbeats from STDIN as a JSON array until EOF') - parser.add_argument('--logfile', dest='logfile', + parser.add_argument('--logfile', dest='logfile', action=StoreWithoutQuotes, help='defaults to ~/.wakatime.log') - parser.add_argument('--apiurl', dest='api_url', + parser.add_argument('--apiurl', dest='api_url', action=StoreWithoutQuotes, help='heartbeats api url; for debugging with a local server') - parser.add_argument('--timeout', dest='timeout', type=int, + parser.add_argument('--timeout', dest='timeout', type=int, action=StoreWithoutQuotes, help='number of seconds to wait when sending heartbeats to api; '+ 'defaults to 60 seconds') - parser.add_argument('--config', dest='config', + parser.add_argument('--config', dest='config', action=StoreWithoutQuotes, help='defaults to ~/.wakatime.cfg') parser.add_argument('--verbose', dest='verbose', action='store_true', help='turns on debug messages in log file')