code_manifest 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []