8000 Add working_directory for subsequent code file by tannewt · Pull Request #10263 · adafruit/circuitpython · GitHub
[go: up one dir, main page]

Skip to content

Add working_directory for subsequent code file #10263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
[submodule "ports/raspberrypi/sdk"]
path = ports/raspberrypi/sdk
url = https://github.com/adafruit/pico-sdk.git
branch = force_inline_critical_section
branch = force_inline_critical_section_2.1.1
[submodule "data/nvm.toml"]
path = data/nvm.toml
url = https://github.com/adafruit/nvm.toml.git
Expand Down
6 changes: 5 additions & 1 deletion extmod/vfs_fat.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

// CIRCUITPY-CHANGE: extra includes
#include <string.h>
#include "py/gc.h"
#include "py/obj.h"
#include "py/objproperty.h"
#include "py/runtime.h"
Expand Down Expand Up @@ -342,7 +343,10 @@ static mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
FRESULT res = f_stat(&self->fatfs, path, &fno);
if (res != FR_OK) {
// CIRCUITPY-CHANGE
mp_raise_OSError_fresult(res);
if (gc_alloc_possible()) {
mp_raise_OSError_fresult(res);
}
return mp_const_none;
}
}

Expand Down
10 changes: 6 additions & 4 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,19 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s
usb_setup_with_vm();
#endif

// Always return to root before trying to run files.
common_hal_os_chdir("/");
// Check if a different run file has been allocated
if (next_code_configuration != NULL) {
next_code_configuration->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
next_code_options = next_code_configuration->options;
if (next_code_configuration->filename[0] != '\0') {
if (next_code_configuration->working_directory != NULL) {
common_hal_os_chdir(next_code_configuration->working_directory);
}
// This is where the user's python code is actually executed:
const char *const filenames[] = { next_code_configuration->filename };
found_main = maybe_run_list(filenames, MP_ARRAY_SIZE(filenames));
found_main = maybe_run_list(filenames, 1);
if (!found_main) {
serial_write(next_code_configuration->filename);
serial_write_compressed(MP_ERROR_TEXT(" not found.\n"));
Expand Down Expand Up @@ -1105,9 +1110,6 @@ int __attribute__((used)) main(void) {
}
simulate_reset = false;

// Always return to root before trying to run files.
common_hal_os_chdir("/");

if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
// If code.py did a fake deep sleep, pretend that we
// are running code.py for the first time after a hard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ SPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ"
LONGINT_IMPL = MPZ

CIRCUITPY_CODEOP = 0
CIRCUITPY_JPEGIO = 0
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ, S25FL064L"
LONGINT_IMPL = MPZ

CIRCUITPY_I2CTARGET = 0
CIRCUITPY_PS2IO = 1
CIRCUITPY_JPEGIO = 0
CIRCUITPY_SPITARGET = 0
Expand Down
4 changes: 3 additions & 1 deletion ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ CHIP_FAMILY = samd51
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ, W25Q16JVxM"
LONGINT_IMPL = MPZ
CIRCUITPY_SYNTHIO = 0

CIRCUITPY_I2CTARGET = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_SPITARGET = 0
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_TILEPALETTEMAPPER = 0
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ CHIP_FAMILY = samd21
SPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "S25FL064L"
LONGINT_IMPL = MPZ

CIRCUITPY_CODEOP = 0
3 changes: 2 additions & 1 deletion ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ CIRCUITPY__EVE = 1
CIRCUITPY_BITMAPFILTER = 0
CIRCUITPY_CANIO = 1
CIRCUITPY_FLOPPYIO = 0
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_GIFIO = 0
CIRCUITPY_I2CTARGET = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_SYNTHIO = 0

CIRCUITPY_LTO_PARTITION = one

Expand Down
5 changes: 3 additions & 2 deletions ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = GD25Q16C
LONGINT_IMPL = MPZ

CIRCUITPY_FLOPPYIO = 0
CIRCUITPY_I2CTARGET = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_KEYPAD = 1
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_FLOPPYIO = 0
CIRCUITPY_TERMINALIO_VT100 = 0
CIRCUITPY_TILEPALETTEMAPPER = 0
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = GD25Q16C
LONGINT_IMPL = MPZ

CIRCUITPY_I2CTARGET = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_SPITARGET = 0
CIRCUITPY_SYNTHIO = 0
Expand Down
2 changes: 2 additions & 0 deletions ports/atmel-samd/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
// See https://github.com/micropython/micropython/pull/11353
#define MICROPY_NLR_THUMB_USE_LONG_JUMP (1)

// Don't store qstr hashes and do string compares instead.
#define MICROPY_QSTR_BYTES_IN_HASH (0)

#endif // SAMD21

Expand Down
2 changes: 2 additions & 0 deletions py/circuitpy_mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ extern void common_hal_mcu_enable_interrupts(void);
#define MICROPY_PY___FILE__ (1)

#if CIRCUITPY_FULL_BUILD
#ifndef MICROPY_QSTR_BYTES_IN_HASH
#define MICROPY_QSTR_BYTES_IN_HASH (1)
#endif
#else
#define MICROPY_QSTR_BYTES_IN_HASH (0)
#endif
Expand Down
1 change: 1 addition & 0 deletions shared-bindings/os/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdbool.h>

#include "py/objtuple.h"
#include "shared-module/os/__init__.h"

void common_hal_os_chdir(const char *path);
mp_obj_t common_hal_os_getcwd(void);
Expand Down
50 changes: 46 additions & 4 deletions shared-bindings/supervisor/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2016-2017 Scott Shawcroft for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <stddef.h>
#include <string.h>

#include "py/obj.h"
Expand All @@ -25,6 +26,7 @@
#include "shared-bindings/time/__init__.h"
#include "shared-bindings/supervisor/Runtime.h"
#include "shared-bindings/supervisor/StatusBar.h"
#include "shared-bindings/util.h"

//| """Supervisor settings"""
//|
Expand Down Expand Up @@ -57,6 +59,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
//| def set_next_code_file(
//| filename: Optional[str],
//| *,
//| working_directory: Optional[str] = None,
//| reload_on_success: bool = False,
//| reload_on_error: bool = False,
//| sticky_on_success: bool = False,
Expand Down Expand Up @@ -99,6 +102,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_filename, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_working_directory, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_reload_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_reload_on_error, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_sticky_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
Expand All @@ -107,6 +111,7 @@ static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
};
struct {
mp_arg_val_t filename;
mp_arg_val_t working_directory;
mp_arg_val_t reload_on_success;
mp_arg_val_t reload_on_error;
mp_arg_val_t sticky_on_success;
Expand All @@ -118,6 +123,11 @@ static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
if (!mp_obj_is_str_or_bytes(filename_obj) && filename_obj != mp_const_none) {
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);
}

mp_obj_t working_directory_obj = args.working_directory.u_obj;
if (!mp_obj_is_str_or_bytes(working_directory_obj) && working_directory_obj != mp_const_none) {
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);
}
if (filename_obj == mp_const_none) {
filename_obj = mp_const_empty_bytes;
}
Expand All @@ -139,18 +149,50 @@ static mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
}
size_t len;
const char *filename = mp_obj_str_get_data(filename_obj, &len);
if (!path_exists(filename)) {
mp_raise_ValueError(MP_ERROR_TEXT("File not found"));
}

size_t working_directory_len = 0;
const char *working_directory = NULL;
if (working_directory_obj != mp_const_none) {
working_directory = mp_obj_str_get_data(working_directory_obj, &working_directory_len);
if (!path_exists(working_directory)) {
mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_working_directory);
}
}
if (next_code_configuration != NULL) {
port_free(next_code_configuration);
next_code_configuration = NULL;
}
if (options != 0 || len != 0) {
next_code_configuration = port_malloc(sizeof(supervisor_next_code_info_t) + len + 1, false);

size_t next_code_size = sizeof(supervisor_next_code_info_t) + len + 1;
if (working_directory_len > 0) {
next_code_size += working_directory_len + 1;
}
next_code_configuration = port_malloc(next_code_size, false);
if (next_code_configuration == NULL) {
m_malloc_fail(sizeof(supervisor_next_code_info_t) + len + 1);
m_malloc_fail(next_code_size);
}
char *filename_ptr = (char *)next_code_configuration + sizeof(supervisor_next_code_info_t);

// Copy filename
memcpy(filename_ptr, filename, len);
filename_ptr[len] = '\0';

char *working_directory_ptr = NULL;
// Copy working directory after filename if present
if (working_directory_len > 0) {
working_directory_ptr = filename_ptr + len + 1;
memcpy(working_directory_ptr, working_directory, working_directory_len);
working_directory_ptr[working_directory_len] = '\0';
}
F438 // Set everything up last. We may have raised an exception early and we
// don't want to free the memory if we failed.
next_code_configuration->filename = filename_ptr;
next_code_configuration->working_directory = working_directory_ptr;
next_code_configuration->options = options | SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
memcpy(&next_code_configuration->filename, filename, len);
next_code_configuration->filename[len] = '\0';
}
return mp_const_none;
}
Expand Down
5 changes: 4 additions & 1 deletion shared-bindings/supervisor/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#pragma once

#include <stddef.h>
#include <stdint.h>
// #include "py/mpconfig.h"
#include "py/obj.h"

Expand All @@ -18,7 +20,8 @@

typedef struct {
uint8_t options;
char filename[];
const char *working_directory;
const char *filename;
} supervisor_next_code_info_t;

extern const super_runtime_obj_t common_hal_supervisor_runtime_obj;
Expand Down
15 changes: 15 additions & 0 deletions shared-bindings/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "shared-bindings/util.h"

#include "shared-bindings/os/__init__.h"

// If so, deinit() has already been called on the object, so complain.
void raise_deinited_error(void) {
mp_raise_ValueError(MP_ERROR_TEXT("Object has been deinitialized and can no longer be used. Create a new object."));
Expand All @@ -33,3 +35,16 @@ void properties_construct_helper(mp_obj_t self_in, const mp_arg_t *args, const m
}
}
}

bool path_exists(const char *path) {
// Use common_hal_os_stat to check if path exists
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
common_hal_os_stat(path);
nlr_pop();
return true;
} else {
// Path doesn't exist
return false;
}
}
1 change: 1 addition & 0 deletions shared-bindings/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
NORETURN void raise_deinited_error(void);
void properties_print_helper(const mp_print_t *print, mp_obj_t self_in, const mp_arg_t *properties, size_t n_properties);
void properties_construct_helper(mp_obj_t self_in, const mp_arg_t *args, const mp_arg_val_t *vals, size_t n_properties);
bool path_exists(const char *path);
Loading
Loading
0