Module: Tidewave::FileTracker

Extended by:
FileTracker
Included in:
FileTracker
Defined in:
lib/tidewave/file_tracker.rb

Instance Method Summary collapse

Instance Method Details

#file_exists?(path) ⇒ Boolean

Check if a file exists

Returns:

  • (Boolean)


100
101
102
# File 'lib/tidewave/file_tracker.rb', line 100

def file_exists?(path)
  File.exist?(file_full_path(path))
end

#file_full_path(path) ⇒ Object



41
42
43
# File 'lib/tidewave/file_tracker.rb', line 41

def file_full_path(path)
  File.join(git_root, path)
end

#file_recordsObject

Hash mapping file paths to their read records



119
120
121
# File 'lib/tidewave/file_tracker.rb', line 119

def file_records
  @file_records ||= {}
end

#file_was_read?(path) ⇒ Boolean

Check if a file has been read

Returns:

  • (Boolean)


95
96
97
# File 'lib/tidewave/file_tracker.rb', line 95

def file_was_read?(path)
  file_records.key?(path)
end

#file_was_read_since_last_write?(path) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/tidewave/file_tracker.rb', line 90

def file_was_read_since_last_write?(path)
  file_was_read?(path) && last_read_at(path) >= last_modified_at(path)
end

#git_rootObject



45
46
47
# File 'lib/tidewave/file_tracker.rb', line 45

def git_root
  @git_root ||= `git rev-parse --show-toplevel`.strip
end

#last_modified_at(path) ⇒ Object



109
110
111
# File 'lib/tidewave/file_tracker.rb', line 109

def last_modified_at(path)
  File.mtime(file_full_path(path))
end

#last_read_at(path) ⇒ Object

Get the timestamp when a file was last read



105
106
107
# File 'lib/tidewave/file_tracker.rb', line 105

def last_read_at(path)
  file_records[path]
end

#project_filesObject



7
8
9
# File 'lib/tidewave/file_tracker.rb', line 7

def project_files
  `git --git-dir #{git_root}/.git ls-files --cached --others --exclude-standard`.split("\n")
end

#read_file(path) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/tidewave/file_tracker.rb', line 11

def read_file(path)
  validate_path_access!(path)

  # Retrieve the full path
  full_path = file_full_path(path)

  # Record the file as read
  record_read(path)

  # Read and return the file contents
  File.read(full_path)
end

#record_read(path) ⇒ Object

Record when a file was read



85
86
87
# File 'lib/tidewave/file_tracker.rb', line 85

def record_read(path)
  file_records[path] = Time.now
end

#resetObject

Reset all tracked files (useful for testing)



114
115
116
# File 'lib/tidewave/file_tracker.rb', line 114

def reset
  @file_records = {}
end

#validate_path_access!(path, validate_existence: true) ⇒ Object

Raises:

  • (ArgumentError)


49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/tidewave/file_tracker.rb', line 49

def validate_path_access!(path, validate_existence: true)
  raise ArgumentError, "File path must not start with '..'" if path.start_with?("..")

  # Ensure the path is within the project
  full_path = file_full_path(path)

  # Verify the file is within the project directory
  raise ArgumentError, "File path must be within the project directory" unless full_path.start_with?(git_root)

  # Verify the file exists
  raise ArgumentError, "File not found: #{path}" unless File.exist?(full_path) && validate_existence

  true
end

#validate_path_has_been_read_since_last_write!(path) ⇒ Object

Raises:

  • (ArgumentError)


78
79
80
81
82
# File 'lib/tidewave/file_tracker.rb', line 78

def validate_path_has_been_read_since_last_write!(path)
  raise ArgumentError, "File has been modified since last read, please read the file again" unless file_was_read_since_last_write?(path)

  true
end

#validate_path_is_editable!(path) ⇒ Object



64
65
66
67
68
69
# File 'lib/tidewave/file_tracker.rb', line 64

def validate_path_is_editable!(path)
  validate_path_access!(path)
  validate_path_has_been_read_since_last_write!(path)

  true
end

#validate_path_is_writable!(path) ⇒ Object



71
72
73
74
75
76
# File 'lib/tidewave/file_tracker.rb', line 71

def validate_path_is_writable!(path)
  validate_path_access!(path, validate_existence: false)
  validate_path_has_been_read_since_last_write!(path)

  true
end

#write_file(path, content) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/tidewave/file_tracker.rb', line 24

def write_file(path, content)
  validate_path_access!(path, validate_existence: false)
  # Retrieve the full path
  full_path = file_full_path(path)

  dirname = File.dirname(full_path)

  # Create the directory if it doesn't exist
  FileUtils.mkdir_p(dirname)

  # Write the file contents
  File.write(full_path, content)

  # Read and return the file contents
  read_file(path)
end