33// SPDX-FileCopyrightText: Copyright (c) 2016-2017 Scott Shawcroft for Adafruit Industries
44//
55// SPDX-License-Identifier: MIT
6+ #include <stddef.h>
67#include <string.h>
78
89#include "py/obj.h"
2526#include "shared-bindings/time/__init__.h"
2627#include "shared-bindings/supervisor/Runtime.h"
2728#include "shared-bindings/supervisor/StatusBar.h"
29+ #include "shared-bindings/util.h"
2830
2931//| """Supervisor settings"""
3032//|
@@ -57,6 +59,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
5759//| def set_next_code_file(
5860//| filename: Optional[str],
5961//| *,
62+ //| working_directory: Optional[str] = None,
6063//| reload_on_success: bool = False,
6164//| reload_on_error: bool = False,
6265//| sticky_on_success: bool = False,
@@ -99,6 +102,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
99102static mp_obj_t supervisor_set_next_code_file (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
100103 static const mp_arg_t allowed_args [] = {
101104 { MP_QSTR_filename , MP_ARG_REQUIRED | MP_ARG_OBJ , {.u_rom_obj = mp_const_none } },
105+ { MP_QSTR_working_directory , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_rom_obj = mp_const_none } },
102106 { MP_QSTR_reload_on_success , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
103107 { MP_QSTR_reload_on_error , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
104108 { MP_QSTR_sticky_on_success , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
@@ -107,6 +111,7 @@ static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
107111 };
108112 struct {
109113 mp_arg_val_t filename ;
114+ mp_arg_val_t working_directory ;
110115 mp_arg_val_t reload_on_success ;
111116 mp_arg_val_t reload_on_error ;
112117 mp_arg_val_t sticky_on_success ;
@@ -118,6 +123,11 @@ static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
118123 if (!mp_obj_is_str_or_bytes (filename_obj ) && filename_obj != mp_const_none ) {
119124 mp_raise_TypeError_varg (MP_ERROR_TEXT ("%q must be of type %q or %q, not %q" ), MP_QSTR_filename , MP_QSTR_str , MP_QSTR_None , mp_obj_get_type (filename_obj )-> name );
120125 }
126+
127+ mp_obj_t working_directory_obj = args .working_directory .u_obj ;
128+ if (!mp_obj_is_str_or_bytes (working_directory_obj ) && working_directory_obj != mp_const_none ) {
129+ mp_raise_TypeError_varg (MP_ERROR_TEXT ("%q must be of type %q or %q, not %q" ), MP_QSTR_working_directory , MP_QSTR_str , MP_QSTR_None , mp_obj_get_type (working_directory_obj )-> name );
130+ }
121131 if (filename_obj == mp_const_none ) {
122132 filename_obj = mp_const_empty_bytes ;
123133 }
@@ -139,18 +149,50 @@ static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
139149 }
140150 size_t len ;
141151 const char * filename = mp_obj_str_get_data (filename_obj , & len );
152+ if (!path_exists (filename )) {
153+ mp_raise_ValueError (MP_ERROR_TEXT ("File not found" ));
154+ }
155+
156+ size_t working_directory_len = 0 ;
157+ const char * working_directory = NULL ;
158+ if (working_directory_obj != mp_const_none ) {
159+ working_directory = mp_obj_str_get_data (working_directory_obj , & working_directory_len );
160+ if (!path_exists (working_directory )) {
161+ mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q" ), MP_QSTR_working_directory );
162+ }
163+ }
142164 if (next_code_configuration != NULL ) {
143165 port_free (next_code_configuration );
144166 next_code_configuration = NULL ;
145167 }
146168 if (options != 0 || len != 0 ) {
147- next_code_configuration = port_malloc (sizeof (supervisor_next_code_info_t ) + len + 1 , false);
169+
170+ size_t next_code_size = sizeof (supervisor_next_code_info_t ) + len + 1 ;
171+ if (working_directory_len > 0 ) {
172+ next_code_size += working_directory_len + 1 ;
173+ }
174+ next_code_configuration = port_malloc (next_code_size , false);
148175 if (next_code_configuration == NULL ) {
149- m_malloc_fail (sizeof (supervisor_next_code_info_t ) + len + 1 );
176+ m_malloc_fail (next_code_size );
177+ }
178+ char * filename_ptr = (char * )next_code_configuration + sizeof (supervisor_next_code_info_t );
179+
180+ // Copy filename
181+ memcpy (filename_ptr , filename , len );
182+ filename_ptr [len ] = '\0' ;
183+
184+ char * working_directory_ptr = NULL ;
185+ // Copy working directory after filename if present
186+ if (working_directory_len > 0 ) {
187+ working_directory_ptr = filename_ptr + len + 1 ;
188+ memcpy (working_directory_ptr , working_directory , working_directory_len );
189+ working_directory_ptr [working_directory_len ] = '\0' ;
150190 }
191+ // Set everything up last. We may have raised an exception early and we
192+ // don't want to free the memory if we failed.
193+ next_code_configuration -> filename = filename_ptr ;
194+ next_code_configuration -> working_directory = working_directory_ptr ;
151195 next_code_configuration -> options = options | SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET ;
152- memcpy (& next_code_configuration -> filename , filename , len );
153- next_code_configuration -> filename [len ] = '\0' ;
154196 }
155197 return mp_const_none ;
156198}
0 commit comments