Class: Daytona::FileSystem

Inherits:
Object
  • Object
show all
Includes:
Instrumentation
Defined in:
lib/daytona/file_system.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Instrumentation

included

Constructor Details

#initialize(sandbox_id:, toolbox_api:, otel_state: nil) ⇒ FileSystem

Initializes a new FileSystem instance.

Parameters:

  • sandbox_id (String)

    The Sandbox ID

  • toolbox_api (DaytonaToolboxApiClient::FileSystemApi)

    API client for Sandbox operations

  • otel_state (Daytona::OtelState, nil) (defaults to: nil)


21
22
23
24
25
# File 'lib/daytona/file_system.rb', line 21

def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
  @sandbox_id = sandbox_id
  @toolbox_api = toolbox_api
  @otel_state = otel_state
end

Instance Attribute Details

#sandbox_idString (readonly)

Returns The Sandbox ID.

Returns:

  • (String)

    The Sandbox ID



11
12
13
# File 'lib/daytona/file_system.rb', line 11

def sandbox_id
  @sandbox_id
end

#toolbox_apiDaytonaToolboxApiClient::FileSystemApi (readonly)

Returns API client for Sandbox operations.

Returns:

  • (DaytonaToolboxApiClient::FileSystemApi)

    API client for Sandbox operations



14
15
16
# File 'lib/daytona/file_system.rb', line 14

def toolbox_api
  @toolbox_api
end

Instance Method Details

#create_folder(path, mode) ⇒ void

This method returns an undefined value.

Creates a new directory in the Sandbox at the specified path with the given permissions.

Examples:

# Create a directory with standard permissions
sandbox.fs.create_folder("workspace/data", "755")

# Create a private directory
sandbox.fs.create_folder("workspace/secrets", "700")

Parameters:

  • path (String)

    Path where the folder should be created. Relative paths are resolved based on the sandbox working directory.

  • mode (String)

    Folder permissions in octal format (e.g., “755” for rwxr-xr-x).

Raises:



42
43
44
45
46
47
# File 'lib/daytona/file_system.rb', line 42

def create_folder(path, mode)
  Sdk.logger.debug("Creating folder #{path} with mode #{mode}")
  toolbox_api.create_folder(path, mode)
rescue StandardError => e
  raise Sdk::Error, "Failed to create folder: #{e.message}"
end

#delete_file(path, recursive: false) ⇒ void

This method returns an undefined value.

Deletes a file from the Sandbox.

Examples:

# Delete a file
sandbox.fs.delete_file("workspace/data/old_file.txt")

# Delete a directory recursively
sandbox.fs.delete_file("workspace/old_dir", recursive: true)

Parameters:

  • path (String)

    Path to the file to delete. Relative paths are resolved based on the sandbox working directory.

  • recursive (Boolean) (defaults to: false)

    If the file is a directory, this must be true to delete it.

Raises:



62
63
64
65
66
# File 'lib/daytona/file_system.rb', line 62

def delete_file(path, recursive: false)
  toolbox_api.delete_file(path, { recursive: })
rescue StandardError => e
  raise Sdk::Error, "Failed to delete file: #{e.message}"
end

#download_file(remote_path, local_path = nil) ⇒ File?

Downloads a file from the Sandbox. Returns the file contents as a string. This method is useful when you want to load the file into memory without saving it to disk. It can only be used for smaller files.

Examples:

# Download and get file content
content = sandbox.fs.download_file("workspace/data/file.txt")
puts content

# Download and save a file locally
sandbox.fs.download_file("workspace/data/file.txt", "local_copy.txt")
size_mb = File.size("local_copy.txt") / 1024.0 / 1024.0
puts "Size of the downloaded file: #{size_mb} MB"

Parameters:

  • remote_path (String)

    Path to the file in the Sandbox. Relative paths are resolved based on the sandbox working directory.

  • local_path (String, nil) (defaults to: nil)

    Optional path to save the file locally. If provided, the file will be saved to disk.

Returns:

  • (File, nil)

    The file if local_path is nil, otherwise nil

Raises:



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/daytona/file_system.rb', line 136

def download_file(remote_path, local_path = nil) # rubocop:disable Metrics/MethodLength
  file = toolbox_api.download_file(remote_path)

  if local_path

    parent_dir = File.dirname(local_path)
    FileUtils.mkdir_p(parent_dir) unless parent_dir == '.'

    File.binwrite(local_path, file.open.read)
    nil
  else
    file
  end
rescue StandardError => e
  raise Sdk::Error, "Failed to download file: #{e.message}"
end

#find_files(path, pattern) ⇒ Array<DaytonaApiClient::Match>

Searches for files containing a pattern, similar to the grep command.

Examples:

# Search for TODOs in Ruby files
matches = sandbox.fs.find_files("workspace/src", "TODO:")
matches.each do |match|
  puts "#{match.file}:#{match.line}: #{match.content.strip}"
end

Parameters:

  • path (String)

    Path to the file or directory to search. If the path is a directory, the search will be performed recursively. Relative paths are resolved based on the sandbox working directory.

  • pattern (String)

    Search pattern to match against file contents.

Returns:

  • (Array<DaytonaApiClient::Match>)

    List of matches found in files

Raises:



229
230
231
232
233
# File 'lib/daytona/file_system.rb', line 229

def find_files(path, pattern)
  toolbox_api.find_in_files(path, pattern)
rescue StandardError => e
  raise Sdk::Error, "Failed to find files: #{e.message}"
end

#get_file_info(path) ⇒ DaytonaApiClient::FileInfo

Gets detailed information about a file or directory, including its size, permissions, and timestamps.

Examples:

# Get file metadata
info = sandbox.fs.get_file_info("workspace/data/file.txt")
puts "Size: #{info.size} bytes"
puts "Modified: #{info.mod_time}"
puts "Mode: #{info.mode}"

# Check if path is a directory
info = sandbox.fs.get_file_info("workspace/data")
puts "Path is a directory" if info.is_dir

Parameters:

  • path (String)

    Path to the file or directory. Relative paths are resolved based on the sandbox working directory.

Returns:

  • (DaytonaApiClient::FileInfo)

    Detailed file information

Raises:



86
87
88
89
90
# File 'lib/daytona/file_system.rb', line 86

def get_file_info(path)
  toolbox_api.get_file_info(path)
rescue StandardError => e
  raise Sdk::Error, "Failed to get file info: #{e.message}"
end

#list_files(path) ⇒ Array<DaytonaApiClient::FileInfo>

Lists files and directories in a given path and returns their information, similar to the ls -l command.

Examples:

# List directory contents
files = sandbox.fs.list_files("workspace/data")

# Print files and their sizes
files.each do |file|
  puts "#{file.name}: #{file.size} bytes" unless file.is_dir
end

# List only directories
dirs = files.select(&:is_dir)
puts "Subdirectories: #{dirs.map(&:name).join(', ')}"

Parameters:

  • path (String)

    Path to the directory to list contents from. Relative paths are resolved based on the sandbox working directory.

Returns:

  • (Array<DaytonaApiClient::FileInfo>)

    List of file and directory information

Raises:



111
112
113
114
115
# File 'lib/daytona/file_system.rb', line 111

def list_files(path)
  toolbox_api.list_files({ path: })
rescue StandardError => e
  raise Sdk::Error, "Failed to list files: #{e.message}"
end

#move_files(source, destination) ⇒ void

This method returns an undefined value.

Moves or renames a file or directory. The parent directory of the destination must exist.

Examples:

# Rename a file
sandbox.fs.move_files(
  "workspace/data/old_name.txt",
  "workspace/data/new_name.txt"
)

# Move a file to a different directory
sandbox.fs.move_files(
  "workspace/data/file.txt",
  "workspace/archive/file.txt"
)

# Move a directory
sandbox.fs.move_files(
  "workspace/old_dir",
  "workspace/new_dir"
)

Parameters:

  • source (String)

    Path to the source file or directory. Relative paths are resolved based on the sandbox working directory.

  • destination (String)

    Path to the destination. Relative paths are resolved based on the sandbox working directory.

Raises:



286
287
288
289
290
# File 'lib/daytona/file_system.rb', line 286

def move_files(source, destination)
  toolbox_api.move_file(source, destination)
rescue StandardError => e
  raise Sdk::Error, "Failed to move files: #{e.message}"
end

#replace_in_files(files:, pattern:, new_value:) ⇒ Array<DaytonaApiClient::ReplaceResult>

Performs search and replace operations across multiple files.

Examples:

# Replace in specific files
results = sandbox.fs.replace_in_files(
  files: ["workspace/src/file1.rb", "workspace/src/file2.rb"],
  pattern: "old_function",
  new_value: "new_function"
)

# Print results
results.each do |result|
  if result.success
    puts "#{result.file}: #{result.success}"
  else
    puts "#{result.file}: #{result.error}"
  end
end

Parameters:

  • files (Array<String>)

    List of file paths to perform replacements in. Relative paths are resolved based on the sandbox working directory.

  • pattern (String)

    Pattern to search for.

  • new_value (String)

    Text to replace matches with.

Returns:

  • (Array<DaytonaApiClient::ReplaceResult>)

    List of results indicating replacements made in each file

Raises:



317
318
319
320
321
322
323
324
325
326
# File 'lib/daytona/file_system.rb', line 317

def replace_in_files(files:, pattern:, new_value:)
  replace_request = DaytonaApiClient::ReplaceRequest.new(
    files: files,
    pattern: pattern,
    new_value: new_value
  )
  toolbox_api.replace_in_files(replace_request)
rescue StandardError => e
  raise Sdk::Error, "Failed to replace in files: #{e.message}"
end

#search_files(path, pattern) ⇒ DaytonaApiClient::SearchFilesResponse

Searches for files and directories whose names match the specified pattern. The pattern can be a simple string or a glob pattern.

Examples:

# Find all Ruby files
result = sandbox.fs.search_files("workspace", "*.rb")
result.files.each { |file| puts file }

# Find files with specific prefix
result = sandbox.fs.search_files("workspace/data", "test_*")
puts "Found #{result.files.length} test files"

Parameters:

  • path (String)

    Path to the root directory to start search from. Relative paths are resolved based on the sandbox working directory.

  • pattern (String)

    Pattern to match against file names. Supports glob patterns (e.g., “*.rb” for Ruby files).

Returns:

  • (DaytonaApiClient::SearchFilesResponse)

Raises:



253
254
255
256
257
# File 'lib/daytona/file_system.rb', line 253

def search_files(path, pattern)
  toolbox_api.search_files(path, pattern)
rescue StandardError => e
  raise Sdk::Error, "Failed to search files: #{e.message}"
end

#set_file_permissions(path:, mode: nil, owner: nil, group: nil) ⇒ void

This method returns an undefined value.

Sets permissions and ownership for a file or directory. Any of the parameters can be nil to leave that attribute unchanged.

Examples:

# Make a file executable
sandbox.fs.set_file_permissions(
  path: "workspace/scripts/run.sh",
  mode: "755"  # rwxr-xr-x
)

# Change file owner
sandbox.fs.set_file_permissions(
  path: "workspace/data/file.txt",
  owner: "daytona",
  group: "daytona"
)

Parameters:

  • path (String)

    Path to the file or directory. Relative paths are resolved based on the sandbox working directory.

  • mode (String, nil) (defaults to: nil)

    File mode/permissions in octal format (e.g., “644” for rw-r–r–).

  • owner (String, nil) (defaults to: nil)

    User owner of the file.

  • group (String, nil) (defaults to: nil)

    Group owner of the file.

Raises:



352
353
354
355
356
357
358
359
360
361
# File 'lib/daytona/file_system.rb', line 352

def set_file_permissions(path:, mode: nil, owner: nil, group: nil)
  opts = {}
  opts[:mode] = mode if mode
  opts[:owner] = owner if owner
  opts[:group] = group if group

  toolbox_api.set_file_permissions(path, opts)
rescue StandardError => e
  raise Sdk::Error, "Failed to set file permissions: #{e.message}"
end

#upload_file(source, remote_path) ⇒ void

This method returns an undefined value.

Uploads a file to the specified path in the Sandbox. If a file already exists at the destination path, it will be overwritten.

Examples:

# Upload a text file from string content
content = "Hello, World!"
sandbox.fs.upload_file(content, "tmp/hello.txt")

# Upload a local file
sandbox.fs.upload_file("local_file.txt", "tmp/file.txt")

# Upload binary data
data = { key: "value" }.to_json
sandbox.fs.upload_file(data, "tmp/config.json")

Parameters:

  • source (String, IO)

    File contents as a string/bytes or a local file path or IO object.

  • remote_path (String)

    Path to the destination file. Relative paths are resolved based on the sandbox working directory.

Raises:



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/daytona/file_system.rb', line 173

def upload_file(source, remote_path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  if source.is_a?(String) && File.exist?(source)
    # Source is a file path
    File.open(source, 'rb') { |file| toolbox_api.upload_file(remote_path, file) }
  elsif source.respond_to?(:read)
    # Source is an IO object
    toolbox_api.upload_file(remote_path, source)
  else
    # Source is string content - create a temporary file
    Tempfile.create('daytona_upload') do |file|
      file.binmode
      file.write(source)
      file.rewind
      toolbox_api.upload_file(remote_path, file)
    end
  end
rescue StandardError => e
  raise Sdk::Error, "Failed to upload file: #{e.message}"
end

#upload_files(files) ⇒ void

This method returns an undefined value.

Uploads multiple files to the Sandbox. If files already exist at the destination paths, they will be overwritten.

Examples:

# Upload multiple files
files = [
  FileUpload.new("Content of file 1", "/tmp/file1.txt"),
  FileUpload.new("workspace/data/file2.txt", "/tmp/file2.txt"),
  FileUpload.new('{"key": "value"}', "/tmp/config.json")
]
sandbox.fs.upload_files(files)

Parameters:

  • files (Array<FileUpload>)

    List of files to upload.

Raises:



208
209
210
211
212
# File 'lib/daytona/file_system.rb', line 208

def upload_files(files)
  files.each { |file_upload| upload_file(file_upload.source, file_upload.destination) }
rescue StandardError => e
  raise Sdk::Error, "Failed to upload files: #{e.message}"
end