k_fileset 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KFileset
4
+ # Glob entry can be used to find <PathEntries> that match a Glob
5
+ # with optional exclusion patterns and flags
6
+ class GlobEntry
7
+ include GlobProps
8
+
9
+ def initialize(working_directory, glob, flags, exclusions)
10
+ @working_directory = working_directory
11
+ @glob = glob
12
+ @flags = flags
13
+ @exclusions = exclusions
14
+ end
15
+
16
+ # Dealing with edge cases:
17
+ # https://bugs.ruby-lang.org/issues/17280
18
+
19
+ def path_entries
20
+ Dir.chdir(working_directory) do
21
+ Dir.glob(glob, flags)
22
+ .reject { |file| exclusions.any? { |pattern| pattern_match?(pattern, file) } }
23
+ .map do |file|
24
+ # pathname = Pathname.new(file)
25
+ # key = pathname.realpath.to_s
26
+ # key = File.join(key, '.') if file.ends_with?('.')
27
+ # PathEntry.new(key, pathname, Dir.pwd, file)
28
+ PathEntry.new(file)
29
+ end
30
+ end
31
+ end
32
+
33
+ def match?(absolute_file)
34
+ # match the inclusion Glob first
35
+
36
+ # Using absolute files because two sibling Globs may have different exclusion rules
37
+ # and the incoming file needs to be tested against the correct Glob and it's exclusions
38
+ absolute_glob = File.expand_path(glob, path)
39
+
40
+ return false unless File.fnmatch?(absolute_glob, absolute_file)
41
+
42
+ true
43
+ end
44
+
45
+ private
46
+
47
+ def pattern_match?(pattern, file)
48
+ return pattern.match?(file) if pattern.is_a?(Regexp)
49
+ return pattern.call(file) if pattern.respond_to?(:call)
50
+
51
+ File.fnmatch?(pattern, file) # As String
52
+ end
53
+ end
54
+ end
55
+ # File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false : wildcard doesn't match '/' on FNM_PATHNAME
56
+ # File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false : ditto
57
+ # File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false : ditto
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KFileset
4
+ # GlobConfig, GlobBuilder
5
+ class GlobInfo
6
+ include GlobProps
7
+
8
+ def initialize(glob, exclude = nil, flags = File::FNM_PATHNAME | File::FNM_EXTGLOB)
9
+ @working_directory = Dir.pwd
10
+ @glob = Pathname.new(glob).cleanpath.to_s
11
+ @glob += File::SEPARATOR if glob.end_with?(File::SEPARATOR)
12
+ @flags = flags
13
+
14
+ # absolute_path_glob
15
+ @exclusions = build_exclusions(exclude)
16
+ end
17
+
18
+ def entry
19
+ GlobEntry.new(working_directory, glob, flags, exclusions)
20
+ end
21
+
22
+ class << self
23
+ # rubocop:disable Metrics/AbcSize:
24
+ def build_glob_entries(glob_infos)
25
+ glob_entries = []
26
+
27
+ glob_infos.each do |glob_info|
28
+ found = glob_entries.find_index { |entry| entry.working_directory == glob_info.working_directory && entry.glob == glob_info.glob }
29
+
30
+ if found
31
+ glob_entries[found].exclusions = (glob_entries[found].exclusions + glob_info.exclusions).uniq
32
+ else
33
+ glob_entries << GlobEntry.new(glob_info.working_directory, glob_info.glob, glob_info.flags, glob_info.exclusions)
34
+ end
35
+ end
36
+ glob_entries
37
+ end
38
+ # rubocop:enable Metrics/AbcSize:
39
+ end
40
+
41
+ private
42
+
43
+ # Handles String based Glob, Regexp pattern or lambda expression
44
+ def build_exclusions(exclude)
45
+ return [] if exclude.nil?
46
+ return [exclude] if valid_exclusion?(exclude)
47
+
48
+ exclude.select { |ex| valid_exclusion?(ex) }
49
+ end
50
+
51
+ def valid_exclusion?(exclusion)
52
+ exclusion.is_a?(String) || exclusion.is_a?(Regexp) || exclusion.respond_to?(:call)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KFileset
4
+ module GlobProps
5
+ attr_accessor :working_directory
6
+ attr_accessor :glob
7
+ attr_accessor :exclusions
8
+ attr_accessor :flags
9
+ end
10
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KFileset
4
+ # PathEntry is a (RUBY) Pathname object with some extra properties
5
+ class PathEntry < Pathname
6
+ include KLog::Logging
7
+ # unique absolute path name e.g.(/abc, /abc/.)
8
+ # attr_reader :key
9
+ # attr_reader :path_name # Pathname
10
+ attr_reader :working_directory
11
+
12
+ # attr_reader :relative_path
13
+
14
+ # _path_name,
15
+ def initialize(path)
16
+ super(path)
17
+ # @key = realpath.to_s
18
+ # @key = File.join(@key, '.') if pathname.ends_with?('.')
19
+ # puts @key
20
+ # @path_name = path_name
21
+ @working_directory = Dir.getwd
22
+ # @pathname = pathname
23
+ # debug
24
+ end
25
+
26
+ def key
27
+ return @key if defined? @key
28
+
29
+ @key = begin
30
+ key = realpath.to_s
31
+ key = File.join(key, '.') if basename.to_s == '.' # if pathname.ends_with?('.')
32
+ key
33
+ end
34
+ end
35
+
36
+ # Realpath (is the absolute path of the entry)
37
+ #
38
+ # The Realpath is based on the current directory at the time this entry was created
39
+ # def realpath
40
+ # path_name.realpath(working_directory).to_s
41
+ # end
42
+
43
+ def path
44
+ realpath.to_s
45
+ end
46
+
47
+ def debug
48
+ # puts "expand_path : #{self.expand_path.to_s}"
49
+ # puts "realdirpath : #{self.realdirpath.to_s}"
50
+ # puts "realpath : #{self.realpath.to_s}"
51
+ # puts "extname : #{self.extname.to_s}"
52
+ # puts "basename : #{self.basename.to_s}"
53
+ # puts "dirname : #{self.dirname.to_s}"
54
+ # puts "to_path : #{self.to_path.to_s}"
55
+ # puts "parent : #{self.parent.to_s}"
56
+ # log.line
57
+ log.kv 'key', key
58
+ log.kv 'working_directory', working_directory
59
+ log.kv 'pathname', path
60
+
61
+ log.kv 'to_path', to_path
62
+ log.kv 'cleanpath', cleanpath
63
+
64
+ # log.kv 'directory?', directory?
65
+ # log.kv 'root?', root?
66
+ # log.kv 'absolute?', absolute?
67
+ # log.kv 'relative?', relative?
68
+ # log.kv 'exist?', exist?
69
+ # log.kv 'file?', file?
70
+ # log.kv 'size?', size?
71
+ # log.kv 'ftype', ftype
72
+ # log.kv 'empty?', empty?
73
+ # log.kv 'readable?', readable?
74
+ # log.kv 'birthtime', birthtime
75
+ # log.kv 'expand_path', expand_path
76
+ # log.kv 'realdirpath', realdirpath
77
+ # log.kv 'realpath', realpath
78
+ # log.kv 'extname', extname
79
+ # log.kv 'basename', basename
80
+ # log.kv 'dirname', dirname
81
+ # log.kv 'to_path', to_path
82
+ # log.kv 'size', size
83
+
84
+ log.line
85
+ end
86
+ end
87
+ end
88
+
89
+ # relative_path() if its in two places
90
+
91
+ # Useful Pathname methods
92
+ #
93
+ # p.directory?
94
+ # p.root?
95
+ # p.absolute?
96
+ # p.relative?
97
+ # p.exist?
98
+ # p.file?
99
+ # p.size?
100
+ # p.zero?
101
+ # p.ftype
102
+ # p.empty?
103
+ # p.each_line
104
+ # p.read
105
+ # p.readlines
106
+
107
+ # p.readable?
108
+ # p.birthtime
109
+
110
+ # p.join
111
+ # p.mkpath
112
+ # p.find
113
+ # p.entries
114
+ # p.stat
115
+ # p.each_entry
116
+ # p.relative_path_from
117
+
118
+ # p.expand_path
119
+ # p.realdirpath
120
+ # p.realpath
121
+ # p.extname
122
+ # p.basename
123
+ # p.dirname
124
+ # p.relative_path_from
125
+ # p.to_path
126
+ # p.parent
127
+ # p.split
128
+ # p.size
129
+ # p.cleanpath
130
+ # p.children
131
+ # p.mkdir
132
+ # p.rmdir
133
+ # p.glob
134
+ # p.fnmatch
135
+ # p.fnmatch?
136
+ # p.delete
137
+ # p.each_filename
138
+ # p.each_line
139
+
140
+ # p.read
141
+ # p.readlines
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KFileset
4
+ VERSION = '0.0.3'
5
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KFileset
4
+ # Whitelist rules around including of files with optional exclusion rules
5
+ class Whitelist
6
+ def initialize
7
+ @glob_entries = nil # glob_entries
8
+ @globs = [] # glob_infos /
9
+ end
10
+
11
+ def path_entries
12
+ glob_entries.flat_map(&:path_entries)
13
+ end
14
+
15
+ def add(glob, exclude = nil, flags = nil)
16
+ flags ||= FileSet::DEF_FLAGS
17
+ @glob_entries = nil
18
+ @globs << KFileset::GlobInfo.new(glob, exclude, flags)
19
+
20
+ self
21
+ end
22
+
23
+ def clear
24
+ @glob_entries = nil
25
+ @globs = []
26
+
27
+ self
28
+ end
29
+
30
+ # Return true if file is matched against an entry in the whitelist
31
+ def match?(file)
32
+ glob_entries.any? { |entry| entry.match?(file) }
33
+ end
34
+
35
+ # Return GlobInfo entries with the directory, glob and exclusions
36
+ #
37
+ # Will denormalize the entries where matching (path and glob), whilst expanding with any new exclusions.
38
+ def glob_entries
39
+ @glob_entries ||= KFileset::GlobInfo.build_glob_entries(@globs)
40
+ end
41
+
42
+ # def glob_entries
43
+ # @glob_entries ||= begin
44
+ # glob_entries = []
45
+
46
+ # @globs.each do |glob|
47
+ # # found = glob_entries.find_index { |entry| entry.path == glob.absolute_path && entry.glob == glob.absolute_glob }
48
+ # found = glob_entries.find_index { |entry| entry.path == glob.path && entry.glob == glob.glob }
49
+
50
+ # if found
51
+ # glob_entries[found].exclusions = (glob_entries[found].exclusions + glob.exclusions).uniq
52
+ # else
53
+ # glob_entries << glob.entry
54
+ # end
55
+ # end
56
+ # glob_entries
57
+ # end
58
+
59
+ # @glob_entries
60
+ # end
61
+ end
62
+ end
data/lib/k_fileset.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'k_log'
4
+ require 'k_fileset/version'
5
+ require 'k_fileset/whitelist'
6
+ require 'k_fileset/path_entry'
7
+ require 'k_fileset/glob_props'
8
+ require 'k_fileset/glob_entry'
9
+ require 'k_fileset/glob_info'
10
+ require 'k_fileset/file_set'
11
+
12
+ module KFileset
13
+ # raise KFileset::Error, 'Sample message'
14
+ class Error < StandardError; end
15
+
16
+ # Your code goes here...
17
+ end
18
+
19
+ if ENV['KLUE_DEBUG']&.to_s&.downcase == 'true'
20
+ namespace = 'KFileset::Version'
21
+ file_path = $LOADED_FEATURES.find { |f| f.include?('k_fileset/version') }
22
+ version = KFileset::VERSION.ljust(9)
23
+ puts "#{namespace.ljust(35)} : #{version.ljust(9)} : #{file_path}"
24
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: k_fileset
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - David Cruwys
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: k_log
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.0
27
+ description: " K-Fileset provides file system snapshot using GLOB inclusions and
28
+ exclusions\n"
29
+ email:
30
+ - david@ideasmen.com.au
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".github/workflows/main.yml"
36
+ - ".gitignore"
37
+ - ".rspec"
38
+ - ".rubocop.yml"
39
+ - CODE_OF_CONDUCT.md
40
+ - Gemfile
41
+ - Guardfile
42
+ - LICENSE.txt
43
+ - README.md
44
+ - Rakefile
45
+ - STORIES.md
46
+ - USAGE.md
47
+ - bin/console
48
+ - bin/k
49
+ - bin/kgitsync
50
+ - bin/khotfix
51
+ - bin/setup
52
+ - hooks/pre-commit
53
+ - hooks/update-version
54
+ - k_fileset.gemspec
55
+ - lib/k_fileset.rb
56
+ - lib/k_fileset/file_set.rb
57
+ - lib/k_fileset/file_set_examples.rb
58
+ - lib/k_fileset/glob_entry.rb
59
+ - lib/k_fileset/glob_info.rb
60
+ - lib/k_fileset/glob_props.rb
61
+ - lib/k_fileset/path_entry.rb
62
+ - lib/k_fileset/version.rb
63
+ - lib/k_fileset/whitelist.rb
64
+ homepage: http://appydave.com/gems/k-fileset
65
+ licenses:
66
+ - MIT
67
+ metadata:
68
+ homepage_uri: http://appydave.com/gems/k-fileset
69
+ source_code_uri: https://github.com/klueless-io/k_fileset
70
+ changelog_uri: https://github.com/klueless-io/k_fileset/commits/master
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '2.5'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubygems_version: 3.2.7
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: K-Fileset provides file system snapshot using GLOB inclusions and exclusions
90
+ test_files: []