- Split the monolith into package/provider/fetch/merge/cache modules with the Resolver deciding install/adopt/update/merge/conflict outcomes - Three-way merges via git merge-file/diff3 against a content-addressed merge-base cache; conflicts go to a .picopackage-merge sibling - Tests for package, provider, resolver, merge, and cache - notes.md: update UX and signing design — diff-by-default, SSH signature identity pinning (TOFU), key changes as a hard stop, exit-code contract - Add CLAUDE.md; remove the pre-refactor exe/pppkg monolith and scratch files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EiyJC73Mz8xZyCTvCEY8qn
32 lines
894 B
Ruby
32 lines
894 B
Ruby
# frozen_string_literal: true
|
|
|
|
module Picopackage
|
|
module Scanner
|
|
Found = Struct.new(:path, :package)
|
|
|
|
# Scanning walks whole trees, so it has to survive binaries, unreadable
|
|
# files and anything large enough that reading it to look for a comment
|
|
# would be silly.
|
|
MAX_SCAN_SIZE = 1024 * 1024
|
|
|
|
def self.scan(directory, pattern: "**/*")
|
|
Dir.glob(File.join(directory, pattern)).sort.filter_map do |path|
|
|
content = readable_text(path)
|
|
next unless content&.match?(METADATA_PATTERN)
|
|
|
|
Found.new(path, Package.new(content: content))
|
|
end
|
|
end
|
|
|
|
def self.readable_text(path)
|
|
return nil unless File.file?(path)
|
|
return nil if File.size(path) > MAX_SCAN_SIZE
|
|
|
|
content = File.read(path, encoding: "UTF-8")
|
|
content.valid_encoding? ? content : nil
|
|
rescue SystemCallError, ArgumentError
|
|
nil
|
|
end
|
|
end
|
|
end
|