From 861a67412b371f868098f9ccf0bf935692d6d770 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:45:00 +0100 Subject: [PATCH 1/7] Simplify getAllFilesInPath by using single glob call with multiple patterns Instead of looping through matched directories and making nested glob calls for each one, use glob's ability to accept an array of patterns. Pass both the original pattern and its recursive variant (pattern/**/*) in one call, eliminating the need for sequential async/sync operations. Co-Authored-By: Claude Opus 4.5 --- packages/js-sdk/src/template/utils.ts | 34 +++++++---------------- packages/python-sdk/e2b/template/utils.py | 33 ++++++++-------------- 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/packages/js-sdk/src/template/utils.ts b/packages/js-sdk/src/template/utils.ts index 34670767c4..be47e53b3e 100644 --- a/packages/js-sdk/src/template/utils.ts +++ b/packages/js-sdk/src/template/utils.ts @@ -86,37 +86,23 @@ export async function getAllFilesInPath( includeDirectories: boolean = true ) { const { glob } = await dynamicImport('glob') - const files = new Map() - const globFiles = await glob(src, { + // Match both the pattern and its recursive contents in one call + // This handles directories (src -> src + src/**/*) and file patterns (*.txt -> just files) + const normalizedSrc = normalizePath(src) + const patterns = [normalizedSrc, `${normalizedSrc}/**/*`] + + const globFiles = await glob(patterns, { ignore: ignorePatterns, withFileTypes: true, - // this is required so that the ignore pattern is relative to the file path + nodir: !includeDirectories, cwd: contextPath, }) + // Deduplicate by full path + const files = new Map() for (const file of globFiles) { - if (file.isDirectory()) { - // For directories, add the directory itself and all files inside it - if (includeDirectories) { - files.set(file.fullpath(), file) - } - const dirPattern = normalizePath( - // When the matched directory is '.', `file.relative()` can be an empty string. - // In that case, we want to match all files under the current directory instead of - // creating an absolute glob like '/**/*' which would traverse the entire filesystem. - path.join(file.relative() || '.', '**/*') - ) - const dirFiles = await glob(dirPattern, { - ignore: ignorePatterns, - withFileTypes: true, - cwd: contextPath, - }) - dirFiles.forEach((f) => files.set(f.fullpath(), f)) - } else { - // For files, just add the file - files.set(file.fullpath(), file) - } + files.set(file.fullpath(), file) } return Array.from(files.values()).sort() diff --git a/packages/python-sdk/e2b/template/utils.py b/packages/python-sdk/e2b/template/utils.py index 09f87ac095..e86a99ba85 100644 --- a/packages/python-sdk/e2b/template/utils.py +++ b/packages/python-sdk/e2b/template/utils.py @@ -81,36 +81,27 @@ def get_all_files_in_path( :param include_directories: Whether to include directories :return: Array of files """ - files = set() - - # Use glob to find all files/directories matching the pattern under context_path abs_context_path = os.path.abspath(context_path) + normalized_src = normalize_path(src) + + # Match both the pattern and its recursive contents in one call + # This handles directories (src -> src + src/**/*) and file patterns (*.txt -> just files) + patterns = [normalized_src, f"{normalized_src}/**/*"] + files_glob = glob.glob( - src, + patterns, flags=glob.GLOBSTAR, root_dir=abs_context_path, exclude=ignore_patterns, ) + # Deduplicate and convert to absolute paths + files = set() for file in files_glob: - # Join it with abs_context_path to get the absolute path file_path = os.path.join(abs_context_path, file) - - if os.path.isdir(file_path): - # If it's a directory, add the directory and all entries recursively - if include_directories: - files.add(file_path) - dir_files = glob.glob( - normalize_path(file) + "/**/*", - flags=glob.GLOBSTAR, - root_dir=abs_context_path, - exclude=ignore_patterns, - ) - for dir_file in dir_files: - dir_file_path = os.path.join(abs_context_path, dir_file) - files.add(dir_file_path) - else: - files.add(file_path) + if not include_directories and os.path.isdir(file_path): + continue + files.add(file_path) return sorted(list(files)) From 88f84824ef3977d8b5e6fed70713c693f922c88a Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:46:25 +0100 Subject: [PATCH 2/7] added changeset --- .changeset/itchy-planes-carry.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/itchy-planes-carry.md diff --git a/.changeset/itchy-planes-carry.md b/.changeset/itchy-planes-carry.md new file mode 100644 index 0000000000..2aefecf71a --- /dev/null +++ b/.changeset/itchy-planes-carry.md @@ -0,0 +1,6 @@ +--- +'@e2b/python-sdk': patch +'e2b': patch +--- + +simplify getAllFilesInPath function From 8c4cc3a96e8c311f4db6d0d21ecbb1ab2106e671 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:56:46 +0100 Subject: [PATCH 3/7] Fix broken symlink handling by removing nodir option The nodir option in glob can interfere with symlink type detection for broken symlinks. Instead, filter directories manually in the loop like the Python implementation does. Co-Authored-By: Claude Opus 4.5 --- packages/js-sdk/src/template/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/js-sdk/src/template/utils.ts b/packages/js-sdk/src/template/utils.ts index be47e53b3e..9dd56775fe 100644 --- a/packages/js-sdk/src/template/utils.ts +++ b/packages/js-sdk/src/template/utils.ts @@ -95,13 +95,15 @@ export async function getAllFilesInPath( const globFiles = await glob(patterns, { ignore: ignorePatterns, withFileTypes: true, - nodir: !includeDirectories, cwd: contextPath, }) // Deduplicate by full path const files = new Map() for (const file of globFiles) { + if (!includeDirectories && file.isDirectory()) { + continue + } files.set(file.fullpath(), file) } From 2bdbb4175e7758caa50768d451e207e52125a2c7 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:06:08 +0100 Subject: [PATCH 4/7] Revert JS getAllFilesInPath to original implementation The glob library has a bug where array patterns cause broken symlinks to have isSymbolicLink() return false, while single patterns work correctly. Reverting to the original nested-call approach to maintain correct symlink detection. The Python SDK simplification is retained since wcmatch may handle this differently. Co-Authored-By: Claude Opus 4.5 --- packages/js-sdk/src/template/utils.ts | 34 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/js-sdk/src/template/utils.ts b/packages/js-sdk/src/template/utils.ts index 9dd56775fe..34670767c4 100644 --- a/packages/js-sdk/src/template/utils.ts +++ b/packages/js-sdk/src/template/utils.ts @@ -86,25 +86,37 @@ export async function getAllFilesInPath( includeDirectories: boolean = true ) { const { glob } = await dynamicImport('glob') + const files = new Map() - // Match both the pattern and its recursive contents in one call - // This handles directories (src -> src + src/**/*) and file patterns (*.txt -> just files) - const normalizedSrc = normalizePath(src) - const patterns = [normalizedSrc, `${normalizedSrc}/**/*`] - - const globFiles = await glob(patterns, { + const globFiles = await glob(src, { ignore: ignorePatterns, withFileTypes: true, + // this is required so that the ignore pattern is relative to the file path cwd: contextPath, }) - // Deduplicate by full path - const files = new Map() for (const file of globFiles) { - if (!includeDirectories && file.isDirectory()) { - continue + if (file.isDirectory()) { + // For directories, add the directory itself and all files inside it + if (includeDirectories) { + files.set(file.fullpath(), file) + } + const dirPattern = normalizePath( + // When the matched directory is '.', `file.relative()` can be an empty string. + // In that case, we want to match all files under the current directory instead of + // creating an absolute glob like '/**/*' which would traverse the entire filesystem. + path.join(file.relative() || '.', '**/*') + ) + const dirFiles = await glob(dirPattern, { + ignore: ignorePatterns, + withFileTypes: true, + cwd: contextPath, + }) + dirFiles.forEach((f) => files.set(f.fullpath(), f)) + } else { + // For files, just add the file + files.set(file.fullpath(), file) } - files.set(file.fullpath(), file) } return Array.from(files.values()).sort() From 8ee2d642790af27b74366108cb785b35b60b917b Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:08:05 +0100 Subject: [PATCH 5/7] Revert Python get_all_files_in_path to original implementation The simplified version changed behavior when includeDirectories=False: - Old: Only top-level matched directories excluded, nested subdirs included - New: All directories excluded Reverting to preserve the original behavior and avoid breaking callers. Co-Authored-By: Claude Opus 4.5 --- packages/python-sdk/e2b/template/utils.py | 33 ++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/python-sdk/e2b/template/utils.py b/packages/python-sdk/e2b/template/utils.py index e86a99ba85..09f87ac095 100644 --- a/packages/python-sdk/e2b/template/utils.py +++ b/packages/python-sdk/e2b/template/utils.py @@ -81,27 +81,36 @@ def get_all_files_in_path( :param include_directories: Whether to include directories :return: Array of files """ - abs_context_path = os.path.abspath(context_path) - normalized_src = normalize_path(src) - - # Match both the pattern and its recursive contents in one call - # This handles directories (src -> src + src/**/*) and file patterns (*.txt -> just files) - patterns = [normalized_src, f"{normalized_src}/**/*"] + files = set() + # Use glob to find all files/directories matching the pattern under context_path + abs_context_path = os.path.abspath(context_path) files_glob = glob.glob( - patterns, + src, flags=glob.GLOBSTAR, root_dir=abs_context_path, exclude=ignore_patterns, ) - # Deduplicate and convert to absolute paths - files = set() for file in files_glob: + # Join it with abs_context_path to get the absolute path file_path = os.path.join(abs_context_path, file) - if not include_directories and os.path.isdir(file_path): - continue - files.add(file_path) + + if os.path.isdir(file_path): + # If it's a directory, add the directory and all entries recursively + if include_directories: + files.add(file_path) + dir_files = glob.glob( + normalize_path(file) + "/**/*", + flags=glob.GLOBSTAR, + root_dir=abs_context_path, + exclude=ignore_patterns, + ) + for dir_file in dir_files: + dir_file_path = os.path.join(abs_context_path, dir_file) + files.add(dir_file_path) + else: + files.add(file_path) return sorted(list(files)) From 776954b2cfb692eddcde102441022f6bb39e2272 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:08:23 +0100 Subject: [PATCH 6/7] Remove changeset (no code changes) --- .changeset/itchy-planes-carry.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .changeset/itchy-planes-carry.md diff --git a/.changeset/itchy-planes-carry.md b/.changeset/itchy-planes-carry.md deleted file mode 100644 index 2aefecf71a..0000000000 --- a/.changeset/itchy-planes-carry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@e2b/python-sdk': patch -'e2b': patch ---- - -simplify getAllFilesInPath function From d29fb7fcc815a3413341d7b55691de39e6c07099 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:13:32 +0100 Subject: [PATCH 7/7] Simplify getAllFilesInPath by using single glob call with multiple patterns Instead of looping through matched directories and making nested glob calls for each one, use glob's ability to accept an array of patterns. Pass both the original pattern and its recursive variant (pattern/**/*) in one call. Note: This changes the behavior of includeDirectories - it now excludes ALL directories when false, not just top-level matched directories. This is the desired behavior for file copying operations. Co-Authored-By: Claude Opus 4.5 --- packages/js-sdk/src/template/utils.ts | 34 +++++++---------------- packages/python-sdk/e2b/template/utils.py | 33 ++++++++-------------- 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/packages/js-sdk/src/template/utils.ts b/packages/js-sdk/src/template/utils.ts index 34670767c4..be47e53b3e 100644 --- a/packages/js-sdk/src/template/utils.ts +++ b/packages/js-sdk/src/template/utils.ts @@ -86,37 +86,23 @@ export async function getAllFilesInPath( includeDirectories: boolean = true ) { const { glob } = await dynamicImport('glob') - const files = new Map() - const globFiles = await glob(src, { + // Match both the pattern and its recursive contents in one call + // This handles directories (src -> src + src/**/*) and file patterns (*.txt -> just files) + const normalizedSrc = normalizePath(src) + const patterns = [normalizedSrc, `${normalizedSrc}/**/*`] + + const globFiles = await glob(patterns, { ignore: ignorePatterns, withFileTypes: true, - // this is required so that the ignore pattern is relative to the file path + nodir: !includeDirectories, cwd: contextPath, }) + // Deduplicate by full path + const files = new Map() for (const file of globFiles) { - if (file.isDirectory()) { - // For directories, add the directory itself and all files inside it - if (includeDirectories) { - files.set(file.fullpath(), file) - } - const dirPattern = normalizePath( - // When the matched directory is '.', `file.relative()` can be an empty string. - // In that case, we want to match all files under the current directory instead of - // creating an absolute glob like '/**/*' which would traverse the entire filesystem. - path.join(file.relative() || '.', '**/*') - ) - const dirFiles = await glob(dirPattern, { - ignore: ignorePatterns, - withFileTypes: true, - cwd: contextPath, - }) - dirFiles.forEach((f) => files.set(f.fullpath(), f)) - } else { - // For files, just add the file - files.set(file.fullpath(), file) - } + files.set(file.fullpath(), file) } return Array.from(files.values()).sort() diff --git a/packages/python-sdk/e2b/template/utils.py b/packages/python-sdk/e2b/template/utils.py index 09f87ac095..e86a99ba85 100644 --- a/packages/python-sdk/e2b/template/utils.py +++ b/packages/python-sdk/e2b/template/utils.py @@ -81,36 +81,27 @@ def get_all_files_in_path( :param include_directories: Whether to include directories :return: Array of files """ - files = set() - - # Use glob to find all files/directories matching the pattern under context_path abs_context_path = os.path.abspath(context_path) + normalized_src = normalize_path(src) + + # Match both the pattern and its recursive contents in one call + # This handles directories (src -> src + src/**/*) and file patterns (*.txt -> just files) + patterns = [normalized_src, f"{normalized_src}/**/*"] + files_glob = glob.glob( - src, + patterns, flags=glob.GLOBSTAR, root_dir=abs_context_path, exclude=ignore_patterns, ) + # Deduplicate and convert to absolute paths + files = set() for file in files_glob: - # Join it with abs_context_path to get the absolute path file_path = os.path.join(abs_context_path, file) - - if os.path.isdir(file_path): - # If it's a directory, add the directory and all entries recursively - if include_directories: - files.add(file_path) - dir_files = glob.glob( - normalize_path(file) + "/**/*", - flags=glob.GLOBSTAR, - root_dir=abs_context_path, - exclude=ignore_patterns, - ) - for dir_file in dir_files: - dir_file_path = os.path.join(abs_context_path, dir_file) - files.add(dir_file_path) - else: - files.add(file_path) + if not include_directories and os.path.isdir(file_path): + continue + files.add(file_path) return sorted(list(files))