def print_result_message(operation, process_id, status_region, res, printer, thread):
    try:
        if 'State' in res and res['State'] == 'Failed' and 'CompilerErrors' in res:
            #here we're parsing a response from the tooling endpoint
            errors = json.loads(res['CompilerErrors'])
            if type(errors) is not list:
                errors = [errors]
            error_message = None
            if "ErrorMsg" in res and res["ErrorMsg"] != None:
                error_message = res["ErrorMsg"]
            if len(errors) > 0:
                for e in errors:
                    line_col = ""
                    line, col = 1, 1
                    if 'line' in e:
                        line = int(e['line'])
                        line_col = ' (Line: '+str(line)
                        util.mark_line_numbers(thread.view, [line], "bookmark")
                    if 'column' in e:
                        col = int(e['column'])
                        line_col += ', Column: '+str(col)
                    if len(line_col):
                        line_col += ')'

                    #scroll to the line and column of the exception
                    #if settings.get('mm_compile_scroll_to_error', True):
                    #open file, if already open it will bring it to focus
                    #view = sublime.active_window().open_file(thread.active_file)
                    view = thread.view
                    pt = view.text_point(line-1, col-1)
                    view.sel().clear()
                    view.sel().add(sublime.Region(pt))
                    view.show(pt)
                    problem = e['problem']
                    problem = html_parser.unescape(problem)
                    if error_message != None:
                        problem += '\n'+error_message    
                    printer.panel.run_command('write_operation_status', {"text": " [COMPILE FAILED]: ({0}) {1} {2}".format(e['name'], problem, line_col), 'region': [status_region.end(), status_region.end()+10] })
            elif "ErrorMsg" in res:
                printer.panel.run_command('write_operation_status', {"text": " [COMPILE FAILED]: {0}".format(error_message), 'region': [status_region.end(), status_region.end()+10] })

        elif 'success' in res and util.to_bool(res['success']) == False and 'messages' in res:
            #here we're parsing a response from the metadata endpoint
            line_col = ""
            msg = None
            failures = None
            if type( res['messages'] ) == list:
                for m in res['messages']:
                    if 'problem' in m:
                        msg = m
                        break
                if msg == None: #must not have been a compile error, must be a test run error
                    if 'run_test_result' in res and 'failures' in res['run_test_result'] and type( res['run_test_result']['failures'] ) == list:
                        failures = res['run_test_result']['failures']
                    elif 'failures' in res['run_test_result']:
                        failures = [res['run_test_result']['failures']]
            else:
                msg = res['messages']
            if msg != None:
                if 'lineNumber' in msg:
                    line_col = ' (Line: '+msg['lineNumber']
                    util.mark_line_numbers(thread.view, [int(float(msg['lineNumber']))], "bookmark")
                if 'columnNumber' in msg:
                    line_col += ', Column: '+msg['columnNumber']
                if len(line_col) > 0:
                    line_col += ')'
                printer.panel.run_command('write_operation_status', {'text': ' [DEPLOYMENT FAILED]: ' + msg['fileName'] + ': ' + msg['problem'] + line_col, 'region': [status_region.end(), status_region.end()+10] })
            elif failures != None:
                msg = ' [DEPLOYMENT FAILED]:'
                for f in failures: 
                    msg += f['name'] + ', ' + f['methodName'] + ': ' + f['message'] + '\n'
                printer.panel.run_command('write_operation_status', {'text': msg, 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and res["success"] == False and 'line' in res:
            #this is a response from the apex compile api
            line_col = ""
            line, col = 1, 1
            if 'line' in res:
                line = int(res['line'])
                line_col = ' (Line: '+str(line)
                util.mark_line_numbers(thread.view, [line], "bookmark")
            if 'column' in res:
                col = int(res['column'])
                line_col += ', Column: '+str(col)
            if len(line_col):
                line_col += ')'

            #scroll to the line and column of the exception
            if settings.get('mm_compile_scroll_to_error', True):
                #open file, if already open it will bring it to focus
                #view = sublime.active_window().open_file(thread.active_file)
                view = thread.view
                pt = view.text_point(line-1, col-1)
                view.sel().clear()
                view.sel().add(sublime.Region(pt))
                view.show(pt)

            printer.panel.run_command('write_operation_status', {'text': ' [COMPILE FAILED]: ' + res['problem'] + line_col, 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == True and 'Messages' in res and len(res['Messages']) > 0:
            msg = ' [Operation completed Successfully - With Compile Errors]\n'
            msg += '[COMPILE ERRORS] - Count:\n'
            for m in res['Messages']:
                msg += ' FileName: ' + m['fileName'] + ': ' + m['problem'] + 'Line: ' + m['lineNumber']
            printer.panel.run_command('write_operation_status', {'text': msg, 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == True:
            printer.panel.run_command('write_operation_status', {'text': ' Success', 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == False and 'body' in res:
            printer.panel.run_command('write_operation_status', {'text': ' [OPERATION FAILED]:' + res['body'], 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == False:
            printer.panel.run_command('write_operation_status', {'text': ' [OPERATION FAILED]', 'region': [status_region.end(), status_region.end()+10] })
        else:
            printer.panel.run_command('write_operation_status', {'text': ' Success', 'region': [status_region.end(), status_region.end()+10] })
    except:
        printer.panel.run_command('write_operation_status', {"text": " [ERROR: COULD NOT PARSE RESPONSE FROM MM]: {0}".format(res), 'region': [status_region.end(), status_region.end()+10] })
    def __handle_compile_response(self, **kwargs):
        debug('HANDLING COMPILE!')
        debug(self.response)
        '''
            LIGHTNING:
            {
              "result": "markup:\/\/mm2:bar:3,19: ParseError at [row,col]:[4,19]\nMessage: XML document structures must start and end within the same entity.: Source",
              "success": false,
              "stack": "FIELD_INTEGRITY_EXCEPTION: markup:\/\/mm2:bar:3,19: ParseError at [row,col]:[4,19]\nMessage: XML document structures must start and end within the same entity.: Source\n    at onResponse (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/lib\/connection.js:368:13)\n    at _fulfilled (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:798:54)\n    at self.promiseDispatch.done (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:827:30)\n    at Promise.promise.promiseDispatch (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:760:13)\n    at \/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:574:44\n    at flush (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:108:17)\n    at process._tickCallback (node.js:419:13)"
            }

            TOOLING/METADATA:
            {
              "result": {
                "checkOnly": false,
                "completedDate": "",
                "createdBy": "",
                "createdByName": "",
                "createdDate": "",
                "details": {
                  "componentSuccesses": [

                  ],
                  "runTestResult": {
                    "numFailures": "0",
                    "numTestsRun": "0",
                    "totalTime": "0.0"
                  },
                  "componentFailures": [
                    {
                      "attributes": {
                        "type": "ContainerAsyncRequest",
                        "url": "\/services\/data\/v32.0\/tooling\/sobjects\/ContainerAsyncRequest\/1dro0000000mhNbAAI"
                      },
                      "Id": "1dro0000000mhNbAAI",
                      "MetadataContainerId": "1dco0000000JuxBAAS",
                      "MetadataContainerMemberId": null,
                      "State": "Failed",
                      "IsCheckOnly": false,
                      "DeployDetails": {
                        "allComponentMessages": [
                          {
                            "changed": false,
                            "columnNumber": -1,
                            "componentType": "ApexClass",
                            "created": false,
                            "createdDate": "2015-02-12T02:59:21.986+0000",
                            "deleted": false,
                            "fileName": "ChangePasswordController",
                            "forPackageManifestFile": false,
                            "fullName": "ChangePasswordController",
                            "id": "01po0000001iVdVAAU",
                            "knownPackagingProblem": false,
                            "lineNumber": 16,
                            "problem": "expecting right curly bracket, found '<EOF>'",
                            "problemType": "Error",
                            "requiresProductionTestRun": false,
                            "success": false,
                            "warning": false
                          }
                        ],
                        "componentFailures": [
                          {
                            "changed": false,
                            "columnNumber": -1,
                            "componentType": "ApexClass",
                            "created": false,
                            "createdDate": "2015-02-12T02:59:21.986+0000",
                            "deleted": false,
                            "fileName": "ChangePasswordController",
                            "forPackageManifestFile": false,
                            "fullName": "ChangePasswordController",
                            "id": "01po0000001iVdVAAU",
                            "knownPackagingProblem": false,
                            "lineNumber": 16,
                            "problem": "expecting right curly bracket, found '<EOF>'",
                            "problemType": "Error",
                            "requiresProductionTestRun": false,
                            "success": false,
                            "warning": false
                          }
                        ],
                        "componentSuccesses": [

                        ],
                        "runTestResult": null
                      },
                      "ErrorMsg": null
                    }
                  ]
                },
                "done": false,
                "id": "",
                "ignoreWarnings": false,
                "lastModifiedDate": "",
                "numberComponentErrors": 1,
                "numberComponentsDeployed": 0,
                "numberComponentsTotal": 0,
                "numberTestErrors": 0,
                "numberTestsCompleted": 0,
                "numberTestsTotal": 0,
                "rollbackOnError": false,
                "runTestsEnabled": "false",
                "startDate": "",
                "status": "",
                "success": false
              }
            }
        '''

        #diffing with server
        if 'status' in self.response['result'] and self.response['result'][
                'status'] == 'Conflict':
            conflicts = self.result['details']['conflicts']
            first_conflict_file_name = list(conflicts.keys())[0]
            first_conflict_data = conflicts[first_conflict_file_name]
            diff_merge_settings = config.settings.get(
                'mm_diff_server_conflicts', False)
            conflict_message = 'A conflict has been detected. ' + first_conflict_file_name + ' was last modified by ' + first_conflict_data[
                'remote']['LastModifiedBy'][
                    'Name'] + ' on ' + first_conflict_data['remote'][
                        'LastModifiedDate']
            if diff_merge_settings:
                if sublime.ok_cancel_dialog(conflict_message,
                                            'Diff with server'):
                    self.__print_to_panel(conflict_message +
                                          ". Diffing with server.")
                    th = MavensMateDiffThread(
                        self.thread.window, self.thread.view,
                        first_conflict_data['remote']['tempPath'])
                    th.start()
                else:
                    self.__print_to_panel('Operation canceled.')
            else:
                if sublime.ok_cancel_dialog(conflict_message,
                                            "Overwrite Server Copy"):
                    self.__print_to_panel(conflict_message +
                                          ". Overwriting server copy.")
                    args = {"paths": [self.thread.view.file_name()]}
                    sublime.set_timeout(
                        lambda: self.thread.window.run_command(
                            'force_compile_file', args), 100)
                else:
                    self.__print_to_panel('Operation canceled.')
        else:
            try:
                success = self.response['result']['success']
                if success:
                    util.clear_marked_line_numbers(self.thread.view)
                    self.__print_to_panel("Success")
                    self.printer.hide()
                    return

                msg = '[OPERATION FAILED]: '

                if type(self.response['result']['details']
                        ['componentFailures']) is not list:
                    self.response['result']['details']['componentFailures'] = [
                        self.response['result']['details']['componentFailures']
                    ]

                for res in self.response['result']['details'][
                        'componentFailures']:
                    if 'DeployDetails' in res and len(
                            res['DeployDetails']['componentFailures']) > 0:
                        for detail in res['DeployDetails'][
                                'componentFailures']:
                            debug(detail)
                            line_col = ''
                            line, col = 1, 1
                            if 'lineNumber' in detail:
                                line = int(detail['lineNumber'])
                                line_col = ' (Line: ' + str(line)
                                util.mark_line_numbers(self.thread.view,
                                                       [line], 'bookmark')
                            if 'columnNumber' in detail:
                                col = int(detail['columnNumber'])
                                line_col += ', Column: ' + str(col)
                            if len(line_col):
                                line_col += ')'

                            #scroll to the line and column of the exception
                            if settings.get('mm_compile_scroll_to_error',
                                            True):
                                view = self.thread.view
                                pt = view.text_point(line - 1, col - 1)
                                view.sel().clear()
                                view.sel().add(sublime.Region(pt))
                                view.show(pt)

                            msg += detail['fileName'] + ': ' + detail[
                                'problem'] + line_col + '\n'
                    elif 'ErrorMsg' in res and res['ErrorMsg'] != None:
                        msg += res['ErrorMsg'] + '\n'
                    else:  # metadata api?
                        msg += res['fullName'] + ': ' + res['problem'] + '\n'

                self.__print_to_panel(msg)

            except Exception as e:
                debug(e)
                debug(traceback.print_exc())
                debug(type(self.response))
                raise e
def print_result_message(operation, process_id, status_region, res, printer, thread):
    try:
        if 'State' in res and res['State'] == 'Error' and 'ErrorMsg' in res:
            printer.panel.run_command('write_operation_status', {"text": " [OPERATION FAILED]: {0}\n\n{1}".format(res['ErrorMsg'], 'If you are having difficulty compiling, try toggling the mm_compile_with_tooling_api setting to \'false\' or cleaning your project.'), 'region': [status_region.end(), status_region.end()+10] })
        elif 'State' in res and res['State'] == 'Failed' and 'CompilerErrors' in res:
            #here we're parsing a response from the tooling endpoint
            errors = json.loads(res['CompilerErrors'])
            if type(errors) is not list:
                errors = [errors]
            if len(errors) > 0:
                for e in errors:
                    line_col = ""
                    line, col = 1, 1
                    if 'line' in e:
                        line = int(e['line'])
                        line_col = ' (Line: '+str(line)
                        util.mark_line_numbers(thread.view, [line], "bookmark")
                    if 'column' in e:
                        col = int(e['column'])
                        line_col += ', Column: '+str(col)
                    if len(line_col):
                        line_col += ')'

                    #scroll to the line and column of the exception
                    #if settings.get('mm_compile_scroll_to_error', True):
                    #open file, if already open it will bring it to focus
                    #view = sublime.active_window().open_file(thread.active_file)
                    view = thread.view
                    pt = view.text_point(line-1, col-1)
                    view.sel().clear()
                    view.sel().add(sublime.Region(pt))
                    view.show(pt)
                    problem = e['problem']
                    problem = html_parser.unescape(problem)
                    printer.panel.run_command('write_operation_status', {"text": " [COMPILE FAILED]: ({0}) {1} {2}".format(e['name'], problem, line_col), 'region': [status_region.end(), status_region.end()+10] })
            elif "ErrorMsg" in res:
                printer.panel.run_command('write_operation_status', {"text": " [COMPILE FAILED]: {0}".format(res['ErrorMsg']), 'region': [status_region.end(), status_region.end()+10] })

        elif 'success' in res and util.to_bool(res['success']) == False and ('messages' in res or 'Messages' in res):
            if 'Messages' in res:
                res['messages'] = res.pop('Messages')
            #here we're parsing a response from the metadata endpoint
            failures = None
            messages = res['messages']
            if type( messages ) is not list:
                messages = [messages]

            problems = 0
            for m in messages:
                if 'problem' in m:
                    problems += 1
                    break

            if problems == 0: #must not have been a compile error, must be a test run error
                if 'runTestResult' in res:
                    if 'runTestResult' in res and 'failures' in res['runTestResult'] and type( res['runTestResult']['failures'] ) == list:
                        failures = res['runTestResult']['failures']
                    elif 'failures' in res['runTestResult']:
                        failures = [res['runTestResult']['failures']]
                    
                    if failures != None:
                        msg = ' [DEPLOYMENT FAILED]:'
                        for f in failures: 
                            msg += f['name'] + ', ' + f['methodName'] + ': ' + f['message'] + '\n'
                        printer.panel.run_command('write_operation_status', {'text': msg, 'region': [status_region.end(), status_region.end()+10] })
                elif 'run_test_result' in res:
                    if 'run_test_result' in res and 'failures' in res['run_test_result'] and type( res['run_test_result']['failures'] ) == list:
                        failures = res['run_test_result']['failures']
                    elif 'failures' in res['run_test_result']:
                        failures = [res['run_test_result']['failures']]
                    
                    if failures != None:
                        msg = ' [DEPLOYMENT FAILED]:'
                        for f in failures: 
                            msg += f['name'] + ', ' + f['methodName'] + ': ' + f['message'] + '\n'
                        printer.panel.run_command('write_operation_status', {'text': msg, 'region': [status_region.end(), status_region.end()+10] })
            else: #compile error, build error message
                msg = ""
                for m in messages:
                    if "success" in m and m["success"] == False:
                        line_col = ""
                        if 'lineNumber' in m:
                            line_col = ' (Line: '+m['lineNumber']
                            util.mark_line_numbers(thread.view, [int(float(m['lineNumber']))], "bookmark")
                        if 'columnNumber' in m:
                            line_col += ', Column: '+m['columnNumber']
                        if len(line_col) > 0:
                            line_col += ')'
                        msg += m['fileName'] + ': ' + m['problem'] + line_col + "\n\n"

                printer.panel.run_command('write_operation_status', {'text': ' [DEPLOYMENT FAILED]: ' + msg, 'region': [status_region.end(), status_region.end()+10] })
                
        elif 'success' in res and res["success"] == False and 'line' in res:
            #this is a response from the apex compile api
            line_col = ""
            line, col = 1, 1
            if 'line' in res:
                line = int(res['line'])
                line_col = ' (Line: '+str(line)
                util.mark_line_numbers(thread.view, [line], "bookmark")
            if 'column' in res:
                col = int(res['column'])
                line_col += ', Column: '+str(col)
            if len(line_col):
                line_col += ')'

            #scroll to the line and column of the exception
            if settings.get('mm_compile_scroll_to_error', True):
                #open file, if already open it will bring it to focus
                #view = sublime.active_window().open_file(thread.active_file)
                view = thread.view
                pt = view.text_point(line-1, col-1)
                view.sel().clear()
                view.sel().add(sublime.Region(pt))
                view.show(pt)

            printer.panel.run_command('write_operation_status', {'text': ' [COMPILE FAILED]: ' + res['problem'] + line_col, 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == True and 'Messages' in res and len(res['Messages']) > 0:
            msg = ' [Operation completed Successfully - With Compile Errors]\n'
            msg += '[COMPILE ERRORS] - Count:\n'
            for m in res['Messages']:
                msg += ' FileName: ' + m['fileName'] + ': ' + m['problem'] + 'Line: ' + m['lineNumber']
            printer.panel.run_command('write_operation_status', {'text': msg, 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == True:
            printer.panel.run_command('write_operation_status', {'text': ' Success', 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == False and 'body' in res:
            printer.panel.run_command('write_operation_status', {'text': ' [OPERATION FAILED]:' + res['body'], 'region': [status_region.end(), status_region.end()+10] })
        elif 'success' in res and util.to_bool(res['success']) == False:
            printer.panel.run_command('write_operation_status', {'text': ' [OPERATION FAILED]', 'region': [status_region.end(), status_region.end()+10] })
        else:
            printer.panel.run_command('write_operation_status', {'text': ' Success', 'region': [status_region.end(), status_region.end()+10] })
    except:
        msg = ""
        if type(res) is dict:
            msg = json.dumps(res)
        elif type(res) is str:
            msg = res
        else:
            msg = "Check Sublime Text console for error and report issue to MavensMate GitHub project."
        printer.panel.run_command('write_operation_status', {'text': ' [OPERATION FAILED]: ' + msg, 'region': [status_region.end(), status_region.end()+10] })
示例#4
0
    def __handle_compile_response(self, **kwargs):
        debug("HANDLING COMPILE!")
        debug(self.result)

        #diffing with server
        if 'actions' in self.result and util.to_bool(
                self.result['success']) == False:
            diff_merge_settings = config.settings.get(
                'mm_diff_server_conflicts', False)
            if diff_merge_settings:
                if sublime.ok_cancel_dialog(self.result["body"],
                                            self.result["actions"][0].title()):
                    self.__print_to_panel("Diffing with server")
                    th = MavensMateDiffThread(self.thread.window,
                                              self.thread.view,
                                              self.result['tmp_file_path'])
                    th.start()
                else:
                    self.__print_to_panel(self.result["actions"][1].title())
            else:
                if sublime.ok_cancel_dialog(self.result["body"],
                                            "Overwrite Server Copy"):
                    self.__print_to_panel("Overwriting server copy")
                    self.thread.params['action'] = 'overwrite'
                    if kwargs.get("callback", None) != None:
                        sublime.set_timeout(
                            lambda: self.callback('compile',
                                                  params=self.thread.params),
                            100)
                else:
                    self.__print_to_panel(self.result["actions"][1].title())
        else:
            try:
                if 'State' in self.result and self.result[
                        'State'] == 'Error' and 'ErrorMsg' in self.result:
                    self.__print_to_panel(
                        "[OPERATION FAILED]: {0}\n\n{1}".format(
                            self.result['ErrorMsg'],
                            'If you are having difficulty compiling, try toggling the mm_compile_with_tooling_api setting to \'false\' or cleaning your project.'
                        ))
                elif 'State' in self.result and self.result[
                        'State'] == 'Failed' and 'CompilerErrors' in self.result:
                    #here we're parsing a response from the tooling endpoint
                    errors = json.loads(self.result['CompilerErrors'])
                    if type(errors) is not list:
                        errors = [errors]
                    if len(errors) > 0:
                        for e in errors:
                            line_col = ""
                            line, col = 1, 1
                            if 'line' in e:
                                if type(e['line']) is list:
                                    line = int(e['line'][0])
                                else:
                                    line = int(e['line'])
                                line_col = ' (Line: ' + str(line)
                            if 'column' in e:
                                if type(e['column']) is list:
                                    line = int(e['column'][0])
                                else:
                                    col = int(e['column'])
                                line_col += ', Column: ' + str(col)
                            if len(line_col):
                                line_col += ')'

                            #scroll to the line and column of the exception
                            #if settings.get('mm_compile_scroll_to_error', True):
                            #open file, if already open it will bring it to focus
                            #view = sublime.active_window().open_file(self.thread.active_file)
                            view = self.thread.view
                            pt = view.text_point(line - 1, col - 1)
                            view.sel().clear()
                            view.sel().add(sublime.Region(pt))
                            view.show(pt)
                            problem = e['problem']
                            if type(problem) is list:
                                problem = problem[0]
                            problem = html_parser.unescape(problem)
                            file_base_name = e['name']
                            if type(file_base_name) is list:
                                file_base_name = file_base_name[0]
                            #if self.thread.window.active_view().name():
                            current_active_view = sublime.active_window(
                            ).active_view()
                            if current_active_view.file_name() != None:
                                current_active_view_file_name = os.path.basename(
                                    current_active_view.file_name())
                                if "." in current_active_view_file_name:
                                    current_active_view_file_name = current_active_view_file_name.split(
                                        ".")[0]
                                debug(current_active_view_file_name)
                                debug(file_base_name)
                                if current_active_view_file_name != file_base_name:
                                    #this is the tooling api throwing a compile error against a different file
                                    msg = "[COMPILE FAILED]: ({0}) {1} {2}".format(
                                        file_base_name, problem, line_col)
                                    msg += "\n\nThe Tooling API has failed to compile a separate element of metadata in your current MetadataContainer. You can either:"
                                    msg += "\n1. Fix the compilation error on " + file_base_name
                                    msg += "\n2. Reset your MetadataContainer to clear this error: MavensMate > Utilities > Reset MetadataContainer"
                                    self.__print_to_panel(msg)
                                elif current_active_view_file_name == file_base_name:
                                    util.mark_line_numbers(
                                        self.thread.view, [line], "bookmark")
                                    self.__print_to_panel(
                                        "[COMPILE FAILED]: ({0}) {1} {2}".
                                        format(file_base_name, problem,
                                               line_col))
                    elif "ErrorMsg" in self.result:
                        msg = ''
                        if 'object has been modified on server' in self.result[
                                'ErrorMsg']:
                            msg = self.result[
                                'ErrorMsg'] + '. You may try resetting your MetadataContainer to clear this error: MavensMate > Utilities > Reset MetadataContainer.'
                        else:
                            msg = self.result['ErrorMsg']
                        self.__print_to_panel(
                            "[COMPILE FAILED]: {0}".format(msg))

                elif 'success' in self.result and util.to_bool(
                        self.result['success']) == False and (
                            ('messages' in self.result or 'Messages'
                             in self.result) or 'details' in self.result):
                    if 'details' in self.result and 'componentFailures' in self.result[
                            'details']:
                        self.result['messages'] = self.result['details'].pop(
                            'componentFailures')
                    elif 'Messages' in self.result:
                        self.result['messages'] = self.result.pop('Messages')

                    #here we're parsing a response from the metadata endpoint
                    failures = None
                    messages = self.result['messages']
                    if type(messages) is not list:
                        messages = [messages]

                    problems = 0
                    for m in messages:
                        if 'problem' in m:
                            problems += 1
                            break

                    if problems == 0:  #must not have been a compile error, must be a test run error
                        if 'runTestResult' in self.result:
                            if 'runTestResult' in self.result and 'failures' in self.result[
                                    'runTestResult'] and type(
                                        self.result['runTestResult']
                                        ['failures']) == list:
                                failures = self.result['runTestResult'][
                                    'failures']
                            elif 'failures' in self.result['runTestResult']:
                                failures = [
                                    self.result['runTestResult']['failures']
                                ]

                            if failures != None:
                                msg = ' [DEPLOYMENT FAILED]:'
                                for f in failures:
                                    msg += f['name'] + ', ' + f[
                                        'methodName'] + ': ' + f[
                                            'message'] + '\n'
                                    self.__print_to_panel(msg)
                        elif 'run_test_result' in self.result:
                            if 'run_test_result' in self.result and 'failures' in self.result[
                                    'run_test_result'] and type(
                                        self.result['run_test_result']
                                        ['failures']) == list:
                                failures = self.result['run_test_result'][
                                    'failures']
                            elif 'failures' in self.result['run_test_result']:
                                failures = [
                                    self.result['run_test_result']['failures']
                                ]

                            if failures != None:
                                msg = ' [DEPLOYMENT FAILED]:'
                                for f in failures:
                                    msg += f['name'] + ', ' + f[
                                        'methodName'] + ': ' + f[
                                            'message'] + '\n'
                                self.__print_to_panel(msg)
                    else:  #compile error, build error message
                        msg = ""
                        for m in messages:
                            if "success" in m and m["success"] == False:
                                line_col = ""
                                if 'lineNumber' in m:
                                    line_col = ' (Line: ' + m['lineNumber']
                                    util.mark_line_numbers(
                                        self.thread.view,
                                        [int(float(m['lineNumber']))],
                                        "bookmark")
                                if 'columnNumber' in m:
                                    line_col += ', Column: ' + m['columnNumber']
                                if len(line_col) > 0:
                                    line_col += ')'
                                filename = m['fileName']
                                filename = re.sub(r'unpackaged/[A-Z,a-z]*/',
                                                  '', filename)
                                msg += filename + ': ' + m[
                                    'problem'] + line_col + "\n"

                        self.__print_to_panel('[DEPLOYMENT FAILED]: ' + msg)

                elif 'success' in self.result and self.result[
                        "success"] == False and 'line' in self.result:
                    #this is a response from the apex compile api
                    line_col = ""
                    line, col = 1, 1
                    if 'line' in self.result:
                        line = int(self.result['line'])
                        line_col = ' (Line: ' + str(line)
                        util.mark_line_numbers(self.thread.view, [line],
                                               "bookmark")
                    if 'column' in self.result:
                        col = int(self.result['column'])
                        line_col += ', Column: ' + str(col)
                    if len(line_col):
                        line_col += ')'

                    #scroll to the line and column of the exception
                    if settings.get('mm_compile_scroll_to_error', True):
                        #open file, if already open it will bring it to focus
                        #view = sublime.active_window().open_file(self.thread.active_file)
                        view = self.thread.view
                        pt = view.text_point(line - 1, col - 1)
                        view.sel().clear()
                        view.sel().add(sublime.Region(pt))
                        view.show(pt)

                        self.__print_to_panel('[COMPILE FAILED]: ' +
                                              self.result['problem'] +
                                              line_col)
                elif 'success' in self.result and util.to_bool(
                        self.result['success']
                ) == True and 'Messages' in self.result and len(
                        self.result['Messages']) > 0:
                    msg = ' [Operation completed Successfully - With Compile Errors]\n'
                    msg += '[COMPILE ERRORS] - Count:\n'
                    for m in self.result['Messages']:
                        msg += ' FileName: ' + m['fileName'] + ': ' + m[
                            'problem'] + 'Line: ' + m['lineNumber']
                    self.__print_to_panel(msg)
                elif 'success' in self.result and util.to_bool(
                        self.result['success']) == True:
                    self.__print_to_panel("Success")
                elif 'success' in self.result and util.to_bool(
                        self.result['success']
                ) == False and 'body' in self.result:
                    self.__print_to_panel('[OPERATION FAILED]: ' +
                                          self.result['body'])
                elif 'success' in self.result and util.to_bool(
                        self.result['success']) == False:
                    self.__print_to_panel('[OPERATION FAILED]')
                else:
                    self.__print_to_panel("Success")
            except Exception as e:
                debug(e)
                debug(traceback.print_exc())
                debug(type(self.result))
                msg = ""
                if type(self.result) is dict:
                    if 'body' in self.result:
                        msg = self.result["body"]
                    else:
                        msg = json.dumps(self.result)
                elif type(self.result) is str:
                    try:
                        m = json.loads(self.result)
                        msg = m["body"]
                    except:
                        msg = self.result
                else:
                    msg = "Check Sublime Text console for error and report issue to MavensMate-SublimeText GitHub project."
                self.__print_to_panel('[OPERATION FAILED]: ' + msg)
    def __handle_compile_response(self, **kwargs):  
        debug("HANDLING COMPILE!")
        debug(self.result)

        #diffing with server
        if 'actions' in self.result and util.to_bool(self.result['success']) == False:
            diff_merge_settings = config.settings.get('mm_diff_server_conflicts', False)
            if diff_merge_settings:
                if sublime.ok_cancel_dialog(self.result["body"], self.result["actions"][0].title()):
                    self.__print_to_panel("Diffing with server", "general")
                    th = MavensMateDiffThread(self.thread.window, self.thread.view, self.result['tmp_file_path'])
                    th.start()
                else:
                    self.__print_to_panel(self.result["actions"][1].title(), "general")
            else:
                if sublime.ok_cancel_dialog(self.result["body"], "Overwrite Server Copy"):
                    self.__print_to_panel("Overwriting server copy", "general")
                    self.thread.params['action'] = 'overwrite'
                    if kwargs.get("callback", None) != None:
                        sublime.set_timeout(lambda: self.callback('compile', params=self.thread.params), 100)   
                else:
                    self.__print_to_panel(self.result["actions"][1].title(), "general")
        else:
            try:
                if 'State' in self.result and self.result['State'] == 'Error' and 'ErrorMsg' in self.result:
                    self.__print_to_panel("[OPERATION FAILED]: {0}\n\n{1}".format(self.result['ErrorMsg'], 'If you are having difficulty compiling, try toggling the mm_compile_with_tooling_api setting to \'false\' or cleaning your project.'), "failure")
                elif 'State' in self.result and self.result['State'] == 'Failed' and ('CompilerErrors' in self.result or 'DeployDetails' in self.result):
                    #here we're parsing a response from the tooling endpoint
                    isLegacy = False #pre 30.0

                    if 'DeployDetails' in self.result: #31.0 and up
                        errors = self.result['DeployDetails']['componentFailures']
                        lineKey = 'lineNumber'
                        colKey = 'columnNumber'
                    else:
                        errors = json.loads(self.result['CompilerErrors'])
                        isLegacy = True
                        lineKey = 'line'
                        colKey = 'column'

                    if type(errors) is not list:
                        errors = [errors]
                    if len(errors) > 0:
                        for e in errors:
                            line_col = ""
                            line, col = 1, 1
                            if lineKey in e:
                                if type(e[lineKey]) is list:
                                    line = int(e[lineKey][0])
                                else:
                                    line = int(e[lineKey])
                                line_col = ' (Line: '+str(line)
                            if colKey in e:
                                if type(e[colKey]) is list:
                                    line = int(e[colKey][0])
                                else:
                                    col = int(e[colKey])
                                line_col += ', Column: '+str(col)
                            if len(line_col):
                                line_col += ')' 

                            #scroll to the line and column of the exception
                            #if settings.get('mm_compile_scroll_to_error', True):
                            #open file, if already open it will bring it to focus
                            #view = sublime.active_window().open_file(self.thread.active_file)
                            view = self.thread.view
                            pt = view.text_point(line-1, col-1)
                            view.sel().clear()
                            view.sel().add(sublime.Region(pt))
                            view.show(pt)
                            problem = e['problem']
                            if type(problem) is list:
                                problem = problem[0]
                            problem = html_parser.unescape(problem)
                            if isLegacy:
                                file_base_name = e['name']
                            else:
                                file_base_name = e['fileName']
                            if type(file_base_name) is list:
                                file_base_name = file_base_name[0]
                            #if self.thread.window.active_view().name():
                            current_active_view = sublime.active_window().active_view()
                            if current_active_view.file_name() != None:
                                current_active_view_file_name = os.path.basename(current_active_view.file_name())
                                if "." in current_active_view_file_name:
                                    current_active_view_file_name = current_active_view_file_name.split(".")[0]
                                debug(current_active_view_file_name)
                                debug(file_base_name)
                                if current_active_view_file_name != file_base_name:
                                    #this is the tooling api throwing a compile error against a different file
                                    msg = "[COMPILE FAILED]: ({0}) {1} {2}".format(file_base_name, problem, line_col)
                                    msg += "\n\nThe Tooling API has failed to compile a separate element of metadata in your current MetadataContainer. You can either:"
                                    msg += "\n1. Fix the compilation error on "+file_base_name
                                    msg += "\n2. Reset your MetadataContainer to clear this error: MavensMate > Utilities > Reset MetadataContainer"
                                    self.__print_to_panel(msg, "failure")
                                elif current_active_view_file_name == file_base_name:
                                    util.mark_line_numbers(self.thread.view, [line], "bookmark")
                                    self.__print_to_panel("[COMPILE FAILED]: ({0}) {1} {2}".format(file_base_name, problem, line_col), "failure")
                    elif "ErrorMsg" in self.result:
                        msg = ''
                        if 'object has been modified on server' in self.result['ErrorMsg']:
                            msg = self.result['ErrorMsg'] + '. You may try resetting your MetadataContainer to clear this error: MavensMate > Utilities > Reset MetadataContainer.'
                        else:
                            msg = self.result['ErrorMsg']
                        self.__print_to_panel("[COMPILE FAILED]: {0}".format(msg), "failure")

                elif 'success' in self.result and util.to_bool(self.result['success']) == False and (('messages' in self.result or 'Messages' in self.result) or 'details' in self.result):
                    if 'details' in self.result and 'componentFailures' in self.result['details']:
                        self.result['messages'] = self.result['details'].pop('componentFailures')
                    elif 'Messages' in self.result:
                        self.result['messages'] = self.result.pop('Messages')
                    
                    #here we're parsing a response from the metadata endpoint
                    failures = None
                    messages = self.result['messages']
                    if type( messages ) is not list:
                        messages = [messages]

                    problems = 0
                    for m in messages:
                        if 'problem' in m:
                            problems += 1
                            break

                    if problems == 0: #must not have been a compile error, must be a test run error
                        if 'runTestResult' in self.result:
                            if 'runTestResult' in self.result and 'failures' in self.result['runTestResult'] and type( self.result['runTestResult']['failures'] ) == list:
                                failures = self.result['runTestResult']['failures']
                            elif 'failures' in self.result['runTestResult']:
                                failures = [self.result['runTestResult']['failures']]
                            
                            if failures != None:
                                msg = ' [DEPLOYMENT FAILED]:'
                                for f in failures: 
                                    msg += f['name'] + ', ' + f['methodName'] + ': ' + f['message'] + '\n'
                                    self.__print_to_panel(msg, "failure")
                        elif 'run_test_result' in self.result:
                            if 'run_test_result' in self.result and 'failures' in self.result['run_test_result'] and type( self.result['run_test_result']['failures'] ) == list:
                                failures = self.result['run_test_result']['failures']
                            elif 'failures' in self.result['run_test_result']:
                                failures = [self.result['run_test_result']['failures']]
                            
                            if failures != None:
                                msg = ' [DEPLOYMENT FAILED]:'
                                for f in failures: 
                                    msg += f['name'] + ', ' + f['methodName'] + ': ' + f['message'] + '\n'
                                self.__print_to_panel(msg, "failure")
                    else: #compile error, build error message
                        msg = ""
                        for m in messages:
                            if "success" in m and m["success"] == False:
                                line_col = ""
                                if 'lineNumber' in m:
                                    line_col = ' (Line: '+m['lineNumber']
                                    util.mark_line_numbers(self.thread.view, [int(float(m['lineNumber']))], "bookmark")
                                if 'columnNumber' in m:
                                    line_col += ', Column: '+m['columnNumber']
                                if len(line_col) > 0:
                                    line_col += ')'
                                filename = m['fileName']
                                filename = re.sub(r'unpackaged/[A-Z,a-z]*/', '', filename)
                                msg += filename + ': ' + m['problem'] + line_col + "\n"

                        self.__print_to_panel('[DEPLOYMENT FAILED]: ' + msg, "failure")
                        
                elif 'success' in self.result and self.result["success"] == False and 'line' in self.result:
                    #this is a response from the apex compile api
                    line_col = ""
                    line, col = 1, 1
                    if 'line' in self.result:
                        line = int(self.result['line'])
                        line_col = ' (Line: '+str(line)
                        util.mark_line_numbers(self.thread.view, [line], "bookmark")
                    if 'column' in self.result:
                        col = int(self.result['column'])
                        line_col += ', Column: '+str(col)
                    if len(line_col):
                        line_col += ')'

                    #scroll to the line and column of the exception
                    if settings.get('mm_compile_scroll_to_error', True):
                        #open file, if already open it will bring it to focus
                        #view = sublime.active_window().open_file(self.thread.active_file)
                        view = self.thread.view
                        pt = view.text_point(line-1, col-1)
                        view.sel().clear()
                        view.sel().add(sublime.Region(pt))
                        view.show(pt)

                        self.__print_to_panel('[COMPILE FAILED]: ' + self.result['problem'] + line_col, "failure")
                elif 'success' in self.result and util.to_bool(self.result['success']) == True and 'Messages' in self.result and len(self.result['Messages']) > 0:
                    msg = ' [Operation completed Successfully - With Compile Errors]\n'
                    msg += '[COMPILE ERRORS] - Count:\n'
                    for m in self.result['Messages']:
                        msg += ' FileName: ' + m['fileName'] + ': ' + m['problem'] + 'Line: ' + m['lineNumber']
                    self.__print_to_panel(msg, "failure")
                elif 'success' in self.result and util.to_bool(self.result['success']) == True:
                    self.__print_to_panel("Success", "success")
                elif 'success' in self.result and util.to_bool(self.result['success']) == False and 'body' in self.result:
                    self.__print_to_panel('[OPERATION FAILED]: ' + self.result['body'], "failure")
                elif 'success' in self.result and util.to_bool(self.result['success']) == False:
                    self.__print_to_panel('[OPERATION FAILED]', "failure")
                else:
                    self.__print_to_panel("Success", "success")
            except Exception as e:
                debug(e)
                debug(traceback.print_exc())
                debug(type(self.result))
                msg = ""
                if type(self.result) is dict:
                    if 'body' in self.result:
                        msg = self.result["body"]
                    else:
                        msg = json.dumps(self.result)
                elif type(self.result) is str:
                    try:
                        m = json.loads(self.result)
                        msg = m["body"]
                    except:
                        msg = self.result
                else:
                    msg = "Check Sublime Text console for error and report issue to MavensMate-SublimeText GitHub project."
                self.__print_to_panel('[OPERATION FAILED]: ' + msg, "failure")
    def __handle_compile_response(self, **kwargs):
        debug('HANDLING COMPILE!')
        debug(self.response)

        '''
            LIGHTNING:
            {
              "result": "markup:\/\/mm2:bar:3,19: ParseError at [row,col]:[4,19]\nMessage: XML document structures must start and end within the same entity.: Source",
              "success": false,
              "stack": "FIELD_INTEGRITY_EXCEPTION: markup:\/\/mm2:bar:3,19: ParseError at [row,col]:[4,19]\nMessage: XML document structures must start and end within the same entity.: Source\n    at onResponse (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/lib\/connection.js:368:13)\n    at _fulfilled (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:798:54)\n    at self.promiseDispatch.done (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:827:30)\n    at Promise.promise.promiseDispatch (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:760:13)\n    at \/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:574:44\n    at flush (\/Users\/josephferraro\/Development\/Github\/MavensMate\/node_modules\/jsforce\/node_modules\/q\/q.js:108:17)\n    at process._tickCallback (node.js:419:13)"
            }

            TOOLING/METADATA:
            {
              "result": {
                "checkOnly": false,
                "completedDate": "",
                "createdBy": "",
                "createdByName": "",
                "createdDate": "",
                "details": {
                  "componentSuccesses": [

                  ],
                  "runTestResult": {
                    "numFailures": "0",
                    "numTestsRun": "0",
                    "totalTime": "0.0"
                  },
                  "componentFailures": [
                    {
                      "attributes": {
                        "type": "ContainerAsyncRequest",
                        "url": "\/services\/data\/v32.0\/tooling\/sobjects\/ContainerAsyncRequest\/1dro0000000mhNbAAI"
                      },
                      "Id": "1dro0000000mhNbAAI",
                      "MetadataContainerId": "1dco0000000JuxBAAS",
                      "MetadataContainerMemberId": null,
                      "State": "Failed",
                      "IsCheckOnly": false,
                      "DeployDetails": {
                        "allComponentMessages": [
                          {
                            "changed": false,
                            "columnNumber": -1,
                            "componentType": "ApexClass",
                            "created": false,
                            "createdDate": "2015-02-12T02:59:21.986+0000",
                            "deleted": false,
                            "fileName": "ChangePasswordController",
                            "forPackageManifestFile": false,
                            "fullName": "ChangePasswordController",
                            "id": "01po0000001iVdVAAU",
                            "knownPackagingProblem": false,
                            "lineNumber": 16,
                            "problem": "expecting right curly bracket, found '<EOF>'",
                            "problemType": "Error",
                            "requiresProductionTestRun": false,
                            "success": false,
                            "warning": false
                          }
                        ],
                        "componentFailures": [
                          {
                            "changed": false,
                            "columnNumber": -1,
                            "componentType": "ApexClass",
                            "created": false,
                            "createdDate": "2015-02-12T02:59:21.986+0000",
                            "deleted": false,
                            "fileName": "ChangePasswordController",
                            "forPackageManifestFile": false,
                            "fullName": "ChangePasswordController",
                            "id": "01po0000001iVdVAAU",
                            "knownPackagingProblem": false,
                            "lineNumber": 16,
                            "problem": "expecting right curly bracket, found '<EOF>'",
                            "problemType": "Error",
                            "requiresProductionTestRun": false,
                            "success": false,
                            "warning": false
                          }
                        ],
                        "componentSuccesses": [

                        ],
                        "runTestResult": null
                      },
                      "ErrorMsg": null
                    }
                  ]
                },
                "done": false,
                "id": "",
                "ignoreWarnings": false,
                "lastModifiedDate": "",
                "numberComponentErrors": 1,
                "numberComponentsDeployed": 0,
                "numberComponentsTotal": 0,
                "numberTestErrors": 0,
                "numberTestsCompleted": 0,
                "numberTestsTotal": 0,
                "rollbackOnError": false,
                "runTestsEnabled": "false",
                "startDate": "",
                "status": "",
                "success": false
              }
            }
        '''

        #diffing with server
        if 'status' in self.response['result'] and self.response['result']['status'] == 'Conflict':
            conflicts = self.result['details']['conflicts']
            first_conflict_file_name = list(conflicts.keys())[0]
            first_conflict_data = conflicts[first_conflict_file_name]
            diff_merge_settings = config.settings.get('mm_diff_server_conflicts', False)
            conflict_message = 'A conflict has been detected. '+first_conflict_file_name+' was last modified by '+first_conflict_data['remote']['LastModifiedBy']['Name']+' on '+first_conflict_data['remote']['LastModifiedDate']
            if diff_merge_settings:
                if sublime.ok_cancel_dialog(conflict_message, 'Diff with server'):
                    self.__print_to_panel(conflict_message + ". Diffing with server.")
                    th = MavensMateDiffThread(self.thread.window, self.thread.view, first_conflict_data['remote']['tempPath'])
                    th.start()
                else:
                    self.__print_to_panel('Operation canceled.')
            else:
                if sublime.ok_cancel_dialog(conflict_message, "Overwrite Server Copy"):
                    self.__print_to_panel(conflict_message + ". Overwriting server copy.")
                    args = {
                        "paths" : [self.thread.view.file_name()]
                    }
                    sublime.set_timeout(lambda: self.thread.window.run_command('force_compile_file', args), 100)
                else:
                    self.__print_to_panel('Operation canceled.')
        else:
            try:
                success = self.response['result']['success']
                if success:
                    util.clear_marked_line_numbers(self.thread.view)
                    self.__print_to_panel("Success")
                    self.printer.hide()
                    return

                msg = '[OPERATION FAILED]: '

                if type(self.response['result']['details']['componentFailures']) is not list:
                    self.response['result']['details']['componentFailures'] = [self.response['result']['details']['componentFailures']]

                for res in self.response['result']['details']['componentFailures']:
                    if 'DeployDetails' in res:
                        for detail in res['DeployDetails']['componentFailures']:
                            debug(detail)
                            line_col = ''
                            line, col = 1, 1
                            if 'lineNumber' in detail:
                                line = int(detail['lineNumber'])
                                line_col = ' (Line: '+str(line)
                                util.mark_line_numbers(self.thread.view, [line], 'bookmark')
                            if 'columnNumber' in detail:
                                col = int(detail['columnNumber'])
                                line_col += ', Column: '+str(col)
                            if len(line_col):
                                line_col += ')'

                            #scroll to the line and column of the exception
                            if settings.get('mm_compile_scroll_to_error', True):
                                view = self.thread.view
                                pt = view.text_point(line-1, col-1)
                                view.sel().clear()
                                view.sel().add(sublime.Region(pt))
                                view.show(pt)

                            msg += detail['fileName']+': '+ detail['problem'] + line_col + '\n'
                    else: # metadata api?
                        msg += res['fullName']+': '+ res['problem'] + '\n'

                self.__print_to_panel(msg)

            except Exception as e:
                debug(e)
                debug(traceback.print_exc())
                debug(type(self.response))
                raise e
def print_result_message(operation, process_id, status_region, res, printer,
                         thread):
    if 'State' in res and res['State'] == 'Error' and 'ErrorMsg' in res:
        printer.panel.run_command(
            'write_operation_status', {
                "text":
                " [OPERATION FAILED]: {0}\n\n{1}".format(
                    res['ErrorMsg'],
                    'If you are having difficulty compiling, try toggling the mm_compile_with_tooling_api setting to \'false\''
                ),
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    elif 'State' in res and res[
            'State'] == 'Failed' and 'CompilerErrors' in res:
        #here we're parsing a response from the tooling endpoint
        errors = json.loads(res['CompilerErrors'])
        if type(errors) is not list:
            errors = [errors]
        if len(errors) > 0:
            for e in errors:
                line_col = ""
                line, col = 1, 1
                if 'line' in e:
                    line = int(e['line'])
                    line_col = ' (Line: ' + str(line)
                    util.mark_line_numbers(thread.view, [line], "bookmark")
                if 'column' in e:
                    col = int(e['column'])
                    line_col += ', Column: ' + str(col)
                if len(line_col):
                    line_col += ')'

                #scroll to the line and column of the exception
                #if settings.get('mm_compile_scroll_to_error', True):
                #open file, if already open it will bring it to focus
                #view = sublime.active_window().open_file(thread.active_file)
                view = thread.view
                pt = view.text_point(line - 1, col - 1)
                view.sel().clear()
                view.sel().add(sublime.Region(pt))
                view.show(pt)
                problem = e['problem']
                problem = html_parser.unescape(problem)
                printer.panel.run_command(
                    'write_operation_status', {
                        "text":
                        " [COMPILE FAILED]: ({0}) {1} {2}".format(
                            e['name'], problem, line_col),
                        'region':
                        [status_region.end(),
                         status_region.end() + 10]
                    })
        elif "ErrorMsg" in res:
            printer.panel.run_command(
                'write_operation_status', {
                    "text": " [COMPILE FAILED]: {0}".format(res['ErrorMsg']),
                    'region': [status_region.end(),
                               status_region.end() + 10]
                })

    elif 'success' in res and util.to_bool(
            res['success']) == False and ('messages' in res
                                          or 'Messages' in res):
        if 'Messages' in res:
            res['messages'] = res.pop('Messages')
        #here we're parsing a response from the metadata endpoint
        failures = None
        messages = res['messages']
        if type(messages) is not list:
            messages = [messages]

        problems = 0
        for m in messages:
            if 'problem' in m:
                problems += 1
                break

        if problems == 0:  #must not have been a compile error, must be a test run error
            if 'run_test_result' in res and 'failures' in res[
                    'run_test_result'] and type(
                        res['run_test_result']['failures']) == list:
                failures = res['run_test_result']['failures']
            elif 'failures' in res['run_test_result']:
                failures = [res['run_test_result']['failures']]

            if failures != None:
                msg = ' [DEPLOYMENT FAILED]:'
                for f in failures:
                    msg += f['name'] + ', ' + f['methodName'] + ': ' + f[
                        'message'] + '\n'
                printer.panel.run_command(
                    'write_operation_status', {
                        'text': msg,
                        'region':
                        [status_region.end(),
                         status_region.end() + 10]
                    })
        else:  #compile error, build error message
            msg = ""
            for m in messages:
                if "success" in m and m["success"] == False:
                    line_col = ""
                    if 'lineNumber' in m:
                        line_col = ' (Line: ' + m['lineNumber']
                        util.mark_line_numbers(thread.view,
                                               [int(float(m['lineNumber']))],
                                               "bookmark")
                    if 'columnNumber' in m:
                        line_col += ', Column: ' + m['columnNumber']
                    if len(line_col) > 0:
                        line_col += ')'
                    msg += m['fileName'] + ': ' + m[
                        'problem'] + line_col + "\n\n"

            printer.panel.run_command(
                'write_operation_status', {
                    'text': ' [DEPLOYMENT FAILED]: ' + msg,
                    'region': [status_region.end(),
                               status_region.end() + 10]
                })

    elif 'success' in res and res["success"] == False and 'line' in res:
        #this is a response from the apex compile api
        line_col = ""
        line, col = 1, 1
        if 'line' in res:
            line = int(res['line'])
            line_col = ' (Line: ' + str(line)
            util.mark_line_numbers(thread.view, [line], "bookmark")
        if 'column' in res:
            col = int(res['column'])
            line_col += ', Column: ' + str(col)
        if len(line_col):
            line_col += ')'

        #scroll to the line and column of the exception
        if settings.get('mm_compile_scroll_to_error', True):
            #open file, if already open it will bring it to focus
            #view = sublime.active_window().open_file(thread.active_file)
            view = thread.view
            pt = view.text_point(line - 1, col - 1)
            view.sel().clear()
            view.sel().add(sublime.Region(pt))
            view.show(pt)

        printer.panel.run_command(
            'write_operation_status', {
                'text': ' [COMPILE FAILED]: ' + res['problem'] + line_col,
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    elif 'success' in res and util.to_bool(
            res['success']) == True and 'Messages' in res and len(
                res['Messages']) > 0:
        msg = ' [Operation completed Successfully - With Compile Errors]\n'
        msg += '[COMPILE ERRORS] - Count:\n'
        for m in res['Messages']:
            msg += ' FileName: ' + m['fileName'] + ': ' + m[
                'problem'] + 'Line: ' + m['lineNumber']
        printer.panel.run_command(
            'write_operation_status', {
                'text': msg,
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    elif 'success' in res and util.to_bool(res['success']) == True:
        printer.panel.run_command(
            'write_operation_status', {
                'text': ' Success',
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    elif 'success' in res and util.to_bool(
            res['success']) == False and 'body' in res:
        printer.panel.run_command(
            'write_operation_status', {
                'text': ' [OPERATION FAILED]:' + res['body'],
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    elif 'success' in res and util.to_bool(res['success']) == False:
        printer.panel.run_command(
            'write_operation_status', {
                'text': ' [OPERATION FAILED]',
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    else:
        printer.panel.run_command(
            'write_operation_status', {
                'text': ' Success',
                'region': [status_region.end(),
                           status_region.end() + 10]
            })
    def __handle_compile_response(self, **kwargs):
        # print("HANDLING COMPILE!")

        # diffing with server
        if "actions" in self.result and util.to_bool(self.result["success"]) == False:
            diff_merge_settings = config.settings.get("mm_diff_server_conflicts", False)
            if diff_merge_settings:
                if sublime.ok_cancel_dialog(self.result["body"], self.result["actions"][0].title()):
                    self.__print_to_panel("Diffing with server")
                    th = MavensMateDiffThread(self.thread.window, self.thread.view, self.result["tmp_file_path"])
                    th.start()
                else:
                    self.__print_to_panel(self.result["actions"][1].title())
            else:
                if sublime.ok_cancel_dialog(self.result["body"], "Overwrite Server Copy"):
                    self.__print_to_panel("Overwriting server copy")
                    self.thread.params["action"] = "overwrite"
                    if kwargs.get("callback", None) != None:
                        sublime.set_timeout(lambda: self.callback("compile", params=self.thread.params), 100)
                else:
                    self.__print_to_panel(self.result["actions"][1].title())
        else:
            try:
                if "State" in self.result and self.result["State"] == "Error" and "ErrorMsg" in self.result:
                    self.__print_to_panel(
                        "[OPERATION FAILED]: {0}\n\n{1}".format(
                            self.result["ErrorMsg"],
                            "If you are having difficulty compiling, try toggling the mm_compile_with_tooling_api setting to 'false' or cleaning your project.",
                        )
                    )
                elif "State" in self.result and self.result["State"] == "Failed" and "CompilerErrors" in self.result:
                    # here we're parsing a response from the tooling endpoint
                    errors = json.loads(self.result["CompilerErrors"])
                    if type(errors) is not list:
                        errors = [errors]
                    if len(errors) > 0:
                        for e in errors:
                            line_col = ""
                            line, col = 1, 1
                            if "line" in e:
                                line = int(e["line"])
                                line_col = " (Line: " + str(line)
                            if "column" in e:
                                col = int(e["column"])
                                line_col += ", Column: " + str(col)
                            if len(line_col):
                                line_col += ")"

                            # scroll to the line and column of the exception
                            # if settings.get('mm_compile_scroll_to_error', True):
                            # open file, if already open it will bring it to focus
                            # view = sublime.active_window().open_file(self.thread.active_file)
                            view = self.thread.view
                            pt = view.text_point(line - 1, col - 1)
                            view.sel().clear()
                            view.sel().add(sublime.Region(pt))
                            view.show(pt)
                            problem = e["problem"]
                            problem = html_parser.unescape(problem)
                            file_base_name = e["name"]
                            # if self.thread.window.active_view().name():
                            current_active_view = sublime.active_window().active_view()
                            if current_active_view.file_name() != None:
                                current_active_view_file_name = os.path.basename(current_active_view.file_name())
                                if "." in current_active_view_file_name:
                                    current_active_view_file_name = current_active_view_file_name.split(".")[0]
                                debug(current_active_view_file_name)
                                debug(file_base_name)
                                if current_active_view_file_name != file_base_name:
                                    # this is the tooling api throwing a compile error against a different file
                                    msg = "[COMPILE FAILED]: ({0}) {1} {2}".format(file_base_name, problem, line_col)
                                    msg += "\n\nThe Tooling API has failed to compile a separate element of metadata in your current MetadataContainer. You can either:"
                                    msg += "\n1. Fix the compilation error on " + file_base_name
                                    msg += "\n2. Reset your MetadataContainer to clear this error: MavensMate > Utilities > Reset MetadataContainer"
                                    self.__print_to_panel(msg)
                                elif current_active_view_file_name == file_base_name:
                                    util.mark_line_numbers(self.thread.view, [line], "bookmark")
                                    self.__print_to_panel(
                                        "[COMPILE FAILED]: ({0}) {1} {2}".format(file_base_name, problem, line_col)
                                    )
                    elif "ErrorMsg" in self.result:
                        self.__print_to_panel("[COMPILE FAILED]: {0}".format(self.result["ErrorMsg"]))

                elif (
                    "success" in self.result
                    and util.to_bool(self.result["success"]) == False
                    and (("messages" in self.result or "Messages" in self.result) or "details" in self.result)
                ):
                    if "details" in self.result and "componentFailures" in self.result["details"]:
                        self.result["messages"] = self.result["details"].pop("componentFailures")
                    elif "Messages" in self.result:
                        self.result["messages"] = self.result.pop("Messages")

                    # here we're parsing a response from the metadata endpoint
                    failures = None
                    messages = self.result["messages"]
                    if type(messages) is not list:
                        messages = [messages]

                    problems = 0
                    for m in messages:
                        if "problem" in m:
                            problems += 1
                            break

                    if problems == 0:  # must not have been a compile error, must be a test run error
                        if "runTestResult" in self.result:
                            if (
                                "runTestResult" in self.result
                                and "failures" in self.result["runTestResult"]
                                and type(self.result["runTestResult"]["failures"]) == list
                            ):
                                failures = self.result["runTestResult"]["failures"]
                            elif "failures" in self.result["runTestResult"]:
                                failures = [self.result["runTestResult"]["failures"]]

                            if failures != None:
                                msg = " [DEPLOYMENT FAILED]:"
                                for f in failures:
                                    msg += f["name"] + ", " + f["methodName"] + ": " + f["message"] + "\n"
                                    self.__print_to_panel(msg)
                        elif "run_test_result" in self.result:
                            if (
                                "run_test_result" in self.result
                                and "failures" in self.result["run_test_result"]
                                and type(self.result["run_test_result"]["failures"]) == list
                            ):
                                failures = self.result["run_test_result"]["failures"]
                            elif "failures" in self.result["run_test_result"]:
                                failures = [self.result["run_test_result"]["failures"]]

                            if failures != None:
                                msg = " [DEPLOYMENT FAILED]:"
                                for f in failures:
                                    msg += f["name"] + ", " + f["methodName"] + ": " + f["message"] + "\n"
                                self.__print_to_panel(msg)
                    else:  # compile error, build error message
                        msg = ""
                        for m in messages:
                            if "success" in m and m["success"] == False:
                                line_col = ""
                                if "lineNumber" in m:
                                    line_col = " (Line: " + m["lineNumber"]
                                    util.mark_line_numbers(self.thread.view, [int(float(m["lineNumber"]))], "bookmark")
                                if "columnNumber" in m:
                                    line_col += ", Column: " + m["columnNumber"]
                                if len(line_col) > 0:
                                    line_col += ")"
                                filename = m["fileName"]
                                filename = re.sub(r"unpackaged/[A-Z,a-z]*/", "", filename)
                                msg += filename + ": " + m["problem"] + line_col + "\n"

                        self.__print_to_panel("[DEPLOYMENT FAILED]: " + msg)

                elif "success" in self.result and self.result["success"] == False and "line" in self.result:
                    # this is a response from the apex compile api
                    line_col = ""
                    line, col = 1, 1
                    if "line" in self.result:
                        line = int(self.result["line"])
                        line_col = " (Line: " + str(line)
                        util.mark_line_numbers(self.thread.view, [line], "bookmark")
                    if "column" in self.result:
                        col = int(self.result["column"])
                        line_col += ", Column: " + str(col)
                    if len(line_col):
                        line_col += ")"

                    # scroll to the line and column of the exception
                    if settings.get("mm_compile_scroll_to_error", True):
                        # open file, if already open it will bring it to focus
                        # view = sublime.active_window().open_file(self.thread.active_file)
                        view = self.thread.view
                        pt = view.text_point(line - 1, col - 1)
                        view.sel().clear()
                        view.sel().add(sublime.Region(pt))
                        view.show(pt)

                        self.__print_to_panel("[COMPILE FAILED]: " + self.result["problem"] + line_col)
                elif (
                    "success" in self.result
                    and util.to_bool(self.result["success"]) == True
                    and "Messages" in self.result
                    and len(self.result["Messages"]) > 0
                ):
                    msg = " [Operation completed Successfully - With Compile Errors]\n"
                    msg += "[COMPILE ERRORS] - Count:\n"
                    for m in self.result["Messages"]:
                        msg += " FileName: " + m["fileName"] + ": " + m["problem"] + "Line: " + m["lineNumber"]
                    self.__print_to_panel(msg)
                elif "success" in self.result and util.to_bool(self.result["success"]) == True:
                    self.__print_to_panel("Success")
                elif (
                    "success" in self.result and util.to_bool(self.result["success"]) == False and "body" in self.result
                ):
                    self.__print_to_panel("[OPERATION FAILED]: " + self.result["body"])
                elif "success" in self.result and util.to_bool(self.result["success"]) == False:
                    self.__print_to_panel("[OPERATION FAILED]")
                else:
                    self.__print_to_panel("Success")
            except Exception as e:
                debug(e)
                debug(type(self.result))
                msg = ""
                if type(self.result) is dict:
                    if "body" in self.result:
                        msg = self.result["body"]
                    else:
                        msg = json.dumps(self.result)
                elif type(self.result) is str:
                    try:
                        m = json.loads(self.result)
                        msg = m["body"]
                    except:
                        msg = self.result
                else:
                    msg = "Check Sublime Text console for error and report issue to MavensMate-SublimeText GitHub project."
                self.__print_to_panel("[OPERATION FAILED]: " + msg)