Upgrade wakatime-cli to v8.0.2
This commit is contained in:
parent
453d96bf9c
commit
2f14009279
6 changed files with 161 additions and 52 deletions
|
@ -1,7 +1,7 @@
|
||||||
__title__ = 'wakatime'
|
__title__ = 'wakatime'
|
||||||
__description__ = 'Common interface to the WakaTime api.'
|
__description__ = 'Common interface to the WakaTime api.'
|
||||||
__url__ = 'https://github.com/wakatime/wakatime'
|
__url__ = 'https://github.com/wakatime/wakatime'
|
||||||
__version_info__ = ('8', '0', '0')
|
__version_info__ = ('8', '0', '2')
|
||||||
__version__ = '.'.join(__version_info__)
|
__version__ = '.'.join(__version_info__)
|
||||||
__author__ = 'Alan Hamlett'
|
__author__ = 'Alan Hamlett'
|
||||||
__author_email__ = 'alan@wakatime.com'
|
__author_email__ = 'alan@wakatime.com'
|
||||||
|
|
|
@ -76,6 +76,10 @@ def parseArguments():
|
||||||
'https://user:pass@host:port or '+
|
'https://user:pass@host:port or '+
|
||||||
'socks5://user:pass@host:port or ' +
|
'socks5://user:pass@host:port or ' +
|
||||||
'domain\\user:pass')
|
'domain\\user:pass')
|
||||||
|
parser.add_argument('--no-ssl-verify', dest='nosslverify',
|
||||||
|
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',
|
||||||
help='optional project name')
|
help='optional project name')
|
||||||
parser.add_argument('--alternate-project', dest='alternate_project',
|
parser.add_argument('--alternate-project', dest='alternate_project',
|
||||||
|
@ -214,6 +218,8 @@ def parseArguments():
|
||||||
'https://user:pass@host:port or ' +
|
'https://user:pass@host:port or ' +
|
||||||
'socks5://user:pass@host:port or ' +
|
'socks5://user:pass@host:port or ' +
|
||||||
'domain\\user:pass.')
|
'domain\\user:pass.')
|
||||||
|
if configs.has_option('settings', 'no_ssl_verify'):
|
||||||
|
args.nosslverify = configs.getboolean('settings', 'no_ssl_verify')
|
||||||
if not args.verbose and configs.has_option('settings', 'verbose'):
|
if not args.verbose and configs.has_option('settings', 'verbose'):
|
||||||
args.verbose = configs.getboolean('settings', 'verbose')
|
args.verbose = configs.getboolean('settings', 'verbose')
|
||||||
if not args.verbose and configs.has_option('settings', 'debug'):
|
if not args.verbose and configs.has_option('settings', 'debug'):
|
||||||
|
|
|
@ -25,6 +25,22 @@ except ImportError:
|
||||||
from .packages import configparser
|
from .packages import configparser
|
||||||
|
|
||||||
|
|
||||||
|
def getConfigFile():
|
||||||
|
"""Returns the config file location.
|
||||||
|
|
||||||
|
If $WAKATIME_HOME env varialbe is defined, returns
|
||||||
|
$WAKATIME_HOME/.wakatime.cfg, otherwise ~/.wakatime.cfg.
|
||||||
|
"""
|
||||||
|
|
||||||
|
fileName = '.wakatime.cfg'
|
||||||
|
|
||||||
|
home = os.environ.get('WAKATIME_HOME')
|
||||||
|
if home:
|
||||||
|
return os.path.join(os.path.expanduser(home), fileName)
|
||||||
|
|
||||||
|
return os.path.join(os.path.expanduser('~'), fileName)
|
||||||
|
|
||||||
|
|
||||||
def parseConfigFile(configFile=None):
|
def parseConfigFile(configFile=None):
|
||||||
"""Returns a configparser.SafeConfigParser instance with configs
|
"""Returns a configparser.SafeConfigParser instance with configs
|
||||||
read from the config file. Default location of the config file is
|
read from the config file. Default location of the config file is
|
||||||
|
@ -32,13 +48,8 @@ def parseConfigFile(configFile=None):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# get config file location from ENV
|
# get config file location from ENV
|
||||||
home = os.environ.get('WAKATIME_HOME')
|
|
||||||
if not configFile and home:
|
|
||||||
configFile = os.path.join(os.path.expanduser(home), '.wakatime.cfg')
|
|
||||||
|
|
||||||
# use default config file location
|
|
||||||
if not configFile:
|
if not configFile:
|
||||||
configFile = os.path.join(os.path.expanduser('~'), '.wakatime.cfg')
|
configFile = getConfigFile()
|
||||||
|
|
||||||
configs = configparser.ConfigParser(delimiters=('='), strict=False)
|
configs = configparser.ConfigParser(delimiters=('='), strict=False)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -38,3 +38,15 @@ UNKNOWN_ERROR = 105
|
||||||
Exit code used when the JSON input from `--extra-heartbeats` is malformed.
|
Exit code used when the JSON input from `--extra-heartbeats` is malformed.
|
||||||
"""
|
"""
|
||||||
MALFORMED_HEARTBEAT_ERROR = 106
|
MALFORMED_HEARTBEAT_ERROR = 106
|
||||||
|
|
||||||
|
""" Connection Error
|
||||||
|
Exit code used when there was proxy or other problem connecting to the WakaTime
|
||||||
|
API servers.
|
||||||
|
"""
|
||||||
|
CONNECTION_ERROR = 107
|
||||||
|
|
||||||
|
""" Max file size supporting line number count stats.
|
||||||
|
Files larger than this in bytes will not have a line count stat for performance.
|
||||||
|
Default is 2MB.
|
||||||
|
"""
|
||||||
|
MAX_FILE_SIZE_SUPPORTED = 2000000
|
||||||
|
|
|
@ -34,8 +34,19 @@ from .constants import (
|
||||||
MALFORMED_HEARTBEAT_ERROR,
|
MALFORMED_HEARTBEAT_ERROR,
|
||||||
)
|
)
|
||||||
from .logger import setup_logging
|
from .logger import setup_logging
|
||||||
|
|
||||||
|
log = logging.getLogger('WakaTime')
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .packages import requests
|
||||||
|
except ImportError:
|
||||||
|
log.traceback(logging.ERROR)
|
||||||
|
print(traceback.format_exc())
|
||||||
|
log.error('Please upgrade Python to the latest version.')
|
||||||
|
print('Please upgrade Python to the latest version.')
|
||||||
|
sys.exit(UNKNOWN_ERROR)
|
||||||
|
|
||||||
from .offlinequeue import Queue
|
from .offlinequeue import Queue
|
||||||
from .packages import requests
|
|
||||||
from .packages.requests.exceptions import RequestException
|
from .packages.requests.exceptions import RequestException
|
||||||
from .project import get_project_info
|
from .project import get_project_info
|
||||||
from .session_cache import SessionCache
|
from .session_cache import SessionCache
|
||||||
|
@ -48,13 +59,11 @@ except (ImportError, SyntaxError): # pragma: nocover
|
||||||
from .packages import tzlocal
|
from .packages import tzlocal
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger('WakaTime')
|
|
||||||
|
|
||||||
|
|
||||||
def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
||||||
entity=None, timestamp=None, is_write=None, plugin=None,
|
entity=None, timestamp=None, is_write=None, plugin=None,
|
||||||
offline=None, entity_type='file', hidefilenames=None,
|
offline=None, entity_type='file', hidefilenames=None,
|
||||||
proxy=None, api_url=None, timeout=None, **kwargs):
|
proxy=None, nosslverify=None, api_url=None, timeout=None,
|
||||||
|
use_ntlm_proxy=False, **kwargs):
|
||||||
"""Sends heartbeat as POST request to WakaTime api server.
|
"""Sends heartbeat as POST request to WakaTime api server.
|
||||||
|
|
||||||
Returns `SUCCESS` when heartbeat was sent, otherwise returns an
|
Returns `SUCCESS` when heartbeat was sent, otherwise returns an
|
||||||
|
@ -126,9 +135,10 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
||||||
session_cache = SessionCache()
|
session_cache = SessionCache()
|
||||||
session = session_cache.get()
|
session = session_cache.get()
|
||||||
|
|
||||||
|
should_try_ntlm = False
|
||||||
proxies = {}
|
proxies = {}
|
||||||
if proxy:
|
if proxy:
|
||||||
if '\\' in proxy:
|
if use_ntlm_proxy:
|
||||||
from .packages.requests_ntlm import HttpNtlmAuth
|
from .packages.requests_ntlm import HttpNtlmAuth
|
||||||
username = proxy.rsplit(':', 1)
|
username = proxy.rsplit(':', 1)
|
||||||
password = ''
|
password = ''
|
||||||
|
@ -137,14 +147,36 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
||||||
username = username[0]
|
username = username[0]
|
||||||
session.auth = HttpNtlmAuth(username, password, session)
|
session.auth = HttpNtlmAuth(username, password, session)
|
||||||
else:
|
else:
|
||||||
|
should_try_ntlm = '\\' in proxy
|
||||||
proxies['https'] = proxy
|
proxies['https'] = proxy
|
||||||
|
|
||||||
# log time to api
|
# send request to api
|
||||||
response = None
|
response = None
|
||||||
try:
|
try:
|
||||||
response = session.post(api_url, data=request_body, headers=headers,
|
response = session.post(api_url, data=request_body, headers=headers,
|
||||||
proxies=proxies, timeout=timeout)
|
proxies=proxies, timeout=timeout,
|
||||||
|
verify=not nosslverify)
|
||||||
except RequestException:
|
except RequestException:
|
||||||
|
if should_try_ntlm:
|
||||||
|
return send_heartbeat(
|
||||||
|
project=project,
|
||||||
|
entity=entity,
|
||||||
|
timestamp=timestamp,
|
||||||
|
branch=branch,
|
||||||
|
hostname=hostname,
|
||||||
|
stats=stats,
|
||||||
|
key=key,
|
||||||
|
is_write=is_write,
|
||||||
|
plugin=plugin,
|
||||||
|
offline=offline,
|
||||||
|
hidefilenames=hidefilenames,
|
||||||
|
entity_type=entity_type,
|
||||||
|
proxy=proxy,
|
||||||
|
api_url=api_url,
|
||||||
|
timeout=timeout,
|
||||||
|
use_ntlm_proxy=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
exception_data = {
|
exception_data = {
|
||||||
sys.exc_info()[0].__name__: u(sys.exc_info()[1]),
|
sys.exc_info()[0].__name__: u(sys.exc_info()[1]),
|
||||||
}
|
}
|
||||||
|
@ -159,6 +191,26 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
||||||
log.error(exception_data)
|
log.error(exception_data)
|
||||||
|
|
||||||
except: # delete cached session when requests raises unknown exception
|
except: # delete cached session when requests raises unknown exception
|
||||||
|
if should_try_ntlm:
|
||||||
|
return send_heartbeat(
|
||||||
|
project=project,
|
||||||
|
entity=entity,
|
||||||
|
timestamp=timestamp,
|
||||||
|
branch=branch,
|
||||||
|
hostname=hostname,
|
||||||
|
stats=stats,
|
||||||
|
key=key,
|
||||||
|
is_write=is_write,
|
||||||
|
plugin=plugin,
|
||||||
|
offline=offline,
|
||||||
|
hidefilenames=hidefilenames,
|
||||||
|
entity_type=entity_type,
|
||||||
|
proxy=proxy,
|
||||||
|
api_url=api_url,
|
||||||
|
timeout=timeout,
|
||||||
|
use_ntlm_proxy=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
exception_data = {
|
exception_data = {
|
||||||
sys.exc_info()[0].__name__: u(sys.exc_info()[1]),
|
sys.exc_info()[0].__name__: u(sys.exc_info()[1]),
|
||||||
'traceback': traceback.format_exc(),
|
'traceback': traceback.format_exc(),
|
||||||
|
@ -168,6 +220,7 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
||||||
queue.push(data, json.dumps(stats), plugin)
|
queue.push(data, json.dumps(stats), plugin)
|
||||||
log.warn(exception_data)
|
log.warn(exception_data)
|
||||||
session_cache.delete()
|
session_cache.delete()
|
||||||
|
return API_ERROR
|
||||||
|
|
||||||
else:
|
else:
|
||||||
code = response.status_code if response is not None else None
|
code = response.status_code if response is not None else None
|
||||||
|
@ -178,6 +231,26 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
|
||||||
})
|
})
|
||||||
session_cache.save(session)
|
session_cache.save(session)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
|
if should_try_ntlm:
|
||||||
|
return send_heartbeat(
|
||||||
|
project=project,
|
||||||
|
entity=entity,
|
||||||
|
timestamp=timestamp,
|
||||||
|
branch=branch,
|
||||||
|
hostname=hostname,
|
||||||
|
stats=stats,
|
||||||
|
key=key,
|
||||||
|
is_write=is_write,
|
||||||
|
plugin=plugin,
|
||||||
|
offline=offline,
|
||||||
|
hidefilenames=hidefilenames,
|
||||||
|
entity_type=entity_type,
|
||||||
|
proxy=proxy,
|
||||||
|
api_url=api_url,
|
||||||
|
timeout=timeout,
|
||||||
|
use_ntlm_proxy=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
if offline:
|
if offline:
|
||||||
if code != 400:
|
if code != 400:
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
|
@ -278,6 +351,7 @@ def process_heartbeat(args, configs, hostname, heartbeat):
|
||||||
heartbeat['offline'] = args.offline
|
heartbeat['offline'] = args.offline
|
||||||
heartbeat['hidefilenames'] = args.hidefilenames
|
heartbeat['hidefilenames'] = args.hidefilenames
|
||||||
heartbeat['proxy'] = args.proxy
|
heartbeat['proxy'] = args.proxy
|
||||||
|
heartbeat['nosslverify'] = args.nosslverify
|
||||||
heartbeat['api_url'] = args.api_url
|
heartbeat['api_url'] = args.api_url
|
||||||
|
|
||||||
return send_heartbeat(**heartbeat)
|
return send_heartbeat(**heartbeat)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .compat import u, open
|
from .compat import u, open
|
||||||
|
from .constants import MAX_FILE_SIZE_SUPPORTED
|
||||||
from .dependencies import DependencyParser
|
from .dependencies import DependencyParser
|
||||||
from .language_priorities import LANGUAGES
|
from .language_priorities import LANGUAGES
|
||||||
|
|
||||||
|
@ -184,6 +185,11 @@ def get_language_from_extension(file_name):
|
||||||
|
|
||||||
|
|
||||||
def number_lines_in_file(file_name):
|
def number_lines_in_file(file_name):
|
||||||
|
try:
|
||||||
|
if os.path.getsize(file_name) > MAX_FILE_SIZE_SUPPORTED:
|
||||||
|
return None
|
||||||
|
except os.error:
|
||||||
|
pass
|
||||||
lines = 0
|
lines = 0
|
||||||
try:
|
try:
|
||||||
with open(file_name, 'r', encoding='utf-8') as fh:
|
with open(file_name, 'r', encoding='utf-8') as fh:
|
||||||
|
|
Loading…
Reference in a new issue