makit 0.0.143 → 0.0.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/makit/cli/base.rb +17 -0
 - data/lib/makit/cli/generators/templates/ruby/gemspec.rb +1 -0
 - data/lib/makit/cli/main.rb +9 -0
 - data/lib/makit/cli/pipeline_commands.rb +311 -0
 - data/lib/makit/cli/strategy_commands.rb +2 -7
 - data/lib/makit/commands/result.rb +1 -1
 - data/lib/makit/configuration/dotnet_project.rb +9 -0
 - data/lib/makit/configuration/gitlab_helper.rb +4 -1
 - data/lib/makit/configuration/project.rb +362 -84
 - data/lib/makit/configuration/timeout.rb +1 -1
 - data/lib/makit/configuration.rb +5 -0
 - data/lib/makit/fileinfo.rb +8 -0
 - data/lib/makit/git/repository.rb +207 -31
 - data/lib/makit/git.rb +6 -0
 - data/lib/makit/gitlab/pipeline.rb +857 -0
 - data/lib/makit/gitlab/pipeline_service_impl.rb +1536 -0
 - data/lib/makit/humanize.rb +81 -0
 - data/lib/makit/io/filesystem.rb +111 -0
 - data/lib/makit/io/filesystem_service_impl.rb +337 -0
 - data/lib/makit/mp/string_mp.rb +15 -9
 - data/lib/makit/podman/podman.rb +458 -0
 - data/lib/makit/podman/podman_service_impl.rb +1081 -0
 - data/lib/makit/process.rb +214 -0
 - data/lib/makit/protoc.rb +6 -1
 - data/lib/makit/services/repository_manager.rb +268 -132
 - data/lib/makit/symbols.rb +5 -0
 - data/lib/makit/v1/configuration/project_service_impl.rb +371 -0
 - data/lib/makit/v1/git/git_repository_service_impl.rb +295 -0
 - data/lib/makit/v1/makit.v1_pb.rb +1 -1
 - data/lib/makit/v1/makit.v1_services_pb.rb +1 -1
 - data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -0
 - data/lib/makit/version.rb +1 -1
 - data/lib/makit.rb +68 -0
 - metadata +61 -36
 
    
        data/lib/makit/humanize.rb
    CHANGED
    
    | 
         @@ -133,5 +133,86 @@ module Makit 
     | 
|
| 
       133 
133 
     | 
    
         
             
                  parts << "0 seconds" if parts.empty?
         
     | 
| 
       134 
134 
     | 
    
         
             
                  parts.join(", ")
         
     | 
| 
       135 
135 
     | 
    
         
             
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                def self.get_pipeline_execution_summary(execution_result)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  summary = "Pipeline Execution Summary\n"
         
     | 
| 
      
 139 
     | 
    
         
            +
                  summary += "  Execution ID: #{execution_result.execution_id}\n"
         
     | 
| 
      
 140 
     | 
    
         
            +
                  summary += "  Status: #{execution_result.status}\n"
         
     | 
| 
      
 141 
     | 
    
         
            +
                  summary += "  Started: #{execution_result.started_at}\n"
         
     | 
| 
      
 142 
     | 
    
         
            +
                  summary += "  Finished: #{execution_result.finished_at}\n" if execution_result.finished_at
         
     | 
| 
      
 143 
     | 
    
         
            +
                  
         
     | 
| 
      
 144 
     | 
    
         
            +
                  if execution_result.respond_to?(:total_duration_seconds) && execution_result.total_duration_seconds
         
     | 
| 
      
 145 
     | 
    
         
            +
                    summary += "  Duration: #{get_humanized_duration(execution_result.total_duration_seconds)}\n"
         
     | 
| 
      
 146 
     | 
    
         
            +
                  end
         
     | 
| 
      
 147 
     | 
    
         
            +
                  
         
     | 
| 
      
 148 
     | 
    
         
            +
                  if execution_result.respond_to?(:podman_version) && execution_result.podman_version
         
     | 
| 
      
 149 
     | 
    
         
            +
                    summary += "  Podman Version: #{execution_result.podman_version}\n"
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
                  
         
     | 
| 
      
 152 
     | 
    
         
            +
                  if execution_result.respond_to?(:execution_host) && execution_result.execution_host
         
     | 
| 
      
 153 
     | 
    
         
            +
                    summary += "  Host: #{execution_result.execution_host}\n"
         
     | 
| 
      
 154 
     | 
    
         
            +
                  end
         
     | 
| 
      
 155 
     | 
    
         
            +
                  
         
     | 
| 
      
 156 
     | 
    
         
            +
                  summary += "  Jobs: (#{execution_result.job_results.length})\n"
         
     | 
| 
      
 157 
     | 
    
         
            +
                  execution_result.job_results.each do |job_result|
         
     | 
| 
      
 158 
     | 
    
         
            +
                    summary += "\n"
         
     | 
| 
      
 159 
     | 
    
         
            +
                    summary += indent_string(get_job_execution_details(job_result), 4)
         
     | 
| 
      
 160 
     | 
    
         
            +
                    summary += "\n"
         
     | 
| 
      
 161 
     | 
    
         
            +
                  end
         
     | 
| 
      
 162 
     | 
    
         
            +
                  
         
     | 
| 
      
 163 
     | 
    
         
            +
                  if execution_result.errors && execution_result.errors.any?
         
     | 
| 
      
 164 
     | 
    
         
            +
                    summary += "\n  Errors:\n"
         
     | 
| 
      
 165 
     | 
    
         
            +
                    execution_result.errors.each do |error|
         
     | 
| 
      
 166 
     | 
    
         
            +
                      summary += "    - #{error}\n"
         
     | 
| 
      
 167 
     | 
    
         
            +
                    end
         
     | 
| 
      
 168 
     | 
    
         
            +
                  end
         
     | 
| 
      
 169 
     | 
    
         
            +
                  
         
     | 
| 
      
 170 
     | 
    
         
            +
                  if execution_result.warnings && execution_result.warnings.any?
         
     | 
| 
      
 171 
     | 
    
         
            +
                    summary += "\n  Warnings:\n"
         
     | 
| 
      
 172 
     | 
    
         
            +
                    execution_result.warnings.each do |warning|
         
     | 
| 
      
 173 
     | 
    
         
            +
                      summary += "    - #{warning}\n"
         
     | 
| 
      
 174 
     | 
    
         
            +
                    end
         
     | 
| 
      
 175 
     | 
    
         
            +
                  end
         
     | 
| 
      
 176 
     | 
    
         
            +
                  
         
     | 
| 
      
 177 
     | 
    
         
            +
                  summary
         
     | 
| 
      
 178 
     | 
    
         
            +
                end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                def self.get_job_execution_details(job_result)
         
     | 
| 
      
 181 
     | 
    
         
            +
                  details = "Job: #{job_result.job_name}\n"
         
     | 
| 
      
 182 
     | 
    
         
            +
                  details += "  Status: #{job_result.status}\n"
         
     | 
| 
      
 183 
     | 
    
         
            +
                  details += "  Started: #{job_result.started_at}\n"
         
     | 
| 
      
 184 
     | 
    
         
            +
                  details += "  Finished: #{job_result.finished_at}\n" if job_result.finished_at
         
     | 
| 
      
 185 
     | 
    
         
            +
                  details += "  Exit Code: #{job_result.exit_code}\n" if job_result.exit_code
         
     | 
| 
      
 186 
     | 
    
         
            +
                  
         
     | 
| 
      
 187 
     | 
    
         
            +
                  if job_result.errors && job_result.errors.any?
         
     | 
| 
      
 188 
     | 
    
         
            +
                    details += "  Errors:\n"
         
     | 
| 
      
 189 
     | 
    
         
            +
                    job_result.errors.each do |error|
         
     | 
| 
      
 190 
     | 
    
         
            +
                      details += "    - #{error}\n"
         
     | 
| 
      
 191 
     | 
    
         
            +
                    end
         
     | 
| 
      
 192 
     | 
    
         
            +
                  end
         
     | 
| 
      
 193 
     | 
    
         
            +
                  
         
     | 
| 
      
 194 
     | 
    
         
            +
                  if job_result.logs && job_result.logs.any?
         
     | 
| 
      
 195 
     | 
    
         
            +
                    details += "  Logs:\n"
         
     | 
| 
      
 196 
     | 
    
         
            +
                    job_result.logs.each do |log|
         
     | 
| 
      
 197 
     | 
    
         
            +
                      details += "    #{log}\n"
         
     | 
| 
      
 198 
     | 
    
         
            +
                    end
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                  
         
     | 
| 
      
 201 
     | 
    
         
            +
                  if job_result.respond_to?(:stdout) && job_result.stdout && !job_result.stdout.empty?
         
     | 
| 
      
 202 
     | 
    
         
            +
                    details += "  Stdout:\n"
         
     | 
| 
      
 203 
     | 
    
         
            +
                    job_result.stdout.split("\n").each do |line|
         
     | 
| 
      
 204 
     | 
    
         
            +
                      details += "    #{line}\n"
         
     | 
| 
      
 205 
     | 
    
         
            +
                    end
         
     | 
| 
      
 206 
     | 
    
         
            +
                  end
         
     | 
| 
      
 207 
     | 
    
         
            +
                  
         
     | 
| 
      
 208 
     | 
    
         
            +
                  if job_result.respond_to?(:stderr) && job_result.stderr && !job_result.stderr.empty?
         
     | 
| 
      
 209 
     | 
    
         
            +
                    details += "  Stderr:\n"
         
     | 
| 
      
 210 
     | 
    
         
            +
                    job_result.stderr.split("\n").each do |line|
         
     | 
| 
      
 211 
     | 
    
         
            +
                      details += "    #{line}\n"
         
     | 
| 
      
 212 
     | 
    
         
            +
                    end
         
     | 
| 
      
 213 
     | 
    
         
            +
                  end
         
     | 
| 
      
 214 
     | 
    
         
            +
                  
         
     | 
| 
      
 215 
     | 
    
         
            +
                  details
         
     | 
| 
      
 216 
     | 
    
         
            +
                end
         
     | 
| 
       136 
217 
     | 
    
         
             
              end
         
     | 
| 
       137 
218 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,111 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "filesystem_service_impl"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Makit
         
     | 
| 
      
 6 
     | 
    
         
            +
              module IO
         
     | 
| 
      
 7 
     | 
    
         
            +
                class FileSystem
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @service = FileSystemServiceImpl.new
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # Get a single file's content and/or metadata
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def get_file(path, include_metadata: true, include_content: true)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    request = {
         
     | 
| 
      
 15 
     | 
    
         
            +
                      path: path,
         
     | 
| 
      
 16 
     | 
    
         
            +
                      include_metadata: include_metadata,
         
     | 
| 
      
 17 
     | 
    
         
            +
                      include_content: include_content
         
     | 
| 
      
 18 
     | 
    
         
            +
                    }
         
     | 
| 
      
 19 
     | 
    
         
            +
                    
         
     | 
| 
      
 20 
     | 
    
         
            +
                    result = @service.get_file(request)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    
         
     | 
| 
      
 22 
     | 
    
         
            +
                    if result.respond_to?(:file)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      # gRPC mode
         
     | 
| 
      
 24 
     | 
    
         
            +
                      result.file
         
     | 
| 
      
 25 
     | 
    
         
            +
                    else
         
     | 
| 
      
 26 
     | 
    
         
            +
                      # Fallback mode
         
     | 
| 
      
 27 
     | 
    
         
            +
                      result[:file]
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # Create or update a file
         
     | 
| 
      
 32 
     | 
    
         
            +
                  def save_file(path, binary_data: nil, text_lines: nil)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    request = {
         
     | 
| 
      
 34 
     | 
    
         
            +
                      path: path,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      binary_data: binary_data,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      text_lines: text_lines
         
     | 
| 
      
 37 
     | 
    
         
            +
                    }
         
     | 
| 
      
 38 
     | 
    
         
            +
                    
         
     | 
| 
      
 39 
     | 
    
         
            +
                    result = @service.save_file(request)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    
         
     | 
| 
      
 41 
     | 
    
         
            +
                    if result.respond_to?(:file)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      # gRPC mode
         
     | 
| 
      
 43 
     | 
    
         
            +
                      result.file
         
     | 
| 
      
 44 
     | 
    
         
            +
                    else
         
     | 
| 
      
 45 
     | 
    
         
            +
                      # Fallback mode
         
     | 
| 
      
 46 
     | 
    
         
            +
                      result[:file]
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  # Delete a file by path
         
     | 
| 
      
 51 
     | 
    
         
            +
                  def delete_file(path)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    request = { path: path }
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @service.delete_file(request)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  # List files in a directory according to query flags
         
     | 
| 
      
 57 
     | 
    
         
            +
                  def list_files(directory, recursive: false, pattern: nil, respect_gitignore: false, include_metadata: true, include_content: false)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    request = {
         
     | 
| 
      
 59 
     | 
    
         
            +
                      directory: directory,
         
     | 
| 
      
 60 
     | 
    
         
            +
                      recursive: recursive,
         
     | 
| 
      
 61 
     | 
    
         
            +
                      pattern: pattern,
         
     | 
| 
      
 62 
     | 
    
         
            +
                      respect_gitignore: respect_gitignore,
         
     | 
| 
      
 63 
     | 
    
         
            +
                      include_metadata: include_metadata,
         
     | 
| 
      
 64 
     | 
    
         
            +
                      include_content: include_content
         
     | 
| 
      
 65 
     | 
    
         
            +
                    }
         
     | 
| 
      
 66 
     | 
    
         
            +
                    
         
     | 
| 
      
 67 
     | 
    
         
            +
                    result = @service.list_files(request)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    
         
     | 
| 
      
 69 
     | 
    
         
            +
                    if result.respond_to?(:files)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      # gRPC mode
         
     | 
| 
      
 71 
     | 
    
         
            +
                      result.files
         
     | 
| 
      
 72 
     | 
    
         
            +
                    else
         
     | 
| 
      
 73 
     | 
    
         
            +
                      # Fallback mode
         
     | 
| 
      
 74 
     | 
    
         
            +
                      result[:files]
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  # Create a directory
         
     | 
| 
      
 79 
     | 
    
         
            +
                  def create_directory(path)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    request = { path: path }
         
     | 
| 
      
 81 
     | 
    
         
            +
                    @service.create_directory(request)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  # Delete a directory
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def delete_directory(path)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    request = { path: path }
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @service.delete_directory(request)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  # Upload large files in chunks
         
     | 
| 
      
 91 
     | 
    
         
            +
                  def upload(chunks)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    request = { chunks: chunks }
         
     | 
| 
      
 93 
     | 
    
         
            +
                    result = @service.upload(request)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    
         
     | 
| 
      
 95 
     | 
    
         
            +
                    if result.respond_to?(:file)
         
     | 
| 
      
 96 
     | 
    
         
            +
                      # gRPC mode
         
     | 
| 
      
 97 
     | 
    
         
            +
                      result.file
         
     | 
| 
      
 98 
     | 
    
         
            +
                    else
         
     | 
| 
      
 99 
     | 
    
         
            +
                      # Fallback mode
         
     | 
| 
      
 100 
     | 
    
         
            +
                      result[:file]
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                  # Download a file in chunks
         
     | 
| 
      
 105 
     | 
    
         
            +
                  def download(path)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    request = { path: path }
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @service.download(request)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,337 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "fileutils"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "mime/types"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "digest"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "time"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Makit
         
     | 
| 
      
 9 
     | 
    
         
            +
              module IO
         
     | 
| 
      
 10 
     | 
    
         
            +
                class FileSystemServiceImpl
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 12 
     | 
    
         
            +
                    # Initialize any required state
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # Check if gRPC service is available
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def self.grpc_available?
         
     | 
| 
      
 17 
     | 
    
         
            +
                    defined?(Makit::Io::FileSystemService)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  # Get a single file's content and/or metadata
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def get_file(request, _unused_call = nil)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    path = request.respond_to?(:path) ? request.path : request[:path]
         
     | 
| 
      
 23 
     | 
    
         
            +
                    include_metadata = request.respond_to?(:include_metadata) ? request.include_metadata : request[:include_metadata]
         
     | 
| 
      
 24 
     | 
    
         
            +
                    include_content = request.respond_to?(:include_content) ? request.include_content : request[:include_content]
         
     | 
| 
      
 25 
     | 
    
         
            +
                    
         
     | 
| 
      
 26 
     | 
    
         
            +
                    # Default to metadata only if not specified
         
     | 
| 
      
 27 
     | 
    
         
            +
                    include_metadata = true if include_metadata.nil?
         
     | 
| 
      
 28 
     | 
    
         
            +
                    include_content = false if include_content.nil?
         
     | 
| 
      
 29 
     | 
    
         
            +
                    
         
     | 
| 
      
 30 
     | 
    
         
            +
                    unless File.exist?(path)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      raise Errno::ENOENT, "No such file or directory: #{path}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                    
         
     | 
| 
      
 34 
     | 
    
         
            +
                    file_data = {
         
     | 
| 
      
 35 
     | 
    
         
            +
                      path: path
         
     | 
| 
      
 36 
     | 
    
         
            +
                    }
         
     | 
| 
      
 37 
     | 
    
         
            +
                    
         
     | 
| 
      
 38 
     | 
    
         
            +
                    if include_content
         
     | 
| 
      
 39 
     | 
    
         
            +
                      if binary_file?(path)
         
     | 
| 
      
 40 
     | 
    
         
            +
                        file_data[:binary_data] = File.binread(path)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      else
         
     | 
| 
      
 42 
     | 
    
         
            +
                        file_data[:text_lines] = File.readlines(path).map(&:chomp)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    
         
     | 
| 
      
 46 
     | 
    
         
            +
                    if include_metadata
         
     | 
| 
      
 47 
     | 
    
         
            +
                      file_data[:metadata] = get_file_metadata(path)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                    
         
     | 
| 
      
 50 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 51 
     | 
    
         
            +
                      Makit::Io::FileResponse.new(file: Makit::Io::File.new(file_data))
         
     | 
| 
      
 52 
     | 
    
         
            +
                    else
         
     | 
| 
      
 53 
     | 
    
         
            +
                      { file: file_data }
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # Create or update a file
         
     | 
| 
      
 58 
     | 
    
         
            +
                  def save_file(request, _unused_call = nil)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    path = request.respond_to?(:path) ? request.path : request[:path]
         
     | 
| 
      
 60 
     | 
    
         
            +
                    binary_data = request.respond_to?(:binary_data) ? request.binary_data : request[:binary_data]
         
     | 
| 
      
 61 
     | 
    
         
            +
                    text_lines = request.respond_to?(:text_lines) ? request.text_lines : request[:text_lines]
         
     | 
| 
      
 62 
     | 
    
         
            +
                    
         
     | 
| 
      
 63 
     | 
    
         
            +
                    # Ensure directory exists
         
     | 
| 
      
 64 
     | 
    
         
            +
                    FileUtils.mkdir_p(File.dirname(path))
         
     | 
| 
      
 65 
     | 
    
         
            +
                    
         
     | 
| 
      
 66 
     | 
    
         
            +
                    if binary_data && !binary_data.empty?
         
     | 
| 
      
 67 
     | 
    
         
            +
                      File.binwrite(path, binary_data)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    elsif text_lines && !text_lines.empty?
         
     | 
| 
      
 69 
     | 
    
         
            +
                      File.write(path, text_lines.join("\n") + "\n")
         
     | 
| 
      
 70 
     | 
    
         
            +
                    else
         
     | 
| 
      
 71 
     | 
    
         
            +
                      raise ArgumentError, "Either binary_data or text_lines must be provided"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
                    
         
     | 
| 
      
 74 
     | 
    
         
            +
                    file_data = {
         
     | 
| 
      
 75 
     | 
    
         
            +
                      path: path,
         
     | 
| 
      
 76 
     | 
    
         
            +
                      metadata: get_file_metadata(path)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    }
         
     | 
| 
      
 78 
     | 
    
         
            +
                    
         
     | 
| 
      
 79 
     | 
    
         
            +
                    if binary_data && !binary_data.empty?
         
     | 
| 
      
 80 
     | 
    
         
            +
                      file_data[:binary_data] = binary_data
         
     | 
| 
      
 81 
     | 
    
         
            +
                    elsif text_lines && !text_lines.empty?
         
     | 
| 
      
 82 
     | 
    
         
            +
                      file_data[:text_lines] = text_lines
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
                    
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 86 
     | 
    
         
            +
                      Makit::Io::FileResponse.new(file: Makit::Io::File.new(file_data))
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      { file: file_data }
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  # Delete a file by path
         
     | 
| 
      
 93 
     | 
    
         
            +
                  def delete_file(request, _unused_call = nil)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    path = request.respond_to?(:path) ? request.path : request[:path]
         
     | 
| 
      
 95 
     | 
    
         
            +
                    
         
     | 
| 
      
 96 
     | 
    
         
            +
                    unless File.exist?(path)
         
     | 
| 
      
 97 
     | 
    
         
            +
                      raise Errno::ENOENT, "No such file or directory: #{path}"
         
     | 
| 
      
 98 
     | 
    
         
            +
                    end
         
     | 
| 
      
 99 
     | 
    
         
            +
                    
         
     | 
| 
      
 100 
     | 
    
         
            +
                    File.delete(path)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    
         
     | 
| 
      
 102 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 103 
     | 
    
         
            +
                      Google::Protobuf::Empty.new
         
     | 
| 
      
 104 
     | 
    
         
            +
                    else
         
     | 
| 
      
 105 
     | 
    
         
            +
                      {}
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  # List files in a directory according to query flags
         
     | 
| 
      
 110 
     | 
    
         
            +
                  def list_files(request, _unused_call = nil)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    directory = request.respond_to?(:directory) ? request.directory : request[:directory]
         
     | 
| 
      
 112 
     | 
    
         
            +
                    recursive = request.respond_to?(:recursive) ? request.recursive : request[:recursive]
         
     | 
| 
      
 113 
     | 
    
         
            +
                    pattern = request.respond_to?(:pattern) ? request.pattern : request[:pattern]
         
     | 
| 
      
 114 
     | 
    
         
            +
                    respect_gitignore = request.respond_to?(:respect_gitignore) ? request.respect_gitignore : request[:respect_gitignore]
         
     | 
| 
      
 115 
     | 
    
         
            +
                    include_metadata = request.respond_to?(:include_metadata) ? request.include_metadata : request[:include_metadata]
         
     | 
| 
      
 116 
     | 
    
         
            +
                    include_content = request.respond_to?(:include_content) ? request.include_content : request[:include_content]
         
     | 
| 
      
 117 
     | 
    
         
            +
                    
         
     | 
| 
      
 118 
     | 
    
         
            +
                    # Default values
         
     | 
| 
      
 119 
     | 
    
         
            +
                    recursive = false if recursive.nil?
         
     | 
| 
      
 120 
     | 
    
         
            +
                    respect_gitignore = false if respect_gitignore.nil?
         
     | 
| 
      
 121 
     | 
    
         
            +
                    include_metadata = true if include_metadata.nil?
         
     | 
| 
      
 122 
     | 
    
         
            +
                    include_content = false if include_content.nil?
         
     | 
| 
      
 123 
     | 
    
         
            +
                    
         
     | 
| 
      
 124 
     | 
    
         
            +
                    unless Dir.exist?(directory)
         
     | 
| 
      
 125 
     | 
    
         
            +
                      raise Errno::ENOENT, "No such file or directory: #{directory}"
         
     | 
| 
      
 126 
     | 
    
         
            +
                    end
         
     | 
| 
      
 127 
     | 
    
         
            +
                    
         
     | 
| 
      
 128 
     | 
    
         
            +
                    files = []
         
     | 
| 
      
 129 
     | 
    
         
            +
                    
         
     | 
| 
      
 130 
     | 
    
         
            +
                    # Get gitignore patterns if requested
         
     | 
| 
      
 131 
     | 
    
         
            +
                    gitignore_patterns = []
         
     | 
| 
      
 132 
     | 
    
         
            +
                    if respect_gitignore
         
     | 
| 
      
 133 
     | 
    
         
            +
                      gitignore_file = File.join(directory, ".gitignore")
         
     | 
| 
      
 134 
     | 
    
         
            +
                      if File.exist?(gitignore_file)
         
     | 
| 
      
 135 
     | 
    
         
            +
                        gitignore_patterns = File.readlines(gitignore_file).map(&:strip).reject(&:empty?)
         
     | 
| 
      
 136 
     | 
    
         
            +
                      end
         
     | 
| 
      
 137 
     | 
    
         
            +
                    end
         
     | 
| 
      
 138 
     | 
    
         
            +
                    
         
     | 
| 
      
 139 
     | 
    
         
            +
                    # Find files
         
     | 
| 
      
 140 
     | 
    
         
            +
                    if recursive
         
     | 
| 
      
 141 
     | 
    
         
            +
                      Dir.glob(File.join(directory, "**", "*")).each do |file_path|
         
     | 
| 
      
 142 
     | 
    
         
            +
                        next if File.directory?(file_path)
         
     | 
| 
      
 143 
     | 
    
         
            +
                        next if should_ignore_file?(file_path, gitignore_patterns)
         
     | 
| 
      
 144 
     | 
    
         
            +
                        next if pattern && !File.fnmatch(pattern, File.basename(file_path))
         
     | 
| 
      
 145 
     | 
    
         
            +
                        
         
     | 
| 
      
 146 
     | 
    
         
            +
                        files << build_file_data(file_path, include_metadata, include_content)
         
     | 
| 
      
 147 
     | 
    
         
            +
                      end
         
     | 
| 
      
 148 
     | 
    
         
            +
                    else
         
     | 
| 
      
 149 
     | 
    
         
            +
                      Dir.entries(directory).each do |entry|
         
     | 
| 
      
 150 
     | 
    
         
            +
                        next if entry == "." || entry == ".."
         
     | 
| 
      
 151 
     | 
    
         
            +
                        
         
     | 
| 
      
 152 
     | 
    
         
            +
                        file_path = File.join(directory, entry)
         
     | 
| 
      
 153 
     | 
    
         
            +
                        next if File.directory?(file_path)
         
     | 
| 
      
 154 
     | 
    
         
            +
                        next if should_ignore_file?(file_path, gitignore_patterns)
         
     | 
| 
      
 155 
     | 
    
         
            +
                        next if pattern && !File.fnmatch(pattern, entry)
         
     | 
| 
      
 156 
     | 
    
         
            +
                        
         
     | 
| 
      
 157 
     | 
    
         
            +
                        files << build_file_data(file_path, include_metadata, include_content)
         
     | 
| 
      
 158 
     | 
    
         
            +
                      end
         
     | 
| 
      
 159 
     | 
    
         
            +
                    end
         
     | 
| 
      
 160 
     | 
    
         
            +
                    
         
     | 
| 
      
 161 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 162 
     | 
    
         
            +
                      Makit::Io::FileList.new(files: files.map { |f| Makit::Io::File.new(f) })
         
     | 
| 
      
 163 
     | 
    
         
            +
                    else
         
     | 
| 
      
 164 
     | 
    
         
            +
                      { files: files }
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                  # Create a directory
         
     | 
| 
      
 169 
     | 
    
         
            +
                  def create_directory(request, _unused_call = nil)
         
     | 
| 
      
 170 
     | 
    
         
            +
                    path = request.respond_to?(:path) ? request.path : request[:path]
         
     | 
| 
      
 171 
     | 
    
         
            +
                    
         
     | 
| 
      
 172 
     | 
    
         
            +
                    FileUtils.mkdir_p(path)
         
     | 
| 
      
 173 
     | 
    
         
            +
                    
         
     | 
| 
      
 174 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 175 
     | 
    
         
            +
                      Google::Protobuf::Empty.new
         
     | 
| 
      
 176 
     | 
    
         
            +
                    else
         
     | 
| 
      
 177 
     | 
    
         
            +
                      {}
         
     | 
| 
      
 178 
     | 
    
         
            +
                    end
         
     | 
| 
      
 179 
     | 
    
         
            +
                  end
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
                  # Delete a directory
         
     | 
| 
      
 182 
     | 
    
         
            +
                  def delete_directory(request, _unused_call = nil)
         
     | 
| 
      
 183 
     | 
    
         
            +
                    path = request.respond_to?(:path) ? request.path : request[:path]
         
     | 
| 
      
 184 
     | 
    
         
            +
                    
         
     | 
| 
      
 185 
     | 
    
         
            +
                    unless Dir.exist?(path)
         
     | 
| 
      
 186 
     | 
    
         
            +
                      raise Errno::ENOENT, "No such file or directory: #{path}"
         
     | 
| 
      
 187 
     | 
    
         
            +
                    end
         
     | 
| 
      
 188 
     | 
    
         
            +
                    
         
     | 
| 
      
 189 
     | 
    
         
            +
                    Dir.rmdir(path)
         
     | 
| 
      
 190 
     | 
    
         
            +
                    
         
     | 
| 
      
 191 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 192 
     | 
    
         
            +
                      Google::Protobuf::Empty.new
         
     | 
| 
      
 193 
     | 
    
         
            +
                    else
         
     | 
| 
      
 194 
     | 
    
         
            +
                      {}
         
     | 
| 
      
 195 
     | 
    
         
            +
                    end
         
     | 
| 
      
 196 
     | 
    
         
            +
                  end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                  # Upload large files in chunks
         
     | 
| 
      
 199 
     | 
    
         
            +
                  def upload(request, _unused_call = nil)
         
     | 
| 
      
 200 
     | 
    
         
            +
                    chunks = request.respond_to?(:chunks) ? request.chunks : request[:chunks]
         
     | 
| 
      
 201 
     | 
    
         
            +
                    
         
     | 
| 
      
 202 
     | 
    
         
            +
                    raise ArgumentError, "No chunks provided" if chunks.nil? || chunks.empty?
         
     | 
| 
      
 203 
     | 
    
         
            +
                    
         
     | 
| 
      
 204 
     | 
    
         
            +
                    # Group chunks by path
         
     | 
| 
      
 205 
     | 
    
         
            +
                    chunks_by_path = {}
         
     | 
| 
      
 206 
     | 
    
         
            +
                    chunks.each do |chunk|
         
     | 
| 
      
 207 
     | 
    
         
            +
                      path = chunk.respond_to?(:path) ? chunk.path : chunk[:path]
         
     | 
| 
      
 208 
     | 
    
         
            +
                      data = chunk.respond_to?(:data) ? chunk.data : chunk[:data]
         
     | 
| 
      
 209 
     | 
    
         
            +
                      metadata = chunk.respond_to?(:metadata) ? chunk.metadata : chunk[:metadata]
         
     | 
| 
      
 210 
     | 
    
         
            +
                      is_final = chunk.respond_to?(:is_final) ? chunk.is_final : chunk[:is_final]
         
     | 
| 
      
 211 
     | 
    
         
            +
                      
         
     | 
| 
      
 212 
     | 
    
         
            +
                      chunks_by_path[path] ||= { data: "", metadata: metadata }
         
     | 
| 
      
 213 
     | 
    
         
            +
                      chunks_by_path[path][:data] += data
         
     | 
| 
      
 214 
     | 
    
         
            +
                    end
         
     | 
| 
      
 215 
     | 
    
         
            +
                    
         
     | 
| 
      
 216 
     | 
    
         
            +
                    # Save each file
         
     | 
| 
      
 217 
     | 
    
         
            +
                    results = []
         
     | 
| 
      
 218 
     | 
    
         
            +
                    chunks_by_path.each do |path, file_info|
         
     | 
| 
      
 219 
     | 
    
         
            +
                      File.binwrite(path, file_info[:data])
         
     | 
| 
      
 220 
     | 
    
         
            +
                      
         
     | 
| 
      
 221 
     | 
    
         
            +
                      file_data = {
         
     | 
| 
      
 222 
     | 
    
         
            +
                        path: path,
         
     | 
| 
      
 223 
     | 
    
         
            +
                        binary_data: file_info[:data],
         
     | 
| 
      
 224 
     | 
    
         
            +
                        metadata: get_file_metadata(path)
         
     | 
| 
      
 225 
     | 
    
         
            +
                      }
         
     | 
| 
      
 226 
     | 
    
         
            +
                      
         
     | 
| 
      
 227 
     | 
    
         
            +
                      results << file_data
         
     | 
| 
      
 228 
     | 
    
         
            +
                    end
         
     | 
| 
      
 229 
     | 
    
         
            +
                    
         
     | 
| 
      
 230 
     | 
    
         
            +
                    # Return the first (or only) file result
         
     | 
| 
      
 231 
     | 
    
         
            +
                    result = results.first
         
     | 
| 
      
 232 
     | 
    
         
            +
                    
         
     | 
| 
      
 233 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 234 
     | 
    
         
            +
                      Makit::Io::FileResponse.new(file: Makit::Io::File.new(result))
         
     | 
| 
      
 235 
     | 
    
         
            +
                    else
         
     | 
| 
      
 236 
     | 
    
         
            +
                      { file: result }
         
     | 
| 
      
 237 
     | 
    
         
            +
                    end
         
     | 
| 
      
 238 
     | 
    
         
            +
                  end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                  # Download a file in chunks
         
     | 
| 
      
 241 
     | 
    
         
            +
                  def download(request, _unused_call = nil)
         
     | 
| 
      
 242 
     | 
    
         
            +
                    path = request.respond_to?(:path) ? request.path : request[:path]
         
     | 
| 
      
 243 
     | 
    
         
            +
                    
         
     | 
| 
      
 244 
     | 
    
         
            +
                    unless File.exist?(path)
         
     | 
| 
      
 245 
     | 
    
         
            +
                      raise Errno::ENOENT, "No such file or directory: #{path}"
         
     | 
| 
      
 246 
     | 
    
         
            +
                    end
         
     | 
| 
      
 247 
     | 
    
         
            +
                    
         
     | 
| 
      
 248 
     | 
    
         
            +
                    content = File.binread(path)
         
     | 
| 
      
 249 
     | 
    
         
            +
                    chunk_size = 1024  # 1KB chunks
         
     | 
| 
      
 250 
     | 
    
         
            +
                    chunks = []
         
     | 
| 
      
 251 
     | 
    
         
            +
                    
         
     | 
| 
      
 252 
     | 
    
         
            +
                    (0...content.length).step(chunk_size) do |i|
         
     | 
| 
      
 253 
     | 
    
         
            +
                      chunk_data = content[i, chunk_size]
         
     | 
| 
      
 254 
     | 
    
         
            +
                      is_final = (i + chunk_size >= content.length)
         
     | 
| 
      
 255 
     | 
    
         
            +
                      
         
     | 
| 
      
 256 
     | 
    
         
            +
                      chunk = {
         
     | 
| 
      
 257 
     | 
    
         
            +
                        path: path,
         
     | 
| 
      
 258 
     | 
    
         
            +
                        data: chunk_data,
         
     | 
| 
      
 259 
     | 
    
         
            +
                        metadata: is_final ? get_file_metadata(path) : nil,
         
     | 
| 
      
 260 
     | 
    
         
            +
                        is_final: is_final
         
     | 
| 
      
 261 
     | 
    
         
            +
                      }
         
     | 
| 
      
 262 
     | 
    
         
            +
                      
         
     | 
| 
      
 263 
     | 
    
         
            +
                      chunks << chunk
         
     | 
| 
      
 264 
     | 
    
         
            +
                    end
         
     | 
| 
      
 265 
     | 
    
         
            +
                    
         
     | 
| 
      
 266 
     | 
    
         
            +
                    if self.class.grpc_available?
         
     | 
| 
      
 267 
     | 
    
         
            +
                      chunks.map { |c| Makit::Io::FileChunk.new(c) }
         
     | 
| 
      
 268 
     | 
    
         
            +
                    else
         
     | 
| 
      
 269 
     | 
    
         
            +
                      chunks
         
     | 
| 
      
 270 
     | 
    
         
            +
                    end
         
     | 
| 
      
 271 
     | 
    
         
            +
                  end
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
                  private
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                  def get_file_metadata(path)
         
     | 
| 
      
 276 
     | 
    
         
            +
                    stat = File.stat(path)
         
     | 
| 
      
 277 
     | 
    
         
            +
                    
         
     | 
| 
      
 278 
     | 
    
         
            +
                    {
         
     | 
| 
      
 279 
     | 
    
         
            +
                      mime_type: get_mime_type(path),
         
     | 
| 
      
 280 
     | 
    
         
            +
                      size_bytes: stat.size,
         
     | 
| 
      
 281 
     | 
    
         
            +
                      created_at: stat.birthtime.iso8601,
         
     | 
| 
      
 282 
     | 
    
         
            +
                      modified_at: stat.mtime.iso8601,
         
     | 
| 
      
 283 
     | 
    
         
            +
                      owner: stat.uid.to_s,
         
     | 
| 
      
 284 
     | 
    
         
            +
                      is_directory: stat.directory?,
         
     | 
| 
      
 285 
     | 
    
         
            +
                      checksum: calculate_checksum(path)
         
     | 
| 
      
 286 
     | 
    
         
            +
                    }
         
     | 
| 
      
 287 
     | 
    
         
            +
                  end
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                  def get_mime_type(path)
         
     | 
| 
      
 290 
     | 
    
         
            +
                    mime_type = MIME::Types.type_for(path).first
         
     | 
| 
      
 291 
     | 
    
         
            +
                    mime_type ? mime_type.content_type : "application/octet-stream"
         
     | 
| 
      
 292 
     | 
    
         
            +
                  end
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                  def calculate_checksum(path)
         
     | 
| 
      
 295 
     | 
    
         
            +
                    Digest::SHA256.file(path).hexdigest
         
     | 
| 
      
 296 
     | 
    
         
            +
                  end
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
                  def binary_file?(path)
         
     | 
| 
      
 299 
     | 
    
         
            +
                    # Simple heuristic: check if file contains null bytes or high bytes
         
     | 
| 
      
 300 
     | 
    
         
            +
                    File.open(path, "rb") do |file|
         
     | 
| 
      
 301 
     | 
    
         
            +
                      chunk = file.read(1024)
         
     | 
| 
      
 302 
     | 
    
         
            +
                      return true if chunk.nil? || chunk.include?("\x00") || chunk.bytes.any? { |b| b > 127 }
         
     | 
| 
      
 303 
     | 
    
         
            +
                    end
         
     | 
| 
      
 304 
     | 
    
         
            +
                    false
         
     | 
| 
      
 305 
     | 
    
         
            +
                  rescue
         
     | 
| 
      
 306 
     | 
    
         
            +
                    true  # If we can't read it, assume it's binary
         
     | 
| 
      
 307 
     | 
    
         
            +
                  end
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
                  def should_ignore_file?(file_path, gitignore_patterns)
         
     | 
| 
      
 310 
     | 
    
         
            +
                    return false if gitignore_patterns.empty?
         
     | 
| 
      
 311 
     | 
    
         
            +
                    
         
     | 
| 
      
 312 
     | 
    
         
            +
                    relative_path = file_path
         
     | 
| 
      
 313 
     | 
    
         
            +
                    gitignore_patterns.any? do |pattern|
         
     | 
| 
      
 314 
     | 
    
         
            +
                      File.fnmatch(pattern, relative_path) || File.fnmatch(pattern, File.basename(relative_path))
         
     | 
| 
      
 315 
     | 
    
         
            +
                    end
         
     | 
| 
      
 316 
     | 
    
         
            +
                  end
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
                  def build_file_data(file_path, include_metadata, include_content)
         
     | 
| 
      
 319 
     | 
    
         
            +
                    file_data = { path: file_path }
         
     | 
| 
      
 320 
     | 
    
         
            +
                    
         
     | 
| 
      
 321 
     | 
    
         
            +
                    if include_content
         
     | 
| 
      
 322 
     | 
    
         
            +
                      if binary_file?(file_path)
         
     | 
| 
      
 323 
     | 
    
         
            +
                        file_data[:binary_data] = File.binread(file_path)
         
     | 
| 
      
 324 
     | 
    
         
            +
                      else
         
     | 
| 
      
 325 
     | 
    
         
            +
                        file_data[:text_lines] = File.readlines(file_path).map(&:chomp)
         
     | 
| 
      
 326 
     | 
    
         
            +
                      end
         
     | 
| 
      
 327 
     | 
    
         
            +
                    end
         
     | 
| 
      
 328 
     | 
    
         
            +
                    
         
     | 
| 
      
 329 
     | 
    
         
            +
                    if include_metadata
         
     | 
| 
      
 330 
     | 
    
         
            +
                      file_data[:metadata] = get_file_metadata(file_path)
         
     | 
| 
      
 331 
     | 
    
         
            +
                    end
         
     | 
| 
      
 332 
     | 
    
         
            +
                    
         
     | 
| 
      
 333 
     | 
    
         
            +
                    file_data
         
     | 
| 
      
 334 
     | 
    
         
            +
                  end
         
     | 
| 
      
 335 
     | 
    
         
            +
                end
         
     | 
| 
      
 336 
     | 
    
         
            +
              end
         
     | 
| 
      
 337 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/makit/mp/string_mp.rb
    CHANGED
    
    | 
         @@ -61,24 +61,30 @@ class String 
     | 
|
| 
       61 
61 
     | 
    
         
             
                Makit::Commands::Runner.default.execute(request)
         
     | 
| 
       62 
62 
     | 
    
         
             
              end
         
     | 
| 
       63 
63 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
              def cache_run(timestamp = nil)
         
     | 
| 
      
 64 
     | 
    
         
            +
              def cache_run(timestamp = nil, timeout: nil)
         
     | 
| 
       65 
65 
     | 
    
         
             
                #puts "cache_run: #{self}"
         
     | 
| 
       66 
66 
     | 
    
         
             
                command = self
         
     | 
| 
       67 
67 
     | 
    
         
             
                request = Makit::Commands::Request.from_string(command)
         
     | 
| 
      
 68 
     | 
    
         
            +
                
         
     | 
| 
      
 69 
     | 
    
         
            +
                # Build request options
         
     | 
| 
      
 70 
     | 
    
         
            +
                request_options = {
         
     | 
| 
      
 71 
     | 
    
         
            +
                  command: request.command,
         
     | 
| 
      
 72 
     | 
    
         
            +
                  arguments: request.arguments,
         
     | 
| 
      
 73 
     | 
    
         
            +
                  directory: request.directory,
         
     | 
| 
      
 74 
     | 
    
         
            +
                  timeout: timeout || request.timeout,
         
     | 
| 
      
 75 
     | 
    
         
            +
                  environment: request.environment || {},
         
     | 
| 
      
 76 
     | 
    
         
            +
                  metadata: request.metadata || {},
         
     | 
| 
      
 77 
     | 
    
         
            +
                }
         
     | 
| 
      
 78 
     | 
    
         
            +
                
         
     | 
| 
       68 
79 
     | 
    
         
             
                if timestamp
         
     | 
| 
       69 
80 
     | 
    
         
             
                  # Add timestamp to metadata for cache key generation
         
     | 
| 
       70 
     | 
    
         
            -
                   
     | 
| 
       71 
     | 
    
         
            -
                    command: request.command,
         
     | 
| 
       72 
     | 
    
         
            -
                    arguments: request.arguments,
         
     | 
| 
       73 
     | 
    
         
            -
                    directory: request.directory,
         
     | 
| 
       74 
     | 
    
         
            -
                    timeout: request.timeout,
         
     | 
| 
       75 
     | 
    
         
            -
                    environment: request.environment || {},
         
     | 
| 
       76 
     | 
    
         
            -
                    metadata: (request.metadata || {}).merge(timestamp: timestamp),
         
     | 
| 
       77 
     | 
    
         
            -
                  )
         
     | 
| 
      
 81 
     | 
    
         
            +
                  request_options[:metadata] = request_options[:metadata].merge(timestamp: timestamp)
         
     | 
| 
       78 
82 
     | 
    
         
             
                  #puts "timestamp: #{timestamp}"
         
     | 
| 
       79 
83 
     | 
    
         
             
                else
         
     | 
| 
       80 
84 
     | 
    
         
             
                  #puts "no timestamp"
         
     | 
| 
       81 
85 
     | 
    
         
             
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
                
         
     | 
| 
      
 87 
     | 
    
         
            +
                request = Makit::Commands::Request.new(**request_options)
         
     | 
| 
       82 
88 
     | 
    
         
             
                Makit::Commands::Runner.default.execute(request)
         
     | 
| 
       83 
89 
     | 
    
         
             
              end
         
     | 
| 
       84 
90 
     | 
    
         |