Skip to content

Commit

Permalink
resolves #3929 treat uri:classloader: as absolute path prefix when ru…
Browse files Browse the repository at this point in the history
…nning on JRuby (PR #4444)
  • Loading branch information
mojavelinux committed May 1, 2023
1 parent 72259cb commit 5559941
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Expand Up @@ -79,6 +79,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

Expand Down
9 changes: 7 additions & 2 deletions docs/modules/html-backend/pages/custom-stylesheet.adoc
Expand Up @@ -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.
Expand Down
10 changes: 8 additions & 2 deletions lib/asciidoctor/helpers.rb
Expand Up @@ -121,8 +121,14 @@ def prepare_source_string data, trim_end = true
# 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.
Expand Down
13 changes: 11 additions & 2 deletions lib/asciidoctor/path_resolver.rb
Expand Up @@ -110,6 +110,7 @@ class PathResolver
SLASH = '/'
BACKSLASH = '\\'
DOUBLE_SLASH = '//'
URI_CLASSLOADER = 'uri:classloader:'
WindowsRootRx = %r(^(?:[a-zA-Z]:)?[\\/])

attr_accessor :file_separator
Expand Down Expand Up @@ -149,8 +150,9 @@ def absolute_path? path
# 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
Expand All @@ -165,6 +167,10 @@ def absolute_path? path
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
Expand Down Expand Up @@ -300,6 +306,9 @@ def partition_path path, web = nil
# 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
Expand Down
36 changes: 36 additions & 0 deletions test/api_test.rb
Expand Up @@ -1348,6 +1348,22 @@ def for name
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
Expand Down Expand Up @@ -1438,6 +1454,26 @@ def for name
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'
Expand Down
15 changes: 15 additions & 0 deletions test/blocks_test.rb
Expand Up @@ -2894,6 +2894,21 @@ def names
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
Expand Down
Binary file added test/fixtures/assets.jar
Binary file not shown.
10 changes: 10 additions & 0 deletions test/helpers_test.rb
Expand Up @@ -52,6 +52,16 @@
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
Expand Down
12 changes: 12 additions & 0 deletions test/paths_test.rb
Expand Up @@ -284,6 +284,18 @@ def setup
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', '')
Expand Down
9 changes: 9 additions & 0 deletions test/reader_test.rb
Expand Up @@ -740,6 +740,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'
----
Expand Down

0 comments on commit 5559941

Please sign in to comment.