8000 Add working_directory for subsequent code file · adafruit/circuitpython@3377765 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3377765

Browse files
committed
Add working_directory for subsequent code file
This allows subfolders to be treated similar to / for multiple apps within different folders. Also, fix up the internal current working directory so it doesn't depend on volumes. Fixes #9045 and fixes #8409.
1 parent 443f829 commit 3377765

File tree

13 files changed

+189
-27
lines changed

13 files changed

+189
-27
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
[submodule "ports/raspberrypi/sdk"]
174174
path = ports/raspberrypi/sdk
175175
url = https://github.com/adafruit/pico-sdk.git
176-
branch = force_inline_critical_section
176+
branch = force_inline_critical_section_2.1.1
177177
[submodule "data/nvm.toml"]
178178
path = data/nvm.toml
179179
url = https://github.com/adafruit/nvm.toml.git

extmod/vfs_fat.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
// CIRCUITPY-CHANGE: extra includes
4040
#include <string.h>
41+
#include "py/gc.h"
4142
#include "py/obj.h"
4243
#include "py/objproperty.h"
4344
#include "py/runtime.h"
@@ -342,7 +343,10 @@ static mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
342343
FRESULT res = f_stat(&self->fatfs, path, &fno);
343344
if (res != FR_OK) {
344345
// CIRCUITPY-CHANGE
345-
mp_raise_OSError_fresult(res);
346+
if (gc_alloc_possible()) {
347+
mp_raise_OSError_fresult(res);
348+
}
349+
return mp_const_none;
346350
}
347351
}
348352

main.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,14 +457,19 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s
457457
usb_setup_with_vm();
458458
#endif
459459

460+
// Always return to root before trying to run files.
461+
common_hal_os_chdir("/");
460462
// Check if a different run file has been allocated
461463
if (next_code_configuration != NULL) {
462464
next_code_configuration->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
463465
next_code_options = next_code_configuration->options;
464466
if (next_code_configuration->filename[0] != '\0') {
467+
if (next_code_configuration->working_directory != NULL) {
468+
common_hal_os_chdir(next_code_configuration->working_directory);
469+
}
465470
// This is where the user's python code is actually executed:
466471
const char *const filenames[] = { next_code_configuration->filename };
467-
found_main = maybe_run_list(filenames, MP_ARRAY_SIZE(filenames));
472+
found_main = maybe_run_list(filenames, 1);
468473
if (!found_main) {
469474
serial_write(next_code_configuration->filename);
470475
serial_write_compressed(MP_ERROR_TEXT(" not found.\n"));
@@ -1105,9 +1110,6 @@ int __attribute__((used)) main(void) {
11051110
}
11061111
simulate_reset = false;
11071112

1108-
// Always return to root before trying to run files.
1109-
common_hal_os_chdir("/");
1110-
11111113
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
11121114
// If code.py did a fake deep sleep, pretend that we
11131115
// are running code.py for the first time after a hard

ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ SPI_FLASH_FILESYSTEM = 1
1010
EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ"
1111
LONGINT_IMPL = MPZ
1212

13+
CIRCUITPY_CODEOP = 0
1314
CIRCUITPY_JPEGIO = 0

ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ CHIP_FAMILY = samd21
99
SPI_FLASH_FILESYSTEM = 1
1010
EXTERNAL_FLASH_DEVICES = "S25FL064L"
1111
LONGINT_IMPL = MPZ
12+
13+
CIRCUITPY_CODEOP = 0

shared-bindings/os/__init__.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdbool.h>
1111

1212
#include "py/objtuple.h"
13+
#include "shared-module/os/__init__.h"
1314

1415
void common_hal_os_chdir(const char *path);
1516
mp_obj_t common_hal_os_getcwd(void);

shared-bindings/supervisor/__init__.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
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"
@@ -25,6 +26,7 @@
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);
99102
static 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
}

shared-bindings/supervisor/__init__.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#pragma once
88

9+
#include <stddef.h>
10+
#include <stdint.h>
911
// #include "py/mpconfig.h"
1012
#include "py/obj.h"
1113

@@ -18,7 +20,8 @@
1820

1921
typedef struct {
2022
uint8_t options;
21-
char filename[];
23+
const char *working_directory;
24+
const char *filename;
2225
} supervisor_next_code_info_t;
2326

2427
extern const super_runtime_obj_t common_hal_supervisor_runtime_obj;

shared-bindings/util.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "shared-bindings/util.h"
1010

11+
#include "shared-bindings/os/__init__.h"
12+
1113
// If so, deinit() has already been called on the object, so complain.
1214
void raise_deinited_error(void) {
1315
mp_raise_ValueError(MP_ERROR_TEXT("Object has been deinitialized and can no longer be used. Create a new object."));
@@ -33,3 +35,16 @@ void properties_construct_helper(mp_obj_t self_in, const mp_arg_t *args, const m
3335
}
3436
}
3537
}
38+
39+
bool path_exists(const char *path) {
40+
// Use common_hal_os_stat to check if path exists
41+
nlr_buf_t nlr;
42+
if (nlr_push(&nlr) == 0) {
43+
common_hal_os_stat(path);
44+
nlr_pop();
45+
return true;
46+
} else {
47+
// Path doesn't exist
48+
return false;
49+
}
50+
}

shared-bindings/util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
NORETURN void raise_deinited_error(void);
1313
void properties_print_helper(const mp_print_t *print, mp_obj_t self_in, const mp_arg_t *properties, size_t n_properties);
1414
void properties_construct_helper(mp_obj_t self_in, const mp_arg_t *args, const mp_arg_val_t *vals, size_t n_properties);
15+
bool path_exists(const char *path);

0 commit comments

Comments
 (0)
0