Exemple #1
0
def load_putty_cli():
    success = True
    std_out = ''
    err_out = ''
    exit_code = 0

    settings = ServerCompilerSettings()

    if not settings.get_serial_port_flag():
        success = False
        exit_code = 55
        err_out = 'Serial Port configured in Settings not accessible.'

    if success:
        baud = settings.get_baud_rate()
        cli_command = ['putty.exe']
        cli_command.append('-serial')
        cli_command.append(settings.get_serial_port_flag())
        cli_command.append('-sercfg')
        cli_command.append(baud)
        # print(cli_command)
        print('\nOpen putty...')
        subprocess.Popen(cli_command, shell=False)

    return success, std_out, err_out, exit_code
Exemple #2
0
def get_serial_ports():
    """
    Creates a JSON string to return to the page with the following format:
    {"response_type" : "settings_serial",
     "element" : "dropdown",
     "options" : [
         {"value" : "XXX", "text" : "XXX"},
         ...]
     "selected": "selected key"}
    """
    json_data = \
        {'setting_type': 'ide',
         'element': 'dropdown',
         'options': []}
    ports = ServerCompilerSettings().get_serial_ports()
    if not ports:
        json_data['options'].append({
            'value':
            'no_ports',
            'display_text':
            'There are no available Serial Ports'
        })
        json_data.update({'selected': 'no_ports'})
    else:
        for key in ports:
            json_data['options'].append({
                'value': key,
                'display_text': ports[key]
            })
        json_data.update({'selected': ServerCompilerSettings().serial_port})
    return json.dumps(json_data)
 def test_sketch_name_valid_accesor(self, mock_isdir):
     self.delete_default_settings_file()
     old_sketch_dir = ServerCompilerSettings().sketch_dir
     mock_isdir.return_value = True
     test_sketch_dir = os.path.join(os.getcwd(), 'unicode_いろΓαζέεςÂaéquo')
     ServerCompilerSettings().sketch_dir = test_sketch_dir
     self.assertEqual(test_sketch_dir, ServerCompilerSettings().sketch_dir)
     self.assertNotEqual(old_sketch_dir, ServerCompilerSettings().sketch_dir)
Exemple #4
0
 def test_settings_file_deletion(self):
     self.delete_default_settings_file()
     settings_file = self.get_default_settings_file_dir()
     self.assertFalse(os.path.exists(settings_file))
     ServerCompilerSettings().save_settings()
     self.assertTrue(os.path.exists(settings_file))
     ServerCompilerSettings().delete_settings_file()
     self.assertFalse(os.path.exists(settings_file))
    def test_load_arduino_cli_invalid(self):
        # Test that an path that is not a file returns error
        success, conclusion, out, error, exit_code =\
            actions.load_arduino_cli(os.getcwd())
        self.assertFalse(success)
        self.assertTrue('Provided sketch path is not a valid' in conclusion)

        # Test for error if compiler dir is not set, default is None
        self.delete_default_settings_file()
        success, conclusion, out, error, exit_code = actions.load_arduino_cli()
        self.assertFalse(success)
        self.assertEqual(conclusion, 'Unable to find Arduino IDE')

        # Test for error if compiler dir is not set
        with mock.patch(
                'ardublocklyserver.actions.ServerCompilerSettings.compiler_dir',
                new_callable=mock.PropertyMock) as mock_compiler_dir:
            with mock.patch(
                    'ardublocklyserver.actions.ServerCompilerSettings.'
                    'load_ide_option', new_callable=mock.PropertyMock) as \
                    mock_load_ide_option:
                mock_compiler_dir.return_value = 'true'  # do nothing command
                mock_load_ide_option.return_value = None
                success, conclusion, out, error, exit_code = \
                    actions.load_arduino_cli()
                self.assertFalse(success)
                self.assertEqual(conclusion,
                                 'What should we do with the Sketch?')

        # Test for error if serial port unset, only required when set to upload
        ServerCompilerSettings().load_ide_option = 'upload'
        with mock.patch(
                'ardublocklyserver.actions.ServerCompilerSettings.compiler_dir',
                new_callable=mock.PropertyMock) as mock_compiler_dir:
            with mock.patch(
                    'ardublocklyserver.actions.ServerCompilerSettings.'
                    'get_serial_port_flag') as mock_get_serial_port_flag:
                mock_compiler_dir.return_value = 'true'  # do nothing command
                mock_get_serial_port_flag.return_value = None
                success, conclusion, out, error, exit_code = \
                    actions.load_arduino_cli()
                self.assertFalse(success)
                self.assertEqual(conclusion, 'Serial Port unavailable')

        # Test for error if board type unset, only required when set to upload
        ServerCompilerSettings().load_ide_option = 'upload'
        with mock.patch(
                'ardublocklyserver.actions.ServerCompilerSettings.compiler_dir',
                new_callable=mock.PropertyMock) as mock_compiler_dir:
            with mock.patch(
                    'ardublocklyserver.actions.ServerCompilerSettings.'
                    'get_arduino_board_flag') as mock_get_arduino_board_flag:
                mock_compiler_dir.return_value = 'true'  # do nothing command
                mock_get_arduino_board_flag.return_value = None
                success, conclusion, out, error, exit_code = \
                    actions.load_arduino_cli()
                self.assertFalse(success)
                self.assertEqual(conclusion, 'Unknown Arduino Board')
Exemple #6
0
 def test_settings_file_simple_read(self):
     """
     Simple test that checks for no exceptions happening while creating
     and loading the created file.
     """
     ServerCompilerSettings()
     ServerCompilerSettings().set_default_settings()
     ServerCompilerSettings().get_settings_file_data()
     ServerCompilerSettings().save_settings()
Exemple #7
0
 def test_sketch_name_invalid_accesor(self):
     """
     Tests path doesn't get saved the input is not a valid directory.
     """
     self.delete_default_settings_file()
     old_sketch_dir = ServerCompilerSettings().sketch_dir
     test_sketch_dir = os.path.join(os.getcwd(), 'random_faKe_dir_ろ')
     ServerCompilerSettings().sketch_dir = test_sketch_dir
     self.assertNotEqual(test_sketch_dir,
                         ServerCompilerSettings().sketch_dir)
     self.assertEqual(old_sketch_dir, ServerCompilerSettings().sketch_dir)
Exemple #8
0
    def test_load_arduino_cli_valid(self, mock_isfile, mock_file_dialog):
        """
        Tests that the set_compiler_path method edits the settings based on the
        output from the gui.browse_file_dialog() function only if it has not
        been cancelled.
        The return value is not tested as it is a direct call to the
        actions.get_compiler_path() function and will be tested individually.
        """
        self.delete_default_settings_file()
        settings = ServerCompilerSettings()
        new_compiler_dir = os.path.join(os.getcwd(), 'arduino_debug.exe')
        mock_file_dialog.return_value = new_compiler_dir
        # The settings.compiler_dir checks for file validity
        mock_isfile.return_value = True
        old_compiler_dir = settings.compiler_dir
        actions.set_compiler_path()
        self.assertNotEqual(old_compiler_dir, settings.compiler_dir)
        # Using in as each OSs will dealt with compiler path differently
        self.assertTrue(new_compiler_dir in settings.compiler_dir)

        # If the dialog is cancelled, the ServerCompilerSettings class should
        # not be invoked at all
        with patch(
                'ardublocklyserver.actions.ServerCompilerSettings.__new__') \
                as mock_settings:
            # Avoid call to ServerCompilerSettings() in get_compiler_path
            with patch('ardublocklyserver.actions.get_compiler_path') \
                    as mock_get_compiler_path:
                mock_file_dialog.return_value = ''  # Dialog cancel return value
                mock_get_compiler_path.return_vale = None  # Don't care
                old_compiler_dir = settings.compiler_dir
                actions.set_compiler_path()
                self.assertEqual(old_compiler_dir, settings.compiler_dir)
                self.assertFalse(mock_settings.called)
Exemple #9
0
def set_load_delay(new_value):
    """Set a new load delay option.

    :param new_value: New load delay option to save in the Settings.
    :return: Same as the get_load_delay_selected() function.
    """
    ServerCompilerSettings().load_delay_option = new_value
    return get_load_delay()
Exemple #10
0
def set_serial_time_stamp(new_value):
    """Set a new Time Stamp option.

    :param new_value: New Time Stamp option to save in the Settings.
    :return: Same as the get_timestamp() function.
    """
    ServerCompilerSettings().serial_time_stamp = new_value
    return get_serial_time_stamp()
Exemple #11
0
def set_load_ide_only(new_value):
    """Set a new Arduino IDE load option.

    :param new_value: New IDE load option to save in the Settings.
    :return: Same as the get_load_ide_selected() function.
    """
    ServerCompilerSettings().load_ide_option = new_value
    return get_load_ide_selected()
Exemple #12
0
def set_end_of_line_only(new_value):
    """Set a new End Of Line option.

    :param new_value: New End Of Line option to save in the Settings.
    :return: Same as the get_end_of_line_selected() function.
    """
    ServerCompilerSettings().end_of_line_option = new_value
    return get_end_of_line_selected()
Exemple #13
0
def set_baud_rate_only(new_value):
    """Set a new Baud Rate option.

    :param new_value: New Baud Rate option to save in the Settings.
    :return: Same as the get_baud_rate_selected() function.
    """
    ServerCompilerSettings().baud_rate_option = new_value
    return get_baud_rate_selected()
Exemple #14
0
def set_serial_port(new_value):
    """Set a new serial port in the Settings.

    :param new_value: New serial port to save.
    :return: Same as get_serial_ports() function.
    """
    ServerCompilerSettings().serial_port = new_value
    return get_serial_port_selected()
Exemple #15
0
    def test_compiler_dir_invalid_accesor(self, mock_os_path_isfile):
        """
        Tests path doesn't get saved if:
             A file that does not exists
             Just a folder
        """
        self.delete_default_settings_file()

        # Test for failure, mock that the file does not exists
        mock_os_path_isfile.return_value = False
        original_dir = self.new_ServerCompilerSettings_instance().compiler_dir
        self.assertIsNone(original_dir)
        new_dir = os.path.join(os.getcwd(), 'random.exe')
        ServerCompilerSettings().compiler_dir = new_dir
        # For now we depend on having CI builds on each platform
        if sys.platform == 'darwin':
            # Mac has to search for the executable inside the app bundle, so it
            # will end up being: new_dir/Contents/MacOS/JavaApplicationStub
            self.assertIsNone(ServerCompilerSettings().compiler_dir)
        else:
            self.assertNotEqual(new_dir, ServerCompilerSettings().compiler_dir)
            self.assertEqual(original_dir,
                             ServerCompilerSettings().compiler_dir)

        # Test for directory not accepted as a valid compiler file
        mock_os_path_isfile.return_value = True
        new_dir = os.getcwd()
        ServerCompilerSettings().compiler_dir = new_dir
        self.assertTrue(new_dir in ServerCompilerSettings().compiler_dir)
        self.assertNotEqual(original_dir,
                            ServerCompilerSettings().compiler_dir)
Exemple #16
0
def set_arduino_board(new_value):
    """Set new Arduino board value in the Settings.

    :param new_value: New Arduino board value, must be the board name, not the
            flag (so 'Uno', not 'arduino:avr:uno').
    :return: Same as the get_arduino_board_selected() function.
    """
    ServerCompilerSettings().arduino_board = new_value
    return get_arduino_board_selected()
Exemple #17
0
 def test_settings_file_creation(self):
     """
     Tests if the settings file is created.
     """
     self.delete_default_settings_file()
     settings_file = self.get_default_settings_file_dir()
     self.assertFalse(os.path.exists(settings_file))
     ServerCompilerSettings().save_settings()
     self.assertTrue(os.path.exists(settings_file))
Exemple #18
0
def get_sketch_path():
    """Return the path to the folder to store the Arduino Sketch.

    :return: String with the sketch path from the Settings.
             None if there is no path saved in the Settings.
    """
    sketch_directory = ServerCompilerSettings().sketch_dir
    if not sketch_directory:
        sketch_directory = None
    return sketch_directory
Exemple #19
0
def get_examples_path():
    """Return the path to the folder to load the block example xml file.

    :return: String with the example path from the Settings.
             None if there is no path saved in the Settings.
    """
    examples_directory = ServerCompilerSettings().examples_dir
    if not examples_directory:
        examples_directory = None
    return examples_directory
Exemple #20
0
def set_compiler_path(new_path):
    """Open the file browser to select an Arduino IDE executable.

    The new file path is saved into ServerCompilerSettings.

    :param new_path: New path for the Arduino IDE executable.
    :return: Same as get_compiler_path().
    """
    ServerCompilerSettings().compiler_dir = new_path
    return get_compiler_path()
Exemple #21
0
def set_sketch_path(new_path):
    """Open the file browser to select an folder to store the Arduino Sketch.

    The new file path is saved into ServerCompilerSettings.

    :param new_path: New path to store the Arduino Sketch.
    :return: Same as get_sketch_path().
    """
    ServerCompilerSettings().sketch_dir = new_path
    return get_sketch_path()
Exemple #22
0
def get_compiler_path():
    """Return the Arduino IDE executable path as stored in the Settings.

    :return: String with compiler path from the Settings.
             None if there is no path saved in the Settings.
    """
    compiler_directory = ServerCompilerSettings().compiler_dir
    if not compiler_directory:
        compiler_directory = None
    return compiler_directory
Exemple #23
0
def set_examples_path(new_path):
    """Open the file browser to select an folder to load the block example xml file.

    The new file path is saved into ServerCompilerSettings.

    :param new_path: New path to load the block example xml file.
    :return: Same as get_examples_path().
    """
    ServerCompilerSettings().examples_dir = new_path
    return get_examples_path()
Exemple #24
0
def set_sketch_path():
    """
    Opens the directory browser to select a file. Saves this directory into
    ServerCompilerSettings and if the directory is different to that stored
    already it triggers the new data to be saved into the settings file.
    """
    new_directory = gui.browse_dir_dialog()
    if new_directory != '':
        ServerCompilerSettings().sketch_dir = new_directory
    return get_sketch_path()
Exemple #25
0
def set_compiler_path():
    """
    Opens the file browser to select a file. Saves this file path into
    ServerCompilerSettings and if the file path is different to that stored
    already it triggers the new data to be saved into the settings file.
    """
    new_path = gui.browse_file_dialog()
    if new_path != '':
        ServerCompilerSettings().compiler_dir = new_path
    return get_compiler_path()
Exemple #26
0
def create_sketch_from_string(sketch_code):
    """Create an Arduino Sketch in location and name given by Settings.

    :param sketch_code: Code for the sketch.
    :return: Sketch location. None if there was a problem.
    """
    settings = ServerCompilerSettings()
    return sketchcreator.create_sketch(sketch_dir=settings.sketch_dir,
                                       sketch_name=settings.sketch_name,
                                       sketch_code=sketch_code)
Exemple #27
0
def get_arduino_boards():
    """
    Creates a JSON string to return to the page with the following format:
    {"response_type" : "settings_board",
     "element" : "dropdown",
     "options" : [
         {"value" : "XXX", "text" : "XXX"},
         ...]
     "selected": "selected key"}
    """
    json_data = \
        {'setting_type': 'ide',
         'element': 'dropdown',
         'options': []}
    #TODO: Check for None, however won't happen because static dict in settings
    boards = ServerCompilerSettings().get_arduino_board_types()
    for item in boards:
        json_data['options'].append({'value': item, 'display_text': item})
    json_data.update({'selected': ServerCompilerSettings().arduino_board})
    return json.dumps(json_data)
Exemple #28
0
def get_load_ide_only():
    """
    Creates a JSON string to return to the page with the following format:
    {"response_type" : "settings_ide",
     "element" : "dropdown",
     "options" : [
         {"value" : "XXX", "text" : "XXX"},
         ...]
     "selected": "selected key"}
    """
    json_data = \
        {'setting_type': 'ide',
         'element': 'dropdown',
         'options': []}
    #TODO: Check for None, however won't happen because static dict in settings
    ide_options = ServerCompilerSettings().get_load_ide_options()
    for key in ide_options:
        json_data['options'].append(
            {'value': key, 'display_text': ide_options[key]})
    json_data.update({'selected': ServerCompilerSettings().load_ide_option})
    return json.dumps(json_data)
Exemple #29
0
 def setUpClass(cls):
     """Create a temporary folder to play round."""
     cls.temp_folder = os.path.join(
         os.path.abspath(os.path.dirname(__file__)),
         'TestTemp_compilersettings')
     if os.path.isdir(cls.temp_folder):
         raise Exception('Directory %s already exists.' % cls.temp_folder)
     os.makedirs(cls.temp_folder)
     # Create settings file and check it's a new instance by looking at path
     cls.settings = ServerCompilerSettings(cls.temp_folder)
     if cls.temp_folder not in cls.settings.get_settings_file_path():
         raise Exception('Settings file not created in temp folder:\n'
                         '\t%s' % cls.settings.get_settings_file_path())
Exemple #30
0
def get_sketch_path():
    """
    Creates a JSON string to return to the page with the following format:
    {"response_type" : "settings_sketch",
     "element" : "text_input",
     "display_text" : "Sketch Directory"}
    """
    sketch_directory = ServerCompilerSettings().sketch_dir
    if not sketch_directory:
        sketch_directory = 'Please select a valid Sketch directory.'
    json_data = {'setting_type': 'compiler',
                 'element': 'text_input',
                 'display_text': sketch_directory}
    return json.dumps(json_data)
Exemple #31
0
def load_arduino_cli(sketch_path):
    """Launch subprocess for Arduino IDE CLI with values from Settings.

    Launches a subprocess to invoke the Arduino IDE command line to open,
    verify or upload an sketch, the location of which is indicated in the input
    parameter.

    :param sketch_path: Path to the sketch to load into the Arduino IDE.
    :return: A tuple with the following data (success, ide_mode, std_out,
            err_out, exit_code)
    """
    success = True
    ide_mode = 'unknown'
    std_out, err_out = '', ''
    exit_code = 0

    # Input sanitation and output defaults
    if not os.path.isfile(sketch_path):
        err_out = 'Provided sketch path is not a valid file: %s' % sketch_path
        success = False
        exit_code = 52
        return success, ide_mode, std_out, err_out, exit_code

    settings = ServerCompilerSettings()

    # Check if CLI flags have been set
    if not settings.compiler_dir:
        success = False
        exit_code = 53
        err_out = 'Compiler directory not configured in the Settings.'
    elif not settings.load_ide_option:
        success = False
        exit_code = 54
        err_out = 'Launch IDE option not configured in the Settings.'
    elif not settings.get_arduino_board_flag() and (
            settings.load_ide_option == 'upload' or
            settings.load_ide_option == 'verify'):
        success = False
        exit_code = 56
        err_out = 'Arduino Board not configured in the Settings.'
    elif not settings.get_serial_port_flag() and \
            settings.load_ide_option == 'upload':
        success = False
        exit_code = 55
        err_out = 'Serial Port configured in Settings not accessible.'

    if success:
        ide_mode = settings.load_ide_option
        # Concatenates the CLI command and execute if the flags are valid
        cli_command = [settings.compiler_dir, "%s" % sketch_path]
        if settings.load_ide_option == 'upload':
            print('\nUploading sketch to Arduino...')
            cli_command.append('--upload')
            cli_command.append('--port')
            cli_command.append(settings.get_serial_port_flag())
            cli_command.append('--board')
            cli_command.append(settings.get_arduino_board_flag())
        elif settings.load_ide_option == 'verify':
            print('\nVerifying the sketch...')
            cli_command.append('--board')
            cli_command.append(settings.get_arduino_board_flag())
            cli_command.append('--verify')
        elif settings.load_ide_option == 'open':
            print('\nOpening the sketch in the Arduino IDE...')
        print('CLI command: %s' % ' '.join(cli_command))
        # Python 2 needs the input to subprocess.Popen to be in system encoding
        if sys.version_info[0] < 3:
            sys_locale = locale.getpreferredencoding()
            cli_command = [x.encode(sys_locale) for x in cli_command]

        if settings.load_ide_option == 'open':
            # Open IDE in a subprocess without capturing outputs
            subprocess.Popen(cli_command, shell=False)
            exit_code = 0
        else:
            # Launch the Arduino CLI in a subprocess and capture output data
            process = subprocess.Popen(
                cli_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                shell=False)
            std_out, err_out = process.communicate()
            std_out = six.u(std_out)
            err_out = six.u(err_out)
            exit_code = process.returncode
            print('Arduino output:\n%s' % std_out)
            print('Arduino Error output:\n%s' % err_out)
            print('Arduino Exit code: %s' % exit_code)
            # For some reason Arduino CLI can return 256 on success
            if (process.returncode != 0) and (process.returncode != 256):
                success = False
                if exit_code >= 50:
                    # Custom exit codes from server start at 50
                    err_out = '%s\nUnexpected Arduino exit error code: %s' % \
                              (err_out, exit_code)
                    exit_code = 50

    return success, ide_mode, std_out, err_out, exit_code
 def test_destructor(self):
     ServerCompilerSettings()
     instance_1 = ServerCompilerSettings()
     instance_1._drop()
     self.assertIsNone(
         instance_1._ServerCompilerSettings__singleton_instance)
def load_arduino_cli(sketch_path=None):
    """
    Launches a subprocess to invoke the Arduino IDE command line to open,
    verify or upload an sketch, the location of which is indicated in the input
    parameter.
    :param sketch_path: Path to the sketch to load into the Arduino IDE.
    :return: A tuple with the following data (success, conclusion, out, error,
            exit_code)
    """
    success = True
    conclusion = error = out = exit_code = ''

    # Input sanitation and output defaults
    if not sketch_path:
        sketch_path = create_sketch_default()
    else:
        if not os.path.isfile(sketch_path):
            conclusion = error = 'Provided sketch path is not a valid file: %s'\
                                 % sketch_path
            success = False
            return success, conclusion, out, error, exit_code

    settings = ServerCompilerSettings()

    # Check if CLI flags have been set
    if not settings.compiler_dir:
        success = False
        conclusion = 'Unable to find Arduino IDE'
        error = 'The compiler directory has not been set.\n' + \
                'Please set it in the Settings.'
    else:
        if not settings.load_ide_option:
            success = False
            conclusion = 'What should we do with the Sketch?'
            error = 'The launch IDE option has not been set.\n' + \
                    'Please select an IDE option in the Settings.'
        elif settings.load_ide_option == 'upload':
            if not settings.get_serial_port_flag():
                success = False
                conclusion = 'Serial Port unavailable'
                error = 'The Serial Port does not exist.\n' + \
                        'Please check if the Arduino is correctly ' + \
                        'connected to the PC and select the Serial Port in ' +\
                        'the Settings.'
            if not settings.get_arduino_board_flag():
                success = False
                conclusion = 'Unknown Arduino Board'
                error = 'The Arduino Board has not been set.\n' + \
                        'Please select the appropriate Arduino Board from ' + \
                        'the settings.'

    if success:
        # Concatenates the CLI command and execute if the flags are valid
        cli_command = [settings.compiler_dir]
        if settings.load_ide_option == 'upload':
            print('\nUploading sketch to Arduino...')
            # This success conclusion message gets overwritten in case of error
            conclusion = 'Successfully Uploaded Sketch'
            cli_command.append('--upload')
            cli_command.append('--port')
            cli_command.append(settings.get_serial_port_flag())
            cli_command.append('--board')
            cli_command.append(settings.get_arduino_board_flag())
        elif settings.load_ide_option == 'verify':
            print('\nVerifying the sketch...')
            # This success conclusion message gets overwritten in case of error
            conclusion = 'Successfully Verified Sketch'
            cli_command.append('--verify')
        elif settings.load_ide_option == 'open':
            print('\nOpening the sketch in the Arduino IDE...')
            conclusion = 'Sketch opened in IDE'
            out = 'The sketch should be loaded in the Arduino IDE.'
        cli_command.append("%s" % sketch_path)
        print('CLI command: %s' % ' '.join(cli_command))
        # Python 2 needs the input to subprocess.Popen to be in system encoding
        if sys.version_info[0] < 3:
            for item in six_moves.range(len(cli_command)):
                cli_command[item] = cli_command[item].encode(
                    locale.getpreferredencoding())

        if settings.load_ide_option == 'open':
            # Open IDE in a subprocess without capturing outputs
            subprocess.Popen(cli_command, shell=False)
            # Wait a few seconds to allow IDE to open before sending back data
            time.sleep(5)
        else:
            # Launch the Arduino CLI in a subprocess and capture output data
            process = subprocess.Popen(
                cli_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                shell=False)
            out, error = process.communicate()
            out = six.u(out)
            error = six.u(error)
            exit_code = process.returncode
            print('Arduino output:\n%s' % out)
            print('Arduino Error output:\n%s' % error)
            print('Arduino Exit code: %s' % exit_code)
            # For some reason Arduino CLI can return 256 on success
            if (process.returncode != 0) and (process.returncode != 256):
                success = False
                if exit_code == 1:
                    conclusion = 'Build or Upload failed'
                elif exit_code == 2:
                    conclusion = 'Sketch not found'
                elif exit_code == 3:
                    conclusion = 'Invalid command line argument'
                elif exit_code == 4:
                    conclusion =\
                        'Preference passed to "get-pref" flag does not exist'
                else:
                    conclusion = 'Unexpected exit error code: %s' % exit_code

    return success, conclusion, out, error, exit_code
Exemple #34
0
def load_arduino_cli(sketch_path=None):
    """
    Launches a subprocess to invoke the Arduino IDE command line to open,
    verify or upload an sketch, the location of which is indicated in the input
    parameter.
    :param sketch_path: Path to the sketch to load into the Arduino IDE.
    :return: A tuple with the following data (success, conclusion, out, error,
            exit_code)
    """
    success = True
    conclusion = error = out = exit_code = ''

    # Input sanitation and output defaults
    if not sketch_path:
        sketch_path = create_sketch_default()
    else:
        if not os.path.isfile(sketch_path):
            conclusion = error = 'Provided sketch path is not a valid file: %s'\
                                 % sketch_path
            success = False
            return success, conclusion, out, error, exit_code

    settings = ServerCompilerSettings()

    # Check if CLI flags have been set
    if not settings.compiler_dir:
        success = False
        conclusion = 'arduinoOpErrorIdeDirTitle'
        error = 'arduinoOpErrorIdeDirBody'
    else:
        if not settings.load_ide_option:
            success = False
            conclusion = 'arduinoOpErrorIdeOptionTitle'
            error = 'arduinoOpErrorIdeOptionBody'
        elif settings.load_ide_option == 'upload':
            if not settings.get_serial_port_flag():
                success = False
                conclusion = 'arduinoOpErrorIdePortTitle'
                error = 'arduinoOpErrorIdePortBody'
            if not settings.get_arduino_board_flag():
                success = False
                conclusion = 'arduinoOpErrorIdeBoardTitle'
                error = 'arduinoOpErrorIdeBoardBody'

    if success:
        # Concatenates the CLI command and execute if the flags are valid
        cli_command = [settings.compiler_dir]
        if settings.load_ide_option == 'upload':
            print('\nUploading sketch to Arduino...')
            # This success conclusion message gets overwritten in case of error
            conclusion = 'arduinoOpUploadedTitle'
            cli_command.append('--upload')
            cli_command.append('--port')
            cli_command.append(settings.get_serial_port_flag())
            cli_command.append('--board')
            cli_command.append(settings.get_arduino_board_flag())
        elif settings.load_ide_option == 'verify':
            print('\nVerifying the sketch...')
            # This success conclusion message gets overwritten in case of error
            conclusion = 'arduinoOpVerifiedTitle'
            cli_command.append('--verify')
        elif settings.load_ide_option == 'open':
            print('\nOpening the sketch in the Arduino IDE...')
            conclusion = 'arduinoOpOpenedTitle'
            out = 'arduinoOpOpenedBody'
        cli_command.append("%s" % sketch_path)
        print('CLI command: %s' % ' '.join(cli_command))
        # Python 2 needs the input to subprocess.Popen to be in system encoding
        if sys.version_info[0] < 3:
            for item in six_moves.range(len(cli_command)):
                cli_command[item] = cli_command[item].encode(
                    locale.getpreferredencoding())

        if settings.load_ide_option == 'open':
            # Open IDE in a subprocess without capturing outputs
            subprocess.Popen(cli_command, shell=False)
            # Wait a few seconds to allow IDE to open before sending back data
            time.sleep(5)
        else:
            # Launch the Arduino CLI in a subprocess and capture output data
            process = subprocess.Popen(
                cli_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                shell=False)
            out, error = process.communicate()
            out = six.u(out)
            error = six.u(error)
            exit_code = process.returncode
            print('Arduino output:\n%s' % out)
            print('Arduino Error output:\n%s' % error)
            print('Arduino Exit code: %s' % exit_code)
            # For some reason Arduino CLI can return 256 on success
            if (process.returncode != 0) and (process.returncode != 256):
                success = False
                if exit_code == 1:
                    conclusion = 'arduinoOpErrorUpVerTitle'
                elif exit_code == 2:
                    conclusion = 'arduinoOpErrorSketchTitle'
                elif exit_code == 3:
                    conclusion = 'arduinoOpErrorFlagTitle'
                elif exit_code == 4:
                    conclusion = 'arduinoOpErrorFlagPrefTitle'
                else:
                    conclusion = 'Unexpected exit error code: %s' % exit_code

    return success, conclusion, out, error, exit_code