Пример #1
0
    def save_component(self, component_attribute, body):
        """
        This method contains 5 steps:
        1. Post classid to get MetadataContainerId
        2. Post Component Member
        3. Post ContainerAsyncRequest to get AsyncRequest Id
        4. Get ContainerAsyncRequest Response by Id in step 3
        5. Delete the MetadataContainerId

        Notes: Because if ContainerAsyncRequest has problem, we can't reuse the 
            MetadataContainerId, so we need to delete it and get it every time.

        @component_attribute
        @body: Code content

        """
        # Component Attribute
        component_type = component_attribute["type"]
        component_id = component_attribute["id"]
        component_body = component_attribute["body"]

        # Get MetadataContainerId
        data = {  
            "name": "Save" + component_type[4 : len(component_type)] + component_id
        }
        container_url = '/services/data/v28.0/tooling/sobjects/MetadataContainer'
        result = self.post(container_url, data)
        print ("MetadataContainer Response: ", result)

        # If status_code < 399, it means post succeed
        if result["status_code"] < 399:
            container_id = result.get("id")
        else:
            # If status_code < 399, it means post failed, 
            # If DUPLICATE Container Id, just delete it and restart this function
            if result["errorCode"] == "DUPLICATE_VALUE":
                error_message = result["message"]
                container_id = error_message[error_message.rindex("1dc"): len(error_message)]
                delete_result = self.delete(container_url + "/" + container_id)
                if delete_result["status_code"] < 399:
                    util.sublime_status_message("container_id is deleted.")
                
                # We can't reuse the container_id which caused error
                # Post Request to get MetadataContainerId
                return self.save_component(component_attribute, body)
            else:
                util.sublime_error_message(result)
                return

        # Post ApexComponentMember
        data = {
            "ContentEntityId": component_id,
            "MetadataContainerId": container_id,
            "Body": body
        }
        url = "/services/data/v28.0/tooling/sobjects/" + component_type + "Member"
        result = self.post(url, data)
        print ("Post ApexComponentMember: ", result)

        # Post ContainerAsyncRequest
        data = {
            "MetadataContainerId": container_id,
            "isCheckOnly": False
        }
        sync_request_url = '/services/data/v28.0/tooling/sobjects/ContainerAsyncRequest'
        result = self.post(sync_request_url, data)
        request_id = result.get("id")
        print ("Post ContainerAsyncRequest: ", result)

        # Get ContainerAsyncRequest Result
        
        result = self.get(sync_request_url + "/" + request_id)
        state = result["State"]
        print ("Get ContainerAsyncRequest: ")
        pprint.pprint(result)

        return_result = {}
        if state == "Completed":
            return_result = {
                "success": True 
            }

        while state == "Queued":
            print ("Async Request is queued, please wait for 5 seconds...")
            time.sleep(5)

            result = self.get(sync_request_url + "/" + request_id)
            state = result["State"]
            if state == "Completed":
                return_result = {
                    "success": True 
                }

        if state == "Failed":
            # This error need more process, because of confused single quote
            compile_errors = unescape(result["CompilerErrors"])
            compile_errors = json.loads(compile_errors)
            if len(compile_errors) > 0:
                compile_error = compile_errors[0]
                extend = util.none_value(compile_error["extent"])
                line = util.none_value(compile_error["line"])
                problem = util.none_value(compile_error["problem"])
                name = util.none_value(compile_error["name"])
                error_message = extend + ": " + name + " has problem: " +\
                    problem + " at line " + str(line)
            else:
                error_message = result["ErrorMsg"]
            error_message = unescape(error_message, {"&apos;": "'", "&quot;": '"'})
            
            return_result = {
                "success": False,
                "message": error_message
            }

        # Whatever succeed or failed, just delete MetadataContainerId
        delete_result = self.delete(container_url + "/" + container_id)
        status_code = delete_result["status_code"]
        if status_code < 399:
            util.sublime_status_message("container_id is deleted.")

        # Result used in thread invoke
        self.result = return_result
Пример #2
0
    def save_component(self, component_attribute, body):
        """
        This method contains 5 steps:
        1. Post classid to get MetadataContainerId
        2. Post Component Member
        3. Post ContainerAsyncRequest to get AsyncRequest Id
        4. Get ContainerAsyncRequest Response by Id in step 3
        5. Delete the MetadataContainerId

        Notes: Because if ContainerAsyncRequest has problem, we can't reuse the 
            MetadataContainerId, so we need to delete it and get it every time.

        @component_attribute
        @body: Code content

        """
        # Component Attribute
        component_type = component_attribute["type"]
        component_id = component_attribute["id"]
        component_body = component_attribute["body"]

        # Get MetadataContainerId
        data = {
            "name":
            "Save" + component_type[4:len(component_type)] + component_id
        }
        container_url = '/services/data/v28.0/tooling/sobjects/MetadataContainer'
        result = self.post(container_url, data)
        print("MetadataContainer Response: ", result)

        # If status_code < 399, it means post succeed
        if result["status_code"] < 399:
            container_id = result.get("id")
        else:
            # If status_code < 399, it means post failed,
            # If DUPLICATE Container Id, just delete it and restart this function
            if result["errorCode"] == "DUPLICATE_VALUE":
                error_message = result["message"]
                container_id = error_message[error_message.
                                             rindex("1dc"):len(error_message)]
                delete_result = self.delete(container_url + "/" + container_id)
                if delete_result["status_code"] < 399:
                    util.sublime_status_message("container_id is deleted.")

                # We can't reuse the container_id which caused error
                # Post Request to get MetadataContainerId
                return self.save_component(component_attribute, body)
            else:
                util.sublime_error_message(result)
                return

        # Post ApexComponentMember
        data = {
            "ContentEntityId": component_id,
            "MetadataContainerId": container_id,
            "Body": body
        }
        url = "/services/data/v28.0/tooling/sobjects/" + component_type + "Member"
        result = self.post(url, data)
        print("Post ApexComponentMember: ", result)

        # Post ContainerAsyncRequest
        data = {"MetadataContainerId": container_id, "isCheckOnly": False}
        sync_request_url = '/services/data/v28.0/tooling/sobjects/ContainerAsyncRequest'
        result = self.post(sync_request_url, data)
        request_id = result.get("id")
        print("Post ContainerAsyncRequest: ", result)

        # Get ContainerAsyncRequest Result

        result = self.get(sync_request_url + "/" + request_id)
        state = result["State"]
        print("Get ContainerAsyncRequest: ", result)

        return_result = {}
        if state == "Completed":
            return_result = {"success": True}

        while state == "Queued":
            print("Async Request is queued, please wait for 5 seconds...")
            time.sleep(5)

            result = self.get(sync_request_url + "/" + request_id)
            state = result["State"]
            if state == "Completed":
                return_result = {"success": True}

        if state == "Failed":
            # This error need more process, because of confused single quote
            compile_errors = unescape(result["CompilerErrors"])
            compile_errors = json.loads(compile_errors)
            if len(compile_errors) > 0:
                compile_error = compile_errors[0]
                extend = util.none_value(compile_error["extent"])
                line = util.none_value(compile_error["line"])
                problem = util.none_value(compile_error["problem"])
                name = util.none_value(compile_error["name"])
                error_message = extend + ": " + name + " has problem: " +\
                    problem + " at line " + str(line)
            else:
                error_message = result["ErrorMsg"]
            error_message = unescape(error_message, {
                "&apos;": "'",
                "&quot;": '"'
            })

            return_result = {"success": False, "message": error_message}

        # Whatever succeed or failed, just delete MetadataContainerId
        delete_result = self.delete(container_url + "/" + container_id)
        status_code = delete_result["status_code"]
        if status_code < 399:
            util.sublime_status_message("container_id is deleted.")

        # Result used in thread invoke
        self.result = return_result
Пример #3
0
    def refresh_components(self, component_types):
        """
        Download the specified components

        @component_types: just support ApexPage, ApexComponent, ApexTrigger and ApexClass
        """
        # Firstly Login
        self.login(True)

        # Put totalSize at first item
        component_metadata = {}
        for component_type in component_types:
            component_type_attrs = self.toolingapi_settings[component_type]
            component_outputdir = component_type_attrs["outputdir"]
            component_body = component_type_attrs["body"]
            component_extension = component_type_attrs["extension"]
            component_soql = component_type_attrs["soql"]

            result = self.query_all(component_soql)
            # The users password has expired, you must call SetPassword 
            # before attempting any other API operations
            # Database.com not support ApexComponent
            if result["status_code"] > 399:
                continue

            size = len(result["records"])
            print (SEPRATE)
            print (str(component_type) + " Size: " + str(size))
            print (SEPRATE)
            records = result["records"]

            component_attributes = {}
            for record in records:
                # Get Component Name of this record
                component_name = record['Name']
                component_url = record['attributes']['url']
                component_id = record["Id"]
                print (str(component_type) + " ==> " + str(record['Name']))

                # Write mapping of component_name with component_url
                # into metadata.sublime-settings
                component_attributes[component_name] = {
                    "url": component_url,
                    "id": component_id
                }

                # Get the body
                body = record[component_body]

                # Save Component Body, Component Type to attribute
                component_attributes[component_name]["body"] = component_body
                component_attributes[component_name]["extension"] = component_extension
                component_attributes[component_name]["type"] = component_type

                # Judge Component is Test Class or not
                if component_type == "ApexClass":
                    if "@isTest" in body or "testMethod" in body or\
                        "testmethod" in body or "test" in component_name or\
                        "Test" in component_name:
                        
                        component_attributes[component_name]["is_test"] = True
                    else:
                        component_attributes[component_name]["is_test"] = False

                # Write body to local file
                fp = open(component_outputdir + "/" + component_name +\
                    component_extension, "wb")
                
                try:
                    body = bytes(body, "UTF-8")
                except:
                    body = body.encode("UTF-8")
                fp.write(body)

                # Set status_message
                util.sublime_status_message(component_name + " ["  + component_type + "] Downloaded")

            component_metadata[component_type] = component_attributes

        # Self.result is used to keep thread result
        self.result = component_metadata
Пример #4
0
    def refresh_components(self, component_types):
        """
        Download the specified components

        @component_types: just support ApexPage, ApexComponent, ApexTrigger and ApexClass
        """
        # Firstly Login
        self.login(True)

        # Put totalSize at first item
        component_metadata = {}
        for component_type in component_types:
            component_type_attrs = self.toolingapi_settings[component_type]
            component_outputdir = component_type_attrs["outputdir"]
            component_body = component_type_attrs["body"]
            component_extension = component_type_attrs["extension"]
            component_soql = component_type_attrs["soql"]

            result = self.query_all(component_soql)
            # The users password has expired, you must call SetPassword
            # before attempting any other API operations
            # Database.com not support ApexComponent
            if result["status_code"] > 399:
                continue

            size = len(result["records"])
            print(SEPRATE)
            print(str(component_type) + " Size: " + str(size))
            print(SEPRATE)
            records = result["records"]

            component_attributes = {}
            for record in records:
                # Get Component Name of this record
                component_name = record['Name']
                component_url = record['attributes']['url']
                component_id = record["Id"]
                print(str(component_type) + " ==> " + str(record['Name']))

                # Write mapping of component_name with component_url
                # into metadata.sublime-settings
                component_attributes[component_name] = {
                    "url": component_url,
                    "id": component_id
                }

                # Get the body
                body = record[component_body]

                # Save Component Body, Component Type to attribute
                component_attributes[component_name]["body"] = component_body
                component_attributes[component_name][
                    "extension"] = component_extension
                component_attributes[component_name]["type"] = component_type

                # Judge Component is Test Class or not
                if component_type == "ApexClass":
                    if "@isTest" in body or "testMethod" in body or\
                        "testmethod" in body or "test" in component_name or\
                        "Test" in component_name:

                        component_attributes[component_name]["is_test"] = True
                    else:
                        component_attributes[component_name]["is_test"] = False

                # Write body to local file
                fp = open(component_outputdir + "/" + component_name +\
                    component_extension, "wb")

                try:
                    body = bytes(body, "UTF-8")
                except:
                    body = body.encode("UTF-8")
                fp.write(body)

                # Set status_message
                util.sublime_status_message(component_name + " [" +
                                            component_type + "] Downloaded")

            component_metadata[component_type] = component_attributes

        # Self.result is used to keep thread result
        self.result = component_metadata