archival 0.0.1 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cb0c34388e5643a954509fca99931fc9b60d2705ba12733ea890eed817a549e
4
- data.tar.gz: 29c8b6c12cd039be464211cd658b76cde06d4e20a8f2dad5b8f1921c0d40e76b
3
+ metadata.gz: 823433cd1bdae7bc4e3a6179451a875e7fbe5de17c4ceaa8a0b246cdd9fa3b61
4
+ data.tar.gz: 778ef490bf23365d6e1fa1207d0f959ead5a59edbaebebeebe16837981a6c230
5
5
  SHA512:
6
- metadata.gz: 1a6015cc2dafc8335acd969a1616b1842e8fb5afa9a6d966920d5399792a9fc774313e67b2c8467767f408f32eddc33660f7389954a515af6dcd386392ee74ba
7
- data.tar.gz: 3b076507b17cde33ef678c8ced6a84efa4e69c927017dc411b6c4a9475eff5344cbeafd11396c5185fa8e3638854ae40e91ef9756a8c02303d2781839e7f886c
6
+ metadata.gz: cbbbd3c0ef92fabfcc08608adc376ce1272c36e30aa6f3b6d9e12d0ce5b9dd781b1fac4663262b144a85fe42ad951df396004f08518059820f6fc0c45d8a082c
7
+ data.tar.gz: fee79490a8d086eee8779e985483f0b80e75b1ec0df657eb19ed8c74a3a2e5590a8c2e4f74f20ce529e1536e204c3f62574cc5c6ac777bc38c07ebcd1723f3b4
data/.rubocop.yml CHANGED
@@ -1,14 +1,17 @@
1
+ inherit_mode:
2
+ merge:
3
+ - Exclude
4
+
1
5
  AllCops:
2
6
  NewCops: enable
3
7
  SuggestExtensions: false
4
8
  Exclude:
5
- - bin/bundle
9
+ - bin/*
6
10
 
7
11
  Layout/LineLength:
8
12
  Max: 80
9
13
  Exclude:
10
14
  - archival.gemspec
11
- - bin/*
12
15
  - spec/spec_helper.rb
13
16
 
14
17
  Layout/TrailingWhitespace:
@@ -29,6 +32,18 @@ Metrics/BlockLength:
29
32
  Metrics/ClassLength:
30
33
  Max: 150
31
34
 
35
+ Metrics/CyclomaticComplexity:
36
+ Max: 10
37
+ Exclude:
38
+ # This file does a lot of defaulting. It's easy to read.
39
+ - lib/archival/config.rb
40
+
41
+ Metrics/PerceivedComplexity:
42
+ Max: 10
43
+ Exclude:
44
+ # This file does a lot of defaulting. It's easy to read.
45
+ - lib/archival/config.rb
46
+
32
47
  Lint/ImplicitStringConcatenation:
33
48
  Exclude:
34
49
  - spec/tags/layout_spec.rb
data/Rakefile CHANGED
@@ -10,3 +10,4 @@ RuboCop::RakeTask.new
10
10
 
11
11
  task default: :spec
12
12
  task lint: :rubocop
13
+ task 'lint:fix': 'rubocop:auto_correct'
data/action.yml CHANGED
@@ -11,4 +11,5 @@ runs:
11
11
  with:
12
12
  ruby-version: 3.0
13
13
  bundler-cache: true
14
- - run: bin/archival build
14
+ - run: bin/archival build
15
+ shell: bash
data/archival.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'archival'
5
- s.version = '0.0.1'
5
+ s.version = '0.0.6'
6
6
  s.summary = 'An incredibly simple CMS for durable websites'
7
7
  s.description = 'https://jesseditson.com/the-simplest-cms-part-1'
8
8
  s.authors = ['Jesse Ditson']
@@ -24,5 +24,6 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.add_dependency 'liquid', '~> 5.1.0'
26
26
  s.add_dependency 'listen', '~> 3.7.0'
27
+ s.add_dependency 'redcarpet', '~> 3.5.1'
27
28
  s.add_dependency 'tomlrb', '~> 2.0.1'
28
29
  end
data/bin/archival CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('archival', 'archival')
29
+ load Gem.bin_path("archival", "archival")
data/bin/bundle CHANGED
@@ -8,46 +8,46 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'rubygems'
11
+ require "rubygems"
12
12
 
13
13
  m = Module.new do
14
14
  module_function
15
15
 
16
16
  def invoked_as_script?
17
- File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
18
  end
19
19
 
20
20
  def env_var_version
21
- ENV['BUNDLER_VERSION']
21
+ ENV["BUNDLER_VERSION"]
22
22
  end
23
23
 
24
24
  def cli_arg_version
25
25
  return unless invoked_as_script? # don't want to hijack other binstubs
26
- return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update`
27
-
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
28
27
  bundler_version = nil
29
28
  update_index = nil
30
29
  ARGV.each_with_index do |a, i|
31
- bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
32
33
  next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
33
-
34
- bundler_version = Regexp.last_match(1)
34
+ bundler_version = $1
35
35
  update_index = i
36
36
  end
37
37
  bundler_version
38
38
  end
39
39
 
40
40
  def gemfile
41
- gemfile = ENV['BUNDLE_GEMFILE']
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
42
  return gemfile if gemfile && !gemfile.empty?
43
43
 
44
- File.expand_path('../Gemfile', __dir__)
44
+ File.expand_path("../../Gemfile", __FILE__)
45
45
  end
46
46
 
47
47
  def lockfile
48
48
  lockfile =
49
49
  case File.basename(gemfile)
50
- when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
51
  else "#{gemfile}.lock"
52
52
  end
53
53
  File.expand_path(lockfile)
@@ -55,17 +55,15 @@ m = Module.new do
55
55
 
56
56
  def lockfile_version
57
57
  return unless File.file?(lockfile)
58
-
59
58
  lockfile_contents = File.read(lockfile)
60
59
  return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
61
-
62
60
  Regexp.last_match(1)
63
61
  end
64
62
 
65
63
  def bundler_requirement
66
64
  @bundler_requirement ||=
67
65
  env_var_version || cli_arg_version ||
68
- bundler_requirement_for(lockfile_version)
66
+ bundler_requirement_for(lockfile_version)
69
67
  end
70
68
 
71
69
  def bundler_requirement_for(version)
@@ -75,32 +73,28 @@ m = Module.new do
75
73
 
76
74
  requirement = bundler_gem_version.approximate_recommendation
77
75
 
78
- return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new('2.7.0')
76
+ return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
79
77
 
80
- requirement += '.a' if bundler_gem_version.prerelease?
78
+ requirement += ".a" if bundler_gem_version.prerelease?
81
79
 
82
80
  requirement
83
81
  end
84
82
 
85
83
  def load_bundler!
86
- ENV['BUNDLE_GEMFILE'] ||= gemfile
84
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
87
85
 
88
86
  activate_bundler
89
87
  end
90
88
 
91
89
  def activate_bundler
92
90
  gem_error = activation_error_handling do
93
- gem 'bundler', bundler_requirement
91
+ gem "bundler", bundler_requirement
94
92
  end
95
93
  return if gem_error.nil?
96
-
97
94
  require_error = activation_error_handling do
98
- require 'bundler/version'
99
- end
100
- if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
101
- return
95
+ require "bundler/version"
102
96
  end
103
-
97
+ return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
104
98
  warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
105
99
  exit 42
106
100
  end
@@ -115,4 +109,6 @@ end
115
109
 
116
110
  m.load_bundler!
117
111
 
118
- load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script?
112
+ if m.invoked_as_script?
113
+ load Gem.bin_path("bundler", "bundle")
114
+ end
data/bin/htmldiff CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('diff-lcs', 'htmldiff')
29
+ load Gem.bin_path("diff-lcs", "htmldiff")
data/bin/ldiff CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('diff-lcs', 'ldiff')
29
+ load Gem.bin_path("diff-lcs", "ldiff")
data/bin/listen CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('listen', 'listen')
29
+ load Gem.bin_path("listen", "listen")
data/bin/rake CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('rake', 'rake')
29
+ load Gem.bin_path("rake", "rake")
data/bin/redcarpet ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'redcarpet' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("redcarpet", "redcarpet")
data/bin/rspec CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('rspec-core', 'rspec')
29
+ load Gem.bin_path("rspec-core", "rspec")
data/bin/rubocop CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('rubocop', 'rubocop')
29
+ load Gem.bin_path("rubocop", "rubocop")
data/bin/ruby-parse CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('parser', 'ruby-parse')
29
+ load Gem.bin_path("parser", "ruby-parse")
data/bin/ruby-rewrite CHANGED
@@ -8,16 +8,14 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
14
 
15
- bundle_binstub = File.expand_path('bundle',
16
- __dir__)
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
17
16
 
18
17
  if File.file?(bundle_binstub)
19
- if File.read(bundle_binstub,
20
- 300) =~ /This file was generated by Bundler/
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
21
19
  load(bundle_binstub)
22
20
  else
23
21
  abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
@@ -25,7 +23,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
25
23
  end
26
24
  end
27
25
 
28
- require 'rubygems'
29
- require 'bundler/setup'
26
+ require "rubygems"
27
+ require "bundler/setup"
30
28
 
31
- load Gem.bin_path('parser', 'ruby-rewrite')
29
+ load Gem.bin_path("parser", "ruby-rewrite")
data/exe/archival CHANGED
@@ -19,17 +19,13 @@ build_dir = Dir.pwd
19
19
 
20
20
  case command
21
21
  when 'build'
22
- builder = Archival::Builder('root' => build_dir)
23
- builder.write_all
24
- when 'run'
25
- Archival.listen(build_dir)
26
- begin
27
- sleep
28
- rescue Interrupt
29
- # Don't print a stack when a user interrupts, as this is the right way to
30
- # stop the development server.
31
- puts ''
22
+ Archival::Logger.benchmark('built') do
23
+ config = Archival::Config.new('root' => build_dir)
24
+ builder = Archival::Builder.new(config)
25
+ builder.write_all
32
26
  end
27
+ when 'run'
28
+ Archival.listen('root' => build_dir)
33
29
  else
34
30
  # print help
35
31
  puts 'archival [command]'
@@ -0,0 +1,91 @@
1
+ /**
2
+ * When running archival in development mode (archival run), this file is
3
+ * injected into all pages, and is responsible for reloading the page when the
4
+ * source has changed.
5
+ */
6
+
7
+ (function () {
8
+ const remotePort = $PORT;
9
+ const CONNECTING_COLOR = "#bd270d";
10
+ const CONNECTED_COLOR = "#19bd0d";
11
+ const CHECK_INTERVAL = 500;
12
+ const DISCONNECTED_INTERVAL = 1000;
13
+ const connectionDot = document.createElement("div");
14
+ connectionDot.style = `position: absolute; z-index: 9999; bottom: 10px; right: 10px; background-color: ${CONNECTING_COLOR}; width: 15px; height: 15px; border-radius: 50%; opacity: 0.8;`;
15
+ connectionDot.setAttribute("title", "Archival Dev Server: Connecting");
16
+ connectionDot.addEventListener(
17
+ "mouseenter",
18
+ () => (connectionDot.style.opacity = 0.2)
19
+ );
20
+ connectionDot.addEventListener(
21
+ "mouseleave",
22
+ () => (connectionDot.style.opacity = 0.8)
23
+ );
24
+
25
+ let lastContact = -1;
26
+ let isConnecting = false;
27
+ let connection;
28
+
29
+ function connectionLoop() {
30
+ connection.send(`page:${window.location.pathname}`);
31
+ if (Date.now() - lastContact > DISCONNECTED_INTERVAL) {
32
+ setConnected(false);
33
+ connectSocket();
34
+ }
35
+ setTimeout(connectionLoop, CHECK_INTERVAL);
36
+ }
37
+
38
+ function setConnected(connected) {
39
+ connectionDot.style.backgroundColor = connected
40
+ ? CONNECTED_COLOR
41
+ : CONNECTING_COLOR;
42
+ connectionDot.setAttribute(
43
+ "title",
44
+ `Archival Dev Server: ${connected ? "Connected" : "Disconnected"}`
45
+ );
46
+ }
47
+
48
+ window.onload = () => {
49
+ connectSocket(true);
50
+ };
51
+
52
+ function connectSocket(init) {
53
+ if (isConnecting) {
54
+ return;
55
+ }
56
+ isConnecting = true;
57
+ console.log(
58
+ `${init ? "connecting" : "reconnecting"} to archival dev server...`
59
+ );
60
+ document.body.appendChild(connectionDot);
61
+ connection = new WebSocket(`ws://localhost:${remotePort}`);
62
+ connection.onerror = () => {
63
+ isConnecting = false;
64
+ };
65
+
66
+ connection.onopen = () => {
67
+ isConnecting = false;
68
+ connection.send("connected");
69
+ if (init) {
70
+ connectionLoop();
71
+ }
72
+ };
73
+ connection.onmessage = (event) => {
74
+ lastContact = Date.now();
75
+ switch (event.data) {
76
+ case "ready":
77
+ console.log("connected to archival dev server.");
78
+ break;
79
+ case "ok":
80
+ setConnected(true);
81
+ break;
82
+ case "refresh":
83
+ window.location.reload();
84
+ break;
85
+ default:
86
+ console.log(`receieved unexpected message ${event.data}`);
87
+ break;
88
+ }
89
+ };
90
+ }
91
+ })();
@@ -3,39 +3,58 @@
3
3
  require 'liquid'
4
4
  require 'tomlrb'
5
5
  require 'tags/layout'
6
+ require 'redcarpet'
6
7
 
7
8
  Liquid::Template.error_mode = :strict
8
9
  Liquid::Template.register_tag('layout', Layout)
9
10
 
10
11
  module Archival
12
+ class DuplicateKeyError < StandardError
13
+ end
14
+
11
15
  class Builder
12
16
  attr_reader :page_templates
13
17
 
14
18
  def initialize(config, *_args)
15
- @config = Config.new(config)
19
+ @config = config
20
+ @markdown = Redcarpet::Markdown.new(
21
+ Redcarpet::Render::HTML.new(prettify: true,
22
+ hard_wrap: true), no_intra_emphasis: true,
23
+ fenced_code_blocks: true,
24
+ autolink: true,
25
+ strikethrough: true,
26
+ underline: true
27
+ )
16
28
  refresh_config
17
29
  end
18
30
 
19
31
  def refresh_config
20
32
  @file_system = Liquid::LocalFileSystem.new(
21
- @config.root, '%s.liquid'
33
+ File.join(@config.root, @config.pages_dir), '%s.liquid'
22
34
  )
23
35
  @variables = {}
24
36
  @object_types = {}
25
37
  @page_templates = {}
26
38
 
27
- Liquid::Template.file_system = @file_system
39
+ Liquid::Template.file_system = Liquid::LocalFileSystem.new(
40
+ File.join(@config.root, @config.pages_dir), '_%s.liquid'
41
+ )
28
42
 
29
43
  objects_definition_file = File.join(@config.root,
30
44
  'objects.toml')
31
45
  if File.file? objects_definition_file
32
- @object_types = read_toml(objects_definition_file)
46
+ @object_types = Tomlrb.load_file(objects_definition_file)
33
47
  end
34
48
 
35
49
  update_pages
36
50
  update_objects
37
51
  end
38
52
 
53
+ def full_rebuild
54
+ Layout.reset_cache
55
+ refresh_config
56
+ end
57
+
39
58
  def update_pages
40
59
  do_update_pages(File.join(@config.root, @config.pages_dir))
41
60
  end
@@ -56,11 +75,9 @@ module Archival
56
75
  if entry.end_with?('.liquid') && !(entry.start_with? '_')
57
76
  page_name = File.basename(entry,
58
77
  '.liquid')
59
- template_file = File.join(
60
- @config.pages_dir,
61
- add_prefix.call(page_name)
62
- )
78
+ template_file = add_prefix.call(page_name)
63
79
  content = @file_system.read_template_file(template_file)
80
+ content += dev_mode_content if @config.dev_mode
64
81
  @page_templates[add_prefix.call(page_name)] =
65
82
  Liquid::Template.parse(content)
66
83
  end
@@ -75,30 +92,50 @@ module Archival
75
92
 
76
93
  def do_update_objects(dir)
77
94
  objects = {}
78
- @object_types.each do |name, _definition|
79
- objects[name] = []
95
+ @object_types.each do |name, definition|
96
+ objects[name] = {}
80
97
  obj_dir = File.join(dir, name)
81
98
  if File.directory? obj_dir
82
99
  Dir.foreach(obj_dir) do |file|
83
100
  if file.end_with? '.toml'
84
- object = read_toml(File.join(
85
- obj_dir, file
86
- ))
101
+ object = Tomlrb.load_file(File.join(
102
+ obj_dir, file
103
+ ))
87
104
  object[:name] =
88
105
  File.basename(file, '.toml')
89
- objects[name].push object
106
+ objects[name][object[:name]] = parse_object(object, definition)
90
107
  end
91
108
  end
92
109
  end
93
- objects[name] = objects[name].sort do |a, b|
94
- (a['order'] || a[:name]).to_s <=> (b['order'] || b[:name]).to_s
95
- end
110
+ objects[name] = sort_objects(objects[name])
96
111
  end
97
112
  @variables['objects'] = objects
98
113
  end
99
114
 
100
- def read_toml(file_path)
101
- Tomlrb.load_file(file_path)
115
+ def sort_objects(objects)
116
+ # Sort by either 'order' key or object name, depending on what is
117
+ # available.
118
+ sorted_by_keys = objects.sort_by do |name, obj|
119
+ obj.key?('order') ? obj['order'].to_s : name
120
+ end
121
+ sorted_objects = Archival::TemplateArray.new
122
+ sorted_by_keys.each do |d|
123
+ raise DuplicateKeyError if sorted_objects.key?(d[0])
124
+
125
+ sorted_objects.push(d[1])
126
+ sorted_objects[d[0]] = d[1]
127
+ end
128
+ sorted_objects
129
+ end
130
+
131
+ def parse_object(object, definition)
132
+ definition.each do |name, type|
133
+ case type
134
+ when 'markdown'
135
+ object[name] = @markdown.render(object[name]) if object[name]
136
+ end
137
+ end
138
+ object
102
139
  end
103
140
 
104
141
  def set_var(name, value)
@@ -122,6 +159,19 @@ module Archival
122
159
  file.write(render(template))
123
160
  end
124
161
  end
162
+ return if @config.dev_mode
163
+
164
+ # in production, also copy all assets to the dist folder.
165
+ @config.assets_dirs.each do |asset_dir|
166
+ FileUtils.copy_entry File.join(@config.root, asset_dir),
167
+ File.join(@config.build_dir, asset_dir)
168
+ end
169
+ end
170
+
171
+ private
172
+
173
+ def dev_mode_content
174
+ "<script src=\"http://localhost:#{@config.helper_port}/js/archival-helper.js\" type=\"application/javascript\"></script>" # rubocop:disable Layout/LineLength
125
175
  end
126
176
  end
127
177
  end
@@ -1,16 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tomlrb'
4
+
3
5
  module Archival
4
6
  class Config
5
- attr_reader :pages_dir, :objects_dir, :root, :build_dir
7
+ attr_reader :pages_dir, :objects_dir, :assets_dirs, :root, :build_dir,
8
+ :helper_port, :dev_mode
6
9
 
7
- def initialize(config)
8
- @pages_dir = config['pages'] || 'pages'
9
- @objects_dir = config['objects'] || 'objects'
10
+ def initialize(config = {})
10
11
  @root = config['root'] || Dir.pwd
11
- @build_dir = config['build_dir'] || File.join(
12
+ manifest = load_manifest
13
+ @pages_dir = config['pages'] || manifest['pages'] || 'pages'
14
+ @objects_dir = config['objects'] || manifest['objects'] || 'objects'
15
+ @build_dir = config['build_dir'] || manifest['build_dir'] || File.join(
12
16
  @root, 'dist'
13
17
  )
18
+ @helper_port = config['helper_port'] || manifest['helper_port'] || 2701
19
+ @assets_dirs = config['assets_dirs'] || manifest['assets'] || []
20
+ @dev_mode = config[:dev_mode] || false
21
+ end
22
+
23
+ def load_manifest
24
+ manifest_file = File.join(@root, 'manifest.toml')
25
+ return Tomlrb.load_file(manifest_file) if File.file? manifest_file
26
+
27
+ {}
14
28
  end
15
29
  end
16
30
  end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+ require 'open-uri'
5
+
6
+ module Archival
7
+ class HelperServer
8
+ attr_reader :page
9
+
10
+ def initialize(port, build_dir)
11
+ @port = port
12
+ @build_dir = build_dir
13
+ @helper_dir = File.expand_path(File.join(File.dirname(__FILE__),
14
+ '../../helper'))
15
+ end
16
+
17
+ def start
18
+ server = TCPServer.new @port
19
+ loop do
20
+ Thread.start(server.accept) do |client|
21
+ req = ''
22
+ method = nil
23
+ path = nil
24
+ while (line = client.gets) && (line != "\r\n")
25
+ unless method
26
+ req_info = line.split
27
+ method = req_info[0]
28
+ path = req_info[1]
29
+ end
30
+ req += line
31
+ end
32
+ client.close unless req
33
+ handle_request(client, req, method, path)
34
+ end
35
+ end
36
+ end
37
+
38
+ def refresh_client
39
+ ws_sendmessage('refresh')
40
+ end
41
+
42
+ private
43
+
44
+ MAGIC_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
45
+
46
+ def handle_request(client, req, method, path)
47
+ if method == 'GET' && path.start_with?('/js/')
48
+ # For static paths, just serve the files they refer to.
49
+ http_response(client, type: 'application/javascript') do
50
+ serve_static(client, path)
51
+ end
52
+ client.close
53
+ elsif (matches = req.match(/^Sec-WebSocket-Key: (\S+)/))
54
+ websocket_key = matches[1]
55
+ # puts "Websocket handshake detected with key: #{websocket_key}"
56
+ connect_socket(client, websocket_key)
57
+ else
58
+ client.close
59
+ end
60
+ end
61
+
62
+ def connect_socket(client, websocket_key)
63
+ @socket = client
64
+ response_key = Digest::SHA1.base64digest([websocket_key,
65
+ MAGIC_GUID].join)
66
+ # puts "Responding to handshake with key: #{response_key}"
67
+
68
+ @socket.write "HTTP/1.1 101 Switching Protocols\r\n"
69
+ @socket.write "Upgrade: websocket\r\n"
70
+ @socket.write "Connection: Upgrade\r\n"
71
+ @socket.write "Sec-WebSocket-Accept: #{response_key}\r\n"
72
+ @socket.write "\r\n"
73
+
74
+ # puts 'Handshake completed.'
75
+ ws_loop
76
+ end
77
+
78
+ def ws_loop
79
+ loop do
80
+ msg = ws_getmessage
81
+ next unless msg
82
+
83
+ if msg == 'connected'
84
+ ws_sendmessage('ready')
85
+ elsif msg.start_with?('page:')
86
+ page_path = Pathname.new(msg.sub(/^page:/, ''))
87
+ @page = page_path.relative_path_from(@build_dir)
88
+ ws_sendmessage('ok')
89
+ end
90
+ end
91
+ end
92
+
93
+ def validate_ws_message
94
+ first_byte = @socket.getbyte
95
+ return unless first_byte
96
+
97
+ fin = first_byte & 0b10000000
98
+ opcode = first_byte & 0b00001111
99
+
100
+ # Our server only supports single-frame, text messages.
101
+ # Raise an exception if the client tries to send anything else.
102
+ raise "We don't support continuations" unless fin
103
+ raise 'We only support opcode 1' unless opcode == 1
104
+
105
+ second_byte = @socket.getbyte
106
+ is_masked = second_byte & 0b10000000
107
+ payload_size = second_byte & 0b01111111
108
+
109
+ raise 'frame masked incorrectly' unless is_masked
110
+ raise 'payload must be < 126 bytes in length' unless payload_size < 126
111
+
112
+ payload_size
113
+ end
114
+
115
+ def ws_getmessage
116
+ payload_size = validate_ws_message
117
+ return unless payload_size
118
+
119
+ # warn "Payload size: #{payload_size} bytes"
120
+
121
+ mask = 4.times.map { @socket.getbyte }
122
+ # warn "Got mask: #{mask.inspect}"
123
+
124
+ data = payload_size.times.map { @socket.getbyte }
125
+ # warn "Got masked data: #{data.inspect}"
126
+
127
+ unmasked_data = data.each_with_index.map do |byte, i|
128
+ byte ^ mask[i % 4]
129
+ end
130
+ # warn "Unmasked the data: #{unmasked_data.inspect}"
131
+
132
+ unmasked_data.pack('C*').force_encoding('utf-8')
133
+ end
134
+
135
+ def ws_sendmessage(message)
136
+ return unless @socket
137
+
138
+ output = [0b10000001, message.size, message]
139
+ @socket.write output.pack("CCA#{message.size}")
140
+ end
141
+
142
+ def serve_static(client, path)
143
+ buffer = File.open(File.join(@helper_dir, path)).read
144
+ buffer.sub! '$PORT', @port.to_s
145
+ client.print buffer
146
+ end
147
+
148
+ def http_response(client, config)
149
+ status = config[:status] ||= 200
150
+ type = config[:type] ||= 'text/html'
151
+ client.print "HTTP/1.1 #{status}\r\n"
152
+ client.print "Content-Type: #{type}\r\n"
153
+ client.print "\r\n"
154
+ yield
155
+ end
156
+ end
157
+ end
@@ -4,40 +4,83 @@ require 'listen'
4
4
  require 'pathname'
5
5
 
6
6
  module Archival
7
- def self.child?(parent, child)
8
- path = Pathname.new(child)
9
- return true if path.fnmatch?(File.join(parent, '**'))
10
-
11
- false
7
+ def listen(config = {})
8
+ @config = Config.new(config.merge(dev_mode: true))
9
+ builder = Builder.new(@config)
10
+ Logger.benchmark('built') do
11
+ builder.write_all
12
+ end
13
+ ignore = %r{/dist/}
14
+ listener = Listen.to(@config.root,
15
+ ignore: ignore) do |modified, added, removed|
16
+ updated_pages = []
17
+ updated_objects = []
18
+ updated_assets = []
19
+ (modified + added + removed).each do |file|
20
+ case change_type(file)
21
+ when :pages
22
+ updated_pages << file
23
+ when :objects
24
+ updated_objects << file
25
+ when :assets
26
+ updated_assets << file
27
+ end
28
+ end
29
+ @server.refresh_client if rebuild?(builder, updated_objects,
30
+ updated_pages, updated_assets)
31
+ end
32
+ listener.start
33
+ serve_helpers
12
34
  end
13
35
 
14
- def self.process_change?(file, builder)
15
- if child?(File.join(@config.root, @config.pages_dir), file)
36
+ module_function :listen
37
+
38
+ class << self
39
+ private
40
+
41
+ def child?(parent, child)
42
+ path = Pathname.new(child)
43
+ return true if path.fnmatch?(File.join(parent, '**'))
44
+
45
+ false
46
+ end
47
+
48
+ def change_type(file)
16
49
  # a page was modified, rebuild the pages.
17
- builder.update_pages
18
- return true
19
- elsif child?(File.join(@config.root, @config.objects_dir), file)
50
+ return :pages if child?(File.join(@config.root, @config.pages_dir),
51
+ file)
20
52
  # an object was modified, rebuild the objects.
21
- builder.update_objects
22
- return true
53
+ return :objects if child?(File.join(@config.root, @config.objects_dir),
54
+ file)
55
+
56
+ # layout and other assets. For now, this is everything.
57
+ @config.assets_dirs.each do |dir|
58
+ return :assets if child?(File.join(@config.root, dir), file)
59
+ end
60
+ return :assets if child?(File.join(@config.root, 'layout'), file)
61
+ return :assets if ['manifest.toml',
62
+ 'objects.toml'].include? File.basename(file)
63
+
64
+ :none
23
65
  end
24
- false
25
- end
26
66
 
27
- def listen(config)
28
- @config = Config.new(config)
29
- builder = Builder.new(config)
30
- builder.write_all
31
- listener = Listen.to(@config.root) do |modified, added, removed|
32
- needs_update = false
33
- (modified + added + removed).each do |file|
34
- needs_update = true if process_change?(file, builder)
67
+ def rebuild?(builder, updated_objects, updated_pages, updated_assets)
68
+ if updated_pages.empty? && updated_objects.empty? && updated_assets.empty?
69
+ return false
70
+ end
71
+
72
+ Logger.benchmark('rebuilt') do
73
+ builder.update_objects if updated_objects.length
74
+ builder.update_pages if updated_pages.length
75
+ builder.full_rebuild if updated_assets.length
76
+ builder.write_all
35
77
  end
36
- builder.write_all if needs_update
78
+ true
37
79
  end
38
- listener.start
39
- listener
40
- end
41
80
 
42
- module_function :listen
81
+ def serve_helpers
82
+ @server = HelperServer.new(@config.helper_port, @config.build_dir)
83
+ @server.start
84
+ end
85
+ end
43
86
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+
5
+ module Archival
6
+ class Logger
7
+ def self.benchmark(message, &block)
8
+ Benchmark.bm do |bm|
9
+ bm.report(message, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -27,19 +27,15 @@ class RakeTasks
27
27
  build_dir = Dir.pwd
28
28
 
29
29
  task 'build' do
30
- builder = Archival::Builder.new('root' => build_dir)
31
- builder.write_all
30
+ Archival::Logger.benchmark('built') do
31
+ config = Archival::Config.new('root' => build_dir)
32
+ builder = Archival::Builder.new(config)
33
+ builder.write_all
34
+ end
32
35
  end
33
36
 
34
37
  task 'run' do
35
- Archival.listen(build_dir)
36
- begin
37
- sleep
38
- rescue Interrupt
39
- # Don't print a stack when a user interrupts, as this is the right way
40
- # to stop the development server.
41
- puts ''
42
- end
38
+ Archival.listen('root' => build_dir)
43
39
  end
44
40
 
45
41
  RakeTasks.instance = self
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archival
4
+ class TemplateArray < Array
5
+ alias subscript_access []
6
+ alias subscript_write []=
7
+
8
+ def initialize(*args)
9
+ super(*args)
10
+ @data = {}
11
+ end
12
+
13
+ def [](*args)
14
+ key = args[0]
15
+ return @data[key] if key.is_a? String
16
+ return @data[key] if key.is_a? Symbol
17
+
18
+ subscript_access(*args)
19
+ end
20
+
21
+ def []=(*args)
22
+ key = args[0]
23
+ if key.is_a?(String) || key.is_a?(Symbol)
24
+ @data[key] = args[1]
25
+ return
26
+ end
27
+ subscript_write(*args)
28
+ end
29
+
30
+ def key?(key)
31
+ @data.key?(key)
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Archival
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.6'
5
5
  end
data/lib/archival.rb CHANGED
@@ -5,6 +5,9 @@ module Archival
5
5
  end
6
6
 
7
7
  require 'archival/version'
8
+ require 'archival/template_array'
9
+ require 'archival/logger'
8
10
  require 'archival/config'
11
+ require 'archival/helper_server'
9
12
  require 'archival/builder'
10
13
  require 'archival/listen'
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archival",
3
- "version": "0.0.1",
3
+ "version": "0.0.6",
4
4
  "description": "An incredibly simple CMS for durable websites",
5
5
  "bin": "build.rb",
6
6
  "directories": {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: archival
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Ditson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-05 00:00:00.000000000 Z
11
+ date: 2021-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 3.7.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: redcarpet
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.5.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.5.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: tomlrb
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -76,17 +90,22 @@ files:
76
90
  - bin/ldiff
77
91
  - bin/listen
78
92
  - bin/rake
93
+ - bin/redcarpet
79
94
  - bin/rspec
80
95
  - bin/rubocop
81
96
  - bin/ruby-parse
82
97
  - bin/ruby-rewrite
83
98
  - bin/setup
84
99
  - exe/archival
100
+ - helper/js/archival-helper.js
85
101
  - lib/archival.rb
86
102
  - lib/archival/builder.rb
87
103
  - lib/archival/config.rb
104
+ - lib/archival/helper_server.rb
88
105
  - lib/archival/listen.rb
106
+ - lib/archival/logger.rb
89
107
  - lib/archival/rake_tasks.rb
108
+ - lib/archival/template_array.rb
90
109
  - lib/archival/version.rb
91
110
  - lib/tags/layout.rb
92
111
  - package.json