code_manifest 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: be523e36c254ee8749c037a2e1c9fa57dd10d2e86d83b49aed3349f56da72bdb
4
+ data.tar.gz: 6741764dfc73fc92fa87f9c5acfbba1fae8650c617a5aa15efabafec25bb8dd0
5
+ SHA512:
6
+ metadata.gz: fc9bd31b43bdc5637de024cb0063f88519c09a3120025f452a5733fff4dfca6d1f4f9c5067866fea82395c846e3a2027388cfe7a74d77f50c13665fde43d6303
7
+ data.tar.gz: e802a2695b4409eb40fac80e9a79a0f88b1fcac45a4549c4be1a496540b4769d99ebbed2389ccb7deeca4bc5a002b1a8515eedd82930c2881ab6e391dc638bbf
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # CodeManifest
2
+
3
+ Simple manifest to fetch file by globs and generate digest.
4
+
5
+ ## Installation
6
+
7
+ Install the gem and add to the application's Gemfile by executing:
8
+
9
+ $ bundle add code_manifest
10
+
11
+ If bundler is not being used to manage dependencies, install the gem by executing:
12
+
13
+ $ gem install code_manifest
14
+
15
+ ## Usage
16
+
17
+ Put a `.code_manifest.yml` config file under your project root, for example:
18
+
19
+ ```yml
20
+ ruby:
21
+ - app/**/*.rb
22
+ js:
23
+ - frontend/**/*.js
24
+ ```
25
+
26
+ Then use it with:
27
+
28
+ ```ruby
29
+ require 'code_manifest'
30
+
31
+ # Returns a `Set` with filepaths
32
+ CodeManifest['ruby'].files
33
+ CodeManifest['js'].files
34
+
35
+ # Returns a digest based on all files specified under same namespace
36
+ CodeManifest['ruby'].digest
37
+ CodeManifest['js'].digest
38
+ ```
39
+
40
+ ## Contributing
41
+
42
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/code_manifest.
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'digest/md5'
5
+ require_relative 'rule'
6
+
7
+ module CodeManifest
8
+ class Manifest
9
+ attr_reader :root
10
+
11
+ def initialize(root, patterns)
12
+ @root = root
13
+ @patterns = patterns.map(&:to_s)
14
+ end
15
+
16
+ def files
17
+ @files ||= (inclusion_rules.map(&:files).reduce(Set.new, :merge) - exclusion_rules.map(&:files).reduce(Set.new, :merge)).sort.to_set
18
+ end
19
+
20
+ def digest
21
+ @digest ||= begin
22
+ digests = files.map { |file| Digest::MD5.file(root.join(file)).hexdigest }
23
+ Digest::MD5.hexdigest(digests.join)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def rules
30
+ @rules ||= @patterns.each_with_object([]) do |pattern, rules|
31
+ pattern = pattern.strip
32
+ unless pattern.match?(/\A(#|\z)/)
33
+ rules << Rule.new(root, pattern)
34
+ end
35
+ end
36
+ end
37
+
38
+ def inclusion_rules
39
+ @inclusion_rules ||= rules.reject(&:exclude)
40
+ end
41
+
42
+ def exclusion_rules
43
+ @exclusion_rules ||= rules.select(&:exclude)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodeManifest
4
+ class Rule
5
+ GLOB_OPTIONS = File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB
6
+
7
+ attr_reader :exclude
8
+ attr_reader :glob
9
+
10
+ def initialize(root, pattern)
11
+ @root = root
12
+ @exclude = false
13
+ @glob = @root
14
+
15
+ if pattern[0] == '!'
16
+ @exclude = true
17
+ pattern = pattern[1..-1]
18
+ end
19
+
20
+ if pattern.start_with?('/')
21
+ pattern = pattern[1..-1]
22
+ else
23
+ @glob = @glob.join('**')
24
+ end
25
+
26
+ @glob = @glob.join(pattern).to_s
27
+ end
28
+
29
+ def files
30
+ @files ||= begin
31
+ matched = Dir.glob(glob, GLOB_OPTIONS)
32
+ matched.map! { |file| Pathname.new(file) }
33
+ matched.reject!(&:directory?)
34
+ matched.map! { |file| file.relative_path_from(@root.expand_path).to_s }
35
+ Set.new(matched.sort!)
36
+ end
37
+ end
38
+
39
+ def match?(file)
40
+ file = Pathname.new(file)
41
+ file = @root.join(file) unless file.absolute?
42
+
43
+ File.fnmatch?(glob, file.to_s, GLOB_OPTIONS)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodeManifest
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require_relative "code_manifest/version"
5
+ require_relative "code_manifest/manifest"
6
+
7
+ module CodeManifest
8
+ class Error < StandardError; end
9
+
10
+ DOTFILE = '.code_manifest.yml'.freeze
11
+ KEY_PATTERN = /[a-z_0-9]+/.freeze
12
+
13
+ class << self
14
+ def [](name)
15
+ manifests[name.to_s]
16
+ end
17
+
18
+ private
19
+
20
+ def manifests
21
+ @manifests ||= begin
22
+ config_file = traverse_files(DOTFILE, Dir.pwd)
23
+
24
+ raise "#{DOTFILE} was not found in your project directory, please check README for instructions." unless config_file
25
+
26
+ root = Pathname.new(config_file).dirname
27
+
28
+ YAML.load_file(config_file).each_with_object({}) do |(name, patterns), collection|
29
+ next unless name.match?(KEY_PATTERN)
30
+
31
+ if collection.key?(name)
32
+ raise ArgumentError, "#{name} defined multiple times in #{DOTFILE}"
33
+ end
34
+
35
+ collection[name] = Manifest.new(root, patterns)
36
+ end
37
+ end
38
+ end
39
+
40
+ def traverse_files(filename, start_dir)
41
+ Pathname.new(start_dir).expand_path.ascend do |dir|
42
+ file = dir.join(filename)
43
+ return file.to_s if file.exist?
44
+ end
45
+ end
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: code_manifest
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gusto Engineers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ description: A code manifest
28
+ email:
29
+ - dev@gusto.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.md
35
+ - lib/code_manifest.rb
36
+ - lib/code_manifest/manifest.rb
37
+ - lib/code_manifest/rule.rb
38
+ - lib/code_manifest/version.rb
39
+ homepage: https://github.com/rubyatscale/code_manifest
40
+ licenses: []
41
+ metadata:
42
+ homepage_uri: https://github.com/rubyatscale/code_manifest
43
+ source_code_uri: https://github.com/rubyatscale/code_manifest
44
+ changelog_uri: https://github.com/rubyatscale/code_manifest/blob/main/releases
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '2.7'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.3.7
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: A code manifest
64
+ test_files: []