diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2023-04-30 22:30:07 -0600 |
|---|---|---|
| committer | Dan Allen <dan.j.allen@gmail.com> | 2023-05-01 00:50:50 -0600 |
| commit | 2ddb9fc0506b6fe7eb07f3c12dd246aaccae4e9f (patch) | |
| tree | 62ccdc20df60b9696fb9a217d96e6ca21e910083 | |
| parent | db5dd8fd2f2e59030c2daac8690a100f22e523b2 (diff) | |
backport fix for #3929 treat uri:classloader: as absolute path prefix when running on JRuby
| -rw-r--r-- | CHANGELOG.adoc | 1 | ||||
| -rw-r--r-- | docs/modules/html-backend/pages/custom-stylesheet.adoc | 9 | ||||
| -rw-r--r-- | lib/asciidoctor/helpers.rb | 10 | ||||
| -rw-r--r-- | lib/asciidoctor/path_resolver.rb | 13 | ||||
| -rw-r--r-- | test/api_test.rb | 73 | ||||
| -rw-r--r-- | test/blocks_test.rb | 15 | ||||
| -rw-r--r-- | test/fixtures/assets.jar | bin | 0 -> 2442 bytes | |||
| -rw-r--r-- | test/helpers_test.rb | 10 | ||||
| -rw-r--r-- | test/paths_test.rb | 12 | ||||
| -rw-r--r-- | test/reader_test.rb | 9 |
10 files changed, 146 insertions, 6 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 00a359b3..84c444e1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -42,6 +42,7 @@ Bug Fixes:: * Adjust font size of term in horizontal dlist to match font size of term in regular dlist * Implicitly attach nested list that starts with block attribute lines to dlist entry (#4268) * Don't swallow square brackets when processing escaped URL macro + * Treat `uri:classloader:` as an absolute path prefix when running on JRuby (#3929) == 2.0.18 (2022-10-15) - @mojavelinux diff --git a/docs/modules/html-backend/pages/custom-stylesheet.adoc b/docs/modules/html-backend/pages/custom-stylesheet.adoc index 3b6f53c8..d808d9f9 100644 --- a/docs/modules/html-backend/pages/custom-stylesheet.adoc +++ b/docs/modules/html-backend/pages/custom-stylesheet.adoc @@ -159,12 +159,17 @@ That means we can use `stylesdir` and `stylesheet` to assemble the path relative Let's revisit the broken scenario from the previous section and use `copycss` to reconcile the problem: $ asciidoctor -a stylesdir=css -a stylesheet=default.css \ - -a copycss=`pwd`/my-styles/my-stylesheet.css -a linkcss -D public my-document.adoc + -a copycss=$PWD/my-styles/my-stylesheet.css -a linkcss -D public my-document.adoc Asciidoctor copies the stylesheet from the absolute path specified by the `copycss` attribute to the path [.path]_public/css/default.css_ and links to it using the path [.path]_css/default.css_. -Notice that we even changed the name of the folder and stylesheet file in the output. +Notice that we changed the name of the folder and stylesheet file in the output. That demonstrates that we have decoupled the path where the stylesheet is read from the location where the stylesheet is published and referenced. +TIP: When running on JRuby, you can point `copycss` to a classloader URI to load a stylesheet from a JAR file (e.g., `uri:classloader:/css/styles.css`). +However, the HTML cannot link to that location. +Therefore, you must use the `stylesheet` attribute (and optionally the `stylesdir`) to specify a filename or relative path where Asciidoctor will write the stylesheet. +The HTML will then be able to link to that destination. + == Styles directory and nested documents when linking When xref:cli:process-multiple-files.adoc[invoking Asciidoctor on a nested set of documents], it's currently not possible to specify a single relative path for the `stylesdir` attribute that works for all of the documents. diff --git a/lib/asciidoctor/helpers.rb b/lib/asciidoctor/helpers.rb index 789cafe0..a5d2b25e 100644 --- a/lib/asciidoctor/helpers.rb +++ b/lib/asciidoctor/helpers.rb @@ -120,8 +120,14 @@ module Helpers # str - the String to check # # returns true if the String is a URI, false if it is not - def uriish? str - (str.include? ':') && (UriSniffRx.match? str) + if ::RUBY_ENGINE == 'jruby' + def uriish? str + (str.include? ':') && !(str.start_with? 'uri:classloader:') && (UriSniffRx.match? str) + end + else + def uriish? str + (str.include? ':') && (UriSniffRx.match? str) + end end # Internal: Encode a URI component String for safe inclusion in a URI. diff --git a/lib/asciidoctor/path_resolver.rb b/lib/asciidoctor/path_resolver.rb index 82964d1a..f9836494 100644 --- a/lib/asciidoctor/path_resolver.rb +++ b/lib/asciidoctor/path_resolver.rb @@ -109,6 +109,7 @@ class PathResolver SLASH = '/' BACKSLASH = '\\' DOUBLE_SLASH = '//' + URI_CLASSLOADER = 'uri:classloader:' WindowsRootRx = %r(^(?:[a-zA-Z]:)?[\\/]) attr_accessor :file_separator @@ -148,8 +149,9 @@ class PathResolver # Public: Check if the specified path is an absolute root path (or, in the # browser environment, an absolute URI as well) # - # This operation considers both posix paths and Windows paths. If the JavaScript IO - # module is xmlhttprequest, this operation also considers absolute URIs. + # This operation considers both POSIX and Windows paths. If the JavaScript IO module + # is xmlhttprequest, this operation also considers absolute URIs. If running on JRuby, + # this operation also considers classloader URIs (starts with uri:classloader:). # # Unix absolute paths and UNC paths start with slash. Windows roots can # start with a drive letter. When the IO module is xmlhttprequest (Opal @@ -164,6 +166,10 @@ class PathResolver def root? path (absolute_path? path) || (path.start_with? 'file://', 'http://', 'https://') end + elsif ::RUBY_ENGINE == 'jruby' + def root? path + (absolute_path? path) || (path.start_with? URI_CLASSLOADER) + end else alias root? absolute_path? end @@ -299,6 +305,9 @@ class PathResolver # ex. /sample/path elsif posix_path.start_with? SLASH root = SLASH + # ex. uri:classloader:sample/path (or uri:classloader:/sample/path) + elsif posix_path.start_with? URI_CLASSLOADER + root = posix_path.slice 0, URI_CLASSLOADER.length # ex. C:/sample/path (or file:///sample/path in browser environment) else root = posix_path.slice 0, (posix_path.index SLASH) + 1 diff --git a/test/api_test.rb b/test/api_test.rb index 3854046f..2a8984e9 100644 --- a/test/api_test.rb +++ b/test/api_test.rb @@ -1337,6 +1337,22 @@ context 'API' do assert_include 'color: green', styles end + test 'should embed custom stylesheet read from classloader URI', if: jruby? do + require fixture_path 'assets.jar' + input = <<~'EOS' + = Document Title + + text + EOS + + output = Asciidoctor.convert input, safe: :unsafe, standalone: true, attributes: { 'stylesdir' => 'uri:classloader:/styles-in-jar', 'stylesheet' => 'custom.css' } + stylenode = xmlnodes_at_css 'html:root > head > style', output, 1 + styles = stylenode.content + refute_nil styles + refute_empty styles.strip + assert_include 'color: green', styles + end + test 'should embed custom stylesheet in remote stylesdir if SafeMode is less than SECURE and allow-uri-read is set' do input = <<~'EOS' = Document Title @@ -1390,6 +1406,63 @@ context 'API' do end end + test 'should copy custom stylesheet to destination dir if copycss is a path string' do + begin + output_dir = fixture_path 'output' + sample_input_path = fixture_path 'sample.adoc' + sample_output_path = File.join output_dir, 'sample.html' + custom_stylesheet_output_path = File.join output_dir, 'styles.css' + Asciidoctor.convert_file sample_input_path, + safe: :safe, to_dir: output_dir, mkdirs: true, attributes: { 'stylesheet' => 'styles.css', 'linkcss' => true, 'copycss' => 'custom.css' } + assert_path_exists sample_output_path + assert_path_exists custom_stylesheet_output_path + output = File.read sample_output_path, mode: Asciidoctor::FILE_READ_MODE + assert_xpath '/html/head/link[@rel="stylesheet"][@href="./styles.css"]', output, 1 + assert_xpath 'style', output, 0 + ensure + FileUtils.rm_r output_dir, force: true, secure: true + end + end + + test 'should copy custom stylesheet to destination dir if copycss is a Pathname object' do + begin + output_dir = fixture_path 'output' + sample_input_path = fixture_path 'sample.adoc' + sample_output_path = File.join output_dir, 'sample.html' + custom_stylesheet_src_path = Pathname.new fixture_path 'custom.css' + custom_stylesheet_output_path = File.join output_dir, 'styles.css' + Asciidoctor.convert_file sample_input_path, + safe: :safe, to_dir: output_dir, mkdirs: true, attributes: { 'stylesheet' => 'styles.css', 'linkcss' => true, 'copycss' => custom_stylesheet_src_path } + assert_path_exists sample_output_path + assert_path_exists custom_stylesheet_output_path + output = File.read sample_output_path, mode: Asciidoctor::FILE_READ_MODE + assert_xpath '/html/head/link[@rel="stylesheet"][@href="./styles.css"]', output, 1 + assert_xpath 'style', output, 0 + ensure + FileUtils.rm_r output_dir, force: true, secure: true + end + end + + test 'should copy custom stylesheet to destination dir if copycss is a classloader URI', if: jruby? do + require fixture_path 'assets.jar' + begin + output_dir = fixture_path 'output' + sample_input_path = fixture_path 'sample.adoc' + sample_output_path = File.join output_dir, 'sample.html' + custom_stylesheet_src_path = 'uri:classloader:/styles-in-jar/custom.css' + custom_stylesheet_output_path = File.join output_dir, 'styles.css' + Asciidoctor.convert_file sample_input_path, + safe: :unsafe, to_dir: output_dir, mkdirs: true, attributes: { 'stylesheet' => 'styles.css', 'linkcss' => true, 'copycss' => custom_stylesheet_src_path } + assert_path_exists sample_output_path + assert_path_exists custom_stylesheet_output_path + output = File.read sample_output_path, mode: Asciidoctor::FILE_READ_MODE + assert_xpath '/html/head/link[@rel="stylesheet"][@href="./styles.css"]', output, 1 + assert_xpath 'style', output, 0 + ensure + FileUtils.rm_r output_dir, force: true, secure: true + end + end + test 'should convert source file and write result to adjacent file by default' do sample_input_path = fixture_path('sample.adoc') sample_output_path = fixture_path('sample.html') diff --git a/test/blocks_test.rb b/test/blocks_test.rb index 0ec49ccb..205be236 100644 --- a/test/blocks_test.rb +++ b/test/blocks_test.rb @@ -2857,6 +2857,21 @@ context 'Blocks' do assert_xpath '//img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Dot"]', output, 1 end + test 'embeds base64-encoded data uri for image in classloader when data-uri attribute is set', if: jruby? do + require fixture_path 'assets.jar' + input = <<~'EOS' + :data-uri: + :imagesdir: uri:classloader:/images-in-jar + + image::dot.gif[Dot] + EOS + + doc = document_from_string input, safe: Asciidoctor::SafeMode::UNSAFE, attributes: { 'docdir' => testdir } + assert_equal 'uri:classloader:/images-in-jar', doc.attributes['imagesdir'] + output = doc.convert + assert_xpath '//img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Dot"]', output, 1 + end + test 'embeds SVG image with image/svg+xml mimetype when file extension is .svg' do input = <<~'EOS' :imagesdir: fixtures diff --git a/test/fixtures/assets.jar b/test/fixtures/assets.jar Binary files differnew file mode 100644 index 00000000..cc47d3b8 --- /dev/null +++ b/test/fixtures/assets.jar diff --git a/test/helpers_test.rb b/test/helpers_test.rb index 17080056..6f733b55 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -51,6 +51,16 @@ context 'Helpers' do assert Asciidoctor::UriSniffRx !~ 'c:\\sample.adoc' end + test 'uriish? should not detect a classloader path as a URI on JRuby' do + input = 'uri:classloader:/sample.png' + assert Asciidoctor::UriSniffRx =~ input + if jruby? + refute Asciidoctor::Helpers.uriish? input + else + assert Asciidoctor::Helpers.uriish? input + end + end + test 'UriSniffRx should not detect URI that does not start on first line' do assert Asciidoctor::UriSniffRx !~ %(text\nhttps://example.org) end diff --git a/test/paths_test.rb b/test/paths_test.rb index 4170e4e5..4e4f2ad4 100644 --- a/test/paths_test.rb +++ b/test/paths_test.rb @@ -294,6 +294,18 @@ context 'Path Resolver' do assert_equal '//server/docs/output.html', @resolver.system_path('//server/docs/output.html') end + test 'resolves classloader path if start is classloader path and target is relative', if: jruby? do + assert_equal 'uri:classloader:images/sample.png', @resolver.system_path('sample.png', 'uri:classloader:images') + end + + test 'resolves classloader path if start is root-relative classloader path and target is relative', if: jruby? do + assert_equal 'uri:classloader:/images/sample.png', @resolver.system_path('sample.png', 'uri:classloader:/images') + end + + test 'preserves classloader path if start is absolute path and target is classloader path', if: jruby? do + assert_equal 'uri:classloader:/images/sample.png', @resolver.system_path('uri:classloader:/images/sample.png', '/home/doctor/docs') + end + test 'resolves relative target relative to current directory if start is empty' do pwd = File.expand_path(Dir.pwd) assert_equal "#{pwd}/images/tiger.png", @resolver.system_path('images/tiger.png', '') diff --git a/test/reader_test.rb b/test/reader_test.rb index cf4eaa57..3c78bed5 100644 --- a/test/reader_test.rb +++ b/test/reader_test.rb @@ -678,6 +678,15 @@ class ReaderTest < Minitest::Test assert_match(/<h1>人<\/h1>/, output) end + test 'should include content from a file on the classloader', if: jruby? do + require fixture_path 'assets.jar' + input = 'include::uri:classloader:/includes-in-jar/include-file.adoc[]' + doc = document_from_string input, safe: :unsafe, standalone: false, base_dir: DIRNAME + output = doc.convert + assert_match(/included from a file/, output) + assert doc.catalog[:includes]['uri:classloader:/includes-in-jar/include-file'] + end + test 'should not track include in catalog for non-AsciiDoc include files' do input = <<~'EOS' ---- |
