bridgetown-core 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +42 -0
  3. data/bridgetown-core.gemspec +46 -0
  4. data/lib/bridgetown-core.rb +202 -0
  5. data/lib/bridgetown-core/cache.rb +190 -0
  6. data/lib/bridgetown-core/cleaner.rb +111 -0
  7. data/lib/bridgetown-core/collection.rb +279 -0
  8. data/lib/bridgetown-core/command.rb +106 -0
  9. data/lib/bridgetown-core/commands/build.rb +96 -0
  10. data/lib/bridgetown-core/commands/clean.rb +43 -0
  11. data/lib/bridgetown-core/commands/console.rb +56 -0
  12. data/lib/bridgetown-core/commands/doctor.rb +172 -0
  13. data/lib/bridgetown-core/commands/help.rb +34 -0
  14. data/lib/bridgetown-core/commands/new.rb +148 -0
  15. data/lib/bridgetown-core/commands/serve.rb +273 -0
  16. data/lib/bridgetown-core/commands/serve/servlet.rb +68 -0
  17. data/lib/bridgetown-core/configuration.rb +323 -0
  18. data/lib/bridgetown-core/converter.rb +54 -0
  19. data/lib/bridgetown-core/converters/identity.rb +39 -0
  20. data/lib/bridgetown-core/converters/markdown.rb +108 -0
  21. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +132 -0
  22. data/lib/bridgetown-core/converters/smartypants.rb +69 -0
  23. data/lib/bridgetown-core/convertible.rb +237 -0
  24. data/lib/bridgetown-core/deprecator.rb +50 -0
  25. data/lib/bridgetown-core/document.rb +475 -0
  26. data/lib/bridgetown-core/drops/bridgetown_drop.rb +32 -0
  27. data/lib/bridgetown-core/drops/collection_drop.rb +20 -0
  28. data/lib/bridgetown-core/drops/document_drop.rb +69 -0
  29. data/lib/bridgetown-core/drops/drop.rb +215 -0
  30. data/lib/bridgetown-core/drops/excerpt_drop.rb +19 -0
  31. data/lib/bridgetown-core/drops/page_drop.rb +14 -0
  32. data/lib/bridgetown-core/drops/site_drop.rb +62 -0
  33. data/lib/bridgetown-core/drops/static_file_drop.rb +14 -0
  34. data/lib/bridgetown-core/drops/unified_payload_drop.rb +26 -0
  35. data/lib/bridgetown-core/drops/url_drop.rb +132 -0
  36. data/lib/bridgetown-core/entry_filter.rb +108 -0
  37. data/lib/bridgetown-core/errors.rb +20 -0
  38. data/lib/bridgetown-core/excerpt.rb +202 -0
  39. data/lib/bridgetown-core/external.rb +62 -0
  40. data/lib/bridgetown-core/filters.rb +467 -0
  41. data/lib/bridgetown-core/filters/date_filters.rb +110 -0
  42. data/lib/bridgetown-core/filters/grouping_filters.rb +64 -0
  43. data/lib/bridgetown-core/filters/url_filters.rb +79 -0
  44. data/lib/bridgetown-core/frontmatter_defaults.rb +238 -0
  45. data/lib/bridgetown-core/generator.rb +5 -0
  46. data/lib/bridgetown-core/hooks.rb +103 -0
  47. data/lib/bridgetown-core/layout.rb +57 -0
  48. data/lib/bridgetown-core/liquid_extensions.rb +22 -0
  49. data/lib/bridgetown-core/liquid_renderer.rb +71 -0
  50. data/lib/bridgetown-core/liquid_renderer/file.rb +67 -0
  51. data/lib/bridgetown-core/liquid_renderer/table.rb +75 -0
  52. data/lib/bridgetown-core/log_adapter.rb +151 -0
  53. data/lib/bridgetown-core/log_writer.rb +60 -0
  54. data/lib/bridgetown-core/mime.types +867 -0
  55. data/lib/bridgetown-core/page.rb +214 -0
  56. data/lib/bridgetown-core/page_without_a_file.rb +14 -0
  57. data/lib/bridgetown-core/path_manager.rb +31 -0
  58. data/lib/bridgetown-core/plugin.rb +80 -0
  59. data/lib/bridgetown-core/plugin_manager.rb +60 -0
  60. data/lib/bridgetown-core/publisher.rb +23 -0
  61. data/lib/bridgetown-core/reader.rb +185 -0
  62. data/lib/bridgetown-core/readers/collection_reader.rb +22 -0
  63. data/lib/bridgetown-core/readers/data_reader.rb +75 -0
  64. data/lib/bridgetown-core/readers/layout_reader.rb +48 -0
  65. data/lib/bridgetown-core/readers/page_reader.rb +24 -0
  66. data/lib/bridgetown-core/readers/post_reader.rb +74 -0
  67. data/lib/bridgetown-core/readers/static_file_reader.rb +24 -0
  68. data/lib/bridgetown-core/regenerator.rb +195 -0
  69. data/lib/bridgetown-core/related_posts.rb +52 -0
  70. data/lib/bridgetown-core/renderer.rb +261 -0
  71. data/lib/bridgetown-core/site.rb +469 -0
  72. data/lib/bridgetown-core/static_file.rb +205 -0
  73. data/lib/bridgetown-core/tags/component.rb +34 -0
  74. data/lib/bridgetown-core/tags/highlight.rb +111 -0
  75. data/lib/bridgetown-core/tags/include.rb +220 -0
  76. data/lib/bridgetown-core/tags/link.rb +41 -0
  77. data/lib/bridgetown-core/tags/post_url.rb +107 -0
  78. data/lib/bridgetown-core/url.rb +164 -0
  79. data/lib/bridgetown-core/utils.rb +367 -0
  80. data/lib/bridgetown-core/utils/ansi.rb +57 -0
  81. data/lib/bridgetown-core/utils/exec.rb +26 -0
  82. data/lib/bridgetown-core/utils/internet.rb +37 -0
  83. data/lib/bridgetown-core/utils/platforms.rb +80 -0
  84. data/lib/bridgetown-core/utils/thread_event.rb +31 -0
  85. data/lib/bridgetown-core/utils/win_tz.rb +75 -0
  86. data/lib/bridgetown-core/version.rb +5 -0
  87. data/lib/bridgetown-core/watcher.rb +139 -0
  88. data/lib/site_template/.gitignore +6 -0
  89. data/lib/site_template/bridgetown.config.yml +21 -0
  90. data/lib/site_template/frontend/javascript/index.js +3 -0
  91. data/lib/site_template/frontend/styles/index.scss +17 -0
  92. data/lib/site_template/package.json +23 -0
  93. data/lib/site_template/src/404.html +9 -0
  94. data/lib/site_template/src/_data/site_metadata.yml +11 -0
  95. data/lib/site_template/src/_includes/footer.html +3 -0
  96. data/lib/site_template/src/_includes/head.html +9 -0
  97. data/lib/site_template/src/_includes/navbar.html +4 -0
  98. data/lib/site_template/src/_layouts/default.html +15 -0
  99. data/lib/site_template/src/_layouts/home.html +7 -0
  100. data/lib/site_template/src/_layouts/page.html +7 -0
  101. data/lib/site_template/src/_layouts/post.html +7 -0
  102. data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +26 -0
  103. data/lib/site_template/src/about.md +11 -0
  104. data/lib/site_template/src/index.md +7 -0
  105. data/lib/site_template/webpack.config.js +60 -0
  106. data/rake/release.rake +30 -0
  107. metadata +106 -1
@@ -0,0 +1,57 @@
1
+ # Frozen-string-literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ module Ansi
6
+ extend self
7
+
8
+ ESCAPE = format("%c", 27)
9
+ MATCH = %r!#{ESCAPE}\[(?:\d+)(?:;\d+)*(j|k|m|s|u|A|B|G)|\e\(B\e\[m!ix.freeze
10
+ COLORS = {
11
+ :red => 31,
12
+ :green => 32,
13
+ :black => 30,
14
+ :magenta => 35,
15
+ :yellow => 33,
16
+ :white => 37,
17
+ :blue => 34,
18
+ :cyan => 36,
19
+ }.freeze
20
+
21
+ # Strip ANSI from the current string. It also strips cursor stuff,
22
+ # well some of it, and it also strips some other stuff that a lot of
23
+ # the other ANSI strippers don't.
24
+
25
+ def strip(str)
26
+ str.gsub MATCH, ""
27
+ end
28
+
29
+ #
30
+
31
+ def has?(str)
32
+ !!(str =~ MATCH)
33
+ end
34
+
35
+ # Reset the color back to the default color so that you do not leak any
36
+ # colors when you move onto the next line. This is probably normally
37
+ # used as part of a wrapper so that we don't leak colors.
38
+
39
+ def reset(str = "")
40
+ @ansi_reset ||= format("%c[0m", 27)
41
+ "#{@ansi_reset}#{str}"
42
+ end
43
+
44
+ # SEE: `self::COLORS` for a list of methods. They are mostly
45
+ # standard base colors supported by pretty much any xterm-color, we do
46
+ # not need more than the base colors so we do not include them.
47
+ # Actually... if I'm honest we don't even need most of the
48
+ # base colors.
49
+
50
+ COLORS.each do |color, num|
51
+ define_method color do |str|
52
+ "#{format("%c", 27)}[#{num}m#{str}#{reset}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ module Bridgetown
6
+ module Utils
7
+ module Exec
8
+ extend self
9
+
10
+ # Runs a program in a sub-shell.
11
+ #
12
+ # *args - a list of strings containing the program name and arguments
13
+ #
14
+ # Returns a Process::Status and a String of output in an array in
15
+ # that order.
16
+ def run(*args)
17
+ stdin, stdout, stderr, process = Open3.popen3(*args)
18
+ out = stdout.read.strip
19
+ err = stderr.read.strip
20
+
21
+ [stdin, stdout, stderr].each(&:close)
22
+ [process.value, out + err]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ module Internet
6
+ # Public: Determine whether the present device has a connection to
7
+ # the Internet. This allows plugin writers which require the outside
8
+ # world to have a neat fallback mechanism for offline building.
9
+ #
10
+ # Example:
11
+ # if Internet.connected?
12
+ # Typhoeus.get("https://pages.github.com/versions.json")
13
+ # else
14
+ # Bridgetown.logger.warn "Warning:", "Version check has been disabled."
15
+ # Bridgetown.logger.warn "", "Connect to the Internet to enable it."
16
+ # nil
17
+ # end
18
+ #
19
+ # Returns true if a DNS call can successfully be made, or false if not.
20
+
21
+ module_function
22
+
23
+ def connected?
24
+ !dns("example.com").nil?
25
+ end
26
+
27
+ def dns(domain)
28
+ require "resolv"
29
+ Resolv::DNS.open do |resolver|
30
+ resolver.getaddress(domain)
31
+ end
32
+ rescue Resolv::ResolvError, Resolv::ResolvTimeout
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ module Platforms
6
+ extend self
7
+
8
+ # TODO: jruby is NOT supported by Bridgetown. This should probably
9
+ # get removed.
10
+ { :jruby? => "jruby", :mri? => "ruby" }.each do |k, v|
11
+ define_method k do
12
+ ::RUBY_ENGINE == v
13
+ end
14
+ end
15
+
16
+ # --
17
+ # Allows you to detect "real" Windows, or what we would consider
18
+ # "real" Windows. That is, that we can pass the basic test and the
19
+ # /proc/version returns nothing to us.
20
+ # --
21
+
22
+ def vanilla_windows?
23
+ RbConfig::CONFIG["host_os"] =~ %r!mswin|mingw|cygwin!i && \
24
+ !proc_version
25
+ end
26
+
27
+ # --
28
+ # XXX: Remove in 4.0
29
+ # --
30
+
31
+ alias_method :really_windows?, \
32
+ :vanilla_windows?
33
+
34
+ #
35
+
36
+ def bash_on_windows?
37
+ RbConfig::CONFIG["host_os"] =~ %r!linux! && \
38
+ proc_version =~ %r!microsoft!i
39
+ end
40
+
41
+ #
42
+
43
+ def windows?
44
+ vanilla_windows? || bash_on_windows?
45
+ end
46
+
47
+ #
48
+
49
+ def linux?
50
+ RbConfig::CONFIG["host_os"] =~ %r!linux! && \
51
+ proc_version !~ %r!microsoft!i
52
+ end
53
+
54
+ # Provides windows?, linux?, osx?, unix? so that we can detect
55
+ # platforms. This is mostly useful for `bridgetown doctor` and for testing
56
+ # where we kick off certain tests based on the platform.
57
+
58
+ { :osx? => %r!darwin|mac os!, :unix? => %r!solaris|bsd! }.each do |k, v|
59
+ define_method k do
60
+ !!(
61
+ RbConfig::CONFIG["host_os"] =~ v
62
+ )
63
+ end
64
+ end
65
+
66
+ #
67
+
68
+ private
69
+
70
+ def proc_version
71
+ @proc_version ||=
72
+ begin
73
+ File.read("/proc/version")
74
+ rescue Errno::ENOENT, Errno::EACCES
75
+ nil
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ # Based on the pattern and code from
6
+ # https://emptysqua.re/blog/an-event-synchronization-primitive-for-ruby/
7
+ class ThreadEvent
8
+ attr_reader :flag
9
+
10
+ def initialize
11
+ @lock = Mutex.new
12
+ @cond = ConditionVariable.new
13
+ @flag = false
14
+ end
15
+
16
+ def set
17
+ @lock.synchronize do
18
+ yield if block_given?
19
+ @flag = true
20
+ @cond.broadcast
21
+ end
22
+ end
23
+
24
+ def wait
25
+ @lock.synchronize do
26
+ @cond.wait(@lock) unless @flag
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ module WinTZ
6
+ extend self
7
+
8
+ # Public: Calculate the Timezone for Windows when the config file has a defined
9
+ # 'timezone' key.
10
+ #
11
+ # timezone - the IANA Time Zone specified in "_config.yml"
12
+ #
13
+ # Returns a string that ultimately re-defines ENV["TZ"] in Windows
14
+ def calculate(timezone)
15
+ External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo)
16
+ tz = TZInfo::Timezone.get(timezone)
17
+ difference = Time.now.to_i - tz.now.to_i
18
+ #
19
+ # POSIX style definition reverses the offset sign.
20
+ # e.g. Eastern Standard Time (EST) that is 5Hrs. to the 'west' of Prime Meridian
21
+ # is denoted as:
22
+ # EST+5 (or) EST+05:00
23
+ # Reference: http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
24
+ sign = difference.negative? ? "-" : "+"
25
+ offset = sign == "-" ? "+" : "-" unless difference.zero?
26
+ #
27
+ # convert the difference (in seconds) to hours, as a rational number, and perform
28
+ # a modulo operation on it.
29
+ modulo = modulo_of(rational_hour(difference))
30
+ #
31
+ # Format the hour as a two-digit number.
32
+ # Establish the minutes based on modulo expression.
33
+ hh = format("%<hour>02d", :hour => absolute_hour(difference).ceil)
34
+ mm = modulo.zero? ? "00" : "30"
35
+
36
+ Bridgetown.logger.debug "Timezone:", "#{timezone} #{offset}#{hh}:#{mm}"
37
+ #
38
+ # Note: The 3-letter-word below doesn't have a particular significance.
39
+ "WTZ#{sign}#{hh}:#{mm}"
40
+ end
41
+
42
+ private
43
+
44
+ # Private: Convert given seconds to an hour as a rational number.
45
+ #
46
+ # seconds - supplied as an integer, it is converted to a rational number.
47
+ # 3600 - no. of seconds in an hour.
48
+ #
49
+ # Returns a rational number.
50
+ def rational_hour(seconds)
51
+ seconds.to_r / 3600
52
+ end
53
+
54
+ # Private: Convert given seconds to an hour as an absolute number.
55
+ #
56
+ # seconds - supplied as an integer, it is converted to its absolute.
57
+ # 3600 - no. of seconds in an hour.
58
+ #
59
+ # Returns an integer.
60
+ def absolute_hour(seconds)
61
+ seconds.abs / 3600
62
+ end
63
+
64
+ # Private: Perform a modulo operation on a given fraction.
65
+ #
66
+ # fraction - supplied as a rational number, its numerator is divided
67
+ # by its denominator and the remainder returned.
68
+ #
69
+ # Returns an integer.
70
+ def modulo_of(fraction)
71
+ fraction.numerator % fraction.denominator
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ VERSION = "0.7.1"
5
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "listen"
4
+
5
+ module Bridgetown
6
+ module Watcher
7
+ extend self
8
+
9
+ # Public: Continuously watch for file changes and rebuild the site
10
+ # whenever a change is detected.
11
+ #
12
+ # If the optional site argument is populated, that site instance will be
13
+ # reused and the options Hash ignored. Otherwise, a new site instance will
14
+ # be instantiated from the options Hash and used.
15
+ #
16
+ # options - A Hash containing the site configuration
17
+ # site - The current site instance (populated starting with Bridgetown 3.2)
18
+ # (optional, default: nil)
19
+ #
20
+ # Returns nothing.
21
+ def watch(options, site = nil)
22
+ ENV["LISTEN_GEM_DEBUGGING"] ||= "1" if options["verbose"]
23
+
24
+ site ||= Bridgetown::Site.new(options)
25
+ listener = build_listener(site, options)
26
+ listener.start
27
+
28
+ Bridgetown.logger.info "Auto-regeneration:", "enabled for '#{options["source"]}'"
29
+
30
+ unless options["serving"]
31
+ trap("INT") do
32
+ listener.stop
33
+ Bridgetown.logger.info "", "Halting auto-regeneration."
34
+ exit 0
35
+ end
36
+
37
+ sleep_forever
38
+ end
39
+ rescue ThreadError
40
+ # You pressed Ctrl-C, oh my!
41
+ end
42
+
43
+ private
44
+
45
+ def build_listener(site, options)
46
+ Listen.to(
47
+ options["source"],
48
+ :ignore => listen_ignore_paths(options),
49
+ :force_polling => options["force_polling"],
50
+ &listen_handler(site)
51
+ )
52
+ end
53
+
54
+ def listen_handler(site)
55
+ proc do |modified, added, removed|
56
+ t = Time.now
57
+ c = modified + added + removed
58
+ n = c.length
59
+
60
+ Bridgetown.logger.info "Regenerating…"
61
+ Bridgetown.logger.info "", "#{n} file(s) changed at #{t.strftime("%Y-%m-%d %H:%M:%S")}"
62
+
63
+ c.each { |path| Bridgetown.logger.info "", path["#{site.source}/".length..-1] }
64
+ process(site, t)
65
+ end
66
+ end
67
+
68
+ def normalize_encoding(obj, desired_encoding)
69
+ case obj
70
+ when Array
71
+ obj.map { |entry| entry.encode!(desired_encoding, entry.encoding) }
72
+ when String
73
+ obj.encode!(desired_encoding, obj.encoding)
74
+ end
75
+ end
76
+
77
+ def custom_excludes(options)
78
+ Array(options["exclude"]).map { |e| Bridgetown.sanitized_path(options["source"], e) }
79
+ end
80
+
81
+ def config_files(options)
82
+ %w(yml yaml toml).map do |ext|
83
+ Bridgetown.sanitized_path(options["source"], "_config.#{ext}")
84
+ end
85
+ end
86
+
87
+ def to_exclude(options)
88
+ [
89
+ config_files(options),
90
+ options["destination"],
91
+ custom_excludes(options),
92
+ ].flatten
93
+ end
94
+
95
+ # Paths to ignore for the watch option
96
+ #
97
+ # options - A Hash of options passed to the command
98
+ #
99
+ # Returns a list of relative paths from source that should be ignored
100
+ # rubocop: disable Metrics/AbcSize
101
+ def listen_ignore_paths(options)
102
+ source = Pathname.new(options["source"]).expand_path
103
+ paths = to_exclude(options)
104
+
105
+ paths.map do |p|
106
+ absolute_path = Pathname.new(normalize_encoding(p, options["source"].encoding)).expand_path
107
+ next unless absolute_path.exist?
108
+
109
+ begin
110
+ relative_path = absolute_path.relative_path_from(source).to_s
111
+ relative_path = File.join(relative_path, "") if absolute_path.directory?
112
+ unless relative_path.start_with?("../")
113
+ path_to_ignore = %r!^#{Regexp.escape(relative_path)}!
114
+ Bridgetown.logger.debug "Watcher:", "Ignoring #{path_to_ignore}"
115
+ path_to_ignore
116
+ end
117
+ rescue ArgumentError
118
+ # Could not find a relative path
119
+ end
120
+ end.compact + [%r!^\.bridgetown\-metadata!]
121
+ end
122
+ # rubocop:enable Metrics/AbcSize
123
+
124
+ def sleep_forever
125
+ loop { sleep 1000 }
126
+ end
127
+
128
+ def process(site, time)
129
+ begin
130
+ site.process
131
+ Bridgetown.logger.info "Done! 🎉", "Completed in #{(Time.now - time).round(3)} seconds."
132
+ rescue StandardError => e
133
+ Bridgetown.logger.warn "Error:", e.message
134
+ Bridgetown.logger.warn "Error:", "Run bridgetown build --trace for more information."
135
+ end
136
+ Bridgetown.logger.info ""
137
+ end
138
+ end
139
+ end