build-files 1.9.0 → 1.10.0
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
 - checksums.yaml.gz.sig +0 -0
 - data/lib/build/files/composite.rb +35 -7
 - data/lib/build/files/difference.rb +25 -6
 - data/lib/build/files/directory.rb +34 -5
 - data/lib/build/files/glob.rb +26 -2
 - data/lib/build/files/list.rb +30 -3
 - data/lib/build/files/path.rb +77 -4
 - data/lib/build/files/paths.rb +28 -3
 - data/lib/build/files/state.rb +29 -6
 - data/lib/build/files/system.rb +16 -4
 - data/lib/build/files/version.rb +4 -2
 - data/lib/build/files.rb +7 -7
 - data/license.md +1 -1
 - data/readme.md +13 -11
 - data/releases.md +3 -0
 - data.tar.gz.sig +1 -2
 - metadata +7 -53
 - metadata.gz.sig +0 -0
 - data/conduct.md +0 -133
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 555dbd01ff6915b1d7a9c11864d95544929e35006094fb0eda4ca7b8d8227006
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 6c17197d4bacc772f1e9aed6bce37cfab7ea4dcfb172c07a7ad955dfd8dc25ce
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 8078524f809ad559c7c62de94ac98db9e6129e7d97f268fa2440a4732fbd3cba590d37775d9021b5a118c6957b81d87dbfb2321065fcd0eb32e9ab6e099617e8
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 951b008d3c8a395024acfa3d83db9dc86cedadb3fbc6af4964f48cf23cc61f4f460eb63df40c7fd89efffaa3f6d6a818f2641a6c49b629d790643b01304c8e49
         
     | 
    
        checksums.yaml.gz.sig
    CHANGED
    
    | 
         Binary file 
     | 
| 
         @@ -1,20 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2019- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2019-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module Build
         
     | 
| 
       9 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
      
 10 
     | 
    
         
            +
            		# Represents a composite list of files from multiple sources.
         
     | 
| 
       10 
11 
     | 
    
         
             
            		class Composite < List
         
     | 
| 
      
 12 
     | 
    
         
            +
            			# Initialize a composite list with multiple file lists.
         
     | 
| 
      
 13 
     | 
    
         
            +
            			# @parameter files [Array] The file lists to combine.
         
     | 
| 
      
 14 
     | 
    
         
            +
            			# @parameter roots [Array(Path) | Nil] The root paths, if known.
         
     | 
| 
       11 
15 
     | 
    
         
             
            			def initialize(files, roots = nil)
         
     | 
| 
       12 
16 
     | 
    
         
             
            				@files = []
         
     | 
| 
       13 
17 
     | 
    
         | 
| 
       14 
18 
     | 
    
         
             
            				files.each do |list|
         
     | 
| 
       15 
19 
     | 
    
         
             
            					if list.kind_of? Composite
         
     | 
| 
       16 
20 
     | 
    
         
             
            						@files += list.files
         
     | 
| 
       17 
     | 
    
         
            -
            					elsif  
     | 
| 
      
 21 
     | 
    
         
            +
            					elsif list.kind_of? List
         
     | 
| 
       18 
22 
     | 
    
         
             
            						@files << list
         
     | 
| 
       19 
23 
     | 
    
         
             
            					else
         
     | 
| 
       20 
24 
     | 
    
         
             
            						# Try to convert into a explicit paths list:
         
     | 
| 
         @@ -28,12 +32,16 @@ module Build 
     | 
|
| 
       28 
32 
     | 
    
         | 
| 
       29 
33 
     | 
    
         
             
            			attr :files
         
     | 
| 
       30 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
            			# Freeze the composite list and its dependencies.
         
     | 
| 
       31 
36 
     | 
    
         
             
            			def freeze
         
     | 
| 
       32 
37 
     | 
    
         
             
            				self.roots
         
     | 
| 
       33 
38 
     | 
    
         | 
| 
       34 
39 
     | 
    
         
             
            				super
         
     | 
| 
       35 
40 
     | 
    
         
             
            			end
         
     | 
| 
       36 
41 
     | 
    
         | 
| 
      
 42 
     | 
    
         
            +
            			# Iterate over all files in the composite list.
         
     | 
| 
      
 43 
     | 
    
         
            +
            			# @yields {|path| ...} Each path in all combined lists.
         
     | 
| 
      
 44 
     | 
    
         
            +
            			#   @parameter path [Path] The current file path.
         
     | 
| 
       37 
45 
     | 
    
         
             
            			def each
         
     | 
| 
       38 
46 
     | 
    
         
             
            				return to_enum(:each) unless block_given?
         
     | 
| 
       39 
47 
     | 
    
         | 
| 
         @@ -42,18 +50,28 @@ module Build 
     | 
|
| 
       42 
50 
     | 
    
         
             
            				end
         
     | 
| 
       43 
51 
     | 
    
         
             
            			end
         
     | 
| 
       44 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
            			# Get all root paths for all lists in the composite.
         
     | 
| 
      
 54 
     | 
    
         
            +
            			# @returns [Array(Path)] The unique root paths.
         
     | 
| 
       45 
55 
     | 
    
         
             
            			def roots
         
     | 
| 
       46 
56 
     | 
    
         
             
            				@roots ||= @files.collect(&:roots).flatten.uniq
         
     | 
| 
       47 
57 
     | 
    
         
             
            			end
         
     | 
| 
       48 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
            			# Check equality with another composite list.
         
     | 
| 
      
 60 
     | 
    
         
            +
            			# @parameter other [Composite] The other composite to compare.
         
     | 
| 
      
 61 
     | 
    
         
            +
            			# @returns [Boolean] True if both composites have the same files.
         
     | 
| 
       49 
62 
     | 
    
         
             
            			def eql?(other)
         
     | 
| 
       50 
63 
     | 
    
         
             
            				self.class.eql?(other.class) and @files.eql?(other.files)
         
     | 
| 
       51 
64 
     | 
    
         
             
            			end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
            			
         
     | 
| 
      
 66 
     | 
    
         
            +
            			# Compute the hash value for this composite.
         
     | 
| 
      
 67 
     | 
    
         
            +
            			# @returns [Integer] The hash value based on files.
         
     | 
| 
       53 
68 
     | 
    
         
             
            			def hash
         
     | 
| 
       54 
69 
     | 
    
         
             
            				@files.hash
         
     | 
| 
       55 
70 
     | 
    
         
             
            			end
         
     | 
| 
       56 
71 
     | 
    
         | 
| 
      
 72 
     | 
    
         
            +
            			# Combine this composite with another list.
         
     | 
| 
      
 73 
     | 
    
         
            +
            			# @parameter list [List] The list to add.
         
     | 
| 
      
 74 
     | 
    
         
            +
            			# @returns [Composite] A new composite containing both lists.
         
     | 
| 
       57 
75 
     | 
    
         
             
            			def +(list)
         
     | 
| 
       58 
76 
     | 
    
         
             
            				if list.kind_of? Composite
         
     | 
| 
       59 
77 
     | 
    
         
             
            					self.class.new(@files + list.files)
         
     | 
| 
         @@ -61,19 +79,29 @@ module Build 
     | 
|
| 
       61 
79 
     | 
    
         
             
            					self.class.new(@files + [list])
         
     | 
| 
       62 
80 
     | 
    
         
             
            				end
         
     | 
| 
       63 
81 
     | 
    
         
             
            			end
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
      
 82 
     | 
    
         
            +
            			
         
     | 
| 
      
 83 
     | 
    
         
            +
            			# Check if the composite includes a specific path.
         
     | 
| 
      
 84 
     | 
    
         
            +
            			# @parameter path [Path] The path to check.
         
     | 
| 
      
 85 
     | 
    
         
            +
            			# @returns [Boolean] True if any list in the composite includes the path.
         
     | 
| 
       65 
86 
     | 
    
         
             
            			def include?(path)
         
     | 
| 
       66 
87 
     | 
    
         
             
            				@files.any? {|list| list.include?(path)}
         
     | 
| 
       67 
88 
     | 
    
         
             
            			end
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
      
 89 
     | 
    
         
            +
            			
         
     | 
| 
      
 90 
     | 
    
         
            +
            			# Rebase all lists in the composite to a new root.
         
     | 
| 
      
 91 
     | 
    
         
            +
            			# @parameter root [Path] The new root path.
         
     | 
| 
      
 92 
     | 
    
         
            +
            			# @returns [Composite] A new composite with rebased lists.
         
     | 
| 
       69 
93 
     | 
    
         
             
            			def rebase(root)
         
     | 
| 
       70 
94 
     | 
    
         
             
            				self.class.new(@files.collect{|list| list.rebase(root)}, [root])
         
     | 
| 
       71 
95 
     | 
    
         
             
            			end
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
            			
         
     | 
| 
      
 97 
     | 
    
         
            +
            			# Convert all lists in the composite to paths.
         
     | 
| 
      
 98 
     | 
    
         
            +
            			# @returns [Composite] A new composite with all lists converted to paths.
         
     | 
| 
       73 
99 
     | 
    
         
             
            			def to_paths
         
     | 
| 
       74 
100 
     | 
    
         
             
            				self.class.new(@files.collect(&:to_paths), roots: @roots)
         
     | 
| 
       75 
101 
     | 
    
         
             
            			end
         
     | 
| 
       76 
102 
     | 
    
         | 
| 
      
 103 
     | 
    
         
            +
            			# Generate a string representation for debugging.
         
     | 
| 
      
 104 
     | 
    
         
            +
            			# @returns [String] A debug string showing the composite structure.
         
     | 
| 
       77 
105 
     | 
    
         
             
            			def inspect
         
     | 
| 
       78 
106 
     | 
    
         
             
            				"<Composite #{@files.inspect}>"
         
     | 
| 
       79 
107 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -1,13 +1,17 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2019- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2019-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module Build
         
     | 
| 
       9 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
      
 10 
     | 
    
         
            +
            		# Represents a list of files with exclusions applied.
         
     | 
| 
       10 
11 
     | 
    
         
             
            		class Difference < List
         
     | 
| 
      
 12 
     | 
    
         
            +
            			# Initialize a difference list.
         
     | 
| 
      
 13 
     | 
    
         
            +
            			# @parameter list [List] The base list of files.
         
     | 
| 
      
 14 
     | 
    
         
            +
            			# @parameter excludes [List] The list of files to exclude.
         
     | 
| 
       11 
15 
     | 
    
         
             
            			def initialize(list, excludes)
         
     | 
| 
       12 
16 
     | 
    
         
             
            				@list = list
         
     | 
| 
       13 
17 
     | 
    
         
             
            				@excludes = excludes
         
     | 
| 
         @@ -15,6 +19,7 @@ module Build 
     | 
|
| 
       15 
19 
     | 
    
         | 
| 
       16 
20 
     | 
    
         
             
            			attr :files
         
     | 
| 
       17 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
            			# Freeze the difference list and its dependencies.
         
     | 
| 
       18 
23 
     | 
    
         
             
            			def freeze
         
     | 
| 
       19 
24 
     | 
    
         
             
            				@list.freeze
         
     | 
| 
       20 
25 
     | 
    
         
             
            				@excludes.freeze
         
     | 
| 
         @@ -22,6 +27,9 @@ module Build 
     | 
|
| 
       22 
27 
     | 
    
         
             
            				super
         
     | 
| 
       23 
28 
     | 
    
         
             
            			end
         
     | 
| 
       24 
29 
     | 
    
         | 
| 
      
 30 
     | 
    
         
            +
            			# Iterate over files in the base list, excluding those in the exclusion list.
         
     | 
| 
      
 31 
     | 
    
         
            +
            			# @yields {|path| ...} Each path not in the exclusion list.
         
     | 
| 
      
 32 
     | 
    
         
            +
            			#   @parameter path [Path] The current file path.
         
     | 
| 
       25 
33 
     | 
    
         
             
            			def each
         
     | 
| 
       26 
34 
     | 
    
         
             
            				return to_enum(:each) unless block_given?
         
     | 
| 
       27 
35 
     | 
    
         | 
| 
         @@ -30,20 +38,31 @@ module Build 
     | 
|
| 
       30 
38 
     | 
    
         
             
            				end
         
     | 
| 
       31 
39 
     | 
    
         
             
            			end
         
     | 
| 
       32 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
            			# Subtract additional files from this difference.
         
     | 
| 
      
 42 
     | 
    
         
            +
            			# @parameter list [List] Additional files to exclude.
         
     | 
| 
      
 43 
     | 
    
         
            +
            			# @returns [Difference] A new difference with expanded exclusions.
         
     | 
| 
       33 
44 
     | 
    
         
             
            			def -(list)
         
     | 
| 
       34 
     | 
    
         
            -
            				self.class.new(@list, Composite.new(@excludes, list))
         
     | 
| 
      
 45 
     | 
    
         
            +
            				self.class.new(@list, Composite.new([@excludes, list]))
         
     | 
| 
       35 
46 
     | 
    
         
             
            			end
         
     | 
| 
       36 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
            			# Check if the difference includes a specific path.
         
     | 
| 
      
 49 
     | 
    
         
            +
            			# @parameter path [Path] The path to check.
         
     | 
| 
      
 50 
     | 
    
         
            +
            			# @returns [Boolean] True if the path is in the base list but not excluded.
         
     | 
| 
       37 
51 
     | 
    
         
             
            			def include?(path)
         
     | 
| 
       38 
     | 
    
         
            -
            				@list. 
     | 
| 
      
 52 
     | 
    
         
            +
            				@list.include?(path) and !@excludes.include?(path)
         
     | 
| 
       39 
53 
     | 
    
         
             
            			end
         
     | 
| 
       40 
54 
     | 
    
         | 
| 
      
 55 
     | 
    
         
            +
            			# Rebase the difference to a new root.
         
     | 
| 
      
 56 
     | 
    
         
            +
            			# @parameter root [Path] The new root path.
         
     | 
| 
      
 57 
     | 
    
         
            +
            			# @returns [Difference] A new difference with rebased files.
         
     | 
| 
       41 
58 
     | 
    
         
             
            			def rebase(root)
         
     | 
| 
       42 
     | 
    
         
            -
            				self.class.new(@ 
     | 
| 
      
 59 
     | 
    
         
            +
            				self.class.new(@list.rebase(root), @excludes.rebase(root))
         
     | 
| 
       43 
60 
     | 
    
         
             
            			end
         
     | 
| 
       44 
61 
     | 
    
         | 
| 
      
 62 
     | 
    
         
            +
            			# Generate a string representation for debugging.
         
     | 
| 
      
 63 
     | 
    
         
            +
            			# @returns [String] A debug string showing the difference structure.
         
     | 
| 
       45 
64 
     | 
    
         
             
            			def inspect
         
     | 
| 
       46 
     | 
    
         
            -
            				"<Difference #{@ 
     | 
| 
      
 65 
     | 
    
         
            +
            				"<Difference #{@list.inspect} - #{@excludes.inspect}>"
         
     | 
| 
       47 
66 
     | 
    
         
             
            			end
         
     | 
| 
       48 
67 
     | 
    
         
             
            		end
         
     | 
| 
       49 
68 
     | 
    
         
             
            	end
         
     | 
| 
         @@ -1,29 +1,42 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module Build
         
     | 
| 
       9 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
      
 10 
     | 
    
         
            +
            		# Represents a directory of files.
         
     | 
| 
       10 
11 
     | 
    
         
             
            		class Directory < List
         
     | 
| 
      
 12 
     | 
    
         
            +
            			# Join path components and create a directory.
         
     | 
| 
      
 13 
     | 
    
         
            +
            			# @parameter args [Array(String)] The path components to join.
         
     | 
| 
      
 14 
     | 
    
         
            +
            			# @returns [Directory] A new directory at the joined path.
         
     | 
| 
       11 
15 
     | 
    
         
             
            			def self.join(*args)
         
     | 
| 
       12 
16 
     | 
    
         
             
            				self.new(Path.join(*args))
         
     | 
| 
       13 
17 
     | 
    
         
             
            			end
         
     | 
| 
       14 
18 
     | 
    
         | 
| 
      
 19 
     | 
    
         
            +
            			# Initialize a directory with a root path.
         
     | 
| 
      
 20 
     | 
    
         
            +
            			# @parameter root [Path | String] The root path of the directory.
         
     | 
| 
       15 
21 
     | 
    
         
             
            			def initialize(root)
         
     | 
| 
       16 
22 
     | 
    
         
             
            				@root = root
         
     | 
| 
       17 
23 
     | 
    
         
             
            			end
         
     | 
| 
       18 
24 
     | 
    
         | 
| 
      
 25 
     | 
    
         
            +
            			# Get the root path of the directory.
         
     | 
| 
      
 26 
     | 
    
         
            +
            			# @returns [Path] The root path.
         
     | 
| 
       19 
27 
     | 
    
         
             
            			def root
         
     | 
| 
       20 
28 
     | 
    
         
             
            				@root
         
     | 
| 
       21 
29 
     | 
    
         
             
            			end
         
     | 
| 
       22 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
            			# Get the root paths as an array.
         
     | 
| 
      
 32 
     | 
    
         
            +
            			# @returns [Array(Path)] An array containing the single root path.
         
     | 
| 
       23 
33 
     | 
    
         
             
            			def roots
         
     | 
| 
       24 
34 
     | 
    
         
             
            				[root]
         
     | 
| 
       25 
35 
     | 
    
         
             
            			end
         
     | 
| 
       26 
36 
     | 
    
         | 
| 
      
 37 
     | 
    
         
            +
            			# Iterate over all files in the directory recursively.
         
     | 
| 
      
 38 
     | 
    
         
            +
            			# @yields {|path| ...} Each file path in the directory.
         
     | 
| 
      
 39 
     | 
    
         
            +
            			#   @parameter path [Path] The current file path.
         
     | 
| 
       27 
40 
     | 
    
         
             
            			def each
         
     | 
| 
       28 
41 
     | 
    
         
             
            				return to_enum(:each) unless block_given?
         
     | 
| 
       29 
42 
     | 
    
         | 
| 
         @@ -33,32 +46,48 @@ module Build 
     | 
|
| 
       33 
46 
     | 
    
         
             
            				end
         
     | 
| 
       34 
47 
     | 
    
         
             
            			end
         
     | 
| 
       35 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
            			# Check equality with another directory.
         
     | 
| 
      
 50 
     | 
    
         
            +
            			# @parameter other [Directory] The other directory to compare.
         
     | 
| 
      
 51 
     | 
    
         
            +
            			# @returns [Boolean] True if both directories have the same root.
         
     | 
| 
       36 
52 
     | 
    
         
             
            			def eql?(other)
         
     | 
| 
       37 
53 
     | 
    
         
             
            				self.class.eql?(other.class) and @root.eql?(other.root)
         
     | 
| 
       38 
54 
     | 
    
         
             
            			end
         
     | 
| 
       39 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
            			# Compute the hash value for this directory.
         
     | 
| 
      
 57 
     | 
    
         
            +
            			# @returns [Integer] The hash value based on the root.
         
     | 
| 
       40 
58 
     | 
    
         
             
            			def hash
         
     | 
| 
       41 
59 
     | 
    
         
             
            				@root.hash
         
     | 
| 
       42 
60 
     | 
    
         
             
            			end
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 61 
     | 
    
         
            +
            			
         
     | 
| 
      
 62 
     | 
    
         
            +
            			# Check if the directory includes a specific path.
         
     | 
| 
      
 63 
     | 
    
         
            +
            			# @parameter path [Path] The path to check.
         
     | 
| 
      
 64 
     | 
    
         
            +
            			# @returns [Boolean] True if the path is within this directory.
         
     | 
| 
       44 
65 
     | 
    
         
             
            			def include?(path)
         
     | 
| 
       45 
66 
     | 
    
         
             
            				# Would be true if path is a descendant of full_path.
         
     | 
| 
       46 
67 
     | 
    
         
             
            				path.start_with?(@root)
         
     | 
| 
       47 
68 
     | 
    
         
             
            			end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 69 
     | 
    
         
            +
            			
         
     | 
| 
      
 70 
     | 
    
         
            +
            			# Rebase the directory to a new root.
         
     | 
| 
      
 71 
     | 
    
         
            +
            			# @parameter root [Path] The new root path.
         
     | 
| 
      
 72 
     | 
    
         
            +
            			# @returns [Directory] A new directory with the rebased root.
         
     | 
| 
       49 
73 
     | 
    
         
             
            			def rebase(root)
         
     | 
| 
       50 
74 
     | 
    
         
             
            				self.class.new(@root.rebase(root))
         
     | 
| 
       51 
75 
     | 
    
         
             
            			end
         
     | 
| 
       52 
76 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
            			# Convert  
     | 
| 
      
 77 
     | 
    
         
            +
            			# Convert the directory to a string for use as a command argument.
         
     | 
| 
      
 78 
     | 
    
         
            +
            			# @returns [String] The root path as a string.
         
     | 
| 
       54 
79 
     | 
    
         
             
            			def to_str
         
     | 
| 
       55 
80 
     | 
    
         
             
            				@root.to_str
         
     | 
| 
       56 
81 
     | 
    
         
             
            			end
         
     | 
| 
       57 
82 
     | 
    
         | 
| 
      
 83 
     | 
    
         
            +
            			# Convert the directory to a string.
         
     | 
| 
      
 84 
     | 
    
         
            +
            			# @returns [String] The root path as a string.
         
     | 
| 
       58 
85 
     | 
    
         
             
            			def to_s
         
     | 
| 
       59 
86 
     | 
    
         
             
            				to_str
         
     | 
| 
       60 
87 
     | 
    
         
             
            			end
         
     | 
| 
       61 
88 
     | 
    
         | 
| 
      
 89 
     | 
    
         
            +
            			# Convert the directory to a path object.
         
     | 
| 
      
 90 
     | 
    
         
            +
            			# @returns [Path] The root path.
         
     | 
| 
       62 
91 
     | 
    
         
             
            			def to_path
         
     | 
| 
       63 
92 
     | 
    
         
             
            				@root
         
     | 
| 
       64 
93 
     | 
    
         
             
            			end
         
     | 
    
        data/lib/build/files/glob.rb
    CHANGED
    
    | 
         @@ -1,19 +1,26 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module Build
         
     | 
| 
       9 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
       10 
10 
     | 
    
         
             
            		class Path
         
     | 
| 
      
 11 
     | 
    
         
            +
            			# Create a glob pattern matcher for files under this path.
         
     | 
| 
      
 12 
     | 
    
         
            +
            			# @parameter pattern [String] The glob pattern to match.
         
     | 
| 
      
 13 
     | 
    
         
            +
            			# @returns [Glob] A glob matcher for the pattern.
         
     | 
| 
       11 
14 
     | 
    
         
             
            			def glob(pattern)
         
     | 
| 
       12 
15 
     | 
    
         
             
            				Glob.new(self, pattern)
         
     | 
| 
       13 
16 
     | 
    
         
             
            			end
         
     | 
| 
       14 
17 
     | 
    
         
             
            		end
         
     | 
| 
       15 
18 
     | 
    
         | 
| 
      
 19 
     | 
    
         
            +
            		# Represents a glob pattern for matching files.
         
     | 
| 
       16 
20 
     | 
    
         
             
            		class Glob < List
         
     | 
| 
      
 21 
     | 
    
         
            +
            			# Initialize a glob with a root path and pattern.
         
     | 
| 
      
 22 
     | 
    
         
            +
            			# @parameter root [Path] The root directory for the glob.
         
     | 
| 
      
 23 
     | 
    
         
            +
            			# @parameter pattern [String] The glob pattern to match.
         
     | 
| 
       17 
24 
     | 
    
         
             
            			def initialize(root, pattern)
         
     | 
| 
       18 
25 
     | 
    
         
             
            				@root = root
         
     | 
| 
       19 
26 
     | 
    
         
             
            				@pattern = pattern
         
     | 
| 
         @@ -22,10 +29,14 @@ module Build 
     | 
|
| 
       22 
29 
     | 
    
         
             
            			attr :root
         
     | 
| 
       23 
30 
     | 
    
         
             
            			attr :pattern
         
     | 
| 
       24 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
            			# Get the root paths for this glob.
         
     | 
| 
      
 33 
     | 
    
         
            +
            			# @returns [Array(Path)] An array containing the root path.
         
     | 
| 
       25 
34 
     | 
    
         
             
            			def roots
         
     | 
| 
       26 
35 
     | 
    
         
             
            				[@root]
         
     | 
| 
       27 
36 
     | 
    
         
             
            			end
         
     | 
| 
       28 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
            			# Get the full pattern including the root path.
         
     | 
| 
      
 39 
     | 
    
         
            +
            			# @returns [String] The complete glob pattern.
         
     | 
| 
       29 
40 
     | 
    
         
             
            			def full_pattern
         
     | 
| 
       30 
41 
     | 
    
         
             
            				Path.join(@root, @pattern)
         
     | 
| 
       31 
42 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -42,22 +53,35 @@ module Build 
     | 
|
| 
       42 
53 
     | 
    
         
             
            				end
         
     | 
| 
       43 
54 
     | 
    
         
             
            			end
         
     | 
| 
       44 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
            			# Check equality with another glob.
         
     | 
| 
      
 57 
     | 
    
         
            +
            			# @parameter other [Glob] The other glob to compare.
         
     | 
| 
      
 58 
     | 
    
         
            +
            			# @returns [Boolean] True if both globs have the same root and pattern.
         
     | 
| 
       45 
59 
     | 
    
         
             
            			def eql?(other)
         
     | 
| 
       46 
60 
     | 
    
         
             
            				self.class.eql?(other.class) and @root.eql?(other.root) and @pattern.eql?(other.pattern)
         
     | 
| 
       47 
61 
     | 
    
         
             
            			end
         
     | 
| 
       48 
62 
     | 
    
         | 
| 
      
 63 
     | 
    
         
            +
            			# Compute the hash value for this glob.
         
     | 
| 
      
 64 
     | 
    
         
            +
            			# @returns [Integer] The hash value based on root and pattern.
         
     | 
| 
       49 
65 
     | 
    
         
             
            			def hash
         
     | 
| 
       50 
66 
     | 
    
         
             
            				[@root, @pattern].hash
         
     | 
| 
       51 
67 
     | 
    
         
             
            			end
         
     | 
| 
       52 
68 
     | 
    
         | 
| 
      
 69 
     | 
    
         
            +
            			# Check if a path matches this glob pattern.
         
     | 
| 
      
 70 
     | 
    
         
            +
            			# @parameter path [Path] The path to check.
         
     | 
| 
      
 71 
     | 
    
         
            +
            			# @returns [Boolean] True if the path matches the pattern.
         
     | 
| 
       53 
72 
     | 
    
         
             
            			def include?(path)
         
     | 
| 
       54 
73 
     | 
    
         
             
            				File.fnmatch(full_pattern, path)
         
     | 
| 
       55 
74 
     | 
    
         
             
            			end
         
     | 
| 
       56 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
            			# Rebase the glob to a new root.
         
     | 
| 
      
 77 
     | 
    
         
            +
            			# @parameter root [Path] The new root path.
         
     | 
| 
      
 78 
     | 
    
         
            +
            			# @returns [Glob] A new glob with the same pattern under the new root.
         
     | 
| 
       57 
79 
     | 
    
         
             
            			def rebase(root)
         
     | 
| 
       58 
80 
     | 
    
         
             
            				self.class.new(root, @pattern)
         
     | 
| 
       59 
81 
     | 
    
         
             
            			end
         
     | 
| 
       60 
82 
     | 
    
         | 
| 
      
 83 
     | 
    
         
            +
            			# Generate a string representation for debugging.
         
     | 
| 
      
 84 
     | 
    
         
            +
            			# @returns [String] A debug string showing the full pattern.
         
     | 
| 
       61 
85 
     | 
    
         
             
            			def inspect
         
     | 
| 
       62 
86 
     | 
    
         
             
            				"<Glob #{full_pattern.inspect}>"
         
     | 
| 
       63 
87 
     | 
    
         
             
            			end
         
     | 
    
        data/lib/build/files/list.rb
    CHANGED
    
    | 
         @@ -1,9 +1,9 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "path"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module Build
         
     | 
| 
       9 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
         @@ -11,6 +11,8 @@ module Build 
     | 
|
| 
       11 
11 
     | 
    
         
             
            		class List
         
     | 
| 
       12 
12 
     | 
    
         
             
            			include Enumerable
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
            			# Get all unique root paths from the list.
         
     | 
| 
      
 15 
     | 
    
         
            +
            			# @returns [Array(Path)] Sorted unique root paths.
         
     | 
| 
       14 
16 
     | 
    
         
             
            			def roots
         
     | 
| 
       15 
17 
     | 
    
         
             
            				collect{|path| path.root}.sort.uniq
         
     | 
| 
       16 
18 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -20,6 +22,9 @@ module Build 
     | 
|
| 
       20 
22 
     | 
    
         
             
            				Composite.new([self, list])
         
     | 
| 
       21 
23 
     | 
    
         
             
            			end
         
     | 
| 
       22 
24 
     | 
    
         | 
| 
      
 25 
     | 
    
         
            +
            			# Subtract a list from this list.
         
     | 
| 
      
 26 
     | 
    
         
            +
            			# @parameter list [List] The list to subtract.
         
     | 
| 
      
 27 
     | 
    
         
            +
            			# @returns [Difference] A difference list excluding the given paths.
         
     | 
| 
       23 
28 
     | 
    
         
             
            			def -(list)
         
     | 
| 
       24 
29 
     | 
    
         
             
            				Difference.new(self, list)
         
     | 
| 
       25 
30 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -40,6 +45,8 @@ module Build 
     | 
|
| 
       40 
45 
     | 
    
         
             
            				other.any?{|path| include?(path)}
         
     | 
| 
       41 
46 
     | 
    
         
             
            			end
         
     | 
| 
       42 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
            			# Check if the list is empty.
         
     | 
| 
      
 49 
     | 
    
         
            +
            			# @returns [Boolean] True if the list contains no paths.
         
     | 
| 
       43 
50 
     | 
    
         
             
            			def empty?
         
     | 
| 
       44 
51 
     | 
    
         
             
            				each do
         
     | 
| 
       45 
52 
     | 
    
         
             
            					return false
         
     | 
| 
         @@ -48,6 +55,12 @@ module Build 
     | 
|
| 
       48 
55 
     | 
    
         
             
            				return true
         
     | 
| 
       49 
56 
     | 
    
         
             
            			end
         
     | 
| 
       50 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
            			# Transform paths with modified attributes.
         
     | 
| 
      
 59 
     | 
    
         
            +
            			# @parameter options [Hash] Options to pass to {Path#with}.
         
     | 
| 
      
 60 
     | 
    
         
            +
            			# @yields {|path, updated_path| ...} Each original and updated path.
         
     | 
| 
      
 61 
     | 
    
         
            +
            			#   @parameter path [Path] The original path.
         
     | 
| 
      
 62 
     | 
    
         
            +
            			#   @parameter updated_path [Path] The modified path.
         
     | 
| 
      
 63 
     | 
    
         
            +
            			# @returns [Paths] A new paths list with transformed paths.
         
     | 
| 
       51 
64 
     | 
    
         
             
            			def with(**options)
         
     | 
| 
       52 
65 
     | 
    
         
             
            				return to_enum(:with, **options) unless block_given?
         
     | 
| 
       53 
66 
     | 
    
         | 
| 
         @@ -64,18 +77,30 @@ module Build 
     | 
|
| 
       64 
77 
     | 
    
         
             
            				return Paths.new(paths)
         
     | 
| 
       65 
78 
     | 
    
         
             
            			end
         
     | 
| 
       66 
79 
     | 
    
         | 
| 
      
 80 
     | 
    
         
            +
            			# Rebase all paths in the list to a new root.
         
     | 
| 
      
 81 
     | 
    
         
            +
            			# @parameter root [Path] The new root path.
         
     | 
| 
      
 82 
     | 
    
         
            +
            			# @returns [Paths] A new paths list with rebased paths.
         
     | 
| 
       67 
83 
     | 
    
         
             
            			def rebase(root)
         
     | 
| 
       68 
84 
     | 
    
         
             
            				Paths.new(self.collect{|path| path.rebase(root)}, [root])
         
     | 
| 
       69 
85 
     | 
    
         
             
            			end
         
     | 
| 
       70 
86 
     | 
    
         | 
| 
      
 87 
     | 
    
         
            +
            			# Convert the list to a Paths instance.
         
     | 
| 
      
 88 
     | 
    
         
            +
            			# @returns [Paths] A paths list containing all items.
         
     | 
| 
       71 
89 
     | 
    
         
             
            			def to_paths
         
     | 
| 
       72 
90 
     | 
    
         
             
            				Paths.new(each.to_a)
         
     | 
| 
       73 
91 
     | 
    
         
             
            			end
         
     | 
| 
       74 
92 
     | 
    
         | 
| 
      
 93 
     | 
    
         
            +
            			# Map over the list and return a Paths instance.
         
     | 
| 
      
 94 
     | 
    
         
            +
            			# @yields {|path| ...} Each path in the list.
         
     | 
| 
      
 95 
     | 
    
         
            +
            			#   @parameter path [Path] The current path.
         
     | 
| 
      
 96 
     | 
    
         
            +
            			# @returns [Paths] A new paths list with mapped values.
         
     | 
| 
       75 
97 
     | 
    
         
             
            			def map
         
     | 
| 
       76 
98 
     | 
    
         
             
            				Paths.new(super)
         
     | 
| 
       77 
99 
     | 
    
         
             
            			end
         
     | 
| 
       78 
100 
     | 
    
         | 
| 
      
 101 
     | 
    
         
            +
            			# Coerce an argument to a List instance.
         
     | 
| 
      
 102 
     | 
    
         
            +
            			# @parameter arg [List | Object] The object to coerce.
         
     | 
| 
      
 103 
     | 
    
         
            +
            			# @returns [List] A list instance.
         
     | 
| 
       79 
104 
     | 
    
         
             
            			def self.coerce(arg)
         
     | 
| 
       80 
105 
     | 
    
         
             
            				if arg.kind_of? self
         
     | 
| 
       81 
106 
     | 
    
         
             
            					arg
         
     | 
| 
         @@ -84,6 +109,8 @@ module Build 
     | 
|
| 
       84 
109 
     | 
    
         
             
            				end
         
     | 
| 
       85 
110 
     | 
    
         
             
            			end
         
     | 
| 
       86 
111 
     | 
    
         | 
| 
      
 112 
     | 
    
         
            +
            			# Convert the list to a string.
         
     | 
| 
      
 113 
     | 
    
         
            +
            			# @returns [String] The string representation.
         
     | 
| 
       87 
114 
     | 
    
         
             
            			def to_s
         
     | 
| 
       88 
115 
     | 
    
         
             
            				inspect
         
     | 
| 
       89 
116 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -91,4 +118,4 @@ module Build 
     | 
|
| 
       91 
118 
     | 
    
         
             
            	end
         
     | 
| 
       92 
119 
     | 
    
         
             
            end
         
     | 
| 
       93 
120 
     | 
    
         | 
| 
       94 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 121 
     | 
    
         
            +
            require_relative "difference"
         
     | 
    
        data/lib/build/files/path.rb
    CHANGED
    
    | 
         @@ -1,20 +1,25 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            module Build
         
     | 
| 
       7 
7 
     | 
    
         
             
            	module Files
         
     | 
| 
       8 
8 
     | 
    
         
             
            		# Represents a file path with an absolute root and a relative offset:
         
     | 
| 
       9 
9 
     | 
    
         
             
            		class Path
         
     | 
| 
      
 10 
     | 
    
         
            +
            			# Get the current working directory as a path.
         
     | 
| 
      
 11 
     | 
    
         
            +
            			# @returns [Path] The current directory path.
         
     | 
| 
       10 
12 
     | 
    
         
             
            			def self.current
         
     | 
| 
       11 
13 
     | 
    
         
             
            				self.new(::Dir.pwd)
         
     | 
| 
       12 
14 
     | 
    
         
             
            			end
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
      
 16 
     | 
    
         
            +
            			# Split a path into directory, filename, and extension components.
         
     | 
| 
      
 17 
     | 
    
         
            +
            			# @parameter path [String] The path to split.
         
     | 
| 
      
 18 
     | 
    
         
            +
            			# @returns [Array(String, String, String)] The directory, filename, and extension.
         
     | 
| 
       14 
19 
     | 
    
         
             
            			def self.split(path)
         
     | 
| 
       15 
20 
     | 
    
         
             
            				# Effectively dirname and basename:
         
     | 
| 
       16 
21 
     | 
    
         
             
            				dirname, separator, filename = path.rpartition(File::SEPARATOR)
         
     | 
| 
       17 
     | 
    
         
            -
            				filename, dot, extension = filename.rpartition( 
     | 
| 
      
 22 
     | 
    
         
            +
            				filename, dot, extension = filename.rpartition(".")
         
     | 
| 
       18 
23 
     | 
    
         | 
| 
       19 
24 
     | 
    
         
             
            				return dirname + separator, filename, dot + extension
         
     | 
| 
       20 
25 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -33,6 +38,9 @@ module Build 
     | 
|
| 
       33 
38 
     | 
    
         
             
            				end
         
     | 
| 
       34 
39 
     | 
    
         
             
            			end
         
     | 
| 
       35 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
            			# Get the root directory of a path.
         
     | 
| 
      
 42 
     | 
    
         
            +
            			# @parameter path [Path | String] The path to get the root from.
         
     | 
| 
      
 43 
     | 
    
         
            +
            			# @returns [String] The root directory.
         
     | 
| 
       36 
44 
     | 
    
         
             
            			def self.root(path)
         
     | 
| 
       37 
45 
     | 
    
         
             
            				if Path === path
         
     | 
| 
       38 
46 
     | 
    
         
             
            					path.root
         
     | 
| 
         @@ -41,7 +49,10 @@ module Build 
     | 
|
| 
       41 
49 
     | 
    
         
             
            				end
         
     | 
| 
       42 
50 
     | 
    
         
             
            			end
         
     | 
| 
       43 
51 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
            			#  
     | 
| 
      
 52 
     | 
    
         
            +
            			# Compute the shortest relative path from root to path.
         
     | 
| 
      
 53 
     | 
    
         
            +
            			# @parameter path [Path | String] The target path.
         
     | 
| 
      
 54 
     | 
    
         
            +
            			# @parameter root [Path | String] The root directory.
         
     | 
| 
      
 55 
     | 
    
         
            +
            			# @returns [String] The shortest relative path.
         
     | 
| 
       45 
56 
     | 
    
         
             
            			def self.shortest_path(path, root)
         
     | 
| 
       46 
57 
     | 
    
         
             
            				path_components = Path.components(path)
         
     | 
| 
       47 
58 
     | 
    
         
             
            				root_components = Path.components(root)
         
     | 
| 
         @@ -61,6 +72,10 @@ module Build 
     | 
|
| 
       61 
72 
     | 
    
         
             
            				end
         
     | 
| 
       62 
73 
     | 
    
         
             
            			end
         
     | 
| 
       63 
74 
     | 
    
         | 
| 
      
 75 
     | 
    
         
            +
            			# Compute the relative path from root to full path.
         
     | 
| 
      
 76 
     | 
    
         
            +
            			# @parameter root [String] The root directory.
         
     | 
| 
      
 77 
     | 
    
         
            +
            			# @parameter full_path [String] The full path.
         
     | 
| 
      
 78 
     | 
    
         
            +
            			# @returns [String] The relative path.
         
     | 
| 
       64 
79 
     | 
    
         
             
            			def self.relative_path(root, full_path)
         
     | 
| 
       65 
80 
     | 
    
         
             
            				relative_offset = root.length
         
     | 
| 
       66 
81 
     | 
    
         | 
| 
         @@ -70,6 +85,9 @@ module Build 
     | 
|
| 
       70 
85 
     | 
    
         
             
            				return full_path.slice(relative_offset..-1)
         
     | 
| 
       71 
86 
     | 
    
         
             
            			end
         
     | 
| 
       72 
87 
     | 
    
         | 
| 
      
 88 
     | 
    
         
            +
            			# Convert a path-like object to a Path instance.
         
     | 
| 
      
 89 
     | 
    
         
            +
            			# @parameter path [Path | String] The path to convert.
         
     | 
| 
      
 90 
     | 
    
         
            +
            			# @returns [Path] A Path instance.
         
     | 
| 
       73 
91 
     | 
    
         
             
            			def self.[] path
         
     | 
| 
       74 
92 
     | 
    
         
             
            				self === path ? path : self.new(path.to_s)
         
     | 
| 
       75 
93 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -91,20 +109,28 @@ module Build 
     | 
|
| 
       91 
109 
     | 
    
         
             
            			attr :root
         
     | 
| 
       92 
110 
     | 
    
         
             
            			attr :full_path
         
     | 
| 
       93 
111 
     | 
    
         | 
| 
      
 112 
     | 
    
         
            +
            			# Get the length of the full path.
         
     | 
| 
      
 113 
     | 
    
         
            +
            			# @returns [Integer] The number of characters in the path.
         
     | 
| 
       94 
114 
     | 
    
         
             
            			def length
         
     | 
| 
       95 
115 
     | 
    
         
             
            				@full_path.length
         
     | 
| 
       96 
116 
     | 
    
         
             
            			end
         
     | 
| 
       97 
117 
     | 
    
         | 
| 
       98 
118 
     | 
    
         
             
            			alias size length
         
     | 
| 
       99 
119 
     | 
    
         | 
| 
      
 120 
     | 
    
         
            +
            			# Get the path components as an array.
         
     | 
| 
      
 121 
     | 
    
         
            +
            			# @returns [Array(String)] The path split by directory separator.
         
     | 
| 
       100 
122 
     | 
    
         
             
            			def components
         
     | 
| 
       101 
123 
     | 
    
         
             
            				@components ||= @full_path.split(File::SEPARATOR).freeze
         
     | 
| 
       102 
124 
     | 
    
         
             
            			end
         
     | 
| 
       103 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
            			# Get the basename of the path.
         
     | 
| 
      
 127 
     | 
    
         
            +
            			# @returns [String] The last component of the path.
         
     | 
| 
       104 
128 
     | 
    
         
             
            			def basename
         
     | 
| 
       105 
129 
     | 
    
         
             
            				self.parts.last
         
     | 
| 
       106 
130 
     | 
    
         
             
            			end
         
     | 
| 
       107 
131 
     | 
    
         | 
| 
      
 132 
     | 
    
         
            +
            			# Get the parent directory path.
         
     | 
| 
      
 133 
     | 
    
         
            +
            			# @returns [Path] The parent directory.
         
     | 
| 
       108 
134 
     | 
    
         
             
            			def parent
         
     | 
| 
       109 
135 
     | 
    
         
             
            				root = @root
         
     | 
| 
       110 
136 
     | 
    
         
             
            				full_path = File.dirname(@full_path)
         
     | 
| 
         @@ -120,22 +146,32 @@ module Build 
     | 
|
| 
       120 
146 
     | 
    
         
             
            				self.class.new(full_path, root)
         
     | 
| 
       121 
147 
     | 
    
         
             
            			end
         
     | 
| 
       122 
148 
     | 
    
         | 
| 
      
 149 
     | 
    
         
            +
            			# Check if the path starts with the given prefix.
         
     | 
| 
      
 150 
     | 
    
         
            +
            			# @parameter args [Array(String)] The prefix strings to check.
         
     | 
| 
      
 151 
     | 
    
         
            +
            			# @returns [Boolean] True if the path starts with any of the prefixes.
         
     | 
| 
       123 
152 
     | 
    
         
             
            			def start_with?(*args)
         
     | 
| 
       124 
153 
     | 
    
         
             
            				@full_path.start_with?(*args)
         
     | 
| 
       125 
154 
     | 
    
         
             
            			end
         
     | 
| 
       126 
155 
     | 
    
         | 
| 
       127 
156 
     | 
    
         
             
            			alias parts components
         
     | 
| 
       128 
157 
     | 
    
         | 
| 
      
 158 
     | 
    
         
            +
            			# Get the relative path from the root.
         
     | 
| 
      
 159 
     | 
    
         
            +
            			# @returns [String] The path relative to the root.
         
     | 
| 
       129 
160 
     | 
    
         
             
            			def relative_path
         
     | 
| 
       130 
161 
     | 
    
         
             
            				@relative_path ||= Path.relative_path(@root.to_s, @full_path.to_s).freeze
         
     | 
| 
       131 
162 
     | 
    
         
             
            			end
         
     | 
| 
       132 
163 
     | 
    
         | 
| 
      
 164 
     | 
    
         
            +
            			# Split the relative path into directory and basename components.
         
     | 
| 
      
 165 
     | 
    
         
            +
            			# @returns [Array(String, String)] The directory and basename.
         
     | 
| 
       133 
166 
     | 
    
         
             
            			def relative_parts
         
     | 
| 
       134 
167 
     | 
    
         
             
            				dirname, _, basename = self.relative_path.rpartition(File::SEPARATOR)
         
     | 
| 
       135 
168 
     | 
    
         | 
| 
       136 
169 
     | 
    
         
             
            				return dirname, basename
         
     | 
| 
       137 
170 
     | 
    
         
             
            			end
         
     | 
| 
       138 
171 
     | 
    
         | 
| 
      
 172 
     | 
    
         
            +
            			# Append an extension to the path.
         
     | 
| 
      
 173 
     | 
    
         
            +
            			# @parameter extension [String] The extension to append.
         
     | 
| 
      
 174 
     | 
    
         
            +
            			# @returns [Path] A new path with the extension appended.
         
     | 
| 
       139 
175 
     | 
    
         
             
            			def append(extension)
         
     | 
| 
       140 
176 
     | 
    
         
             
            				self.class.new(@full_path + extension, @root)
         
     | 
| 
       141 
177 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -160,10 +196,18 @@ module Build 
     | 
|
| 
       160 
196 
     | 
    
         
             
            				end
         
     | 
| 
       161 
197 
     | 
    
         
             
            			end
         
     | 
| 
       162 
198 
     | 
    
         | 
| 
      
 199 
     | 
    
         
            +
            			# Rebase the path to a new root directory.
         
     | 
| 
      
 200 
     | 
    
         
            +
            			# @parameter root [Path | String] The new root.
         
     | 
| 
      
 201 
     | 
    
         
            +
            			# @returns [Path] A new path with the same relative path under the new root.
         
     | 
| 
       163 
202 
     | 
    
         
             
            			def rebase(root)
         
     | 
| 
       164 
203 
     | 
    
         
             
            				self.class.new(File.join(root, relative_path), root)
         
     | 
| 
       165 
204 
     | 
    
         
             
            			end
         
     | 
| 
       166 
205 
     | 
    
         | 
| 
      
 206 
     | 
    
         
            +
            			# Create a modified path with new root, extension, or basename.
         
     | 
| 
      
 207 
     | 
    
         
            +
            			# @parameter root [Path | String] The new root directory.
         
     | 
| 
      
 208 
     | 
    
         
            +
            			# @parameter extension [String | Nil] An extension to add.
         
     | 
| 
      
 209 
     | 
    
         
            +
            			# @parameter basename [String | Boolean | Nil] A new basename or `true` to keep existing.
         
     | 
| 
      
 210 
     | 
    
         
            +
            			# @returns [Path] A new path with the specified modifications.
         
     | 
| 
       167 
211 
     | 
    
         
             
            			def with(root: @root, extension: nil, basename: false)
         
     | 
| 
       168 
212 
     | 
    
         
             
            				relative_path = self.relative_path
         
     | 
| 
       169 
213 
     | 
    
         | 
| 
         @@ -183,6 +227,10 @@ module Build 
     | 
|
| 
       183 
227 
     | 
    
         
             
            				self.class.new(File.join(root, relative_path), root, relative_path)
         
     | 
| 
       184 
228 
     | 
    
         
             
            			end
         
     | 
| 
       185 
229 
     | 
    
         | 
| 
      
 230 
     | 
    
         
            +
            			# Join a root and relative path to create a new Path.
         
     | 
| 
      
 231 
     | 
    
         
            +
            			# @parameter root [String] The root directory.
         
     | 
| 
      
 232 
     | 
    
         
            +
            			# @parameter relative_path [String] The relative path.
         
     | 
| 
      
 233 
     | 
    
         
            +
            			# @returns [Path] A new path combining root and relative path.
         
     | 
| 
       186 
234 
     | 
    
         
             
            			def self.join(root, relative_path)
         
     | 
| 
       187 
235 
     | 
    
         
             
            				self.new(File.join(root, relative_path), root)
         
     | 
| 
       188 
236 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -196,56 +244,81 @@ module Build 
     | 
|
| 
       196 
244 
     | 
    
         
             
            				end
         
     | 
| 
       197 
245 
     | 
    
         
             
            			end
         
     | 
| 
       198 
246 
     | 
    
         | 
| 
      
 247 
     | 
    
         
            +
            			# Compute the shortest path from this path to a root.
         
     | 
| 
      
 248 
     | 
    
         
            +
            			# @parameter root [Path | String] The root directory.
         
     | 
| 
      
 249 
     | 
    
         
            +
            			# @returns [String] The shortest relative path.
         
     | 
| 
       199 
250 
     | 
    
         
             
            			def shortest_path(root)
         
     | 
| 
       200 
251 
     | 
    
         
             
            				self.class.shortest_path(self, root)
         
     | 
| 
       201 
252 
     | 
    
         
             
            			end
         
     | 
| 
       202 
253 
     | 
    
         | 
| 
      
 254 
     | 
    
         
            +
            			# Convert the path to a string.
         
     | 
| 
      
 255 
     | 
    
         
            +
            			# @returns [String] The full path as a string.
         
     | 
| 
       203 
256 
     | 
    
         
             
            			def to_str
         
     | 
| 
       204 
257 
     | 
    
         
             
            				@full_path.to_str
         
     | 
| 
       205 
258 
     | 
    
         
             
            			end
         
     | 
| 
       206 
259 
     | 
    
         | 
| 
      
 260 
     | 
    
         
            +
            			# Convert the path to a path string.
         
     | 
| 
      
 261 
     | 
    
         
            +
            			# @returns [String] The full path.
         
     | 
| 
       207 
262 
     | 
    
         
             
            			def to_path
         
     | 
| 
       208 
263 
     | 
    
         
             
            				@full_path
         
     | 
| 
       209 
264 
     | 
    
         
             
            			end
         
     | 
| 
       210 
265 
     | 
    
         | 
| 
      
 266 
     | 
    
         
            +
            			# Convert the path to a string representation.
         
     | 
| 
      
 267 
     | 
    
         
            +
            			# @returns [String] The full path as a string.
         
     | 
| 
       211 
268 
     | 
    
         
             
            			def to_s
         
     | 
| 
       212 
269 
     | 
    
         
             
            				# It's not guaranteed to be string.
         
     | 
| 
       213 
270 
     | 
    
         
             
            				@full_path.to_s
         
     | 
| 
       214 
271 
     | 
    
         
             
            			end
         
     | 
| 
       215 
272 
     | 
    
         | 
| 
      
 273 
     | 
    
         
            +
            			# Generate a string representation for debugging.
         
     | 
| 
      
 274 
     | 
    
         
            +
            			# @returns [String] A debug string showing root and relative path.
         
     | 
| 
       216 
275 
     | 
    
         
             
            			def inspect
         
     | 
| 
       217 
276 
     | 
    
         
             
            				"#{@root.inspect}/#{relative_path.inspect}"
         
     | 
| 
       218 
277 
     | 
    
         
             
            			end
         
     | 
| 
       219 
278 
     | 
    
         | 
| 
      
 279 
     | 
    
         
            +
            			# Compute the hash value for this path.
         
     | 
| 
      
 280 
     | 
    
         
            +
            			# @returns [Integer] The hash value based on root and full path.
         
     | 
| 
       220 
281 
     | 
    
         
             
            			def hash
         
     | 
| 
       221 
282 
     | 
    
         
             
            				[@root, @full_path].hash
         
     | 
| 
       222 
283 
     | 
    
         
             
            			end
         
     | 
| 
       223 
284 
     | 
    
         | 
| 
      
 285 
     | 
    
         
            +
            			# Check equality with another path.
         
     | 
| 
      
 286 
     | 
    
         
            +
            			# @parameter other [Path] The other path to compare.
         
     | 
| 
      
 287 
     | 
    
         
            +
            			# @returns [Boolean] True if both paths have the same root and full path.
         
     | 
| 
       224 
288 
     | 
    
         
             
            			def eql?(other)
         
     | 
| 
       225 
289 
     | 
    
         
             
            				self.class.eql?(other.class) and @root.eql?(other.root) and @full_path.eql?(other.full_path)
         
     | 
| 
       226 
290 
     | 
    
         
             
            			end
         
     | 
| 
       227 
291 
     | 
    
         | 
| 
       228 
292 
     | 
    
         
             
            			include Comparable
         
     | 
| 
       229 
293 
     | 
    
         | 
| 
      
 294 
     | 
    
         
            +
            			# Compare this path with another for sorting.
         
     | 
| 
      
 295 
     | 
    
         
            +
            			# @parameter other [Path] The other path to compare.
         
     | 
| 
      
 296 
     | 
    
         
            +
            			# @returns [Integer] -1, 0, or 1 for less than, equal, or greater than.
         
     | 
| 
       230 
297 
     | 
    
         
             
            			def <=>(other)
         
     | 
| 
       231 
298 
     | 
    
         
             
            				self.to_s <=> other.to_s
         
     | 
| 
       232 
299 
     | 
    
         
             
            			end
         
     | 
| 
       233 
300 
     | 
    
         | 
| 
       234 
301 
     | 
    
         
             
            			# Match a path with a given pattern, using `File#fnmatch`.
         
     | 
| 
       235 
302 
     | 
    
         
             
            			def match(pattern, flags = 0)
         
     | 
| 
       236 
     | 
    
         
            -
            				path = pattern.start_with?( 
     | 
| 
      
 303 
     | 
    
         
            +
            				path = pattern.start_with?("/") ? full_path : relative_path
         
     | 
| 
       237 
304 
     | 
    
         | 
| 
       238 
305 
     | 
    
         
             
            				return File.fnmatch(pattern, path, flags)
         
     | 
| 
       239 
306 
     | 
    
         
             
            			end
         
     | 
| 
       240 
307 
     | 
    
         | 
| 
      
 308 
     | 
    
         
            +
            			# Get file opening arguments for reading.
         
     | 
| 
      
 309 
     | 
    
         
            +
            			# @returns [Array] The path and file mode for reading.
         
     | 
| 
       241 
310 
     | 
    
         
             
            			def for_reading
         
     | 
| 
       242 
311 
     | 
    
         
             
            				[@full_path, File::RDONLY]
         
     | 
| 
       243 
312 
     | 
    
         
             
            			end
         
     | 
| 
       244 
313 
     | 
    
         | 
| 
      
 314 
     | 
    
         
            +
            			# Get file opening arguments for writing.
         
     | 
| 
      
 315 
     | 
    
         
            +
            			# @returns [Array] The path and file mode for writing.
         
     | 
| 
       245 
316 
     | 
    
         
             
            			def for_writing
         
     | 
| 
       246 
317 
     | 
    
         
             
            				[@full_path, File::CREAT|File::TRUNC|File::WRONLY]
         
     | 
| 
       247 
318 
     | 
    
         
             
            			end
         
     | 
| 
       248 
319 
     | 
    
         | 
| 
      
 320 
     | 
    
         
            +
            			# Get file opening arguments for appending.
         
     | 
| 
      
 321 
     | 
    
         
            +
            			# @returns [Array] The path and file mode for appending.
         
     | 
| 
       249 
322 
     | 
    
         
             
            			def for_appending
         
     | 
| 
       250 
323 
     | 
    
         
             
            				[@full_path, File::CREAT|File::APPEND|File::WRONLY]
         
     | 
| 
       251 
324 
     | 
    
         
             
            			end
         
     | 
    
        data/lib/build/files/paths.rb
    CHANGED
    
    | 
         @@ -1,13 +1,17 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module Build
         
     | 
| 
       9 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
      
 10 
     | 
    
         
            +
            		# Represents an explicit list of file paths.
         
     | 
| 
       10 
11 
     | 
    
         
             
            		class Paths < List
         
     | 
| 
      
 12 
     | 
    
         
            +
            			# Initialize a paths list.
         
     | 
| 
      
 13 
     | 
    
         
            +
            			# @parameter list [Array] The array of paths.
         
     | 
| 
      
 14 
     | 
    
         
            +
            			# @parameter roots [Array(Path) | Nil] The root paths, if known.
         
     | 
| 
       11 
15 
     | 
    
         
             
            			def initialize(list, roots = nil)
         
     | 
| 
       12 
16 
     | 
    
         
             
            				@list = Array(list).freeze
         
     | 
| 
       13 
17 
     | 
    
         
             
            				@roots = roots
         
     | 
| 
         @@ -20,32 +24,50 @@ module Build 
     | 
|
| 
       20 
24 
     | 
    
         
             
            				@roots ||= super
         
     | 
| 
       21 
25 
     | 
    
         
             
            			end
         
     | 
| 
       22 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
            			# Get the count of paths in the list.
         
     | 
| 
      
 28 
     | 
    
         
            +
            			# @returns [Integer] The number of paths.
         
     | 
| 
       23 
29 
     | 
    
         
             
            			def count
         
     | 
| 
       24 
30 
     | 
    
         
             
            				@list.count
         
     | 
| 
       25 
31 
     | 
    
         
             
            			end
         
     | 
| 
       26 
32 
     | 
    
         | 
| 
      
 33 
     | 
    
         
            +
            			# Iterate over all paths in the list.
         
     | 
| 
      
 34 
     | 
    
         
            +
            			# @yields {|path| ...} Each path in the list.
         
     | 
| 
      
 35 
     | 
    
         
            +
            			#   @parameter path [Path] The current path.
         
     | 
| 
       27 
36 
     | 
    
         
             
            			def each
         
     | 
| 
       28 
37 
     | 
    
         
             
            				return to_enum(:each) unless block_given?
         
     | 
| 
       29 
38 
     | 
    
         | 
| 
       30 
39 
     | 
    
         
             
            				@list.each{|path| yield path}
         
     | 
| 
       31 
40 
     | 
    
         
             
            			end
         
     | 
| 
       32 
41 
     | 
    
         | 
| 
      
 42 
     | 
    
         
            +
            			# Check equality with another paths list.
         
     | 
| 
      
 43 
     | 
    
         
            +
            			# @parameter other [Paths] The other paths list to compare.
         
     | 
| 
      
 44 
     | 
    
         
            +
            			# @returns [Boolean] True if both have the same paths.
         
     | 
| 
       33 
45 
     | 
    
         
             
            			def eql?(other)
         
     | 
| 
       34 
46 
     | 
    
         
             
            				self.class.eql?(other.class) and @list.eql?(other.list)
         
     | 
| 
       35 
47 
     | 
    
         
             
            			end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 48 
     | 
    
         
            +
            			
         
     | 
| 
      
 49 
     | 
    
         
            +
            			# Compute the hash value for this paths list.
         
     | 
| 
      
 50 
     | 
    
         
            +
            			# @returns [Integer] The hash value based on the list.
         
     | 
| 
       37 
51 
     | 
    
         
             
            			def hash
         
     | 
| 
       38 
52 
     | 
    
         
             
            				@list.hash
         
     | 
| 
       39 
53 
     | 
    
         
             
            			end
         
     | 
| 
       40 
54 
     | 
    
         | 
| 
      
 55 
     | 
    
         
            +
            			# Return this paths list unchanged.
         
     | 
| 
      
 56 
     | 
    
         
            +
            			# @returns [Paths] Self.
         
     | 
| 
       41 
57 
     | 
    
         
             
            			def to_paths
         
     | 
| 
       42 
58 
     | 
    
         
             
            				self
         
     | 
| 
       43 
59 
     | 
    
         
             
            			end
         
     | 
| 
       44 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
            			# Generate a string representation for debugging.
         
     | 
| 
      
 62 
     | 
    
         
            +
            			# @returns [String] A debug string showing the paths.
         
     | 
| 
       45 
63 
     | 
    
         
             
            			def inspect
         
     | 
| 
       46 
64 
     | 
    
         
             
            				"<Paths #{@list.inspect}>"
         
     | 
| 
       47 
65 
     | 
    
         
             
            			end
         
     | 
| 
       48 
66 
     | 
    
         | 
| 
      
 67 
     | 
    
         
            +
            			# Create a paths list from a directory root and relative paths.
         
     | 
| 
      
 68 
     | 
    
         
            +
            			# @parameter root [Path] The root directory.
         
     | 
| 
      
 69 
     | 
    
         
            +
            			# @parameter relative_paths [Array(String)] The relative paths.
         
     | 
| 
      
 70 
     | 
    
         
            +
            			# @returns [Paths] A new paths list.
         
     | 
| 
       49 
71 
     | 
    
         
             
            			def self.directory(root, relative_paths)
         
     | 
| 
       50 
72 
     | 
    
         
             
            				paths = relative_paths.collect do |path|
         
     | 
| 
       51 
73 
     | 
    
         
             
            					Path.join(root, path)
         
     | 
| 
         @@ -56,6 +78,9 @@ module Build 
     | 
|
| 
       56 
78 
     | 
    
         
             
            		end
         
     | 
| 
       57 
79 
     | 
    
         | 
| 
       58 
80 
     | 
    
         
             
            		class Path
         
     | 
| 
      
 81 
     | 
    
         
            +
            			# Create a paths list from relative paths under this path.
         
     | 
| 
      
 82 
     | 
    
         
            +
            			# @parameter relative_paths [Array(String)] The relative paths.
         
     | 
| 
      
 83 
     | 
    
         
            +
            			# @returns [Paths] A new paths list.
         
     | 
| 
       59 
84 
     | 
    
         
             
            			def list(*relative_paths)
         
     | 
| 
       60 
85 
     | 
    
         
             
            				Paths.directory(self, relative_paths)
         
     | 
| 
       61 
86 
     | 
    
         
             
            			end
         
     | 
    
        data/lib/build/files/state.rb
    CHANGED
    
    | 
         @@ -1,11 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
            require  
     | 
| 
      
 8 
     | 
    
         
            +
            require "forwardable"
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            module Build
         
     | 
| 
       11 
11 
     | 
    
         
             
            	module Files
         
     | 
| 
         @@ -17,6 +17,9 @@ module Build 
     | 
|
| 
       17 
17 
     | 
    
         
             
            			class FileTime
         
     | 
| 
       18 
18 
     | 
    
         
             
            				include Comparable
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
      
 20 
     | 
    
         
            +
            				# Initialize a file time record.
         
     | 
| 
      
 21 
     | 
    
         
            +
            				# @parameter path [Path] The file path.
         
     | 
| 
      
 22 
     | 
    
         
            +
            				# @parameter time [Time] The modification time.
         
     | 
| 
       20 
23 
     | 
    
         
             
            				def initialize(path, time)
         
     | 
| 
       21 
24 
     | 
    
         
             
            					@path = path
         
     | 
| 
       22 
25 
     | 
    
         
             
            					@time = time
         
     | 
| 
         @@ -25,15 +28,23 @@ module Build 
     | 
|
| 
       25 
28 
     | 
    
         
             
            				attr :path
         
     | 
| 
       26 
29 
     | 
    
         
             
            				attr :time
         
     | 
| 
       27 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
            				# Compare file times for ordering.
         
     | 
| 
      
 32 
     | 
    
         
            +
            				# @parameter other [FileTime] The other file time to compare.
         
     | 
| 
      
 33 
     | 
    
         
            +
            				# @returns [Integer] -1, 0, or 1 for less than, equal, or greater than.
         
     | 
| 
       28 
34 
     | 
    
         
             
            				def <=> other
         
     | 
| 
       29 
35 
     | 
    
         
             
            					@time <=> other.time
         
     | 
| 
       30 
36 
     | 
    
         
             
            				end
         
     | 
| 
       31 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
            				# Generate a string representation for debugging.
         
     | 
| 
      
 39 
     | 
    
         
            +
            				# @returns [String] A debug string showing path and time.
         
     | 
| 
       32 
40 
     | 
    
         
             
            				def inspect
         
     | 
| 
       33 
41 
     | 
    
         
             
            					"<FileTime #{@path.inspect} #{@time.inspect}>"
         
     | 
| 
       34 
42 
     | 
    
         
             
            				end
         
     | 
| 
       35 
43 
     | 
    
         
             
            			end
         
     | 
| 
       36 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
            			# Initialize file state tracking.
         
     | 
| 
      
 46 
     | 
    
         
            +
            			# @parameter files [List] The list of files to track.
         
     | 
| 
      
 47 
     | 
    
         
            +
            			# @raises [ArgumentError] If files is not a Files::List.
         
     | 
| 
       37 
48 
     | 
    
         
             
            			def initialize(files)
         
     | 
| 
       38 
49 
     | 
    
         
             
            				raise ArgumentError.new("Invalid files list: #{files}") unless Files::List === files
         
     | 
| 
       39 
50 
     | 
    
         | 
| 
         @@ -55,6 +66,8 @@ module Build 
     | 
|
| 
       55 
66 
     | 
    
         | 
| 
       56 
67 
     | 
    
         
             
            			def_delegators :@files, :each, :roots, :count
         
     | 
| 
       57 
68 
     | 
    
         | 
| 
      
 69 
     | 
    
         
            +
            			# Update the state by checking all files for changes.
         
     | 
| 
      
 70 
     | 
    
         
            +
            			# @returns [Boolean] True if any files were added, changed, removed, or are missing.
         
     | 
| 
       58 
71 
     | 
    
         
             
            			def update!
         
     | 
| 
       59 
72 
     | 
    
         
             
            				last_times = @times
         
     | 
| 
       60 
73 
     | 
    
         
             
            				@times = {}
         
     | 
| 
         @@ -72,7 +85,7 @@ module Build 
     | 
|
| 
       72 
85 
     | 
    
         | 
| 
       73 
86 
     | 
    
         
             
            					if File.exist?(path)
         
     | 
| 
       74 
87 
     | 
    
         
             
            						modified_time = File.mtime(path)
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
      
 88 
     | 
    
         
            +
            						
         
     | 
| 
       76 
89 
     | 
    
         
             
            						if last_time = last_times.delete(path)
         
     | 
| 
       77 
90 
     | 
    
         
             
            							# Path was valid last update:
         
     | 
| 
       78 
91 
     | 
    
         
             
            							if modified_time != last_time
         
     | 
| 
         @@ -86,9 +99,9 @@ module Build 
     | 
|
| 
       86 
99 
     | 
    
         | 
| 
       87 
100 
     | 
    
         
             
            							# puts "Added: #{path}"
         
     | 
| 
       88 
101 
     | 
    
         
             
            						end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 102 
     | 
    
         
            +
            						
         
     | 
| 
       90 
103 
     | 
    
         
             
            						@times[path] = modified_time
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 104 
     | 
    
         
            +
            						
         
     | 
| 
       92 
105 
     | 
    
         
             
            						unless File.directory?(path)
         
     | 
| 
       93 
106 
     | 
    
         
             
            							file_times << FileTime.new(path, modified_time)
         
     | 
| 
       94 
107 
     | 
    
         
             
            						end
         
     | 
| 
         @@ -111,14 +124,20 @@ module Build 
     | 
|
| 
       111 
124 
     | 
    
         
             
            			attr :oldest_time
         
     | 
| 
       112 
125 
     | 
    
         
             
            			attr :newest_time
         
     | 
| 
       113 
126 
     | 
    
         | 
| 
      
 127 
     | 
    
         
            +
            			# Check if any files are missing.
         
     | 
| 
      
 128 
     | 
    
         
            +
            			# @returns [Boolean] True if any files do not exist.
         
     | 
| 
       114 
129 
     | 
    
         
             
            			def missing?
         
     | 
| 
       115 
130 
     | 
    
         
             
            				!@missing.empty?
         
     | 
| 
       116 
131 
     | 
    
         
             
            			end
         
     | 
| 
       117 
132 
     | 
    
         | 
| 
      
 133 
     | 
    
         
            +
            			# Check if the state is empty.
         
     | 
| 
      
 134 
     | 
    
         
            +
            			# @returns [Boolean] True if no files are being tracked.
         
     | 
| 
       118 
135 
     | 
    
         
             
            			def empty?
         
     | 
| 
       119 
136 
     | 
    
         
             
            				@times.empty?
         
     | 
| 
       120 
137 
     | 
    
         
             
            			end
         
     | 
| 
       121 
138 
     | 
    
         | 
| 
      
 139 
     | 
    
         
            +
            			# Generate a string representation for debugging.
         
     | 
| 
      
 140 
     | 
    
         
            +
            			# @returns [String] A debug string showing state changes.
         
     | 
| 
       122 
141 
     | 
    
         
             
            			def inspect
         
     | 
| 
       123 
142 
     | 
    
         
             
            				"<State Added:#{@added} Removed:#{@removed} Changed:#{@changed} Missing:#{@missing}>"
         
     | 
| 
       124 
143 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -149,6 +168,10 @@ module Build 
     | 
|
| 
       149 
168 
     | 
    
         
             
            				return true
         
     | 
| 
       150 
169 
     | 
    
         
             
            			end
         
     | 
| 
       151 
170 
     | 
    
         | 
| 
      
 171 
     | 
    
         
            +
            			# Check if outputs are dirty with respect to inputs.
         
     | 
| 
      
 172 
     | 
    
         
            +
            			# @parameter inputs [State] The input files state.
         
     | 
| 
      
 173 
     | 
    
         
            +
            			# @parameter outputs [State] The output files state.
         
     | 
| 
      
 174 
     | 
    
         
            +
            			# @returns [Boolean] True if outputs need to be regenerated.
         
     | 
| 
       152 
175 
     | 
    
         
             
            			def self.dirty?(inputs, outputs)
         
     | 
| 
       153 
176 
     | 
    
         
             
            				outputs.dirty?(inputs)
         
     | 
| 
       154 
177 
     | 
    
         
             
            			end
         
     | 
    
        data/lib/build/files/system.rb
    CHANGED
    
    | 
         @@ -1,12 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require  
     | 
| 
      
 6 
     | 
    
         
            +
            require "fileutils"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
            require_relative  
     | 
| 
       9 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative "path"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative "list"
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            module Build
         
     | 
| 
       12 
12 
     | 
    
         
             
            	module Files
         
     | 
| 
         @@ -30,6 +30,8 @@ module Build 
     | 
|
| 
       30 
30 
     | 
    
         
             
            				end
         
     | 
| 
       31 
31 
     | 
    
         
             
            			end
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
      
 33 
     | 
    
         
            +
            			# Copy the path to a destination.
         
     | 
| 
      
 34 
     | 
    
         
            +
            			# @parameter destination [Path] The destination path.
         
     | 
| 
       33 
35 
     | 
    
         
             
            			def copy(destination)
         
     | 
| 
       34 
36 
     | 
    
         
             
            				if directory?
         
     | 
| 
       35 
37 
     | 
    
         
             
            					destination.create
         
     | 
| 
         @@ -43,6 +45,8 @@ module Build 
     | 
|
| 
       43 
45 
     | 
    
         
             
            				FileUtils.touch(self.to_s)
         
     | 
| 
       44 
46 
     | 
    
         
             
            			end
         
     | 
| 
       45 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
            			# Get file statistics.
         
     | 
| 
      
 49 
     | 
    
         
            +
            			# @returns [File::Stat] The file statistics.
         
     | 
| 
       46 
50 
     | 
    
         
             
            			def stat
         
     | 
| 
       47 
51 
     | 
    
         
             
            				File.stat(self.to_s)
         
     | 
| 
       48 
52 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -57,14 +61,20 @@ module Build 
     | 
|
| 
       57 
61 
     | 
    
         
             
            				File.directory?(self.to_s)
         
     | 
| 
       58 
62 
     | 
    
         
             
            			end
         
     | 
| 
       59 
63 
     | 
    
         | 
| 
      
 64 
     | 
    
         
            +
            			# Check if the path refers to a regular file.
         
     | 
| 
      
 65 
     | 
    
         
            +
            			# @returns [Boolean] True if the path is a file.
         
     | 
| 
       60 
66 
     | 
    
         
             
            			def file?
         
     | 
| 
       61 
67 
     | 
    
         
             
            				File.file?(self.to_s)
         
     | 
| 
       62 
68 
     | 
    
         
             
            			end
         
     | 
| 
       63 
69 
     | 
    
         | 
| 
      
 70 
     | 
    
         
            +
            			# Check if the path is a symbolic link.
         
     | 
| 
      
 71 
     | 
    
         
            +
            			# @returns [Boolean] True if the path is a symlink.
         
     | 
| 
       64 
72 
     | 
    
         
             
            			def symlink?
         
     | 
| 
       65 
73 
     | 
    
         
             
            				File.symlink?(self.to_s)
         
     | 
| 
       66 
74 
     | 
    
         
             
            			end
         
     | 
| 
       67 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
            			# Check if the file is readable.
         
     | 
| 
      
 77 
     | 
    
         
            +
            			# @returns [Boolean] True if the file can be read.
         
     | 
| 
       68 
78 
     | 
    
         
             
            			def readable?
         
     | 
| 
       69 
79 
     | 
    
         
             
            				File.readable?(self.to_s)
         
     | 
| 
       70 
80 
     | 
    
         
             
            			end
         
     | 
| 
         @@ -110,6 +120,8 @@ module Build 
     | 
|
| 
       110 
120 
     | 
    
         
             
            				each(&:delete)
         
     | 
| 
       111 
121 
     | 
    
         
             
            			end
         
     | 
| 
       112 
122 
     | 
    
         | 
| 
      
 123 
     | 
    
         
            +
            			# Copy all files in the list to a destination.
         
     | 
| 
      
 124 
     | 
    
         
            +
            			# @parameter destination [Path] The destination root path.
         
     | 
| 
       113 
125 
     | 
    
         
             
            			def copy(destination)
         
     | 
| 
       114 
126 
     | 
    
         
             
            				each do |path|
         
     | 
| 
       115 
127 
     | 
    
         
             
            					path.copy(destination / path.relative_path)
         
     | 
    
        data/lib/build/files/version.rb
    CHANGED
    
    | 
         @@ -1,10 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
            # @namespace
         
     | 
| 
       6 
7 
     | 
    
         
             
            module Build
         
     | 
| 
      
 8 
     | 
    
         
            +
            	# @namespace
         
     | 
| 
       7 
9 
     | 
    
         
             
            	module Files
         
     | 
| 
       8 
     | 
    
         
            -
            		VERSION = "1. 
     | 
| 
      
 10 
     | 
    
         
            +
            		VERSION = "1.10.0"
         
     | 
| 
       9 
11 
     | 
    
         
             
            	end
         
     | 
| 
       10 
12 
     | 
    
         
             
            end
         
     | 
    
        data/lib/build/files.rb
    CHANGED
    
    | 
         @@ -1,12 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Released under the MIT License.
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright, 2014- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright, 2014-2025, by Samuel Williams.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            require_relative  
     | 
| 
       7 
     | 
    
         
            -
            require_relative  
     | 
| 
       8 
     | 
    
         
            -
            require_relative  
     | 
| 
       9 
     | 
    
         
            -
            require_relative  
     | 
| 
       10 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "files/list"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative "files/composite"
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative "files/paths"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative "files/glob"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative "files/directory"
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            require_relative  
     | 
| 
      
 12 
     | 
    
         
            +
            require_relative "files/system"
         
     | 
    
        data/license.md
    CHANGED
    
    
    
        data/readme.md
    CHANGED
    
    | 
         @@ -20,19 +20,13 @@ Or install it yourself as: 
     | 
|
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            ## Usage
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
      
 23 
     | 
    
         
            +
            Please see the [project documentation](https://github.com/ioquatix/build-files) for more details.
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                
         
     | 
| 
       27 
     | 
    
         
            -
                path = Build::Files::Path("/foo/bar/baz")
         
     | 
| 
       28 
     | 
    
         
            -
                => "/foo/bar"/"baz"
         
     | 
| 
       29 
     | 
    
         
            -
                
         
     | 
| 
       30 
     | 
    
         
            -
                > path.root
         
     | 
| 
       31 
     | 
    
         
            -
                => "/foo/bar"
         
     | 
| 
       32 
     | 
    
         
            -
                > path.relative_path
         
     | 
| 
       33 
     | 
    
         
            -
                => "baz"
         
     | 
| 
      
 25 
     | 
    
         
            +
            ## Releases
         
     | 
| 
       34 
26 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
            Please see the [project releases](https://github.com/ioquatix/build-filesreleases/index) for all releases.
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            ### v1.10.0
         
     | 
| 
       36 
30 
     | 
    
         | 
| 
       37 
31 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       38 
32 
     | 
    
         | 
| 
         @@ -43,3 +37,11 @@ We welcome contributions to this project. 
     | 
|
| 
       43 
37 
     | 
    
         
             
            3.  Commit your changes (`git commit -am 'Add some feature'`).
         
     | 
| 
       44 
38 
     | 
    
         
             
            4.  Push to the branch (`git push origin my-new-feature`).
         
     | 
| 
       45 
39 
     | 
    
         
             
            5.  Create new Pull Request.
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            ### Developer Certificate of Origin
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            ### Community Guidelines
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
         
     | 
    
        data/releases.md
    ADDED
    
    
    
        data.tar.gz.sig
    CHANGED
    
    | 
         @@ -1,2 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
            n��k�[�����
         
     | 
| 
      
 1 
     | 
    
         
            +
            M�H�A��*L�ʌ��E%HH${�}��rE}��!�'ӄ�0�5�F�#Zw�3�ʡ�`�ON���^��\��k�ɾ |����,X�/�|�i�%{>|�i��@.��Hjǂg��_�4��hQ~��P�\����9!wG}���`AT�DŽ��!>��x�o��"���/��
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,11 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: build-files
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.10.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Samuel Williams
         
     | 
| 
       8 
     | 
    
         
            -
            autorequire:
         
     | 
| 
       9 
8 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
9 
     | 
    
         
             
            cert_chain:
         
     | 
| 
       11 
10 
     | 
    
         
             
            - |
         
     | 
| 
         @@ -37,57 +36,12 @@ cert_chain: 
     | 
|
| 
       37 
36 
     | 
    
         
             
              Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
         
     | 
| 
       38 
37 
     | 
    
         
             
              voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
         
     | 
| 
       39 
38 
     | 
    
         
             
              -----END CERTIFICATE-----
         
     | 
| 
       40 
     | 
    
         
            -
            date:  
     | 
| 
       41 
     | 
    
         
            -
            dependencies:
         
     | 
| 
       42 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       43 
     | 
    
         
            -
              name: bundler
         
     | 
| 
       44 
     | 
    
         
            -
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       45 
     | 
    
         
            -
                requirements:
         
     | 
| 
       46 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       47 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       48 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       49 
     | 
    
         
            -
              type: :development
         
     | 
| 
       50 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       51 
     | 
    
         
            -
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       52 
     | 
    
         
            -
                requirements:
         
     | 
| 
       53 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       54 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       55 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       56 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       57 
     | 
    
         
            -
              name: covered
         
     | 
| 
       58 
     | 
    
         
            -
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       59 
     | 
    
         
            -
                requirements:
         
     | 
| 
       60 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       61 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       62 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       63 
     | 
    
         
            -
              type: :development
         
     | 
| 
       64 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       65 
     | 
    
         
            -
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       66 
     | 
    
         
            -
                requirements:
         
     | 
| 
       67 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       68 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       69 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       70 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       71 
     | 
    
         
            -
              name: sus
         
     | 
| 
       72 
     | 
    
         
            -
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       73 
     | 
    
         
            -
                requirements:
         
     | 
| 
       74 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       75 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       76 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       77 
     | 
    
         
            -
              type: :development
         
     | 
| 
       78 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       79 
     | 
    
         
            -
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       80 
     | 
    
         
            -
                requirements:
         
     | 
| 
       81 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       82 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       83 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       84 
     | 
    
         
            -
            description:
         
     | 
| 
       85 
     | 
    
         
            -
            email:
         
     | 
| 
      
 39 
     | 
    
         
            +
            date: 1980-01-02 00:00:00.000000000 Z
         
     | 
| 
      
 40 
     | 
    
         
            +
            dependencies: []
         
     | 
| 
       86 
41 
     | 
    
         
             
            executables: []
         
     | 
| 
       87 
42 
     | 
    
         
             
            extensions: []
         
     | 
| 
       88 
43 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
       89 
44 
     | 
    
         
             
            files:
         
     | 
| 
       90 
     | 
    
         
            -
            - conduct.md
         
     | 
| 
       91 
45 
     | 
    
         
             
            - lib/build/files.rb
         
     | 
| 
       92 
46 
     | 
    
         
             
            - lib/build/files/composite.rb
         
     | 
| 
       93 
47 
     | 
    
         
             
            - lib/build/files/difference.rb
         
     | 
| 
         @@ -101,12 +55,13 @@ files: 
     | 
|
| 
       101 
55 
     | 
    
         
             
            - lib/build/files/version.rb
         
     | 
| 
       102 
56 
     | 
    
         
             
            - license.md
         
     | 
| 
       103 
57 
     | 
    
         
             
            - readme.md
         
     | 
| 
      
 58 
     | 
    
         
            +
            - releases.md
         
     | 
| 
       104 
59 
     | 
    
         
             
            homepage: https://github.com/ioquatix/build-files
         
     | 
| 
       105 
60 
     | 
    
         
             
            licenses:
         
     | 
| 
       106 
61 
     | 
    
         
             
            - MIT
         
     | 
| 
       107 
62 
     | 
    
         
             
            metadata:
         
     | 
| 
       108 
63 
     | 
    
         
             
              funding_uri: https://github.com/sponsors/ioquatix/
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
      
 64 
     | 
    
         
            +
              source_code_uri: https://github.com/ioquatix/build-files.git
         
     | 
| 
       110 
65 
     | 
    
         
             
            rdoc_options: []
         
     | 
| 
       111 
66 
     | 
    
         
             
            require_paths:
         
     | 
| 
       112 
67 
     | 
    
         
             
            - lib
         
     | 
| 
         @@ -114,15 +69,14 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       114 
69 
     | 
    
         
             
              requirements:
         
     | 
| 
       115 
70 
     | 
    
         
             
              - - ">="
         
     | 
| 
       116 
71 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       117 
     | 
    
         
            -
                  version: '2 
     | 
| 
      
 72 
     | 
    
         
            +
                  version: '3.2'
         
     | 
| 
       118 
73 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       119 
74 
     | 
    
         
             
              requirements:
         
     | 
| 
       120 
75 
     | 
    
         
             
              - - ">="
         
     | 
| 
       121 
76 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       122 
77 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       123 
78 
     | 
    
         
             
            requirements: []
         
     | 
| 
       124 
     | 
    
         
            -
            rubygems_version: 3. 
     | 
| 
       125 
     | 
    
         
            -
            signing_key:
         
     | 
| 
      
 79 
     | 
    
         
            +
            rubygems_version: 3.7.2
         
     | 
| 
       126 
80 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       127 
81 
     | 
    
         
             
            summary: Abstractions for handling and mapping paths.
         
     | 
| 
       128 
82 
     | 
    
         
             
            test_files: []
         
     | 
    
        metadata.gz.sig
    CHANGED
    
    | 
         Binary file 
     | 
    
        data/conduct.md
    DELETED
    
    | 
         @@ -1,133 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
            # Contributor Covenant Code of Conduct
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            ## Our Pledge
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            We as members, contributors, and leaders pledge to make participation in our
         
     | 
| 
       7 
     | 
    
         
            -
            community a harassment-free experience for everyone, regardless of age, body
         
     | 
| 
       8 
     | 
    
         
            -
            size, visible or invisible disability, ethnicity, sex characteristics, gender
         
     | 
| 
       9 
     | 
    
         
            -
            identity and expression, level of experience, education, socio-economic status,
         
     | 
| 
       10 
     | 
    
         
            -
            nationality, personal appearance, race, caste, color, religion, or sexual
         
     | 
| 
       11 
     | 
    
         
            -
            identity and orientation.
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            We pledge to act and interact in ways that contribute to an open, welcoming,
         
     | 
| 
       14 
     | 
    
         
            -
            diverse, inclusive, and healthy community.
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            ## Our Standards
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
            Examples of behavior that contributes to a positive environment for our
         
     | 
| 
       19 
     | 
    
         
            -
            community include:
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
            * Demonstrating empathy and kindness toward other people
         
     | 
| 
       22 
     | 
    
         
            -
            * Being respectful of differing opinions, viewpoints, and experiences
         
     | 
| 
       23 
     | 
    
         
            -
            * Giving and gracefully accepting constructive feedback
         
     | 
| 
       24 
     | 
    
         
            -
            * Accepting responsibility and apologizing to those affected by our mistakes,
         
     | 
| 
       25 
     | 
    
         
            -
              and learning from the experience
         
     | 
| 
       26 
     | 
    
         
            -
            * Focusing on what is best not just for us as individuals, but for the overall
         
     | 
| 
       27 
     | 
    
         
            -
              community
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            Examples of unacceptable behavior include:
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
            * The use of sexualized language or imagery, and sexual attention or advances of
         
     | 
| 
       32 
     | 
    
         
            -
              any kind
         
     | 
| 
       33 
     | 
    
         
            -
            * Trolling, insulting or derogatory comments, and personal or political attacks
         
     | 
| 
       34 
     | 
    
         
            -
            * Public or private harassment
         
     | 
| 
       35 
     | 
    
         
            -
            * Publishing others' private information, such as a physical or email address,
         
     | 
| 
       36 
     | 
    
         
            -
              without their explicit permission
         
     | 
| 
       37 
     | 
    
         
            -
            * Other conduct which could reasonably be considered inappropriate in a
         
     | 
| 
       38 
     | 
    
         
            -
              professional setting
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
            ## Enforcement Responsibilities
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
            Community leaders are responsible for clarifying and enforcing our standards of
         
     | 
| 
       43 
     | 
    
         
            -
            acceptable behavior and will take appropriate and fair corrective action in
         
     | 
| 
       44 
     | 
    
         
            -
            response to any behavior that they deem inappropriate, threatening, offensive,
         
     | 
| 
       45 
     | 
    
         
            -
            or harmful.
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
            Community leaders have the right and responsibility to remove, edit, or reject
         
     | 
| 
       48 
     | 
    
         
            -
            comments, commits, code, wiki edits, issues, and other contributions that are
         
     | 
| 
       49 
     | 
    
         
            -
            not aligned to this Code of Conduct, and will communicate reasons for moderation
         
     | 
| 
       50 
     | 
    
         
            -
            decisions when appropriate.
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
            ## Scope
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
            This Code of Conduct applies within all community spaces, and also applies when
         
     | 
| 
       55 
     | 
    
         
            -
            an individual is officially representing the community in public spaces.
         
     | 
| 
       56 
     | 
    
         
            -
            Examples of representing our community include using an official e-mail address,
         
     | 
| 
       57 
     | 
    
         
            -
            posting via an official social media account, or acting as an appointed
         
     | 
| 
       58 
     | 
    
         
            -
            representative at an online or offline event.
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
            ## Enforcement
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
            Instances of abusive, harassing, or otherwise unacceptable behavior may be
         
     | 
| 
       63 
     | 
    
         
            -
            reported to the community leaders responsible for enforcement at
         
     | 
| 
       64 
     | 
    
         
            -
            [INSERT CONTACT METHOD].
         
     | 
| 
       65 
     | 
    
         
            -
            All complaints will be reviewed and investigated promptly and fairly.
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
            All community leaders are obligated to respect the privacy and security of the
         
     | 
| 
       68 
     | 
    
         
            -
            reporter of any incident.
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
            ## Enforcement Guidelines
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
            Community leaders will follow these Community Impact Guidelines in determining
         
     | 
| 
       73 
     | 
    
         
            -
            the consequences for any action they deem in violation of this Code of Conduct:
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
            ### 1. Correction
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
            **Community Impact**: Use of inappropriate language or other behavior deemed
         
     | 
| 
       78 
     | 
    
         
            -
            unprofessional or unwelcome in the community.
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
            **Consequence**: A private, written warning from community leaders, providing
         
     | 
| 
       81 
     | 
    
         
            -
            clarity around the nature of the violation and an explanation of why the
         
     | 
| 
       82 
     | 
    
         
            -
            behavior was inappropriate. A public apology may be requested.
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
            ### 2. Warning
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
            **Community Impact**: A violation through a single incident or series of
         
     | 
| 
       87 
     | 
    
         
            -
            actions.
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
            **Consequence**: A warning with consequences for continued behavior. No
         
     | 
| 
       90 
     | 
    
         
            -
            interaction with the people involved, including unsolicited interaction with
         
     | 
| 
       91 
     | 
    
         
            -
            those enforcing the Code of Conduct, for a specified period of time. This
         
     | 
| 
       92 
     | 
    
         
            -
            includes avoiding interactions in community spaces as well as external channels
         
     | 
| 
       93 
     | 
    
         
            -
            like social media. Violating these terms may lead to a temporary or permanent
         
     | 
| 
       94 
     | 
    
         
            -
            ban.
         
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
            ### 3. Temporary Ban
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
            **Community Impact**: A serious violation of community standards, including
         
     | 
| 
       99 
     | 
    
         
            -
            sustained inappropriate behavior.
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
            **Consequence**: A temporary ban from any sort of interaction or public
         
     | 
| 
       102 
     | 
    
         
            -
            communication with the community for a specified period of time. No public or
         
     | 
| 
       103 
     | 
    
         
            -
            private interaction with the people involved, including unsolicited interaction
         
     | 
| 
       104 
     | 
    
         
            -
            with those enforcing the Code of Conduct, is allowed during this period.
         
     | 
| 
       105 
     | 
    
         
            -
            Violating these terms may lead to a permanent ban.
         
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
            ### 4. Permanent Ban
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
            **Community Impact**: Demonstrating a pattern of violation of community
         
     | 
| 
       110 
     | 
    
         
            -
            standards, including sustained inappropriate behavior, harassment of an
         
     | 
| 
       111 
     | 
    
         
            -
            individual, or aggression toward or disparagement of classes of individuals.
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
            **Consequence**: A permanent ban from any sort of public interaction within the
         
     | 
| 
       114 
     | 
    
         
            -
            community.
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
            ## Attribution
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
            This Code of Conduct is adapted from the [Contributor Covenant][homepage],
         
     | 
| 
       119 
     | 
    
         
            -
            version 2.1, available at
         
     | 
| 
       120 
     | 
    
         
            -
            [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
            Community Impact Guidelines were inspired by
         
     | 
| 
       123 
     | 
    
         
            -
            [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
            For answers to common questions about this code of conduct, see the FAQ at
         
     | 
| 
       126 
     | 
    
         
            -
            [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
         
     | 
| 
       127 
     | 
    
         
            -
            [https://www.contributor-covenant.org/translations][translations].
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
            [homepage]: https://www.contributor-covenant.org
         
     | 
| 
       130 
     | 
    
         
            -
            [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
         
     | 
| 
       131 
     | 
    
         
            -
            [Mozilla CoC]: https://github.com/mozilla/diversity
         
     | 
| 
       132 
     | 
    
         
            -
            [FAQ]: https://www.contributor-covenant.org/faq
         
     | 
| 
       133 
     | 
    
         
            -
            [translations]: https://www.contributor-covenant.org/translations
         
     |